fix(pcat): robust year extraction across key spelling + date format
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Broadened extractYearFromPcatCar after auditing 176 null-year prod pcat vehicles: the build date sits under "production date" (space) far more often than "production_date" (underscore), and values come both year-first (2006/02/27) and day-first (08/03/2016). Match the date key by spelling-agnostic substring and pull the 4-digit year via regex so parseInt no longer reads the day. Concrete Year param still wins over build date. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -654,19 +654,33 @@ describe("VehiclesService", () => {
|
||||
expect(year).toBe(2021);
|
||||
});
|
||||
|
||||
it("falls back to production_date when no numeric Year param exists", () => {
|
||||
const extractYear = (parameters: unknown[]) => {
|
||||
const { service } = createService();
|
||||
const year = (
|
||||
return (
|
||||
service as unknown as {
|
||||
extractYearFromPcatCar: (c: { parameters: unknown[] }) => number | null;
|
||||
}
|
||||
).extractYearFromPcatCar({
|
||||
parameters: [
|
||||
).extractYearFromPcatCar({ parameters });
|
||||
};
|
||||
|
||||
it("falls back to year-first production date (space-keyed)", () => {
|
||||
expect(
|
||||
extractYear([
|
||||
{ key: "year", name: "Year", value: "All" },
|
||||
{ key: "production_date", name: "Production date", value: "2020/10/05" },
|
||||
],
|
||||
});
|
||||
expect(year).toBe(2020);
|
||||
{ key: "production date", name: "Production date", value: "2020/10/05" },
|
||||
]),
|
||||
).toBe(2020);
|
||||
});
|
||||
|
||||
it("reads the year from a DAY-first production date (DD/MM/YYYY)", () => {
|
||||
// parseInt("08/03/2016") would have returned 8 (the day) — regex saves us.
|
||||
expect(
|
||||
extractYear([{ key: "production date", name: "Production date", value: "08/03/2016" }]),
|
||||
).toBe(2016);
|
||||
});
|
||||
|
||||
it("ignores the year=All axis with no concrete year/date", () => {
|
||||
expect(extractYear([{ key: "year", name: "Year", value: "All" }])).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1186,25 +1186,31 @@ export class VehiclesService {
|
||||
|
||||
private extractYearFromPcatCar(car: PcatCar): number | null {
|
||||
if (!car.parameters) return null;
|
||||
// pcat returns a faceting AXIS param `year` (often value "All") BEFORE the
|
||||
// concrete per-car `Year` param, so a naive find(includes("year")) grabs the
|
||||
// axis → parseInt("All") = NaN → null. Scan every year-ish param and take the
|
||||
// first that parses to a plausible year; only then fall back to a
|
||||
// production_date like "2020/10/05".
|
||||
const plausible = (raw: string | undefined): number | null => {
|
||||
const num = Number.parseInt(raw ?? "", 10);
|
||||
return num > 1900 && num < 2100 ? num : null;
|
||||
// pcat is messy about year. Three traps:
|
||||
// 1. A faceting AXIS param key="year" value="All" precedes the concrete
|
||||
// per-car key="Year" value="2021" — a naive find(includes("year")) grabs
|
||||
// the axis and parseInt("All")=NaN.
|
||||
// 2. The build date lives under key "production date" (space) on most cars,
|
||||
// "production_date" (underscore) on others.
|
||||
// 3. Those dates come in BOTH "2006/02/27" (year-first) and "08/03/2016"
|
||||
// (day-first), so parseInt would read the day. Pull a 4-digit 19xx/20xx
|
||||
// token by regex instead — robust to either ordering.
|
||||
const yearIn = (raw: string | undefined): number | null => {
|
||||
const m = (raw ?? "").match(/\b(19|20)\d{2}\b/);
|
||||
return m ? Number.parseInt(m[0], 10) : null;
|
||||
};
|
||||
// Prefer an explicit year param (skips the "All" axis, which has no digits).
|
||||
for (const p of car.parameters) {
|
||||
const key = p.key.toLowerCase();
|
||||
if (key.includes("year") || key.includes("model_year")) {
|
||||
const year = plausible(p.value);
|
||||
const year = yearIn(p.value);
|
||||
if (year) return year;
|
||||
}
|
||||
}
|
||||
// Fall back to the specific car's build date (either key spelling / format).
|
||||
for (const p of car.parameters) {
|
||||
if (p.key.toLowerCase().includes("production_date")) {
|
||||
const year = plausible(p.value);
|
||||
if (p.key.toLowerCase().includes("production") && p.key.toLowerCase().includes("date")) {
|
||||
const year = yearIn(p.value);
|
||||
if (year) return year;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user