Files
familienarchiv/frontend/src/lib/timeline/dateLabel.ts
Marcel 956a23d0a8 feat(timeline): add precision-aware date-label facade
timelineDateLabel delegates to the shared formatDocumentDate so a timeline
chip renders identically to the same date on a document, in the active
locale (REQ-001/REQ-002). UNKNOWN precision and null/undefined/'' eventDate
short-circuit to null with no formatter call (REQ-003/REQ-004); raw is always
null since timeline events carry no verbatim spreadsheet cell. The facade
owns no precision logic of its own (REQ-005).

Register the new `timeline` frontend domain in the eslint boundaries config
(allowed to import only `shared`) and add src/lib/timeline/** to the vitest
coverage include (REQ-006). The spec partially mocks the paraglide runtime
via importOriginal so getLocale is stubbed while the formatter still resolves
real season/range message exports.

Refs #778
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 13:16:33 +02:00

31 lines
1.5 KiB
TypeScript

import { formatDocumentDate, type DatePrecision } from '$lib/shared/utils/documentDate';
import { getLocale } from '$lib/paraglide/runtime.js';
/**
* Renders a timeline event's date by delegating to the shared
* {@link formatDocumentDate} — so a timeline chip reads identically to the same
* date on a document, in whichever locale is active. This module is a thin
* façade: it owns NO precision or rendering logic (REQ-005), only the two
* timeline-specific decisions below.
*
* @param eventDate the event's anchor day (`YYYY-MM-DD`). `null`, `undefined`
* and `''` are equivalent — all mean "undated" and yield `null` WITHOUT
* calling the formatter (REQ-004).
* @param precision the event's precision metadata; `'UNKNOWN'` yields `null`
* (no chip) even when a date is present (REQ-003).
* @param eventDateEnd the RANGE end day; `undefined` and `null` are equivalent
* and both mean an open-ended range.
* @returns the localized label, or `null` for an UNKNOWN/undated event.
*/
export function timelineDateLabel(
eventDate: string | null | undefined,
precision: DatePrecision,
eventDateEnd?: string | null
): string | null {
if (precision === 'UNKNOWN' || !eventDate) return null;
// raw is always null for timeline events — there is no verbatim spreadsheet
// cell to interpolate; season words derive from the structured anchor month
// (never from untrusted text). See documentDate.ts for the raw contract.
return formatDocumentDate(eventDate, precision, eventDateEnd ?? null, null, getLocale());
}