fix(jobdanmark-search): accept a comma after the postcode in location extraction

The location regex required whitespace after the 4-digit postcode, but
live companyAddress values frequently read "2670, Greve" - those results
emitted location: null (7/30 in the review's live sample; 1/30 after this
fix), leaving /scrape's geography filter nothing to act on. Extraction is
now a helper with a comma fallback that requires a non-digit city start,
so a 4-digit street number never wins over the real postcode, and the
captured city is trimmed. Review finding F2 (2026-08-19).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mads Lorentzen
2026-08-19 19:46:34 +02:00
co-authored by Claude Opus 5
parent b2545d5121
commit 7aba0b4a9d
3 changed files with 47 additions and 1 deletions
@@ -39,6 +39,18 @@ function toContractDate(value: string | null): string | null {
return match ? `${match[3]}-${match[2]}-${match[1]}` : (value ?? null)
}
// Live companyAddress values put the city after the postcode either as
// "Lautruphoej 2, 2750 Ballerup" or "2670, Greve". The comma fallback
// requires a non-digit after the comma so a 4-digit street number
// ("Vejlevej 1234, 7100 Vejle") never wins over the real postcode.
function extractCity(address: string | null): string | null {
if (!address) return null
const city =
address.match(/\d{4}\s+(.+)$/)?.[1] ?? address.match(/\d{4}\s*,\s*([^\d,].*)$/)?.[1]
const trimmed = city?.trim()
return trimmed ? trimmed : null
}
export function normalizeItem(item: ApiSearchItem): Record<string, unknown> {
const relativeUrl = item.url
const fullUrl = relativeUrl.startsWith("http")
@@ -83,7 +95,7 @@ export function normalizeItem(item: ApiSearchItem): Record<string, unknown> {
coverImage,
silhouetteLogo: item.silhouetteLogo,
company: item.companyName,
location: item.companyAddress?.match(/\d{4}\s+(.+)$/)?.[1] ?? null,
location: extractCity(item.companyAddress),
date: toContractDate(item.publishedDate),
deadline: toContractDate(item.applicationDeadline),
}
@@ -44,6 +44,33 @@ describe("Jobdanmark search normalization", () => {
expect(result.company).toBe("Statens It");
});
test("extracts the city when a comma follows the postcode (live jobdanmark shape)", () => {
const result = normalizeItem({
...item(),
companyAddress: "2670, Greve",
});
expect(result.location).toBe("Greve");
});
test("trims trailing whitespace from the extracted city", () => {
const result = normalizeItem({
...item(),
companyAddress: "7100, Vejle ",
});
expect(result.location).toBe("Vejle");
});
test("does not mistake a 4-digit street number for the postcode", () => {
const result = normalizeItem({
...item(),
companyAddress: "Vejlevej 1234, 7100 Vejle",
});
expect(result.location).toBe("Vejle");
});
test("survives a null companyAddress from the API", () => {
const result = normalizeItem({
...item(),
+7
View File
@@ -56,6 +56,13 @@ per-file diff commands.
### Fixed
- **`jobdanmark-search` extracts the city when a comma follows the postcode** - the
`location` regex required whitespace after the 4-digit postcode, but live
`companyAddress` values frequently read `"2670, Greve"`; those results emitted
`location: null` (7 of 30 in a live sample), so `/scrape`'s geography/commute filter
(Rule 3) had nothing to act on. The extraction now accepts an optional comma, trims the
captured city, and still refuses to mistake a 4-digit street number for the postcode.
Pinned by three new cases in `tests/search-normalization.test.ts`.
- **Example-CV bullets no longer swallowed as LaTeX optional labels** - every placeholder
bullet written as `\item [text]` (11 in `cv/main_example.tex`, 3 in
`06-cover-letter-templates.md`'s taught template) let LaTeX parse the bracketed text as