From 063d1aac55c3f8924bbd41e7cba9f9d5c10fdec2 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 14 Jun 2026 20:21:21 +0200 Subject: [PATCH] refactor(frontend): share formatDatePart between life dates and relationships MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit formatLifeDate and the relationship formatEnd were the same nullable-date → formatDocumentDate delegation (YEAR fallback, '' on null). Hoist that core into formatDatePart in documentDate.ts; formatLifeDate becomes a thin glyph-free alias and formatRelationshipDateRange calls the shared helper directly. The two range composers stay separate — they genuinely differ (*/† glyphs vs leading dash). relationshipDates, personLifeDates and documentDate specs (60) stay green. Co-Authored-By: Claude Opus 4.8 --- frontend/src/lib/person/personLifeDates.ts | 18 +++++---------- frontend/src/lib/person/relationshipDates.ts | 23 +++---------------- frontend/src/lib/shared/utils/documentDate.ts | 21 +++++++++++++++++ 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/frontend/src/lib/person/personLifeDates.ts b/frontend/src/lib/person/personLifeDates.ts index c6d72adc..05af302a 100644 --- a/frontend/src/lib/person/personLifeDates.ts +++ b/frontend/src/lib/person/personLifeDates.ts @@ -1,23 +1,17 @@ -import { formatDocumentDate, type DatePrecision } from '$lib/shared/utils/documentDate'; +import { formatDatePart, type DatePrecision } from '$lib/shared/utils/documentDate'; /** - * Formats one life date (birth or death) at the precision the data claims, - * delegating all rendering to {@link formatDocumentDate}. Returns '' for a - * missing date. Carries no * / † glyph — components that need the glyphs wrap - * them in their own `aria-hidden` markup so screen readers only hear the date. - * - * A missing precision falls back to YEAR: pre-V76 rows only knew a year, and - * a bare year is the only safe rendering for a date without precision metadata. + * Formats one life date (birth or death) at the precision the data claims. + * Thin domain alias over the shared {@link formatDatePart}: carries no * / † + * glyph — components that need the glyphs wrap them in their own `aria-hidden` + * markup so screen readers only hear the date. */ export function formatLifeDate( date: string | null | undefined, precision: DatePrecision | null | undefined, locale?: string ): string { - if (!date) { - return ''; - } - return formatDocumentDate(date, precision ?? 'YEAR', null, null, locale); + return formatDatePart(date, precision, locale); } /** diff --git a/frontend/src/lib/person/relationshipDates.ts b/frontend/src/lib/person/relationshipDates.ts index 8d2a74a0..76bc79f9 100644 --- a/frontend/src/lib/person/relationshipDates.ts +++ b/frontend/src/lib/person/relationshipDates.ts @@ -1,21 +1,4 @@ -import { formatDocumentDate, type DatePrecision } from '$lib/shared/utils/documentDate'; - -/** - * Formats one relationship endpoint (start or end) at the precision the data - * claims, delegating all rendering to {@link formatDocumentDate}. Returns '' for - * a missing date. A missing precision falls back to YEAR — pre-V78 rows only knew - * a year. Mirrors {@link formatLifeDate} for the person life-date pattern. - */ -function formatEnd( - date: string | null | undefined, - precision: DatePrecision | null | undefined, - locale?: string -): string { - if (!date) { - return ''; - } - return formatDocumentDate(date, precision ?? 'YEAR', null, null, locale); -} +import { formatDatePart, type DatePrecision } from '$lib/shared/utils/documentDate'; /** * Formats a relationship's start–end range as plain text, e.g. for a marriage row. @@ -32,8 +15,8 @@ export function formatRelationshipDateRange( toDatePrecision: DatePrecision | null | undefined, locale?: string ): string { - const from = formatEnd(fromDate, fromDatePrecision, locale); - const to = formatEnd(toDate, toDatePrecision, locale); + const from = formatDatePart(fromDate, fromDatePrecision, locale); + const to = formatDatePart(toDate, toDatePrecision, locale); if (from && to) { return `${from} – ${to}`; } diff --git a/frontend/src/lib/shared/utils/documentDate.ts b/frontend/src/lib/shared/utils/documentDate.ts index d46f6346..01143892 100644 --- a/frontend/src/lib/shared/utils/documentDate.ts +++ b/frontend/src/lib/shared/utils/documentDate.ts @@ -66,6 +66,27 @@ export function formatDocumentDate( } } +/** + * Formats one nullable date at the precision the data claims, delegating all + * rendering to {@link formatDocumentDate}. Returns '' for a missing date; a + * missing precision falls back to YEAR — pre-precision rows knew only a year, + * and a bare year is the only safe rendering without precision metadata. + * + * This is the shared core of {@link formatLifeDate} (person birth/death) and the + * relationship from/to formatter. Range-level glyphs and dashes belong in those + * domain wrappers, never here. + */ +export function formatDatePart( + date: string | null | undefined, + precision: DatePrecision | null | undefined, + locale?: string +): string { + if (!date) { + return ''; + } + return formatDocumentDate(date, precision ?? 'YEAR', null, null, locale); +} + // ─── precision branches ────────────────────────────────────────────────────── function longDate(iso: string, locale: string): string {