mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-09-17 08:36:25 +00:00
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:
co-authored by
Claude Opus 5
parent
b2545d5121
commit
7aba0b4a9d
@@ -39,6 +39,18 @@ function toContractDate(value: string | null): string | null {
|
|||||||
return match ? `${match[3]}-${match[2]}-${match[1]}` : (value ?? 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> {
|
export function normalizeItem(item: ApiSearchItem): Record<string, unknown> {
|
||||||
const relativeUrl = item.url
|
const relativeUrl = item.url
|
||||||
const fullUrl = relativeUrl.startsWith("http")
|
const fullUrl = relativeUrl.startsWith("http")
|
||||||
@@ -83,7 +95,7 @@ export function normalizeItem(item: ApiSearchItem): Record<string, unknown> {
|
|||||||
coverImage,
|
coverImage,
|
||||||
silhouetteLogo: item.silhouetteLogo,
|
silhouetteLogo: item.silhouetteLogo,
|
||||||
company: item.companyName,
|
company: item.companyName,
|
||||||
location: item.companyAddress?.match(/\d{4}\s+(.+)$/)?.[1] ?? null,
|
location: extractCity(item.companyAddress),
|
||||||
date: toContractDate(item.publishedDate),
|
date: toContractDate(item.publishedDate),
|
||||||
deadline: toContractDate(item.applicationDeadline),
|
deadline: toContractDate(item.applicationDeadline),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,33 @@ describe("Jobdanmark search normalization", () => {
|
|||||||
expect(result.company).toBe("Statens It");
|
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", () => {
|
test("survives a null companyAddress from the API", () => {
|
||||||
const result = normalizeItem({
|
const result = normalizeItem({
|
||||||
...item(),
|
...item(),
|
||||||
|
|||||||
@@ -56,6 +56,13 @@ per-file diff commands.
|
|||||||
|
|
||||||
### Fixed
|
### 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
|
- **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
|
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
|
`06-cover-letter-templates.md`'s taught template) let LaTeX parse the bracketed text as
|
||||||
|
|||||||
Reference in New Issue
Block a user