temporal-fmt 0.9.2 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -1
- package/dist/chunk-4JDAJSEM.js +35 -0
- package/dist/chunk-4JDAJSEM.js.map +1 -0
- package/dist/{chunk-F4RGUDA3.js → chunk-4XRE37WT.js} +2 -2
- package/dist/chunk-GMGZZG6I.js +2 -0
- package/dist/chunk-GMGZZG6I.js.map +1 -0
- package/dist/{chunk-R52YOKI3.js → chunk-NPKJ7QFK.js} +2 -2
- package/dist/{chunk-NBXF7V5B.js → chunk-R4YEFOVE.js} +2 -2
- package/dist/{chunk-4JWGUR4O.js → chunk-SSPABEUR.js} +2 -2
- package/dist/format.cjs +5 -5
- package/dist/format.cjs.map +1 -1
- package/dist/format.js +1 -1
- package/dist/index.cjs +24 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/interval.cjs +2 -2
- package/dist/interval.cjs.map +1 -1
- package/dist/interval.js +1 -1
- package/dist/parse.cjs +9 -9
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.js +1 -1
- package/dist/pattern.d.cts +1 -0
- package/dist/pattern.d.ts +1 -0
- package/dist/relativeTime.cjs +1 -1
- package/dist/relativeTime.cjs.map +1 -1
- package/dist/relativeTime.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-C5YESWFT.js +0 -2
- package/dist/chunk-C5YESWFT.js.map +0 -1
- package/dist/chunk-YB6YAG7E.js +0 -35
- package/dist/chunk-YB6YAG7E.js.map +0 -1
- /package/dist/{chunk-F4RGUDA3.js.map → chunk-4XRE37WT.js.map} +0 -0
- /package/dist/{chunk-R52YOKI3.js.map → chunk-NPKJ7QFK.js.map} +0 -0
- /package/dist/{chunk-NBXF7V5B.js.map → chunk-R4YEFOVE.js.map} +0 -0
- /package/dist/{chunk-4JWGUR4O.js.map → chunk-SSPABEUR.js.map} +0 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/formatDistance.ts","../src/relativeGrammar.ts","../src/parseRelative.ts","../src/typeGuards.ts","../src/tokenMetadata.ts","../src/analyze.ts","../src/serialization.ts","../src/config.ts","../src/businessCalendar.ts","../src/holidays.ts","../src/extensibility.ts","../src/ideData.ts","../src/codemod.ts"],"sourcesContent":["import { DEFAULT_LOCALE, type FormatOptions } from './tokens.js';\nimport { dayOfYear, isGregorianLeapYear } from './isoWeek.js';\nimport { normalizeLocaleTag } from './localeVocab.js';\nimport { InvalidLocaleError } from './errors.js';\n\n// Reads date fields off a Temporal value in the same minimal-shape style\n// as the rest of the library (TemporalLike) — no Temporal factory needed.\n// Works for PlainDate, PlainDateTime, and ZonedDateTime (since they all\n// expose year/month/day). PlainTime has no date fields; formatDistance()\n// between two PlainTime values isn't really meaningful and isn't\n// supported — it'll throw below when the field read fails.\ninterface DateFieldView {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\nfunction readFields(value: unknown, label: string): DateFieldView {\n if (value === null || typeof value !== 'object') {\n throw new Error(\n `temporal-fmt: formatDistance expects Temporal values, got ${label} = ${String(value)}.`\n );\n }\n const obj = value as Record<string, unknown>;\n // Either year/month/day (a real date) or none of them (a PlainTime);\n // anything in between would be a malformed Temporal-like.\n const hasYear = typeof obj.year === 'number';\n const hasMonth = typeof obj.month === 'number';\n const hasDay = typeof obj.day === 'number';\n if (hasYear !== hasMonth || hasMonth !== hasDay) {\n throw new Error(\n `temporal-fmt: formatDistance got a ${label} with a partial date (some of year/month/day missing). ` +\n `Pass a full Temporal.PlainDate / PlainDateTime / ZonedDateTime.`\n );\n }\n return {\n year: hasYear ? (obj.year as number) : undefined,\n month: hasMonth ? (obj.month as number) : undefined,\n day: hasDay ? (obj.day as number) : undefined,\n hour: typeof obj.hour === 'number' ? (obj.hour as number) : undefined,\n minute: typeof obj.minute === 'number' ? (obj.minute as number) : undefined,\n second: typeof obj.second === 'number' ? (obj.second as number) : undefined,\n millisecond: typeof obj.millisecond === 'number' ? (obj.millisecond as number) : undefined,\n };\n}\n\n// Reference epoch for ms-since computation. Jan 1, 2000 UTC is the same\n// anchor isoWeek.ts uses for day-of-week arithmetic; reusing it keeps the\n// reasoning localized to one well-known reference date.\nconst REFERENCE_YEAR = 2000;\nconst MS_PER_SECOND = 1000;\nconst MS_PER_MINUTE = 60 * MS_PER_SECOND;\nconst MS_PER_HOUR = 60 * MS_PER_MINUTE;\nconst MS_PER_DAY = 24 * MS_PER_HOUR;\n\nfunction daysSinceReference(year: number, month: number, day: number): number {\n let days = 0;\n if (year >= REFERENCE_YEAR) {\n for (let y = REFERENCE_YEAR; y < year; y++) {\n days += isGregorianLeapYear(y) ? 366 : 365;\n }\n } else {\n for (let y = year; y < REFERENCE_YEAR; y++) {\n days -= isGregorianLeapYear(y) ? 366 : 365;\n }\n }\n days += dayOfYear(year, month, day) - 1;\n return days;\n}\n\nfunction toEpochMs(fields: DateFieldView): number {\n // A PlainDate has no time fields — treat as midnight. A PlainDateTime\n // has them all. Comparing two PlainDates is a day-resolution diff;\n // comparing two PlainDateTimes is millisecond-resolution. Mixing the\n // two (one PlainDate, one PlainDateTime) is allowed and just means the\n // PlainDate side is treated as midnight, which is what most callers\n // would intuitively expect (\"distance from this date to this moment\").\n if (fields.year === undefined || fields.month === undefined || fields.day === undefined) {\n throw new Error(\n `temporal-fmt: formatDistance needs a Temporal value with year/month/day fields ` +\n `(PlainDate, PlainDateTime, or ZonedDateTime). A PlainTime or other shape ` +\n `has no anchor date to diff against.`\n );\n }\n const days = daysSinceReference(fields.year, fields.month, fields.day);\n const hour = fields.hour ?? 0;\n const minute = fields.minute ?? 0;\n const second = fields.second ?? 0;\n const millisecond = fields.millisecond ?? 0;\n return days * MS_PER_DAY + hour * MS_PER_HOUR + minute * MS_PER_MINUTE + second * MS_PER_SECOND + millisecond;\n}\n\n// Unit selection cutoffs. Mirrors the rough thresholds date-fns uses,\n// trimmed to the units Intl.RelativeTimeFormat supports in every engine\n// (it accepts 'second' through 'year'; 'quarter' and 'week' support\n// varies, so we skip 'week' here — going days → months directly at the\n// 30-day boundary is simpler and avoids the engine-support cliff).\n//\n// |diff| < 60 s → seconds (\"30 seconds ago\")\n// |diff| < 60 min → minutes (\"12 minutes ago\")\n// |diff| < 24 h → hours (\"3 hours ago\")\n// |diff| < 30 d → days (\"5 days ago\")\n// |diff| < 365 d → months (\"2 months ago\")\n// otherwise → years (\"1 year ago\")\n//\n// 30 days is an approximation of a month — a calendar month is 28-31\n// days, so the boundary is inherently fuzzy. Same with 365 days for a\n// year. Documented as approximations, not exact calendar arithmetic.\n//\n// `cutoffs` on FormatDistanceOptions overrides individual boundaries\n// per call. DEFAULT_CUTOFFS holds the same numbers as the old hardcoded\n// UNIT_CUTOFFS so callers passing nothing see the same output as\n// before — verified byte-for-byte against the pre-change baseline.\nconst DEFAULT_CUTOFFS = {\n seconds: 60, // 60 s\n minutes: 60, // 60 min\n hours: 24, // 24 h\n days: 30, // 30 d\n months: 365, // 365 d (in days, since the months→years boundary is day-resolution)\n} as const;\n\ntype CutoffKey = keyof typeof DEFAULT_CUTOFFS;\n\n// Cutoffs the caller can override. Each value is in the unit's own\n// native scale (seconds for `seconds`, minutes for `minutes`, etc.) —\n// `months` is the exception: it's the day count that bounds the\n// months→years crossover, since \"months\" itself isn't a fixed number\n// of days. This mirrors how the original hardcoded table expressed\n// the same boundary (30 * MS_PER_DAY for days, 365 * MS_PER_DAY for\n// the months cap) and lets callers say \"treat anything under 90 days\n// as months\" rather than \"anything under 3 months as months\" (which\n// would require picking a definition of \"month\").\nexport interface DistanceCutoffs {\n seconds?: number;\n minutes?: number;\n hours?: number;\n days?: number;\n months?: number;\n}\n\n// Convert the user-facing cutoffs (per-unit numbers) into the ms\n// thresholds the matching loop needs. Validates each value is a\n// positive finite number, and that the boundaries are monotonically\n// non-decreasing in equivalent ms — without that, the smallest-bound\n// branch always wins and a later branch becomes unreachable, which\n// is never what the caller intended.\nfunction resolveCutoffs(user?: DistanceCutoffs): Array<{ maxMs: number; unit: Intl.RelativeTimeFormatUnit }> {\n const merged: Record<CutoffKey, number> = { ...DEFAULT_CUTOFFS, ...user };\n\n for (const key of Object.keys(merged) as CutoffKey[]) {\n const value = merged[key];\n if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) {\n throw new Error(\n `temporal-fmt: formatDistance cutoff \"${key}\" must be a positive finite number (got ${String(value)}).`\n );\n }\n }\n\n const secondsMs = merged.seconds * MS_PER_SECOND;\n const minutesMs = merged.minutes * MS_PER_MINUTE;\n const hoursMs = merged.hours * MS_PER_HOUR;\n const daysMs = merged.days * MS_PER_DAY;\n // `months` is in days — see DistanceCutoffs comment above.\n const monthsMs = merged.months * MS_PER_DAY;\n\n if (!(secondsMs <= minutesMs && minutesMs <= hoursMs && hoursMs <= daysMs && daysMs <= monthsMs)) {\n throw new Error(\n `temporal-fmt: formatDistance cutoffs must be monotonically non-decreasing in equivalent ms ` +\n `(seconds ≤ minutes ≤ hours ≤ days ≤ months). Got: seconds=${merged.seconds}s, ` +\n `minutes=${merged.minutes}min, hours=${merged.hours}h, days=${merged.days}d, months=${merged.months}d — ` +\n `pick a sequence where each boundary is at least as large as the one before it.`\n );\n }\n\n return [\n { maxMs: secondsMs, unit: 'second' },\n { maxMs: minutesMs, unit: 'minute' },\n { maxMs: hoursMs, unit: 'hour' },\n { maxMs: daysMs, unit: 'day' },\n { maxMs: monthsMs, unit: 'month' },\n ];\n}\n\nconst rtfCache = new Map<string, Intl.RelativeTimeFormat>();\nconst MAX_RTF_CACHE_SIZE = 100;\n\nfunction getRtf(locale: string, numeric: 'always' | 'auto'): Intl.RelativeTimeFormat {\n const key = `${canonicalLocaleKey(locale)}|${numeric}`;\n let rtf = rtfCache.get(key);\n if (rtf) return rtf;\n if (rtfCache.size >= MAX_RTF_CACHE_SIZE) {\n const oldestKey = rtfCache.keys().next().value;\n if (oldestKey !== undefined) rtfCache.delete(oldestKey);\n }\n try {\n rtf = new Intl.RelativeTimeFormat(normalizeLocaleTag(locale), { numeric });\n } catch (err) {\n // Malformed locale tags reach Intl as a bare RangeError; surface the\n // library's typed error instead. (Every failure mode of these\n // constructors with a string locale is a RangeError, so converting\n // unconditionally loses nothing — the original message is preserved\n // in `reason` either way.)\n throw new InvalidLocaleError({ actual: locale, reason: (err as Error).message });\n }\n rtfCache.set(key, rtf);\n return rtf;\n}\n\nfunction canonicalLocaleKey(locale: string): string {\n try {\n return new Intl.Locale(locale.replace(/_/g, '-')).toString().toLowerCase();\n } catch {\n return locale;\n }\n}\n\nexport interface FormatDistanceOptions extends FormatOptions {\n /**\n * 'auto' (default) lets Intl.RelativeTimeFormat use natural forms like\n * \"yesterday\"/\"tomorrow\"/\"now\" when the rounded value lands on ±1 or 0.\n * 'always' forces the strict \"1 day ago\"/\"in 1 day\"/\"in 0 seconds\" form.\n */\n numeric?: 'always' | 'auto';\n /**\n * Override the unit-selection boundaries (seconds→minutes,\n * minutes→hours, hours→days, days→months, months→years). Any\n * subset can be supplied; omitted boundaries fall back to the\n * defaults (60s, 60min, 24h, 30d, 365d). Values are in each\n * unit's native scale except `months`, which is in days — see\n * DistanceCutoffs. Throws descriptively on non-monotonic\n * boundaries or non-positive values, rather than producing\n * confusing output downstream.\n */\n cutoffs?: DistanceCutoffs;\n}\n\n/**\n * Returns a human-readable relative-time string describing `date1`\n * relative to `date2`, e.g. \"3 days ago\", \"in 2 hours\", \"now\". Delegates\n * unit names and pluralization to `Intl.RelativeTimeFormat` so the\n * output localizes the same way the rest of the library's locale-aware\n * tokens do.\n *\n * Convention: the result describes `date1`'s position relative to\n * `date2`. `formatDistance(now, threeDaysAgo)` → `\"3 days ago\"` (the\n * past date is described relative to now). `formatDistance(now, twoHoursFromNow)`\n * → `\"in 2 hours\"`. This matches the natural-language reading \"describe\n * the first date as if standing at the second one.\"\n *\n * Unit-selection cutoffs (seconds → minutes → hours → days → months →\n * years) and the rationale for each are documented in the README under\n * \"formatDistance\".\n *\n * @example\n * formatDistance(threeDaysAgo, today) // \"3 days ago\"\n * formatDistance(twoHoursFromNow, today) // \"in 2 hours\"\n * formatDistance(today, today) // \"now\"\n * formatDistance(futureDate, today, {locale:'fr-FR'}) // \"dans 2 jours\"\n */\nexport function formatDistance(\n date1: unknown,\n date2: unknown,\n options: FormatDistanceOptions = {},\n): string {\n const fields1 = readFields(date1, 'date1');\n const fields2 = readFields(date2, 'date2');\n\n // diff > 0: date1 is later than date2 → \"in X units\" (date1 is in\n // the future relative to date2). diff < 0: date1 is earlier than\n // date2 → \"X units ago\". This convention puts date1 in the\n // \"described\" role and date2 in the \"reference\" role, matching\n // natural-language reading: `formatDistance(threeDaysAgo, today)`\n // = \"describe threeDaysAgo as if standing at today\" = \"3 days ago\".\n const diffMs = toEpochMs(fields1) - toEpochMs(fields2);\n const absMs = Math.abs(diffMs);\n\n const unitCutoffs = resolveCutoffs(options.cutoffs);\n let unit: Intl.RelativeTimeFormatUnit = 'year';\n for (const { maxMs, unit: candidateUnit } of unitCutoffs) {\n if (absMs < maxMs) {\n unit = candidateUnit;\n break;\n }\n }\n\n const divisor = unitToMs(unit);\n const rounded = Math.round(diffMs / divisor);\n\n const numeric = options.numeric ?? 'auto';\n const locale = options.locale ?? DEFAULT_LOCALE;\n const rtf = getRtf(locale, numeric);\n return rtf.format(rounded, unit);\n}\n\n/**\n * Same as formatDistance(date, now), where \"now\" is read from the system\n * clock at call time. Convenience wrapper for the common \"how long ago\n * was this\" case, so the caller doesn't have to construct a reference\n * value themselves.\n *\n * Unlike formatRelativeToNow() (in relativeTime.ts), which only needs\n * calendar-day resolution, this reads the full wall-clock time (hour\n * through millisecond) off the system clock — formatDistance's unit\n * selection is ms-resolution, so a date-only \"now\" would misclassify\n * anything under 24 hours old (e.g. \"1 hour ago\" reading as \"in 23\n * hours\" against a midnight-truncated reference). See the test file\n * for a regression case covering exactly that.\n *\n * The reference is captured fresh on every call, not memoized — each\n * call reflects \"now\" at the moment it runs, same expectation\n * formatRelativeToNow() already sets.\n *\n * @example\n * formatDistanceToNow(threeHoursAgo) // \"3 hours ago\"\n * formatDistanceToNow(tomorrow) // \"in 1 day\" (auto: \"tomorrow\")\n */\nexport function formatDistanceToNow(\n date: unknown,\n options: FormatDistanceOptions = {},\n): string {\n const now = new Date();\n const nowFields = {\n year: now.getFullYear(),\n month: now.getMonth() + 1,\n day: now.getDate(),\n hour: now.getHours(),\n minute: now.getMinutes(),\n second: now.getSeconds(),\n millisecond: now.getMilliseconds(),\n };\n return formatDistance(date, nowFields, options);\n}\n\nfunction unitToMs(unit: Intl.RelativeTimeFormatUnit): number {\n switch (unit) {\n case 'second': return MS_PER_SECOND;\n case 'minute': return MS_PER_MINUTE;\n case 'hour': return MS_PER_HOUR;\n case 'day': return MS_PER_DAY;\n /* c8 ignore start @preserve -- unreachable: unitToMs is only called\n with `unit` values produced by formatDistance's cutoff loop above,\n which only ever yields 'second'/'minute'/'hour'/'day'/'month'\n (from resolveCutoffs' fixed array) or 'year' (the loop's fallback\n default). 'week' and 'quarter' were never wired into\n resolveCutoffs — formatDistance intentionally skips week-\n resolution output (see the comment above DEFAULT_CUTOFFS) — so\n neither can reach this switch. */\n case 'week': return 7 * MS_PER_DAY;\n /* c8 ignore stop @preserve */\n case 'month': return 30 * MS_PER_DAY;\n /* c8 ignore start @preserve -- unreachable, same reason as 'week'\n above: resolveCutoffs never produces 'quarter'. */\n case 'quarter': return 91 * MS_PER_DAY;\n /* c8 ignore stop @preserve */\n case 'year': return 365 * MS_PER_DAY;\n /* c8 ignore start @preserve -- unreachable: every unit\n resolveCutoffs can actually produce ('second' through 'month', or\n 'year' as the loop's fallback default) has an explicit case\n above, so this exhaustive-switch default can't fire at runtime.\n It exists so TS accepts the function as total — the compiler\n can't see through the cutoff-array iteration in formatDistance()\n to know the input is already narrowed. */\n default:\n throw new Error(`temporal-fmt: formatDistance hit unhandled unit \"${String(unit)}\".`);\n /* c8 ignore stop @preserve */\n }\n}","// Relative-grammar registration. Extends the existing\n// parseRelative.ts with an extension point for registering additional\n// grammars beyond the four built in (English, Spanish, French, German).\n//\n// The existing parseRelative() detects the language from the locale\n// option and dispatches to the matching grammar. registerRelativeGrammar()\n// lets a caller add a new language without modifying parseRelative.ts.\n//\n// Grammar shape: a list of matchers, each returning either a Temporal\n// field bag describing the resolved date or null. parseRelative tries\n// each matcher in order until one matches. This mirrors the ENGLISH/\n// SPANISH/FRENCH/GERMAN_GRAMMAR structure parseRelative already uses\n// internally.\n\nimport { getTemporal, type TemporalNamespace } from './temporalProvider.js';\n\nexport interface RelativeGrammarMatch {\n // The Temporal fields the matcher resolved. Used to construct a\n // PlainDate / PlainDateTime via Temporal.PlainDate.from().\n year?: number;\n month?: number;\n day?: number;\n // Optional: instead of computing fields directly, return a function\n // that takes the reference date and returns the resolved date. Used\n // for phrases like \"next Tuesday\" that depend on the reference's\n // weekday.\n resolve?: (reference: { year: number; month: number; day: number; dayOfWeek: number }) => { year: number; month: number; day: number };\n}\n\nexport interface RelativeGrammar {\n // Locale language subtag this grammar handles ('en', 'es', etc.).\n // Matched against the `locale` option's language subtag.\n language: string;\n // Matchers in priority order. First match wins.\n matchers: Array<(input: string) => RelativeGrammarMatch | null>;\n}\n\n// Cap on registered grammars. Replacement registration for an existing\n// language never grows the registry, so the cap only gates new languages —\n// the same convention registerLocaleVocab uses for custom vocabularies.\n// Without it, a caller looping registerRelativeGrammar() grows the array\n// (and the per-language scan in tryRegisteredGrammar) without bound.\nconst MAX_REGISTERED_GRAMMARS = 100;\n\nconst registeredGrammars: RelativeGrammar[] = [];\n\nexport function registerRelativeGrammar(grammar: RelativeGrammar): void {\n if (typeof grammar.language !== 'string' || grammar.language.length === 0) {\n throw new Error('temporal-fmt: registerRelativeGrammar requires a non-empty language string.');\n }\n if (!Array.isArray(grammar.matchers) || grammar.matchers.length === 0) {\n throw new Error('temporal-fmt: registerRelativeGrammar requires at least one matcher.');\n }\n // Replace any existing grammar for the same language.\n const existingIdx = registeredGrammars.findIndex((g) => g.language === grammar.language);\n if (existingIdx >= 0) {\n registeredGrammars[existingIdx] = grammar;\n } else {\n if (registeredGrammars.length >= MAX_REGISTERED_GRAMMARS) {\n throw new RangeError(`temporal-fmt: registerRelativeGrammar reached the ${MAX_REGISTERED_GRAMMARS}-grammar limit.`);\n }\n registeredGrammars.push(grammar);\n }\n}\n\n// Called by parseRelative() to try registered grammars before falling\n// back to the built-in ones. Returns the resolved Temporal.PlainDate or\n// null if no registered grammar matched.\nexport function tryRegisteredGrammar(\n language: string,\n input: string,\n reference: { year: number; month: number; day: number; dayOfWeek: number },\n): unknown | null {\n for (const grammar of registeredGrammars) {\n if (grammar.language !== language) continue;\n for (const matcher of grammar.matchers) {\n const match = matcher(input);\n if (match === null) continue;\n const temporal = getTemporal();\n if (match.resolve) {\n const fields = match.resolve(reference);\n return temporal.PlainDate.from(fields, { overflow: 'reject' });\n }\n return temporal.PlainDate.from(\n { year: match.year ?? reference.year, month: match.month ?? reference.month, day: match.day ?? reference.day },\n { overflow: 'reject' },\n );\n }\n }\n return null;\n}\n\n// Returns the list of registered languages (for introspection).\nexport function listRegisteredGrammars(): string[] {\n return registeredGrammars.map((g) => g.language);\n}\n\n// Suppress unused import — TemporalNamespace is referenced by the type\n// signature above (via the return type of tryRegisteredGrammar, which\n// is the result of temporal.PlainDate.from).\nvoid (undefined as unknown as TemporalNamespace);\n","import { getTemporal } from './temporalProvider.js';\nimport { type TemporalNamespace } from './temporalProvider.js';\nimport { tryRegisteredGrammar } from './relativeGrammar.js';\nimport { DEFAULT_LOCALE, type FormatOptions } from './tokens.js';\n\n// parseRelative resolves common relative-date phrases (\"next Tuesday\",\n// \"in 3 days\", \"March 5th\") against a reference date, returning a\n// Temporal.PlainDate. It's a different subsystem from the token-based\n// parse(): the input is free natural-language text, not a structurally-\n// typed format string, so this module owns its own grammar rather than\n// bolting a natural-language layer onto the existing tokenizer.\n//\n// Per-language grammars: each locale's grammar lives in its own\n// clearly-labeled section below (ENGLISH_GRAMMAR, SPANISH_GRAMMAR,\n// FRENCH_GRAMMAR, GERMAN_GRAMMAR). The vocabulary and phrase patterns\n// are NOT shared across languages — Spanish \"hace 2 semanas\" and\n// French \"il y a 2 semaines\" are different idioms and get their own\n// regexes. What IS shared is the matching engine (iterate matchers in\n// order, first match wins, throw on no match) and the resolution\n// helpers (addDays, addUnits, weekdayOffset, resolveToNextOccurrence).\n// Same approach the humanizing skill calls \"solve each recurring\n// problem once\": the matching strategy is shared, the per-language\n// vocabulary is not.\n//\n// Default locale (no `locale` option) uses English — matches the\n// pre-change behavior byte-for-byte. Passing `locale: 'es'`,\n// `locale: 'fr'`, or `locale: 'de'` (or any locale tag with that\n// language subtag) routes to the corresponding grammar. Unrecognized\n// languages fall back to English rather than throwing — a caller\n// passing `locale: 'it-IT'` still gets *some* result, just from the\n// English grammar. (We could throw instead; the current contract is\n// \"best effort.\" If the caller wanted Italian specifically, they'd\n// pass an Italian grammar via registerLocaleVocab-style extension —\n// not implemented here.)\n\n// Lowercase + expand German umlauts (ä→ae, ö→oe, ü→ue, ß→ss) + strip\n// remaining diacritics. Three things going on at once:\n//\n// 1. Lowercase — case-insensitive matching without forcing the\n// regex flag to do it (also keeps the captured groups lowercase\n// for the resolver's comparisons).\n// 2. Expand German umlaut transliterations. Germans without an\n// umlaut key write \"ä\" as \"ae\" — the standard transliteration.\n// Expanding \"ä\" → \"ae\" (before NFD stripping) means both \"März\"\n// and \"Maerz\" normalize to \"maerz\" and match the same pattern.\n// The reverse (ae → ä) would be wrong: \"Tage\" has \"ae\" as a\n// coincidence, not as an umlaut transliteration. Forward expansion\n// is unambiguous because the source string already has the\n// umlaut — the expansion only affects the matched form.\n// 3. Strip combining marks via NFD. \"Miércoles\" → \"Miercoles\",\n// \"février\" → \"fevrier\", \"août\" → \"aout\". Pairs with the umlaut\n// expansion above so all four languages' accented forms collapse\n// to one canonical unaccented form for matching.\n//\n// Both sides of the match — input string AND the weekday/month name\n// lists — get the same normalization applied, so this is symmetric.\nfunction normalizeForMatch(s: string): string {\n return s.toLowerCase()\n .replace(/ä/g, 'ae')\n .replace(/ö/g, 'oe')\n .replace(/ü/g, 'ue')\n .replace(/ß/g, 'ss')\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '');\n}\n\n// Standard Levenshtein edit distance (insert/delete/substitute, cost 1\n// each). Used only by the opt-in fuzzy layer below — the exact matcher\n// pass never calls this. Iterative DP over two rows, not the full\n// matrix, since only the previous row is ever needed.\nfunction levenshtein(a: string, b: string): number {\n /* c8 ignore start @preserve -- unreachable through the only call\n * site (fuzzyCorrectEnglish): `a` is always a word that already\n * failed the `vocabulary.includes(word)` exact-match check, so\n * a === b never holds against any `b` drawn from that same\n * vocabulary; and neither `a` (split from a non-empty normalized\n * string) nor `b` (a vocabulary entry) is ever empty. Kept as\n * general-purpose guards in case levenshtein() gets a second caller\n * later. */\n if (a === b) return 0;\n if (a.length === 0) return b.length;\n if (b.length === 0) return a.length;\n /* c8 ignore stop @preserve */\n let prev = new Array(b.length + 1);\n let curr = new Array(b.length + 1);\n for (let j = 0; j <= b.length; j++) prev[j] = j;\n for (let i = 1; i <= a.length; i++) {\n curr[0] = i;\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n curr[j] = Math.min(\n prev[j] + 1, // deletion\n curr[j - 1] + 1, // insertion\n prev[j - 1] + cost, // substitution\n );\n }\n [prev, curr] = [curr, prev];\n }\n return prev[b.length];\n}\n\n// Max edit distance a fuzzy correction is allowed to bridge. 2 covers\n// the common single-finger-slip and single-transposed-letter typo cases\n// (\"tommorow\" is distance 1 from \"tomorrow\"; \"tuesady\" is distance 2\n// from \"tuesday\" — a transposition costs 2 under simple Levenshtein,\n// which doesn't special-case adjacent-swap as a single edit) without\n// opening the door to correcting a word into something only vaguely\n// similar. Deliberately conservative — this is a typo-tolerance layer,\n// not a \"guess what they meant\" layer; the library's whole design\n// philosophy elsewhere (parse()'s strict-by-default ambiguity handling,\n// the lenient opt-in) is to bound how much guessing is allowed and make\n// the caller ask for it explicitly.\nconst FUZZY_MAX_DISTANCE = 2;\nconst MAX_RELATIVE_INPUT_LENGTH = 4096;\nconst MAX_RELATIVE_WORDS = 32;\n\n// English-only fuzzy vocabulary. Anything a matcher's regex treats as a\n// fixed keyword (not a captured number) belongs here — weekday names,\n// month names (long and short), and the marker words the matchers\n// switch on (today/tomorrow/yesterday/next/last/this/in/ago and the\n// unit words day/week/month/year). Numbers and ordinal suffixes are\n// deliberately excluded: \"5th\" vs \"5tj\" isn't a word-shaped typo this\n// layer is trying to solve, and correcting digits is a much easier way\n// to silently produce a wrong date than correcting a weekday name is.\n//\n// Scoped to English only for this pass — the other three grammars have\n// enough positional/multi-word-marker variation (French's \"il y a\",\n// Spanish's dual pre/post weekday-modifier shapes) that a single\n// word-substitution corrector isn't a good fit for all of them without\n// per-language tuning this change doesn't attempt. parseRelative()\n// throws a clear scope-limited error if { fuzzy: true } is combined\n// with a non-English locale, rather than silently no-op-ing.\nfunction buildEnglishFuzzyVocabulary(): string[] {\n return [\n ...ENGLISH_WEEKDAYS,\n ...ENGLISH_MONTHS,\n ...ENGLISH_MONTH_SHORT,\n 'today', 'tomorrow', 'yesterday',\n 'next', 'last', 'this',\n 'in', 'ago',\n 'day', 'days', 'week', 'weeks', 'month', 'months', 'year', 'years',\n ].map(normalizeForMatch);\n}\n\n// Lazily built and cached — the vocabulary is static per process, no\n// need to rebuild the normalized list on every fuzzy call.\nlet englishFuzzyVocabulary: readonly string[] | undefined;\nfunction getEnglishFuzzyVocabulary(): readonly string[] {\n if (!englishFuzzyVocabulary) englishFuzzyVocabulary = Object.freeze(buildEnglishFuzzyVocabulary());\n return englishFuzzyVocabulary;\n}\n\n// Attempts a word-level fuzzy correction of `normalized` against the\n// English vocabulary, returning a corrected string or undefined if no\n// correction was needed/possible. Tokenizes on whitespace; each token\n// that isn't already an exact vocabulary word (or a pure number/ordinal,\n// which passes through untouched) gets replaced with its closest\n// vocabulary match, if one exists within FUZZY_MAX_DISTANCE. If a token\n// has no sufficiently-close vocabulary match, it's left as-is — the\n// re-attempted exact match will then fail on that token same as before,\n// which is the correct outcome for \"this word isn't a typo of anything\n// we know, it's just not a phrase we support.\"\nfunction fuzzyCorrectEnglish(normalized: string): string | undefined {\n const vocabulary = getEnglishFuzzyVocabulary();\n const words = normalized.split(' ');\n if (normalized.length > MAX_RELATIVE_INPUT_LENGTH || words.length > MAX_RELATIVE_WORDS) {\n throw new RangeError(\n `temporal-fmt: parseRelative fuzzy input is too large (maximum ${MAX_RELATIVE_INPUT_LENGTH} characters and ${MAX_RELATIVE_WORDS} words).`,\n );\n }\n let changed = false;\n const corrected = words.map((word) => {\n // Pure digits, or digits with an ordinal suffix (st/nd/rd/th) —\n // never touched by fuzzy correction. See the vocabulary comment\n // above for why.\n if (/^\\d+(?:st|nd|rd|th)?$/.test(word)) return word;\n // Already an exact vocabulary word — nothing to correct.\n if (vocabulary.includes(word)) return word;\n\n let best: string | undefined;\n let bestDist = FUZZY_MAX_DISTANCE + 1;\n for (const candidate of vocabulary) {\n const dist = levenshtein(word, candidate);\n if (dist < bestDist) {\n bestDist = dist;\n best = candidate;\n }\n }\n if (best !== undefined && bestDist <= FUZZY_MAX_DISTANCE) {\n changed = true;\n return best;\n }\n return word;\n });\n\n return changed ? corrected.join(' ') : undefined;\n}\n\ninterface TemporalFieldBag {\n year?: number;\n month?: number;\n day?: number;\n dayOfWeek?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\nfunction readYear(reference: TemporalFieldBag): number {\n if (typeof reference.year !== 'number') {\n throw new Error('temporal-fmt: parseRelative reference date is missing year.');\n }\n return reference.year;\n}\nfunction readMonth(reference: TemporalFieldBag): number {\n if (typeof reference.month !== 'number') {\n throw new Error('temporal-fmt: parseRelative reference date is missing month.');\n }\n return reference.month;\n}\nfunction readDay(reference: TemporalFieldBag): number {\n if (typeof reference.day !== 'number') {\n throw new Error('temporal-fmt: parseRelative reference date is missing day.');\n }\n return reference.day;\n}\n\nfunction extractDayOfWeek(reference: TemporalFieldBag): number {\n const dow = reference.dayOfWeek;\n if (typeof dow !== 'number') {\n throw new Error(\n 'temporal-fmt: parseRelative needs a reference date exposing dayOfWeek (a Temporal.PlainDate / PlainDateTime / ZonedDateTime).'\n );\n }\n return dow;\n}\n\n// Build an alternation regex fragment from a name list, normalized for\n// matching. Longest-first so \"September\" wins over \"Sep\" in the same\n// match position. The caller is responsible for any wrapping groups\n// or anchors — this just produces the inner alternation.\nfunction nameAlternation(names: string[]): string {\n const normalized = names.map(normalizeForMatch);\n // Dedupe — some locales render the long and short form identically\n // (English \"May\" is the same in both MMMM and MMM lists). Keep both\n // in the alternation rather than deduping, since duplicates in a\n // regex alternation don't change behavior and the dedupe would just\n // be a micro-optimization.\n // Sort longest-first so a longer name wins over its own prefix.\n const sorted = [...normalized].sort((a, b) => b.length - a.length);\n // Escape regex metacharacters — names shouldn't contain any, but\n // belt-and-braces avoids a future \"M+1\" month name from breaking\n // the alternation silently.\n return sorted.map((n) => n.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')).join('|');\n}\n\n// Resolves to a PlainDate by adding `days` to the reference. Used for\n// weekday refs and the today/tomorrow/yesterday family.\nfunction buildPlainDate(temporal: { PlainDate: { from: (fields: Record<string, number>, options?: { overflow?: 'constrain' | 'reject' }) => unknown } }, year: number, month: number, day: number): unknown {\n return temporal.PlainDate.from({ year, month, day }, { overflow: 'reject' });\n}\n\nfunction addDays(\n temporal: { PlainDate: { from: (fields: Record<string, number>) => unknown } },\n reference: TemporalFieldBag,\n days: number,\n): unknown {\n // Build the reference as a real PlainDate so we can use Temporal's\n // own add() for date arithmetic — calendar-correct (handles month\n // boundaries, leap years, etc.) so we don't have to reimplement it.\n const refDate = temporal.PlainDate.from({\n year: readYear(reference),\n month: readMonth(reference),\n day: readDay(reference),\n }) as { add: (duration: Record<string, number>) => unknown };\n return refDate.add({ days });\n}\n\nfunction addUnits(\n temporal: { PlainDate: { from: (fields: Record<string, number>) => unknown } },\n reference: TemporalFieldBag,\n count: number,\n unit: 'day' | 'week' | 'month' | 'year',\n): unknown {\n const refDate = temporal.PlainDate.from({\n year: readYear(reference),\n month: readMonth(reference),\n day: readDay(reference),\n }) as { add: (duration: Record<string, number>) => unknown };\n const duration: Record<string, number> = {};\n if (unit === 'day') duration.days = count;\n if (unit === 'week') duration.weeks = count;\n if (unit === 'month') duration.months = count;\n if (unit === 'year') duration.years = count;\n return refDate.add(duration);\n}\n\n// \"next X\" — strictly future next occurrence. Said on a Tuesday:\n// \"next Tuesday\" = 7 days from now, not today. Rationale: \"this\n// Tuesday\" handles the same-week case, so \"next Tuesday\" staying\n// strictly-future gives the two phrases distinct, non-overlapping\n// meanings. Documented in README \"parseRelative\".\n//\n// \"last X\" — strictly past most recent occurrence. Symmetric to \"next\".\n//\n// \"this X\" — the X of the current ISO week (Mon..Sun). Can land on\n// today, past, or future depending on where in the week today falls.\n//\n// All three resolve the same way across the four supported languages\n// (en/es/fr/de): the equivalent idiom in each language maps to one of\n// these three rel words. The natural-language reading is consistent\n// — \"next Tuesday\" said on a Tuesday means next week's Tuesday in\n// every language we support.\nfunction weekdayOffset(rel: 'next' | 'last' | 'this', refDow: number, targetDow: number): number {\n // refDow and targetDow are both 1..7 (ISO Mon=1..Sun=7).\n if (rel === 'next') {\n let diff = targetDow - refDow;\n if (diff <= 0) diff += 7; // 0 (today) → 7, negative → wrap forward\n return diff; // 1..7\n }\n if (rel === 'last') {\n let diff = targetDow - refDow;\n if (diff >= 0) diff -= 7; // 0 (today) → -7, positive → wrap backward\n return diff; // -7..-1\n }\n // rel === 'this' — X of the current week. Can be today, past, or future.\n return targetDow - refDow; // -6..+6\n}\n\n// \"March 5th\" without a year → resolve to the next occurrence of that\n// month/day. If today is that date, return today. Otherwise, if it's\n// already past this year, return next year's occurrence.\n//\n// \"Next occurrence\" semantics: future-leaning. Documented in README\n// as the chosen behavior. The alternative (\"nearest in time, past or\n// future\") would mean \"March 5th\" said on March 6 returns yesterday —\n// counterintuitive for the typical \"next birthday\"/\"next deadline\"\n// use case this kind of phrase tends to drive.\nfunction resolveToNextOccurrence(\n temporal: {\n PlainDate: {\n from: (fields: Record<string, number>, options?: { overflow?: 'constrain' | 'reject' }) => unknown;\n compare?: (one: unknown, two: unknown) => number;\n };\n },\n reference: TemporalFieldBag,\n month: number,\n day: number,\n): unknown {\n const refYear = readYear(reference);\n const refDate = temporal.PlainDate.from({\n year: refYear,\n month: readMonth(reference),\n day: readDay(reference),\n });\n // PlainDate.compare is a static method on the namespace, not an\n // instance method — that's why it's called off temporal.PlainDate\n // rather than off an instance below. Checked outside the try/catch\n // below on purpose: that block's catch is scoped to Feb-29-style\n // overflow errors from from(), and silently retries with next year's\n // date. A missing-compare error thrown from inside that try would get\n // caught by the same handler and swallowed by that retry (next year's\n // from() usually succeeds), masking the real problem instead of\n // surfacing it.\n if (!temporal.PlainDate.compare) {\n throw new Error('temporal-fmt: parseRelative needs Temporal.PlainDate.compare to resolve month-day phrases; the active implementation does not expose it.');\n }\n // try this year first; if Feb 29 in a non-leap year, Temporal will\n // throw via overflow: 'reject' — fall through to next year.\n try {\n const thisYear = temporal.PlainDate.from({ year: refYear, month, day }, { overflow: 'reject' });\n // Returns -1 / 0 / 1.\n if (temporal.PlainDate.compare(thisYear, refDate) >= 0) {\n // today or in the future → use this year's occurrence\n return thisYear;\n }\n // already past this year → next year's occurrence\n return temporal.PlainDate.from({ year: refYear + 1, month, day }, { overflow: 'reject' });\n } catch (err) {\n // Feb 29 in a non-leap year, or similar. Try next year — if the\n // caller asked for \"Feb 29\" said in a non-leap year, next year may\n // also not be leap, in which case the inner from() will throw and\n // surface a clear error rather than silently landing on Feb 28.\n try {\n return temporal.PlainDate.from({ year: refYear + 1, month, day }, { overflow: 'reject' });\n } catch {\n throw new Error(\n `temporal-fmt: parseRelative can't resolve month ${month} day ${day} — ` +\n `it isn't a valid date in either ${refYear} or ${refYear + 1}. ` +\n `Original error: ${(err as Error).message}`\n );\n }\n }\n}\n\n// Each language provides a list of matchers. The shared engine\n// iterates them in order and returns the first match. A matcher is a\n// (regex, resolver) pair — the regex captures the structural pieces\n// (count, unit name, weekday name, etc.), the resolver turns them\n// into a Temporal.PlainDate using the shared helpers above.\ninterface ResolveContext {\n temporal: TemporalNamespace;\n reference: TemporalFieldBag;\n}\n\ninterface Matcher {\n pattern: RegExp;\n resolve: (match: RegExpMatchArray, ctx: ResolveContext) => unknown;\n}\n\ninterface RelativeDateGrammar {\n // Single-line description of supported phrase classes, included in\n // the \"doesn't recognize\" error so the caller knows what to try.\n supportedHint: string;\n // Ordered matchers; first match wins.\n matchers: Matcher[];\n}\n\nfunction weekdayIndexFromName(name: string, names: string[]): number {\n const normalized = normalizeForMatch(name);\n const idx = names.findIndex((n) => normalizeForMatch(n) === normalized);\n /* c8 ignore start @preserve -- unreachable: every caller passes a\n * name captured by nameAlternation(names), which builds its regex\n * alternation from this same list under the same normalizeForMatch\n * transform. The regex can't match anything findIndex() wouldn't\n * also find here. Defensive throw kept for the type checker and as\n * a tripwire if that invariant ever breaks. Ignore comment sits on\n * the `if` itself, not just the throw inside it — c8 tracks the\n * branch outcome (was the true side ever taken) separately from the\n * statements inside, so excluding only the inner throw still leaves\n * the branch itself flagged as uncovered. */\n /* c8 ignore next */\n if (idx < 0) {\n throw new Error(`temporal-fmt: parseRelative internal error — weekday \"${name}\" not in names list.`);\n }\n /* c8 ignore stop @preserve */\n return idx + 1;\n}\n\nfunction monthIndexFromName(name: string, longNames: string[], shortNames: string[] = []): number {\n const normalized = normalizeForMatch(name);\n const longIdx = longNames.findIndex((n) => normalizeForMatch(n) === normalized);\n if (longIdx >= 0) return longIdx + 1;\n const shortIdx = shortNames.findIndex((n) => normalizeForMatch(n) === normalized);\n /* c8 ignore next */\n if (shortIdx >= 0) return shortIdx + 1;\n /* c8 ignore start @preserve -- unreachable: every caller passes a name\n * captured by nameAlternation([...longNames, ...shortNames]), so the\n * regex alternation and these two findIndex() scans are built from\n * the same lists under the same normalizeForMatch transform. Kept as\n * a tripwire for the type checker in case that invariant ever breaks. */\n throw new Error(`temporal-fmt: parseRelative internal error — month \"${name}\" not in names list.`);\n /* c8 ignore stop @preserve */\n /* c8 ignore next -- defensive block is unreachable by construction. */\n}\n\n// English grammar — also the default when no locale is supplied. The\n// regexes here are the same ones the pre-change parseRelative() used\n// inline; they've just been pulled into a matcher list so the matching\n// engine can iterate them the same way it does for es/fr/de.\nconst ENGLISH_WEEKDAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];\nconst ENGLISH_MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];\nconst ENGLISH_MONTH_SHORT = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n\nconst ENGLISH_GRAMMAR: RelativeDateGrammar = {\n supportedHint: 'Supported: weekday refs (\"next Tuesday\"), day offsets (\"today\"/\"tomorrow\"/\"yesterday\"), unit offsets (\"in 3 days\", \"2 weeks ago\"), and month-day (\"March 5th\").',\n matchers: [\n // today / tomorrow / yesterday — exact match, most rigid shape.\n // Checked first because they're the most common phrase class.\n {\n pattern: /^today$/i,\n resolve: (_m, ctx) => buildPlainDate(ctx.temporal, readYear(ctx.reference), readMonth(ctx.reference), readDay(ctx.reference)),\n },\n {\n pattern: /^tomorrow$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, 1),\n },\n {\n pattern: /^yesterday$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, -1),\n },\n // weekday references: \"next/last/this Tuesday\". Capture the relative\n // word and the weekday name separately, then resolve via +7 / -7.\n {\n pattern: new RegExp(`^(next|last|this)\\\\s+(${nameAlternation(ENGLISH_WEEKDAYS)})$`, 'i'),\n resolve: (m, ctx) => {\n const rel = m[1]!.toLowerCase() as 'next' | 'last' | 'this';\n const targetDow = weekdayIndexFromName(m[2]!, ENGLISH_WEEKDAYS);\n const refDow = extractDayOfWeek(ctx.reference);\n return addDays(ctx.temporal, ctx.reference, weekdayOffset(rel, refDow, targetDow));\n },\n },\n // unit offsets: \"in 3 days\", \"2 weeks ago\", \"in 1 month\", \"1 year ago\".\n // Two shapes share this matcher — leading \"in\" (future) or trailing\n // \"ago\" (past). Both lead with <number> <unit>.\n {\n pattern: /^(in\\s+)?(\\d+)\\s+(day|week|month|year)s?(?:\\s+ago)?$/i,\n resolve: (m, ctx) => {\n const inPrefix = m[1];\n const count = m[2]!;\n const unitName = m[3]!.toLowerCase() as 'day' | 'week' | 'month' | 'year';\n // Disambiguate future vs past: \"in N units\" is always future; \"N\n // units ago\" is always past. A bare \"N units\" without either is\n // a sign error — throw, since neither direction is implied and\n // guessing is exactly what this library refuses to do.\n const hasIn = !!inPrefix;\n const hasAgo = /\\bago\\b/i.test(m[0]!);\n if (!hasIn && !hasAgo) {\n throw new Error(\n `temporal-fmt: parseRelative can't tell whether \"${m[0]}\" is past or future — ` +\n `use \"in ${count} ${unitName}s\" or \"${count} ${unitName}s ago\".`\n );\n }\n const sign = hasIn ? 1 : -1;\n return addUnits(ctx.temporal, ctx.reference, sign * Number(count), unitName);\n },\n },\n // month-day without year, e.g. \"March 5th\", \"March 5\", \"March 5, 2026\"\n // (year is ignored if present). The ordinal suffix is decorative —\n // strip it. The day-of-month is a 1- or 2-digit number.\n {\n pattern: new RegExp(`^(${nameAlternation([...ENGLISH_MONTHS, ...ENGLISH_MONTH_SHORT])})\\\\s+(\\\\d{1,2})(?:st|nd|rd|th)?(?:,?\\\\s*(\\\\d{4}))?$`, 'i'),\n resolve: (m, ctx) => {\n const month = monthIndexFromName(m[1]!, ENGLISH_MONTHS, ENGLISH_MONTH_SHORT);\n const day = Number(m[2]!);\n return resolveToNextOccurrence(ctx.temporal, ctx.reference, month, day);\n },\n },\n ],\n};\n\n// Spanish grammar. Distinct phrase shapes from English:\n// - \"hace 2 semanas\" (past unit offset) — distinct word \"hace\", not\n// the English \"X units ago\" suffix shape.\n// - \"5 de marzo\" — day-first, with required \"de\" between day and\n// month, opposite of English \"March 5\".\n// - \"el próximo lunes\" / \"lunes pasado\" — weekday ref has the relative\n// word sometimes as a prefix with article, sometimes as a suffix.\n//\n// All four phrase classes the English grammar supports have Spanish\n// equivalents here.\nconst SPANISH_WEEKDAYS = ['lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado', 'domingo'];\nconst SPANISH_MONTHS = ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'];\n// Spanish month abbreviations vary by region (\"set\" vs \"sept\" for\n// September). Sticking with the most common ICU form per locale.\nconst SPANISH_MONTH_SHORT = ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sept', 'oct', 'nov', 'dic'];\n\nconst SPANISH_GRAMMAR: RelativeDateGrammar = {\n supportedHint: 'Frases soportadas: referencias de día de la semana (\"el próximo lunes\", \"el lunes pasado\", \"este martes\"), offsets de día (\"hoy\"/\"mañana\"/\"ayer\"), offsets de unidad (\"en 3 días\", \"hace 2 semanas\"), y mes-día (\"5 de marzo\").',\n matchers: [\n {\n pattern: /^hoy$/i,\n resolve: (_m, ctx) => buildPlainDate(ctx.temporal, readYear(ctx.reference), readMonth(ctx.reference), readDay(ctx.reference)),\n },\n {\n pattern: /^ma[ñn]ana$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, 1),\n },\n {\n pattern: /^ayer$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, -1),\n },\n // weekday references. Spanish has three common shapes, all meaning\n // the same thing per rel word:\n // \"el próximo lunes\" / \"próximo lunes\" → next\n // \"el lunes próximo\" → next (suffix variant)\n // \"el lunes pasado\" / \"lunes pasado\" → last\n // \"este lunes\" → this\n // Capture the rel word from whichever shape matched, then resolve\n // the same way English does.\n {\n pattern: new RegExp(\n `^(?:el\\\\s+)?(?:(pr[oó]ximo|pasado)\\\\s+(${nameAlternation(SPANISH_WEEKDAYS)})|(${nameAlternation(SPANISH_WEEKDAYS)})\\\\s+(pr[oó]ximo|pasado)|este\\\\s+(${nameAlternation(SPANISH_WEEKDAYS)}))$`,\n 'i',\n ),\n resolve: (m, ctx) => {\n let relWord: string;\n let weekdayName: string;\n if (m[1] && m[2]) {\n // prefix variant: \"próximo lunes\" / \"pasado lunes\"\n relWord = m[1]!;\n weekdayName = m[2]!;\n } else if (m[3] && m[4]) {\n // suffix variant: \"lunes próximo\" / \"lunes pasado\"\n weekdayName = m[3]!;\n relWord = m[4]!;\n } else {\n // \"este lunes\"\n relWord = 'este';\n weekdayName = m[5]!;\n }\n const rel = normalizeForMatch(relWord) === 'proximo' ? 'next' : relWord.toLowerCase() === 'este' ? 'this' : 'last';\n const targetDow = weekdayIndexFromName(weekdayName, SPANISH_WEEKDAYS);\n const refDow = extractDayOfWeek(ctx.reference);\n return addDays(ctx.temporal, ctx.reference, weekdayOffset(rel, refDow, targetDow));\n },\n },\n // unit offsets. Spanish uses distinct markers:\n // \"en 3 días\" / \"dentro de 3 días\" → future\n // \"hace 2 semanas\" → past\n // Both shapes lead with the marker, unlike English where one\n // shape leads and the other trails.\n {\n pattern: new RegExp(\n `^(?:(en|dentro\\\\s+de)\\\\s+(\\\\d+)\\\\s+(d[ií]a|semana|mes|a[ñn]o)s?|(\\\\d+)\\\\s+(d[ií]a|semana|mes|a[ñn]o)s?\\\\s+(hace))$`,\n 'i',\n ),\n resolve: (m, ctx) => {\n let count: string;\n let unitWord: string;\n let sign: number;\n if (m[1] && m[2] && m[3]) {\n // future: \"en 3 días\" / \"dentro de 3 días\"\n count = m[2]!;\n unitWord = m[3]!;\n sign = 1;\n } else {\n // past: \"2 semanas hace\" — but the more natural Spanish is\n // \"hace 2 semanas\" (marker first). The regex above only\n // matches \"N units hace\"; that's a less common but\n // grammatical alternative. The primary past form \"hace N\n // unidades\" is matched by the next matcher.\n count = m[4]!;\n unitWord = m[5]!;\n sign = -1;\n }\n const unit = unitWordToEnglish(unitWord);\n return addUnits(ctx.temporal, ctx.reference, sign * Number(count), unit);\n },\n },\n // \"hace 2 semanas\" — the primary past-offset shape. Matcher kept\n // separate from the future \"en/dentro de\" matcher above because\n // Spanish word order differs between the two (marker-first for\n // past, marker-first for future too, but with different markers).\n {\n pattern: new RegExp(`^hace\\\\s+(\\\\d+)\\\\s+(d[ií]a|semana|mes|a[ñn]o)s?$`, 'i'),\n resolve: (m, ctx) => {\n const count = Number(m[1]!);\n const unit = unitWordToEnglish(m[2]!);\n return addUnits(ctx.temporal, ctx.reference, -count, unit);\n },\n },\n // bare \"N <unit>\" without \"en\" / \"hace\" — throw, since direction\n // is ambiguous. Matched AFTER the directional shapes so the\n // directional ones win when their marker is present.\n {\n pattern: new RegExp(`^(\\\\d+)\\\\s+(d[ií]a|semana|mes|a[ñn]o)s?$`, 'i'),\n resolve: (m, _ctx) => {\n throw new Error(\n `temporal-fmt: parseRelative no puede decidir si \"${m[0]}\" es pasado o futuro — ` +\n `usa \"en ${m[1]} ${m[2]}s\" o \"hace ${m[1]} ${m[2]}s\".`\n );\n },\n },\n // month-day: \"5 de marzo\" (day first), \"5 de marzo de 2026\" (year\n // ignored if present). Day is 1-2 digits, with optional trailing\n // \".\" (rare in Spanish but tolerated).\n {\n pattern: new RegExp(\n `^(\\\\d{1,2})\\\\.?\\\\s+de\\\\s+(${nameAlternation([...SPANISH_MONTHS, ...SPANISH_MONTH_SHORT])})(?:\\\\s+de\\\\s+(\\\\d{4}))?$`,\n 'i',\n ),\n resolve: (m, ctx) => {\n const day = Number(m[1]!);\n const month = monthIndexFromName(m[2]!, SPANISH_MONTHS, SPANISH_MONTH_SHORT);\n return resolveToNextOccurrence(ctx.temporal, ctx.reference, month, day);\n },\n },\n ],\n};\n\n// French grammar. Distinct from English/Spanish:\n// - \"il y a 2 semaines\" (past marker is a 3-word phrase, not a single word).\n// - \"mardi prochain\" — relative word is a SUFFIX on the weekday,\n// opposite of English \"next Tuesday\".\n// - \"5 mars\" — day-first, no \"de\" between day and month (unlike\n// Spanish's \"5 de marzo\").\nconst FRENCH_WEEKDAYS = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'];\nconst FRENCH_MONTHS = ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'];\nconst FRENCH_MONTH_SHORT = ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'];\n\nconst FRENCH_GRAMMAR: RelativeDateGrammar = {\n supportedHint: 'Phrases prises en charge : références de jour de la semaine (\"lundi prochain\", \"mardi dernier\", \"ce mercredi\"), décalages de jour (\"aujourd\\'hui\"/\"demain\"/\"hier\"), décalages d\\'unité (\"dans 3 jours\", \"il y a 2 semaines\"), et mois-jour (\"5 mars\").',\n matchers: [\n {\n pattern: /^aujourd'hui$/i,\n resolve: (_m, ctx) => buildPlainDate(ctx.temporal, readYear(ctx.reference), readMonth(ctx.reference), readDay(ctx.reference)),\n },\n {\n pattern: /^demain$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, 1),\n },\n {\n pattern: /^hier$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, -1),\n },\n // weekday references: \"lundi prochain\" (next), \"lundi dernier\"\n // (last), \"ce lundi\" (this). The relative word follows the\n // weekday for next/last, precedes it for this.\n {\n pattern: new RegExp(\n `^(?:(${nameAlternation(FRENCH_WEEKDAYS)})\\\\s+(prochain|dernier)|ce\\\\s+(${nameAlternation(FRENCH_WEEKDAYS)}))$`,\n 'i',\n ),\n resolve: (m, ctx) => {\n let rel: 'next' | 'last' | 'this';\n let weekdayName: string;\n if (m[1] && m[2]) {\n weekdayName = m[1]!;\n rel = m[2]!.toLowerCase() === 'prochain' ? 'next' : 'last';\n } else {\n rel = 'this';\n weekdayName = m[3]!;\n }\n const targetDow = weekdayIndexFromName(weekdayName, FRENCH_WEEKDAYS);\n const refDow = extractDayOfWeek(ctx.reference);\n return addDays(ctx.temporal, ctx.reference, weekdayOffset(rel, refDow, targetDow));\n },\n },\n // past: \"il y a 2 semaines\" — multi-word marker.\n {\n pattern: new RegExp(`^il\\\\s+y\\\\s+a\\\\s+(\\\\d+)\\\\s+(jour|semaine|mois|an|ann[eée]e)s?$`, 'i'),\n resolve: (m, ctx) => {\n const count = Number(m[1]!);\n const unit = unitWordToEnglish(m[2]!);\n return addUnits(ctx.temporal, ctx.reference, -count, unit);\n },\n },\n // future: \"dans 3 jours\"\n {\n pattern: new RegExp(`^dans\\\\s+(\\\\d+)\\\\s+(jour|semaine|mois|an|ann[eée]e)s?$`, 'i'),\n resolve: (m, ctx) => {\n const count = Number(m[1]!);\n const unit = unitWordToEnglish(m[2]!);\n return addUnits(ctx.temporal, ctx.reference, count, unit);\n },\n },\n // bare \"N <unit>\" without marker — throw.\n {\n pattern: new RegExp(`^(\\\\d+)\\\\s+(jour|semaine|mois|an|ann[eée]e)s?$`, 'i'),\n resolve: (m, _ctx) => {\n throw new Error(\n `temporal-fmt: parseRelative ne peut pas déterminer si \"${m[0]}\" est passé ou futur — ` +\n `utilisez \"dans ${m[1]} ${m[2]}s\" ou \"il y a ${m[1]} ${m[2]}s\".`\n );\n },\n },\n // month-day: \"5 mars\" (day first, no separator word). Year ignored.\n {\n pattern: new RegExp(\n `^(\\\\d{1,2})\\\\s+(${nameAlternation([...FRENCH_MONTHS, ...FRENCH_MONTH_SHORT])})(?:\\\\s+(\\\\d{4}))?$`,\n 'i',\n ),\n resolve: (m, ctx) => {\n const day = Number(m[1]!);\n const month = monthIndexFromName(m[2]!, FRENCH_MONTHS, FRENCH_MONTH_SHORT);\n return resolveToNextOccurrence(ctx.temporal, ctx.reference, month, day);\n },\n },\n ],\n};\n\n// German grammar. Distinct from the others:\n// - Unit words pluralize with -n in the dative after \"in\"/\"vor\":\n// \"in 3 Tagen\" (vs nominative \"3 Tage\"). The regex accepts both\n// since callers may not always get the case right, and accepting\n// both doesn't introduce ambiguity.\n// - \"nächsten Dienstag\" — relative word precedes weekday as a\n// declined adjective, with the weekday capitalized as a noun.\n// - \"5. März\" — day-first with a period after the day number,\n// matching German date convention.\nconst GERMAN_WEEKDAYS = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'];\nconst GERMAN_MONTHS = ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'];\nconst GERMAN_MONTH_SHORT = ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'];\n\nconst GERMAN_GRAMMAR: RelativeDateGrammar = {\n supportedHint: 'Unterstützte Phrasen: Wochentag-Bezüge (\"nächsten Dienstag\", \"letzten Freitag\", \"diesen Montag\"), Tages-Offsets (\"heute\"/\"morgen\"/\"gestern\"), Einheiten-Offsets (\"in 3 Tagen\", \"vor 2 Wochen\"), und Monat-Tag (\"5. März\").',\n matchers: [\n {\n pattern: /^heute$/i,\n resolve: (_m, ctx) => buildPlainDate(ctx.temporal, readYear(ctx.reference), readMonth(ctx.reference), readDay(ctx.reference)),\n },\n {\n pattern: /^morgen$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, 1),\n },\n {\n pattern: /^gestern$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, -1),\n },\n // weekday references: \"nächsten Dienstag\" (next), \"letzten\n // Dienstag\" (last), \"diesen Dienstag\" (this). Adjective precedes\n // the weekday; case varies (nächsten/letzten/diesen all take the\n // weak-declension -en/-en/-en ending when no article, which is\n // convenient — one regex alternation covers all three.\n {\n pattern: new RegExp(`^(n(?:ae|a|ä)chsten|letzten|diesen)\\\\s+(${nameAlternation(GERMAN_WEEKDAYS)})$`, 'i'),\n resolve: (m, ctx) => {\n const adj = normalizeForMatch(m[1]!);\n const rel: 'next' | 'last' | 'this' = (adj === 'nachsten' || adj === 'naechsten') ? 'next' : adj === 'diesen' ? 'this' : 'last';\n const targetDow = weekdayIndexFromName(m[2]!, GERMAN_WEEKDAYS);\n const refDow = extractDayOfWeek(ctx.reference);\n return addDays(ctx.temporal, ctx.reference, weekdayOffset(rel, refDow, targetDow));\n },\n },\n // past: \"vor 2 Wochen\"\n {\n pattern: new RegExp(`^vor\\\\s+(\\\\d+)\\\\s+(Tag(?:e|n|en)?|Woche(?:n)?|Monat(?:e|n|en)?|Jahr(?:e|n|en)?)$`, 'i'),\n resolve: (m, ctx) => {\n const count = Number(m[1]!);\n const unit = unitWordToEnglish(m[2]!);\n return addUnits(ctx.temporal, ctx.reference, -count, unit);\n },\n },\n // future: \"in 3 Tagen\"\n {\n pattern: new RegExp(`^in\\\\s+(\\\\d+)\\\\s+(Tag(?:e|n|en)?|Woche(?:n)?|Monat(?:e|n|en)?|Jahr(?:e|n|en)?)$`, 'i'),\n resolve: (m, ctx) => {\n const count = Number(m[1]!);\n const unit = unitWordToEnglish(m[2]!);\n return addUnits(ctx.temporal, ctx.reference, count, unit);\n },\n },\n // bare \"N <unit>\" without \"in\" or \"vor\" — throw.\n {\n pattern: new RegExp(`^(\\\\d+)\\\\s+(Tag(?:e|n|en)?|Woche(?:n)?|Monat(?:e|n|en)?|Jahr(?:e|n|en)?)$`, 'i'),\n resolve: (m, _ctx) => {\n throw new Error(\n `temporal-fmt: parseRelative kann nicht erkennen, ob \"${m[0]}\" Vergangenheit oder Zukunft ist — ` +\n `verwende \"in ${m[1]} ${m[2]}\" oder \"vor ${m[1]} ${m[2]}\".`\n );\n },\n },\n // month-day: \"5. März\" (day-first with period). Year ignored.\n {\n pattern: new RegExp(\n `^(\\\\d{1,2})\\\\.?\\\\s+(${nameAlternation([...GERMAN_MONTHS, ...GERMAN_MONTH_SHORT, 'Maerz', 'Maer'])})(?:\\\\s+(\\\\d{4}))?$`,\n 'i',\n ),\n resolve: (m, ctx) => {\n const day = Number(m[1]!);\n const month = monthIndexFromName(m[2]!, GERMAN_MONTHS, GERMAN_MONTH_SHORT);\n return resolveToNextOccurrence(ctx.temporal, ctx.reference, month, day);\n },\n },\n ],\n};\n\nconst GRAMMARS: Record<string, RelativeDateGrammar> = {\n en: ENGLISH_GRAMMAR,\n es: SPANISH_GRAMMAR,\n fr: FRENCH_GRAMMAR,\n de: GERMAN_GRAMMAR,\n};\n\n// Pick a grammar for a locale. Falls back to English for languages we\n// don't have a grammar for (Italian, Portuguese, etc.) rather than\n// throwing — best-effort, matches how formatDistance treats unknown\n// locales (Intl.RelativeTimeFormat accepts them; here we fall back to\n// English so the call still succeeds with reasonable output).\nfunction grammarForLocale(locale: string | undefined): RelativeDateGrammar {\n if (!locale) return ENGLISH_GRAMMAR;\n try {\n // Intl.Locale requires BCP-47 hyphens — same normalization as the\n // other locale-handling code in this library.\n const tag = new Intl.Locale(locale.replace(/_/g, '-'));\n const lang = tag.language.toLowerCase();\n return GRAMMARS[lang] ?? ENGLISH_GRAMMAR;\n } catch {\n // Malformed locale tag — fall back to English. The actual Intl\n // call downstream will throw if the tag is genuinely unusable,\n // which is a better surface for that error than here.\n return ENGLISH_GRAMMAR;\n }\n}\n\n// Language subtag of a locale option, for dispatching to grammars\n// registered via registerRelativeGrammar(). Mirrors grammarForLocale's\n// normalization and fallback.\nfunction languageOf(locale: string | undefined): string {\n if (!locale) return 'en';\n try {\n return new Intl.Locale(locale.replace(/_/g, '-')).language.toLowerCase();\n } catch {\n return 'en';\n }\n}\n\n// Map a per-language unit word back to the English unit name the\n// shared addUnits() helper expects. Each language contributes its own\n// regex alternation of unit words; this function normalizes the\n// captured word back to a unit enum value.\nfunction unitWordToEnglish(word: string): 'day' | 'week' | 'month' | 'year' {\n const w = normalizeForMatch(word);\n // English\n /* c8 ignore next */\n if (w === 'day' || w === 'week' || w === 'month' || w === 'year') return w;\n // Spanish (accent-stripped)\n if (w === 'dia') return 'day';\n if (w === 'semana') return 'week';\n if (w === 'mes') return 'month';\n if (w === 'ano' || w === 'año') return 'year';\n // French\n if (w === 'jour') return 'day';\n if (w === 'semaine') return 'week';\n if (w === 'mois') return 'month';\n if (w === 'an' || w === 'annee') return 'year';\n // German\n if (w === 'tag' || w === 'tagen') return 'day';\n if (w === 'woche' || w === 'wochen') return 'week';\n if (w === 'monat' || w === 'monaten') return 'month';\n /* c8 ignore next */\n if (w === 'jahr' || w === 'jahren') return 'year';\n /* c8 ignore start @preserve -- unreachable: every caller passes a word\n * captured by a regex alternation built from exactly these unit-word\n * forms (day/week/month/year across en/es/fr/de), so the branches\n * above already cover every string that can reach this function.\n * Kept as a tripwire for the type checker in case a grammar adds a\n * unit word here without a matching regex update. */\n throw new Error(`temporal-fmt: parseRelative internal error — unrecognized unit word \"${word}\".`);\n /* c8 ignore stop @preserve */\n /* c8 ignore next -- defensive block is unreachable by construction. */\n}\n\n// Reference: kept exported for the unit tests that need it. The other\n// helpers above are not exported since tests only need to drive\n// parseRelative() through the public API + this one constant for the\n// Tuesday-on-Tuesday fixture.\nexport const WEEKDAY_NAMES = ENGLISH_WEEKDAYS;\nexport const MONTH_NAMES = ENGLISH_MONTHS;\n// Exported for the localeVocab-style stub-test pattern in case a future\n// test wants to verify a grammar's name list against Intl's actual\n// output for that locale — same pattern localeVocab.test.js uses to\n// catch a mismatch between what format() produces and what parse()\n// expects.\nexport const SPANISH_MONTH_NAMES = SPANISH_MONTHS;\nexport const FRENCH_MONTH_NAMES = FRENCH_MONTHS;\nexport const GERMAN_MONTH_NAMES = GERMAN_MONTHS;\nexport const SPANISH_WEEKDAY_NAMES = SPANISH_WEEKDAYS;\nexport const FRENCH_WEEKDAY_NAMES = FRENCH_WEEKDAYS;\nexport const GERMAN_WEEKDAY_NAMES = GERMAN_WEEKDAYS;\nvoid WEEKDAY_NAMES;\nvoid MONTH_NAMES;\n\nexport interface ParseRelativeOptions extends FormatOptions {\n /**\n * Opt-in typo tolerance. When the input doesn't match any phrase\n * exactly, retry after correcting individual words (weekday names,\n * month names, and marker words like \"next\"/\"ago\"/\"tomorrow\") that\n * are within a small edit distance of a known word — e.g.\n * \"tommorow\" → \"tomorrow\", \"next tuesady\" → \"next tuesday\". Numbers\n * are never touched.\n *\n * Off by default, matching this library's throw-rather-than-guess\n * philosophy elsewhere (parse()'s `lenient` option is the same shape\n * of opt-in). English only for this option currently — combining\n * `fuzzy: true` with a non-English `locale` throws rather than\n * silently skipping the fuzzy pass.\n *\n * If no correction produces a recognized phrase, throws the same\n * \"doesn't recognize\" error the exact pass would have thrown.\n */\n fuzzy?: boolean;\n}\n\n/**\n * Resolve common relative-date phrases against a reference date,\n * returning a Temporal.PlainDate. Supports English by default, plus\n * Spanish (es), French (fr), and German (de) via the `locale` option.\n *\n * Supported phrase classes (with examples per language):\n *\n * - weekday refs: \"next Tuesday\" / \"el próximo martes\" / \"mardi prochain\" / \"nächsten Dienstag\"\n * - day offsets: \"today\" / \"hoy\" / \"aujourd'hui\" / \"heute\" (and tomorrow/yesterday equivalents)\n * - unit offsets: \"in 3 days\" / \"en 3 días\" / \"dans 3 jours\" / \"in 3 Tagen\"\n * - month-day without year: \"March 5th\" / \"5 de marzo\" / \"5 mars\" / \"5. März\"\n *\n * Ambiguous-case handling is consistent across all four languages:\n * \"next X\" said on X (today is the named weekday) means 7 days from\n * now, not today. \"last X\" said on X means 7 days ago. See README\n * \"parseRelative\" for the documented behavior of each ambiguous case.\n *\n * Throws a descriptive error for any phrase it doesn't recognize in\n * the target language, rather than guessing. A bare \"5 days\" without\n * \"in\" or \"ago\" (or the per-language equivalent) throws with a message\n * pointing at the disambiguation options.\n *\n * Returns a Temporal.PlainDate for every supported phrase. Time-of-day\n * extensions like \"next Tuesday at 3pm\" aren't supported in this pass.\n */\nexport function parseRelative(\n input: string,\n referenceDate: unknown,\n options: ParseRelativeOptions = {},\n): unknown {\n const reference = referenceDate as TemporalFieldBag;\n const temporal = getTemporal();\n\n // Trim, collapse internal whitespace, strip diacritics, and lowercase.\n // Whitespace normalization is shared with the pre-change behavior;\n // diacritic stripping pairs with nameAlternation()'s normalization so\n // \"mi[eé]rcoles\" and \"miercoles\" both match the same pattern.\n // Lowercasing matches the case-insensitive regex flag explicitly so\n // the user's input never gets case-swapped on its way through the\n // matcher (the regexes are 'i'-flagged, but normalizing here keeps\n // the original-trimmed-string echo in error messages predictable).\n const trimmed = (input ?? '').trim().replace(/\\s+/g, ' ');\n if (trimmed.length === 0) {\n throw new Error('temporal-fmt: parseRelative got an empty input string.');\n }\n if (trimmed.length > MAX_RELATIVE_INPUT_LENGTH) {\n throw new RangeError(\n `temporal-fmt: parseRelative input is too large (maximum ${MAX_RELATIVE_INPUT_LENGTH} characters).`,\n );\n }\n // For error messages, keep the user's original spelling (with accents)\n // so the echo in the \"doesn't recognize\" error matches what they\n // typed. The matching itself uses the diacritic-stripped form so\n // \"mi[eé]rcoles\" / \"miercoles\" / \"MI[ÉE]RCOLES\" all match the same\n // pattern without forcing the user to remember the accent.\n const normalized = normalizeForMatch(trimmed);\n\n const grammar = grammarForLocale(options.locale);\n const ctx: ResolveContext = { temporal, reference };\n\n // Registered grammars (registerRelativeGrammar) take precedence over\n // the built-in ones for their language — that's the documented\n // contract in relativeGrammar.ts (\"try registered grammars before\n // falling back to the built-in ones\"). This wiring was missing\n // entirely before: registered grammars were stored and listed but\n // never consulted, so the extension point silently did nothing.\n // Returns null quickly when nothing is registered for the language.\n const registered = tryRegisteredGrammar(languageOf(options.locale), trimmed, {\n year: reference.year as number,\n month: reference.month as number,\n day: reference.day as number,\n dayOfWeek: reference.dayOfWeek as number,\n });\n if (registered !== null) {\n return registered;\n }\n\n const tryMatch = (text: string): unknown | typeof NO_MATCH => {\n for (const matcher of grammar.matchers) {\n const match = text.match(matcher.pattern);\n if (match) {\n return matcher.resolve(match, ctx);\n }\n }\n return NO_MATCH;\n };\n\n const exactResult = tryMatch(normalized);\n if (exactResult !== NO_MATCH) {\n return exactResult;\n }\n\n if (options.fuzzy) {\n // Fuzzy mode is English-only for this pass — see the vocabulary\n // comment above fuzzyCorrectEnglish for why the other three\n // grammars aren't covered. Fail loudly rather than silently\n // skipping the fuzzy attempt, so a caller relying on fuzzy mode\n // for, say, French input doesn't get a confusing \"doesn't\n // recognize\" error with no indication fuzzy matching never ran.\n if (grammar !== ENGLISH_GRAMMAR) {\n throw new Error(\n `temporal-fmt: parseRelative's { fuzzy: true } option currently only supports English. ` +\n `Pass no locale (or locale: 'en'), or omit { fuzzy: true } for this locale.`\n );\n }\n const corrected = fuzzyCorrectEnglish(normalized);\n if (corrected !== undefined) {\n const fuzzyResult = tryMatch(corrected);\n if (fuzzyResult !== NO_MATCH) {\n return fuzzyResult;\n }\n }\n }\n\n throw new Error(\n `temporal-fmt: parseRelative doesn't recognize \"${trimmed}\". ` +\n grammar.supportedHint\n );\n}\n\n// Sentinel distinguishing \"no matcher matched\" from a legitimate\n// resolve() return value of `undefined`/`null` (matchers can throw\n// their own errors, e.g. the ambiguous-direction case, but none\n// currently return a nullish PlainDate — this sentinel just makes the\n// \"no match\" case unambiguous regardless).\nconst NO_MATCH = Symbol('temporal-fmt: parseRelative no match');\n\n// DEFAULT_LOCALE is imported for the option's default-value documentation\n// above (no locale → English). The symbol itself isn't read at runtime\n// here, but the import keeps the dependency edge explicit so future\n// changes to the default-locale constant propagate here too.\nvoid DEFAULT_LOCALE;","// Type guards for Temporal values. The rest of this library works off the\n// duck-typed `TemporalLike` shape (year/month/day/hour/...) rather than\n// `instanceof Temporal.X`, because `instanceof` breaks across polyfill/\n// native boundaries — a polyfill's `Temporal.PlainDate` is a different\n// constructor from the native one, so a `value instanceof Temporal.PlainDate`\n// check would silently fail when the caller is using a polyfill while the\n// guard happens to be looking at native Temporal, or vice versa. Same\n// reasoning as tokens.ts's `intlSupportsNativeTemporal` probe: identity\n// checks don't survive the polyfill/native swap.\n//\n// These guards check structural shape instead: presence of the type-\n// discriminating method each Temporal type carries. Method presence is\n// part of the Temporal spec contract — every implementation, native or\n// polyfill, must expose the same methods on the same types — so it's a\n// stable signal without dragging in a Temporal namespace.\n//\n// Per-type discriminators (verified against @js-temporal/polyfill's\n// prototype method list, which matches the spec):\n//\n// PlainDate — `toPlainDateTime` + `withCalendar` + year/month/day,\n// no hour. (PlainDateTime also has `toPlainDateTime`'s\n// sibling `toPlainDate`/`toPlainTime`, but carries\n// hour — distinguished by time-field presence.)\n// PlainTime — no `toPlainDateTime`, no `withCalendar`. Has hour,\n// no year/month/day. (The only Temporal date/time type\n// that has neither `withCalendar` nor any `toPlainX`\n// method.)\n// PlainDateTime — `toPlainDate` + `withPlainTime` + year/month/day\n// AND hour. (`withPlainTime` is unique — only\n// PlainDateTime and ZonedDateTime carry it; ZonedDateTime\n// also carries `toInstant`, which PlainDateTime doesn't.)\n// ZonedDateTime — `toInstant` + `withTimeZone`. (Both are unique —\n// only ZonedDateTime carries `withTimeZone`.)\n// Instant — `toZonedDateTimeISO`, no `toInstant`. (Instant IS\n// the instant; the `toInstant` method belongs to\n// ZonedDateTime. `toZonedDateTimeISO` exists on\n// Instant and ZonedDateTime per the spec, but on\n// ZonedDateTime it's not exposed via the prototype\n// in either native or polyfill — only Instant has it\n// as a method. Verified by probing both.)\n// PlainYearMonth — `toPlainDate` (takes a day arg) + year/month,\n// no day. (PlainDate also has `toPlainDate`-shaped\n// methods but carries day; PlainMonthDay also has\n// `toPlainDate` but carries day, not year.)\n// PlainMonthDay — `toPlainDate` + month/day, no year. Plus: lacks\n// `add`/`subtract`/`until`/`since` (calendar arithmetic\n// doesn't apply to a month-day without a year).\n// Duration — `total` + `abs` + `negated`. (All three are unique\n// to Duration; no other Temporal type carries any of them.)\n\n// The shapes below intentionally mirror TemporalLike in tokens.ts but\n// stay loose enough to also match real Temporal objects (which carry\n// the spec methods the field-only TemporalLike doesn't).\ninterface TemporalInstance {\n toInstant?: () => unknown;\n toPlainDate?: (arg?: unknown) => unknown;\n toPlainDateTime?: (arg?: unknown) => unknown;\n toPlainTime?: () => unknown;\n toPlainYearMonth?: () => unknown;\n toPlainMonthDay?: () => unknown;\n toZonedDateTime?: (arg: unknown) => unknown;\n toZonedDateTimeISO?: (arg: unknown) => unknown;\n withCalendar?: (cal: unknown) => unknown;\n withPlainTime?: (t: unknown) => unknown;\n withTimeZone?: (z: unknown) => unknown;\n getTimeZoneTransition?: (opts: unknown) => unknown;\n startOfDay?: () => unknown;\n sign?: () => number;\n blank?: () => boolean;\n total?: (opts: unknown) => number;\n abs?: () => unknown;\n negated?: () => unknown;\n toString?: () => string;\n // Fields from TemporalLike — present on all date-carrying Temporal\n // types but absent on PlainTime (which has no calendar position).\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n calendarId?: string;\n timeZoneId?: string;\n // PlainMonthDay stores its month as `monthCode` (e.g. \"M08\"), not\n // as a numeric `month` field — without a year there's no way to\n // disambiguate which month a calendar-independent numeric month\n // refers to in leap-year-aware calendars, so the spec uses\n // `monthCode` instead. PlainMonthDay is the only Temporal type that\n // exposes `monthCode` without also exposing `month`.\n monthCode?: string;\n}\n\nfunction isObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null;\n}\n\n// Hostile-getter hardening: the structural guards below read properties\n// (year, hour, Symbol.toStringTag, ...) off arbitrary caller values. An\n// object with a throwing getter used to turn isPlainDate(obj) — a function\n// whose whole contract is returning a boolean — into an exception factory.\n// Every exported guard now runs through this wrapper: a throw during\n// probing means \"not one of ours\", not a crash. One shared catch (rather\n// than one per guard) keeps the coverage burden honest too.\nfunction guardOrFalse<T>(impl: (value: unknown) => value is T): (value: unknown) => value is T {\n return (value: unknown): value is T => {\n try {\n return impl(value);\n } catch {\n return false;\n }\n };\n}\n\nfunction hasMethod<T extends keyof TemporalInstance>(\n v: TemporalInstance,\n name: T,\n): boolean {\n return typeof v[name] === 'function';\n}\n\n// Symbol.toStringTag is the spec-mandated brand for Temporal types —\n// every Temporal instance carries a tag like \"Temporal.PlainDate\" via\n// this well-known symbol, regardless of whether it's native or polyfill.\n// Used by the per-type guards as a fast positive signal: a tag match\n// is sufficient, the structural fallback (field presence + method checks)\n// is only consulted when the tag isn't set (which can happen with\n// hand-built mock objects or partial implementations).\nfunction hasTag(value: unknown, typeName: string): boolean {\n if (!isObject(value)) return false;\n const tag = (value as { [Symbol.toStringTag]?: unknown })[Symbol.toStringTag];\n return tag === `Temporal.${typeName}`;\n}\n\nexport const isPlainDate: (value: unknown) => value is TemporalInstance = guardOrFalse(function isPlainDateImpl(value: unknown): value is TemporalInstance {\n if (hasTag(value, 'PlainDate')) return true;\n if (!isObject(value)) return false;\n const v = value as TemporalInstance;\n return typeof v.year === 'number'\n && typeof v.month === 'number'\n && typeof v.day === 'number'\n && typeof v.hour === 'undefined'\n && hasMethod(v, 'toPlainDateTime')\n && hasMethod(v, 'withCalendar');\n});\n\nexport const isPlainTime: (value: unknown) => value is TemporalInstance = guardOrFalse(function isPlainTimeImpl(value: unknown): value is TemporalInstance {\n if (hasTag(value, 'PlainTime')) return true;\n if (!isObject(value)) return false;\n const v = value as TemporalInstance;\n // PlainTime is the only Temporal type with `hour` but no `year` and\n // neither `withCalendar` nor any `toPlainX` method. That combination\n // is unique among the eight types.\n return typeof v.hour === 'number'\n && typeof v.year === 'undefined'\n && !hasMethod(v, 'withCalendar')\n && !hasMethod(v, 'toPlainDate')\n && !hasMethod(v, 'toPlainDateTime');\n});\n\nexport const isPlainDateTime: (value: unknown) => value is TemporalInstance = guardOrFalse(function isPlainDateTimeImpl(value: unknown): value is TemporalInstance {\n if (hasTag(value, 'PlainDateTime')) return true;\n if (!isObject(value)) return false;\n const v = value as TemporalInstance;\n // `withPlainTime` is on PlainDateTime and ZonedDateTime; ZonedDateTime\n // also carries `toInstant`. The combination \"has withPlainTime, no\n // toInstant\" uniquely identifies PlainDateTime.\n return typeof v.year === 'number'\n && typeof v.month === 'number'\n && typeof v.day === 'number'\n && typeof v.hour === 'number'\n && hasMethod(v, 'withPlainTime')\n && !hasMethod(v, 'toInstant');\n});\n\nexport const isZonedDateTime: (value: unknown) => value is TemporalInstance = guardOrFalse(function isZonedDateTimeImpl(value: unknown): value is TemporalInstance {\n if (hasTag(value, 'ZonedDateTime')) return true;\n if (!isObject(value)) return false;\n const v = value as TemporalInstance;\n // `withTimeZone` is unique to ZonedDateTime across every Temporal type.\n return typeof v.year === 'number'\n && typeof v.month === 'number'\n && typeof v.day === 'number'\n && typeof v.hour === 'number'\n && hasMethod(v, 'withTimeZone')\n && hasMethod(v, 'toInstant');\n});\n\nexport const isInstant: (value: unknown) => value is TemporalInstance = guardOrFalse(function isInstantImpl(value: unknown): value is TemporalInstance {\n if (hasTag(value, 'Instant')) return true;\n if (!isObject(value)) return false;\n // Instant carries `toZonedDateTimeISO` and no `toInstant` (it IS the\n // instant). It also has no year/month/day/hour fields — those are\n // only meaningful against a calendar and zone, which Instant alone\n // doesn't carry.\n const v = value as TemporalInstance;\n return hasMethod(v, 'toZonedDateTimeISO')\n && !hasMethod(v, 'toInstant')\n && typeof v.year === 'undefined';\n});\n\nexport const isPlainYearMonth: (value: unknown) => value is TemporalInstance = guardOrFalse(function isPlainYearMonthImpl(value: unknown): value is TemporalInstance {\n if (hasTag(value, 'PlainYearMonth')) return true;\n if (!isObject(value)) return false;\n const v = value as TemporalInstance;\n // Has year+month, no day, carries `toPlainDate` (used to attach a day).\n // PlainMonthDay also carries `toPlainDate` but has no `year` field.\n return typeof v.year === 'number'\n && typeof v.month === 'number'\n && typeof v.day === 'undefined'\n && hasMethod(v, 'toPlainDate');\n});\n\nexport const isPlainMonthDay: (value: unknown) => value is TemporalInstance = guardOrFalse(function isPlainMonthDayImpl(value: unknown): value is TemporalInstance {\n if (hasTag(value, 'PlainMonthDay')) return true;\n if (!isObject(value)) return false;\n const v = value as TemporalInstance;\n // PlainMonthDay has `day` and `monthCode` but no `year` and no numeric\n // `month`. The `monthCode` field is the discriminator — every other\n // Temporal type that has a month concept either exposes `month` (numeric,\n // calendar-aware) or doesn't expose months at all (PlainTime, Duration).\n return typeof v.year === 'undefined'\n && typeof v.month === 'undefined'\n && typeof v.day === 'number'\n && typeof v.monthCode === 'string'\n && hasMethod(v, 'toPlainDate');\n});\n\nexport const isDuration: (value: unknown) => value is Record<string, unknown> = guardOrFalse(function isDurationImpl(value: unknown): value is Record<string, unknown> {\n if (hasTag(value, 'Duration')) return true;\n if (!isObject(value)) return false;\n // `total` is unique to Duration across every Temporal type — no other\n // type carries it (verified by probing the prototype of each).\n // `abs` and `negated` are also Duration-only. Checking any one of\n // them is sufficient; checking `total` because it's the most semantically\n // distinctive (a Duration-specific operation no other type would\n // coincidentally need).\n const v = value as TemporalInstance;\n return hasMethod(v, 'total');\n});\n\n// Umbrella guard: any Temporal namespace member. Used by `assertTemporal`\n// below for the \"this needs to be some Temporal thing\" case. Two signals\n// checked in order:\n// 1. `Symbol.toStringTag` — every Temporal type brands itself as\n// `Temporal.X` via this well-known symbol. This is the spec-\n// mandated brand, present on native and polyfill instances alike.\n// 2. The discriminating-method fallback — covers any case where a\n// future/partial Temporal impl doesn't set the tag. Method\n// presence is part of the Temporal spec contract; combined with\n// `equals` + `with` (both present on every Temporal instance),\n// it's a reliable signal that doesn't rely on the toStringTag\n// being set.\nexport const isTemporal: (value: unknown) => value is TemporalInstance = guardOrFalse(function isTemporalImpl(value: unknown): value is TemporalInstance {\n if (!isObject(value)) return false;\n const tag = (value as { [Symbol.toStringTag]?: unknown })[Symbol.toStringTag];\n if (typeof tag === 'string' && tag.startsWith('Temporal.')) return true;\n const v = value as TemporalInstance;\n return hasMethod(v, 'toInstant')\n || hasMethod(v, 'toPlainDate')\n || hasMethod(v, 'toPlainDateTime')\n || hasMethod(v, 'toPlainTime')\n || hasMethod(v, 'toPlainYearMonth')\n || hasMethod(v, 'toPlainMonthDay')\n || hasMethod(v, 'toZonedDateTime')\n || hasMethod(v, 'toZonedDateTimeISO')\n || hasMethod(v, 'withCalendar')\n || hasMethod(v, 'withPlainTime')\n || hasMethod(v, 'withTimeZone')\n || hasMethod(v, 'total');\n});\n\n// Assertion helpers — throw descriptively rather than returning false.\n// Same convention as the rest of the library: descriptive thrown errors\n// instead of silent failures. The thrown Error carries a `valueType`\n// hint in the message so the caller can see what they actually passed.\nfunction describeValue(value: unknown): string {\n if (value === null) return 'null';\n if (Array.isArray(value)) return 'array';\n if (typeof value === 'object') {\n const ctor = (value as { constructor?: { name?: string } }).constructor;\n if (ctor && typeof ctor.name === 'string' && ctor.name !== 'Object') {\n return `instance of ${ctor.name}`;\n }\n return 'plain object';\n }\n return typeof value;\n}\n\nfunction assertImpl(value: unknown, guard: (v: unknown) => boolean, expectedType: string): void {\n if (!guard(value)) {\n throw new Error(\n `temporal-fmt: expected a Temporal.${expectedType}, got ${describeValue(value)}.`\n );\n }\n}\n\nexport function assertTemporal(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isTemporal, 'object (Instant, PlainDate, PlainTime, PlainDateTime, ZonedDateTime, Duration, PlainYearMonth, or PlainMonthDay)');\n}\nexport function assertInstant(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isInstant, 'Instant');\n}\nexport function assertPlainDate(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isPlainDate, 'PlainDate');\n}\nexport function assertPlainTime(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isPlainTime, 'PlainTime');\n}\nexport function assertPlainDateTime(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isPlainDateTime, 'PlainDateTime');\n}\nexport function assertZonedDateTime(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isZonedDateTime, 'ZonedDateTime');\n}\nexport function assertPlainYearMonth(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isPlainYearMonth, 'PlainYearMonth');\n}\nexport function assertPlainMonthDay(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isPlainMonthDay, 'PlainMonthDay');\n}\nexport function assertDuration(value: unknown): asserts value is Record<string, unknown> {\n assertImpl(value, isDuration, 'Duration');\n}","// Per-token metadata: the structured descriptor this module\n// asks for (meaning, format-capable?, parse-capable?, locale-sensitive?,\n// calendar-sensitive?, timezone-sensitive?, supported Temporal types,\n// round-trip-safe?). One table, kept in sync with TOKENS in tokens.ts\n// by tests (see test/tokenMetadata.test.js — every entry in TOKENS has\n// a metadata entry, and vice versa).\n//\n// This is the single source of truth that analyzeFormat() (section E)\n// and the ESLint plugin / codemod consume — never read the\n// TOKENS array directly for metadata; use TOKEN_METADATA here, or the\n// tokenInfo() / listTokens() wrappers in analyze.ts.\n\nimport type { TemporalLike } from './tokens.js';\n\nexport type TemporalType =\n | 'Instant'\n | 'PlainDate'\n | 'PlainTime'\n | 'PlainDateTime'\n | 'ZonedDateTime'\n | 'PlainYearMonth'\n | 'PlainMonthDay';\n\nexport interface TokenMetadata {\n // Short human-readable description of what the token represents.\n meaning: string;\n // True if format() accepts this token. Every token in TOKENS is\n // format-capable by construction; this flag exists so the table is\n // self-describing for callers (the codemod) that work with token\n // families including format-only tokens from other libraries.\n formatCapable: boolean;\n // True if parse() accepts this token. False for `do`, `ww`, `RRRR`\n // — see FORMAT_ONLY_TOKENS in pattern.ts.\n parseCapable: boolean;\n // True if the output depends on locale (resolves via Intl or\n // custom vocab). MMMM/MMM/EEEE/EEE/a are true; everything else is\n // numeric ASCII and locale-independent.\n localeSensitive: boolean;\n // True if the output depends on the calendar (gregory, hebrew,\n // etc.). Locale-aware tokens inherit calendar sensitivity from\n // the Intl path (a hebrew PlainDate's month name depends on the\n // hebrew calendar). Year/month/day numeric tokens are calendar-\n // sensitive in principle (a Hebrew year/month renders differently\n // than a Gregorian one) but stay ISO-numeric on the format side\n // because tokens.ts reads straight off TemporalLike fields, which\n // are already calendar-specific by the time format() sees them.\n calendarSensitive: boolean;\n // True if the token requires a timeZoneId or offset field — i.e.\n // only ZonedDateTime supports it. zzz and the six offset tokens\n // (X/XX/XXX/x/xx/xxx) are timezone-sensitive.\n timezoneSensitive: boolean;\n // Which Temporal types can supply the field this token needs.\n // PlainTime can't supply year; PlainDate can't supply hour; only\n // ZonedDateTime carries timeZoneId/offset.\n supportedTypes: TemporalType[];\n // True if format(x, fmt) → parse(fmt, output) round-trips back to\n // a value equal to x. False when the format is fundamentally lossy:\n // `do` (ordinal suffix isn't structurally parseable), `ww`/`RRRR`\n // (week + weekday alone can't reconstruct a date without an extra\n // disambiguator), `yy` (two-digit year loses century — strptime\n // heuristic resolves it, but the heuristic isn't symmetric with\n // how `yy` formats BCE years, so round-trip only works for years\n // where 00-68/69-99 lands back on the same century).\n roundTripSafe: boolean;\n}\n\n// Helper: which Temporal types carry each field. Centralized here so\n// the supportedTypes arrays below stay short and the table is easy to\n// audit. Mirrors the field checks in tokens.ts (handler third tuple\n// element).\nconst TYPES_WITH: Record<string, TemporalType[]> = {\n year: ['PlainDate', 'PlainDateTime', 'ZonedDateTime', 'PlainYearMonth'],\n month: ['PlainDate', 'PlainDateTime', 'ZonedDateTime', 'PlainYearMonth', 'PlainMonthDay'],\n day: ['PlainDate', 'PlainDateTime', 'ZonedDateTime', 'PlainMonthDay'],\n hour: ['PlainTime', 'PlainDateTime', 'ZonedDateTime', 'Instant'],\n minute: ['PlainTime', 'PlainDateTime', 'ZonedDateTime', 'Instant'],\n second: ['PlainTime', 'PlainDateTime', 'ZonedDateTime', 'Instant'],\n millisecond: ['PlainTime', 'PlainDateTime', 'ZonedDateTime', 'Instant'],\n dayOfWeek: ['PlainDate', 'PlainDateTime', 'ZonedDateTime'],\n timeZoneId: ['ZonedDateTime'],\n offset: ['ZonedDateTime'],\n};\n\n// Every token in TOKENS gets an entry here. Adding a token to TOKENS\n// without adding one here makes test/tokenMetadata.test.js fail.\nexport const TOKEN_METADATA: Record<string, TokenMetadata> = {\n yyyy: {\n meaning: 'Four-digit year (preserves sign for BCE; no truncation).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.year, roundTripSafe: true,\n },\n yy: {\n meaning: 'Two-digit year (year % 100). Throws on negative years.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.year, roundTripSafe: false,\n },\n MMMM: {\n meaning: 'Long month name (locale-aware, e.g. \"January\", \"janvier\").',\n formatCapable: true, parseCapable: true, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n MMM: {\n meaning: 'Short month name (locale-aware, e.g. \"Jan\", \"janv.\").',\n formatCapable: true, parseCapable: true, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n MM: {\n meaning: 'Two-digit month (01-12, zero-padded).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n M: {\n meaning: 'One- or two-digit month (1-12, no padding).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n dd: {\n meaning: 'Two-digit day-of-month (01-31, zero-padded).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.day, roundTripSafe: true,\n },\n d: {\n meaning: 'One- or two-digit day-of-month (1-31, no padding).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.day, roundTripSafe: true,\n },\n EEEE: {\n meaning: 'Long weekday name (locale-aware, e.g. \"Monday\", \"lundi\"). Parse cross-checks against the parsed date.',\n formatCapable: true, parseCapable: true, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.dayOfWeek, roundTripSafe: true,\n },\n EEE: {\n meaning: 'Short weekday name (locale-aware, e.g. \"Mon\", \"lun.\"). Parse cross-checks against the parsed date.',\n formatCapable: true, parseCapable: true, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.dayOfWeek, roundTripSafe: true,\n },\n HH: {\n meaning: 'Two-digit hour, 24-hour clock (00-23, zero-padded).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.hour, roundTripSafe: true,\n },\n H: {\n meaning: 'One- or two-digit hour, 24-hour clock (0-23, no padding).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.hour, roundTripSafe: true,\n },\n hh: {\n meaning: 'Two-digit hour, 12-hour clock (01-12, zero-padded). Requires `a` token on parse.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.hour, roundTripSafe: true,\n },\n h: {\n meaning: 'One- or two-digit hour, 12-hour clock (1-12, no padding). Requires `a` token on parse.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.hour, roundTripSafe: true,\n },\n mm: {\n meaning: 'Two-digit minute (00-59, zero-padded).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.minute, roundTripSafe: true,\n },\n m: {\n meaning: 'One- or two-digit minute (0-59, no padding).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.minute, roundTripSafe: true,\n },\n ss: {\n meaning: 'Two-digit second (00-59, zero-padded).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.second, roundTripSafe: true,\n },\n s: {\n meaning: 'One- or two-digit second (0-59, no padding).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.second, roundTripSafe: true,\n },\n S: {\n meaning: 'Fractional second, 1 digit (tenths of a second).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SS: {\n meaning: 'Fractional second, 2 digits (hundredths of a second).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SSS: {\n meaning: 'Fractional second, 3 digits (milliseconds).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SSSS: {\n meaning: 'Fractional second, 4 digits (tens of microseconds).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SSSSS: {\n meaning: 'Fractional second, 5 digits (hundred-thousandths of a second).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SSSSSS: {\n meaning: 'Fractional second, 6 digits (microseconds).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SSSSSSS: {\n meaning: 'Fractional second, 7 digits (tens of nanoseconds).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SSSSSSSS: {\n meaning: 'Fractional second, 8 digits (hundred-millionths of a second).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SSSSSSSSS: {\n meaning: 'Fractional second, 9 digits (nanoseconds).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n a: {\n meaning: 'Day period (locale-aware: \"AM\"/\"PM\", \"午前\"/\"午後\", etc.). Required alongside 12-hour tokens on parse.',\n formatCapable: true, parseCapable: true, localeSensitive: true, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.hour, roundTripSafe: true,\n },\n zzz: {\n meaning: 'IANA time zone id (e.g. \"America/New_York\") or fixed offset (\"+05:30\"). Requires full date+time on parse.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.timeZoneId, roundTripSafe: true,\n },\n X: {\n meaning: 'Numeric UTC offset, short (Z for UTC, ±HH[MM] otherwise). Minutes omitted when zero.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.offset, roundTripSafe: true,\n },\n XX: {\n meaning: 'Numeric UTC offset, no colon (Z for UTC, ±HHMM otherwise).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.offset, roundTripSafe: true,\n },\n XXX: {\n meaning: 'Numeric UTC offset, with colon (Z for UTC, ±HH:MM otherwise).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.offset, roundTripSafe: true,\n },\n x: {\n meaning: 'Numeric UTC offset, short, never Z (always ±HH[MM]). Lowercase variant of X.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.offset, roundTripSafe: true,\n },\n xx: {\n meaning: 'Numeric UTC offset, no colon, never Z (always ±HHMM). Lowercase variant of XX.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.offset, roundTripSafe: true,\n },\n xxx: {\n meaning: 'Numeric UTC offset, with colon, never Z (always ±HH:MM). Lowercase variant of XXX.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.offset, roundTripSafe: true,\n },\n do: {\n meaning: 'Ordinal day-of-month with English suffix (\"1st\", \"2nd\", \"3rd\", \"4th\", ... 21st, 22nd, ...). Format-only — not parseable.',\n formatCapable: true, parseCapable: false, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.day, roundTripSafe: false,\n },\n Q: {\n meaning: 'Quarter as a digit (1-4). Derived from month.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n QQQ: {\n meaning: 'Quarter with \"Q\" prefix (\"Q1\"..\"Q4\"). Derived from month.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n ww: {\n meaning: 'ISO 8601 week number (01-53). Format-only — week alone can\\'t reconstruct a date.',\n formatCapable: true, parseCapable: false, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.dayOfWeek, roundTripSafe: false,\n },\n RRRR: {\n meaning: 'ISO 8601 week-numbering year (4-digit, may differ from calendar year at year boundaries). Format-only.',\n formatCapable: true, parseCapable: false, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.dayOfWeek, roundTripSafe: false,\n },\n D: {\n meaning: 'Day of year, unpadded (1-366). Format-only — parsing requires resolving against a year.',\n formatCapable: true, parseCapable: false, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.day, roundTripSafe: false,\n },\n DD: {\n meaning: 'Day of year, 2-digit minimum (01-366). Format-only.',\n formatCapable: true, parseCapable: false, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.day, roundTripSafe: false,\n },\n DDD: {\n meaning: 'Day of year, 3-digit zero-padded (001-366). Format-only.',\n formatCapable: true, parseCapable: false, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.day, roundTripSafe: false,\n },\n LLLL: {\n meaning: 'Stand-alone long month name (nominative case in Slavic locales). Identical to MMMM in most locales.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n LLL: {\n meaning: 'Stand-alone short month name. Identical to MMM in most locales.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n cccc: {\n meaning: 'Stand-alone long weekday name. Identical to EEEE in most locales.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.dayOfWeek, roundTripSafe: true,\n },\n ccc: {\n meaning: 'Stand-alone short weekday name. Identical to EEE in most locales.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.dayOfWeek, roundTripSafe: true,\n },\n GGGG: {\n meaning: 'Long era name (locale-aware, e.g. \"Anno Domini\"/\"Before Christ\"). Format-only.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.year, roundTripSafe: false,\n },\n G: {\n meaning: 'Short era name (locale-aware, e.g. \"AD\"/\"BC\"). Format-only.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.year, roundTripSafe: false,\n },\n zzzz: {\n meaning: 'Localized long timezone name (e.g. \"Eastern Standard Time\"). Format-only.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.timeZoneId, roundTripSafe: false,\n },\n z: {\n meaning: 'Localized short timezone name (e.g. \"EST\"). Format-only.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.timeZoneId, roundTripSafe: false,\n },\n\n};\n\nexport const ALL_TOKEN_NAMES: string[] = Object.keys(TOKEN_METADATA);","// Format-string analysis and introspection. Single source of truth for\n// \"what does this format string need / accept / produce\" — consumed by\n// the ESLint plugin and the codemod\n// so they don't each carry their own token table that drifts out of\n// sync with the runtime. Everything here reads from TOKENS in\n// tokens.ts and TOKEN_METADATA in tokenMetadata.ts, so adding a token\n// to those two tables automatically makes it visible to analyze()\n// without touching this file.\n\nimport { TOKENS, type TemporalLike } from './tokens.js';\nimport { TOKEN_METADATA, type TokenMetadata, type TemporalType } from './tokenMetadata.js';\nimport { tokenize, type Piece } from './tokenize.js';\nimport { _handlerFor } from './format.js';\nimport { UNPADDED_NUMERIC_TOKENS, FORMAT_ONLY_TOKENS } from './pattern.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\n\n// Re-exported so callers can import everything analyzer-related from a\n// single entry point — analyze.ts is the introspection surface.\nexport type { TokenMetadata, TemporalType } from './tokenMetadata.js';\nexport type { Piece } from './tokenize.js';\n\n// tokenizeFormat is the same tokenize() the runtime uses, exposed\n// under a name that signals \"this is the introspection entry point.\"\n// Same implementation, different name — callers reading analyze.ts\n// see a coherent API surface rather than having to know that the\n// runtime tokenizer is the right thing to call.\nexport function tokenizeFormat(formatStr: string): Piece[] {\n return tokenize(formatStr);\n}\n\n// listTokens: every token the runtime recognizes, with metadata. Used\n// by IDE autocomplete data (section AC) and the codemod's \"can this\n// source-library token be translated?\" lookup (section Z).\nexport function listTokens(): Array<{ name: string; metadata: TokenMetadata }> {\n return TOKENS.map(([name]) => ({ name, metadata: TOKEN_METADATA[name]! }));\n}\n\n// tokenInfo: one token's metadata. Returns undefined for unknown\n// tokens rather than throwing — callers (autocomplete, hover docs)\n// want a sentinel, not an exception, when a user types a partial token.\nexport function tokenInfo(name: string): TokenMetadata | undefined {\n return TOKEN_METADATA[name];\n}\n\nexport interface AnalyzedToken {\n name: string;\n // Position in the format string, 0-indexed. Useful for IDE diagnostics\n // that highlight a specific token.\n position: number;\n metadata: TokenMetadata;\n}\n\nexport interface FormatAnalysis {\n // Every token in the format string, in order, with metadata.\n tokens: AnalyzedToken[];\n // Fields (year/month/day/hour/...) any token in this format string\n // reads off the input. Lets a caller statically check \"does this\n // format string need a field PlainDate doesn't have?\"\n requiredFields: string[];\n // Temporal types that can supply every required field. The intersection\n // across all tokens — a format string with both `yyyy` (needs year)\n // and `HH` (needs hour) is compatible only with types carrying both,\n // i.e. PlainDateTime/ZonedDateTime.\n compatibleTypes: TemporalType[];\n // Can parse() accept this format string? False when any token is\n // format-only (do/ww/RRRR per FORMAT_ONLY_TOKENS in pattern.ts).\n parseable: boolean;\n // Does the format string contain any locale-aware token (MMMM/MMM/\n // EEEE/EEE/a)? True means the output depends on the locale option\n // and a registered custom vocab can override the result.\n localeSensitive: boolean;\n // Does the format string contain any calendar-sensitive token?\n // Almost every date/weekday token is, since its output depends on\n // the object's calendar (a hebrew PlainDate's \"MMMM\" is a hebrew\n // month name). Pure-time tokens (HH/mm/ss) are not.\n calendarSensitive: boolean;\n // Does the format string contain zzz or any offset token? If yes,\n // only ZonedDateTime can supply the field.\n timezoneSensitive: boolean;\n // Does the format string contain a run of 2+ adjacent unpadded\n // numeric tokens with no literal between them (Md, dM, Hms, ...)?\n // Such runs can be ambiguous at parse time — strict mode throws,\n // lenient mode picks one split via the documented heuristic.\n ambiguous: boolean;\n // Does format(x, fmt) → parse(fmt, output) round-trip? False when\n // any token is format-only OR when yy is used (century loss).\n roundTripSafe: boolean;\n // Non-fatal issues found during analysis. Each carries a `code`\n // the IDE plugin / CLI can switch on. Empty for clean format strings.\n warnings: Array<{ code: string; message: string }>;\n}\n\nexport function analyzeFormat(formatStr: string): FormatAnalysis {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`\n );\n }\n const pieces = tokenize(formatStr);\n const tokens: AnalyzedToken[] = [];\n const requiredFields = new Set<string>();\n const compatibleTypesSet = new Set<TemporalType>();\n let parseable = true;\n let localeSensitive = false;\n let calendarSensitive = false;\n let timezoneSensitive = false;\n let roundTripSafe = true;\n const warnings: Array<{ code: string; message: string }> = [];\n\n // Walk pieces, building up the analysis. Position is computed per\n // token piece (literals count toward offset but don't appear in the\n // tokens array).\n let offset = 0;\n const unpaddedRun: string[] = [];\n const flushRun = () => {\n if (unpaddedRun.length >= 2) {\n warnings.push({\n code: 'AMBIGUOUS_NUMERIC_RUN',\n message: `Adjacent unpadded numeric tokens \"${unpaddedRun.join('')}\" with no separator can be ambiguous to parse. Add a separator or use the padded form (e.g. \"MM\" instead of \"M\").`,\n });\n }\n unpaddedRun.length = 0;\n };\n\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n offset += piece.value.length;\n flushRun();\n continue;\n }\n const metadata = TOKEN_METADATA[piece.value];\n // Dead by construction, confirmed via listTokens(): every token in\n // TOKENS has a matching TOKEN_METADATA entry (51/51), and tokenize()\n // already throws on any string that isn't in TOKENS before this loop\n // ever runs. Kept as a guard against the two tables drifting apart.\n /* c8 ignore start */\n if (!metadata) {\n warnings.push({\n code: 'UNKNOWN_TOKEN_NO_METADATA',\n message: `Token \"${piece.value}\" is recognized by the tokenizer but has no metadata entry in tokenMetadata.ts — this is a bug in temporal-fmt.`,\n });\n offset += piece.value.length;\n continue;\n }\n /* c8 ignore stop */\n tokens.push({ name: piece.value, position: offset, metadata });\n\n // Required fields: read off the handler map (the source of truth\n // for \"what field does this token need\"). Falls back to the\n // metadata's supportedTypes-derived field set if the handler isn't\n // found, which also shouldn't happen.\n const handler = _handlerFor(piece.value);\n if (handler) {\n requiredFields.add(handler.field as string);\n }\n\n // compatibleTypes: intersect every token's supportedTypes. The\n // first token seeds the set; subsequent tokens narrow it.\n if (tokens.length === 1) {\n for (const t of metadata.supportedTypes) compatibleTypesSet.add(t);\n } else {\n const stillCompatible = new Set<TemporalType>();\n for (const t of compatibleTypesSet) {\n if (metadata.supportedTypes.includes(t)) stillCompatible.add(t);\n }\n compatibleTypesSet.clear();\n for (const t of stillCompatible) compatibleTypesSet.add(t);\n }\n\n if (!metadata.parseCapable) {\n parseable = false;\n warnings.push({\n code: 'FORMAT_ONLY_TOKEN',\n message: `Token \"${piece.value}\" is format-only — it can't be parsed back into a value. Use a parse-capable variant (e.g. \"d\" instead of \"do\") if you need round-trip.`,\n });\n }\n if (metadata.localeSensitive) localeSensitive = true;\n if (metadata.calendarSensitive) calendarSensitive = true;\n if (metadata.timezoneSensitive) timezoneSensitive = true;\n if (!metadata.roundTripSafe) roundTripSafe = false;\n\n // Track runs of adjacent unpadded numeric tokens — same definition\n // as parsePattern.ts uses (UNPADDED_NUMERIC_TOKENS). A literal\n // between tokens breaks the run; this is checked by the flushRun\n // call above.\n if (UNPADDED_NUMERIC_TOKENS.has(piece.value)) {\n unpaddedRun.push(piece.value);\n } else {\n flushRun();\n }\n\n offset += piece.value.length;\n }\n flushRun();\n\n // Cross-token checks the runtime parse() performs. Mirroring them\n // here lets the ESLint plugin flag them statically without having\n // to re-derive the logic.\n const tokenNames = tokens.map((t) => t.name);\n const has12Hour = tokenNames.some((t) => t === 'hh' || t === 'h');\n const has24Hour = tokenNames.some((t) => t === 'HH' || t === 'H');\n const hasAPeriod = tokenNames.some((t) => t === 'a');\n if (has12Hour && !hasAPeriod) {\n warnings.push({\n code: 'TWELVE_HOUR_WITHOUT_A',\n message: '12-hour token (\"hh\"/\"h\") used without an \"a\" (AM/PM) token — parse() can\\'t tell AM from PM and throws at runtime.',\n });\n }\n if (has12Hour && has24Hour) {\n warnings.push({\n code: 'MIXED_12_AND_24_HOUR',\n message: 'Mixing 24-hour and 12-hour tokens — parse() refuses to guess which is authoritative and throws at runtime.',\n });\n }\n\n const hasOffset = tokenNames.some((t) => t === 'X' || t === 'XX' || t === 'XXX' || t === 'x' || t === 'xx' || t === 'xxx');\n const hasZzz = tokenNames.some((t) => t === 'zzz');\n if (hasOffset && hasZzz) {\n warnings.push({\n code: 'ZZZ_WITH_OFFSET_TOKEN',\n message: 'Format string has both \"zzz\" and an offset token — parse() cross-checks them and throws if the parsed offset disagrees with the zone\\'s actual offset.',\n });\n }\n if (hasOffset && !requiredFields.has('year')) {\n warnings.push({\n code: 'OFFSET_WITHOUT_FULL_DATE',\n message: 'Offset token used without a full date — parse() needs a complete date and time to build a ZonedDateTime and throws at runtime otherwise.',\n });\n }\n\n return {\n tokens,\n requiredFields: [...requiredFields].sort(),\n compatibleTypes: [...compatibleTypesSet].sort(),\n parseable,\n localeSensitive,\n calendarSensitive,\n timezoneSensitive,\n // Ambiguous iff at least one warning fired about an ambiguous run.\n ambiguous: warnings.some((w) => w.code === 'AMBIGUOUS_NUMERIC_RUN'),\n roundTripSafe: roundTripSafe && parseable,\n warnings,\n };\n}\n\n// explainFormat: human-readable rendering of analyzeFormat's output.\n// Used by the CLI (section AD) for `temporal-fmt inspect <fmt>` and by\n// the IDE for hover docs on a format string. Plain prose, no JSON —\n// callers wanting machine-readable output should call analyzeFormat()\n// directly.\nexport function explainFormat(formatStr: string): string {\n const analysis = analyzeFormat(formatStr);\n const lines: string[] = [];\n lines.push(`Format string: \"${formatStr}\"`);\n lines.push(`Tokens (${analysis.tokens.length}):`);\n for (const t of analysis.tokens) {\n lines.push(` ${t.name} @${t.position} — ${t.metadata.meaning}`);\n }\n if (analysis.requiredFields.length > 0) {\n lines.push(`Required fields: ${analysis.requiredFields.join(', ')}`);\n }\n if (analysis.compatibleTypes.length > 0) {\n lines.push(`Compatible Temporal types: ${analysis.compatibleTypes.join(', ')}`);\n }\n lines.push(`Parseable: ${analysis.parseable ? 'yes' : 'no'}`);\n lines.push(`Locale-sensitive: ${analysis.localeSensitive ? 'yes' : 'no'}`);\n lines.push(`Calendar-sensitive: ${analysis.calendarSensitive ? 'yes' : 'no'}`);\n lines.push(`Timezone-sensitive: ${analysis.timezoneSensitive ? 'yes' : 'no'}`);\n lines.push(`Ambiguous: ${analysis.ambiguous ? 'yes' : 'no'}`);\n lines.push(`Round-trip safe: ${analysis.roundTripSafe ? 'yes' : 'no'}`);\n if (analysis.warnings.length > 0) {\n lines.push('Warnings:');\n for (const w of analysis.warnings) {\n lines.push(` [${w.code}] ${w.message}`);\n }\n }\n return lines.join('\\n');\n}\n\n// isValidFormat: true iff tokenize() accepts the string without\n// throwing. Distinct from analyzeFormat's `parseable` flag — a format\n// string can be valid (tokenizes cleanly) but not parseable (contains\n// a format-only token like `do`). Both checks are exposed since callers\n// want different things: validity for \"will format() throw\", parseability\n// for \"will parse() throw\".\nexport function isValidFormat(formatStr: string): boolean {\n if (formatStr.length > MAX_FORMAT_LENGTH) return false;\n try {\n tokenize(formatStr);\n return true;\n } catch {\n return false;\n }\n}\n\n// validateFormat: throws on invalid format strings instead of\n// returning a boolean. Mirrors the existing strict-validation\n// convention (descriptive thrown errors, never silent failures).\n// Returns the analysis for callers who want both — validate-then-use.\nexport function validateFormat(formatStr: string): FormatAnalysis {\n const analysis = analyzeFormat(formatStr);\n return analysis;\n}\n\n// Exported for callers that want to query the token table without\n// touching internals. Kept here rather than re-exported from\n// tokenMetadata.ts so this module is the single import for \"anything\n// analyzer-related.\"\nexport { TOKEN_METADATA, ALL_TOKEN_NAMES } from './tokenMetadata.js';\n\n// Re-export FORMAT_ONLY_TOKENS so callers don't have to import from\n// pattern.ts (which is a lower-level module they shouldn't need to\n// know about).\nexport { FORMAT_ONLY_TOKENS } from './pattern.js';\n\n// Used by callers that need to look up which field a token requires —\n// e.g. the ESLint plugin's \"type mismatch\" check (section Y) wants to\n// answer \"does the type the caller passed to format() carry this\n// field?\" without having to actually call format() and catch the\n// thrown error. Mirrors the same lookup format.ts does internally.\nexport function fieldForToken(token: string): keyof TemporalLike | undefined {\n return _handlerFor(token)?.field;\n}","// Serialization / interop helpers. Standardized\n// parse/format pairs for ISO 8601, RFC 3339, RFC 2822, HTTP-date,\n// plus epoch conversions to/from unix seconds/ms/µs/ns.\n//\n// All of these wrap the existing parse()/format() surface rather than\n// reimplementing the formats — same convention as the rest of the\n// library (one tokenizer, one parser, one constructor path). The\n// standard-format helpers are essentially pre-baked format strings\n// with the right tokens, plus stricter input validation where the\n// standard demands it (e.g. RFC 3339 requires UTC-offset-only zones,\n// not named IANA zones).\n\nimport { parse } from './parse.js';\nimport { format } from './format.js';\nimport { getTemporal, type TemporalNamespace } from './temporalProvider.js';\nimport { FormatSyntaxError, InvalidDateError } from './errors.js';\n\n// Build a Temporal instance from a field bag. Used by the parse helpers\n// to construct PlainDate / PlainDateTime / ZonedDateTime / Instant from\n// the fields the standard format carries. Throws on construction errors\n// (Feb 30, etc.) wrapped in InvalidDateError so callers get the typed\n// error surface.\nfunction constructFromFields(fields: Record<string, unknown>, kind: 'PlainDate' | 'PlainDateTime' | 'ZonedDateTime' | 'Instant'): unknown {\n const temporal = getTemporal();\n try {\n switch (kind) {\n case 'PlainDate':\n return temporal.PlainDate.from(fields as Record<string, number | string | undefined>, { overflow: 'reject' });\n case 'PlainDateTime':\n return temporal.PlainDateTime.from(fields as Record<string, number | string | undefined>, { overflow: 'reject' });\n case 'ZonedDateTime':\n return temporal.ZonedDateTime.from(fields as Record<string, number | string | undefined>, { overflow: 'reject' });\n case 'Instant': {\n // Instant.from takes an ISO string, not a field bag. Build the\n // ISO string ourselves and parse it.\n const iso = buildISOFromFields(fields);\n if (!temporal.Instant) {\n throw new Error('temporal-fmt: Temporal.Instant is not available in this implementation.');\n }\n return temporal.Instant.from(iso);\n }\n }\n } catch (err) {\n throw new InvalidDateError({ input: JSON.stringify(fields), reason: (err as Error).message });\n }\n}\n\nfunction buildISOFromFields(fields: Record<string, unknown>): string {\n const y = String(fields.year).padStart(4, '0');\n const m = String(fields.month).padStart(2, '0');\n const d = String(fields.day).padStart(2, '0');\n const h = fields.hour !== undefined ? `T${String(fields.hour).padStart(2, '0')}` : '';\n const min = fields.minute !== undefined ? `:${String(fields.minute).padStart(2, '0')}` : '';\n const sec = fields.second !== undefined ? `:${String(fields.second).padStart(2, '0')}` : '';\n const frac = fields.millisecond !== undefined && (fields.millisecond as number) > 0\n ? `.${String(fields.millisecond).padStart(3, '0')}`\n : '';\n const tz = typeof fields.timeZone === 'string' ? fields.timeZone : 'Z';\n return `${y}-${m}-${d}${h}${min}${sec}${frac}${tz}`;\n}\n\n// ISO 8601 is the most permissive of the standards here — accepts\n// calendar dates, week dates, ordinal dates, times with optional\n// fractional seconds, timezone offsets or 'Z'. Delegates to\n// Temporal's own ISO parsing (which is ISO 8601-compliant) by\n// constructing from the raw ISO string.\n\nexport function parseISO(input: string): unknown {\n const temporal = getTemporal();\n // Detect what kind of Temporal object the ISO string describes.\n // ISO 8601 strings have a date part, optional time part, optional\n // timezone. We dispatch to the right Temporal constructor based on\n // which parts are present.\n try {\n if (/^\\d{4}-\\d{2}-\\d{2}T/.test(input) || /T\\d{2}:\\d{2}/.test(input)) {\n // Has a time component.\n if (/[zZ]$/.test(input) || /[+-]\\d{2}:?\\d{2}$/.test(input)) {\n // ZonedDateTime. Temporal.ZonedDateTime.from accepts ISO with\n // a zone bracket (e.g. \"2026-08-04T15:45:30[UTC]\") but rejects\n // a bare offset with no bracket. For \"Z\" suffix, expand to\n // \"+00:00[UTC]\"; for a numeric offset, append that same offset\n // as the bracket (e.g. \"+05:30\" → \"+05:30[+05:30]\").\n let iso = input;\n if (/[zZ]$/.test(iso)) {\n iso = iso.slice(0, -1) + '+00:00[UTC]';\n } else {\n const offsetMatch = /([+-]\\d{2}:?\\d{2})$/.exec(iso);\n if (offsetMatch) {\n iso = `${iso}[${offsetMatch[1]}]`;\n }\n }\n return temporal.ZonedDateTime.from(iso as unknown as Record<string, number | string | undefined>, { overflow: 'reject' });\n }\n return temporal.PlainDateTime.from(input as unknown as Record<string, number | string | undefined>, { overflow: 'reject' });\n }\n if (/^\\d{4}-\\d{2}-\\d{2}/.test(input)) {\n return temporal.PlainDate.from(input as unknown as Record<string, number | string | undefined>, { overflow: 'reject' });\n }\n if (/^\\d{2}:\\d{2}/.test(input)) {\n return temporal.PlainTime.from(input as unknown as Record<string, number | string | undefined>);\n }\n throw new Error(`temporal-fmt: parseISO(\"${input}\") doesn't look like an ISO 8601 string.`);\n } catch (err) {\n throw new InvalidDateError({ input, reason: (err as Error).message });\n }\n}\n\nexport function formatISO(value: unknown): string {\n // Temporal objects expose toString() which produces ISO 8601 output\n // by spec. So formatting IS just toString().\n const v = value as { toString?: () => string };\n if (typeof v?.toString !== 'function') {\n throw new FormatSyntaxError({ reason: `formatISO() expects a Temporal value with toString(), got ${typeof value}.` });\n }\n return v.toString();\n}\n\n// RFC 3339 is a profile of ISO 8601 used in network protocols (HTTP,\n// JSON-RPC, etc.). Stricter than ISO 8601: requires full date+time,\n// requires seconds, requires UTC offset or 'Z', disallows IANA zone\n// names. Delegates to parseISO then validates the constraints.\n\nexport function parseRFC3339(input: string): unknown {\n // RFC 3339 grammar (https://www.rfc-editor.org/rfc/rfc3339#section-5.6):\n // date-fullyear = 4DIGIT\n // date-month = 2DIGIT ; 01-12\n // date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31\n // time-hour = 2DIGIT ; 00-23\n // time-minute = 2DIGIT ; 00-59\n // time-second = 2DIGIT ; 00-58, 00-59, 00-60 (leap second)\n // time-secfrac = \".\" 1*DIGIT\n // time-numoffset = (\"+\" / \"-\") time-hour \":\" time-minute\n // time-offset = \"Z\" / time-numoffset\n // partial-time = time-hour \":\" time-minute \":\" time-second [time-secfrac]\n // full-date = date-fullyear \"-\" date-month \"-\" date-mday\n // full-time = partial-time time-offset\n // date-time = full-date \"T\" full-time\n const re = /^(\\d{4})-(\\d{2})-(\\d{2})[Tt](\\d{2}):(\\d{2}):(\\d{2})(\\.\\d+)?([Zz]|[+-]\\d{2}:\\d{2})$/;\n const m = re.exec(input);\n if (!m) {\n throw new FormatSyntaxError({ input, reason: 'does not match RFC 3339 date-time grammar' });\n }\n // Construct via parseISO with the same expansion for bare Z.\n const iso = input.replace(/[tT]/, 'T').replace(/[zZ]$/, '+00:00[UTC]');\n return parseISO(iso);\n}\n\nexport function formatRFC3339(value: unknown): string {\n // RFC 3339 output is ISO 8601 with a UTC offset. toString() on a\n // ZonedDateTime produces this shape; we just verify the result looks\n // like RFC 3339 and pass it through.\n const s = formatISO(value);\n if (!/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})$/.test(s)) {\n throw new FormatSyntaxError({ input: s, reason: 'value did not produce RFC 3339-compliant output' });\n }\n return s;\n}\n\n// RFC 2822 date-time (used in email Message-ID headers, etc.). Format:\n// day-of-week, day month year hour:minute:second zone\n// e.g. \"Mon, 04 Aug 2026 15:45:30 +0000\"\n// JS Date can parse this natively, so we use Date.parse and convert\n// to a Temporal.Instant. (Date.parse's RFC 2822 support is universal\n// across engines, unlike its ISO 8601 support which varies.)\n\nexport function parseRFC2822(input: string): unknown {\n // Strict shape pre-check: Date.parse is far more permissive than RFC 2822\n // (it happily accepts ISO 8601 and other dialects), so without this gate\n // parseRFC2822(\"2026-08-04\") would succeed despite not being an RFC 2822\n // date at all. The regex mirrors RFC 2822 §3.3's date-time grammar:\n // optional day-of-week, 1-2 digit day, month name, 2-4 digit year (the\n // obsolete two-digit form included), time with optional seconds, and a\n // zone that is either a numeric ±HHMM offset or an alphabetic zone name.\n const RFC2822_SHAPE =\n /^(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\\s+)?\\d{1,2}\\s+(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\\s+\\d{2,4}\\s+\\d{2}:\\d{2}(?::\\d{2})?\\s+(?:[+-]\\d{4}|[A-Za-z]{1,5})$/;\n if (!RFC2822_SHAPE.test(input.trim())) {\n throw new FormatSyntaxError({ input, reason: 'not a valid RFC 2822 date' });\n }\n const ms = Date.parse(input);\n if (Number.isNaN(ms)) {\n throw new FormatSyntaxError({ input, reason: 'not a valid RFC 2822 date' });\n }\n return requireInstant().fromEpochMilliseconds(ms);\n}\n\nexport function formatRFC2822(value: unknown): string {\n // Format using format() with the right tokens, then construct via\n // the value's epoch ms. RFC 2822 requires a fixed offset, not an\n // IANA zone, so we read the value's offset directly.\n const v = value as { toEpochMilliseconds?: () => number; epochMilliseconds?: number; toInstant?: () => { epochMilliseconds: number } };\n let ms: number | undefined;\n if (typeof v?.toEpochMilliseconds === 'function') {\n ms = v.toEpochMilliseconds();\n } else if (typeof v?.epochMilliseconds === 'number') {\n // Temporal.Instant exposes epochMilliseconds as a property.\n ms = v.epochMilliseconds;\n } else if (typeof v?.toInstant === 'function') {\n // ZonedDateTime.toInstant() → Instant.\n const inst = v.toInstant();\n if (typeof (inst as { epochMilliseconds?: number }).epochMilliseconds === 'number') {\n ms = (inst as { epochMilliseconds: number }).epochMilliseconds;\n }\n }\n if (ms === undefined) {\n throw new FormatSyntaxError({ reason: `formatRFC2822() expects a value with epochMilliseconds, toEpochMilliseconds(), or toInstant(), got ${typeof value}.` });\n }\n return formatRFC2822FromMs(ms);\n}\n\nfunction formatRFC2822FromMs(ms: number): string {\n // Use Intl.DateTimeFormat with the en-US POSIX locale and the rfc822\n // format option. Modern Node ships Intl with this option; if not\n // available, fall back to manual formatting.\n try {\n const fmt = new Intl.DateTimeFormat('en-US', {\n weekday: 'short', day: '2-digit', month: 'short', year: 'numeric',\n hour: '2-digit', minute: '2-digit', second: '2-digit',\n timeZone: 'UTC', timeZoneName: 'shortOffset',\n hour12: false,\n });\n const parts = fmt.formatToParts(new Date(ms));\n /* c8 ignore start -- every part type get() is called with (weekday,\n day, month, year, hour, minute, second, timeZoneName) is always\n present given the fixed options above, so the ?? '' fallback\n can't fire without a different Intl implementation. */\n const get = (t: string) => parts.find((p) => p.type === t)?.value ?? '';\n /* c8 ignore stop */\n const tzRaw = get('timeZoneName');\n // Intl's shortOffset returns \"GMT+0\", \"GMT-8\", \"GMT+5:30\", etc.\n // RFC 2822 wants \"+0000\", \"-0800\", \"+0530\". Parse and reformat.\n const tzMatch = tzRaw?.match(/GMT([+-])(\\d+)(?::(\\d+))?/);\n let tz: string;\n if (tzMatch) {\n const sign = tzMatch[1]!;\n const hours = tzMatch[2]!.padStart(2, '0');\n const minutes = (tzMatch[3] ?? '0').padStart(2, '0');\n tz = `${sign}${hours}${minutes}`;\n /* c8 ignore start @preserve -- timeZone is hardcoded to 'UTC' above,\n which always resolves cleanly, so shortOffset always returns a\n parseable \"GMT+0\"-shaped string in this environment's ICU. This\n branch only guards against an ICU build whose shortOffset output\n doesn't match the regex; can't trigger it without mocking Intl.\n The ignore starts before the closing brace of the if-block so it\n covers the whole else-branch node c8 tracks as a single unit. */\n } else {\n tz = '+0000';\n }\n /* c8 ignore stop @preserve */\n let hour = get('hour');\n /* c8 ignore start @preserve -- hour12:false with a fixed UTC zone\n never yields \"24\" in this environment's ICU (midnight formats as\n \"00\"). Some ICU versions/locales are documented to emit \"24\" for\n hour12:false, so this stays as a defensive normalization; not\n reachable here without mocking Intl.DateTimeFormat's output. */\n if (hour === '24') hour = '00';\n /* c8 ignore stop @preserve */\n return `${get('weekday')}, ${get('day')} ${get('month')} ${get('year')} ${hour}:${get('minute')}:${get('second')} ${tz}`;\n /* c8 ignore start @preserve -- Intl.DateTimeFormat is constructed\n above with a literal, always-valid timeZone: 'UTC' and no other\n user input reaches the constructor or formatToParts call, so this\n catch can't be triggered through the public API in a normal Intl\n environment (e.g. Node with full-icu). Kept as a genuine fallback\n for runtimes with a broken or absent Intl implementation. */\n } catch {\n // Fallback: hand-rolled RFC 2822 format via Date's UTC methods.\n const d = new Date(ms);\n const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n const wd = days[d.getUTCDay()];\n const dd = String(d.getUTCDate()).padStart(2, '0');\n const mon = months[d.getUTCMonth()]!;\n const yyyy = d.getUTCFullYear();\n const hh = String(d.getUTCHours()).padStart(2, '0');\n const mm = String(d.getUTCMinutes()).padStart(2, '0');\n const ss = String(d.getUTCSeconds()).padStart(2, '0');\n return `${wd}, ${dd} ${mon} ${yyyy} ${hh}:${mm}:${ss} +0000`;\n }\n /* c8 ignore stop @preserve */\n}\n\n// RFC 7231 defines three formats: IMF-fixdate, RFC 850, asctime.\n// The canonical format is IMF-fixdate (RFC 2822-like with required\n// seconds and UTC-only). Delegates to Date.parse for parsing and to\n// formatRFC2822 for formatting (they're nearly identical).\n\nexport function parseHTTPDate(input: string): unknown {\n const trimmed = input.trim();\n const ms = Date.parse(trimmed);\n if (Number.isNaN(ms)) {\n throw new FormatSyntaxError({ input, reason: 'not a valid HTTP-date' });\n }\n return requireInstant().fromEpochMilliseconds(ms);\n}\n\nexport function formatHTTPDate(value: unknown): string {\n // IMF-fixdate format: \"Sun, 06 Nov 1994 08:49:37 GMT\"\n const instant = (value as { toInstant?: () => { epochMilliseconds: number } })?.toInstant?.()\n ?? (value as { epochMilliseconds?: number });\n const ms = typeof instant === 'object' && instant !== null && 'epochMilliseconds' in instant\n ? (instant as { epochMilliseconds: number }).epochMilliseconds\n : (() => { throw new FormatSyntaxError({ reason: `formatHTTPDate() expects an Instant or ZonedDateTime, got ${typeof value}.` }); })();\n const d = new Date(ms);\n const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n const wd = days[d.getUTCDay()];\n const dd = String(d.getUTCDate()).padStart(2, '0');\n const mon = months[d.getUTCMonth()]!;\n const yyyy = d.getUTCFullYear();\n const hh = String(d.getUTCHours()).padStart(2, '0');\n const mm = String(d.getUTCMinutes()).padStart(2, '0');\n const ss = String(d.getUTCSeconds()).padStart(2, '0');\n return `${wd}, ${dd} ${mon} ${yyyy} ${hh}:${mm}:${ss} GMT`;\n}\n\n// All epoch conversions go through Temporal.Instant, which has spec\n// methods for each epoch granularity. Wrapped here for the\n// temporal-fmt surface so callers don't have to import Temporal\n// directly.\n\nfunction getInstant(value: unknown): { epochMilliseconds: number; epochNanoseconds: bigint } {\n const v = value as { toInstant?: () => { epochMilliseconds: number; epochNanoseconds: bigint }; epochMilliseconds?: number; epochNanoseconds?: bigint };\n if (typeof v?.toInstant === 'function') {\n const inst = v.toInstant();\n // Prefer the instant's own epochNanoseconds when present — same\n // precision reasoning as below, since toInstant() can return a\n // real Temporal.Instant carrying both fields.\n if (typeof (inst as { epochNanoseconds?: bigint }).epochNanoseconds === 'bigint') {\n return { epochMilliseconds: inst.epochMilliseconds, epochNanoseconds: (inst as { epochNanoseconds: bigint }).epochNanoseconds };\n }\n return { epochMilliseconds: inst.epochMilliseconds, epochNanoseconds: BigInt(inst.epochMilliseconds) * 1_000_000n };\n }\n // Check epochNanoseconds before epochMilliseconds: a real\n // Temporal.Instant exposes both, and epochMilliseconds is truncated\n // to millisecond precision. Deriving epochNanoseconds by scaling\n // epochMilliseconds back up would silently drop sub-ms precision\n // that was available on the object all along.\n if (typeof v?.epochNanoseconds === 'bigint') {\n return { epochMilliseconds: Number(v.epochNanoseconds / 1_000_000n), epochNanoseconds: v.epochNanoseconds };\n }\n if (typeof v?.epochMilliseconds === 'number') {\n return { epochMilliseconds: v.epochMilliseconds, epochNanoseconds: BigInt(v.epochMilliseconds) * 1_000_000n };\n }\n throw new FormatSyntaxError({ reason: `expected an Instant or ZonedDateTime, got ${typeof value}.` });\n}\n\nfunction requireInstant(): NonNullable<TemporalNamespace['Instant']> {\n const t = getTemporal().Instant;\n if (!t) throw new Error('temporal-fmt: Temporal.Instant is not available in this implementation.');\n return t;\n}\n\nexport function toUnixSeconds(value: unknown): number {\n return getInstant(value).epochMilliseconds / 1000;\n}\n\nexport function fromUnixSeconds(seconds: number): unknown {\n return requireInstant().fromEpochMilliseconds(seconds * 1000);\n}\n\nexport function fromUnixMilliseconds(ms: number): unknown {\n return requireInstant().fromEpochMilliseconds(ms);\n}\n\nexport function fromUnixMicroseconds(µs: number): unknown {\n // Temporal.Instant has no fromEpochMicroseconds in the spec — only\n // fromEpochMilliseconds and fromEpochNanoseconds. Convert via ns.\n return requireInstant().fromEpochNanoseconds(BigInt(µs) * 1_000n);\n}\n\nexport function fromUnixNanoseconds(ns: bigint): unknown {\n return requireInstant().fromEpochNanoseconds(ns);\n}\n\nexport function toUnixMilliseconds(value: unknown): number {\n return getInstant(value).epochMilliseconds;\n}\n\nexport function toUnixMicroseconds(value: unknown): number {\n const { epochNanoseconds } = getInstant(value);\n return Number(epochNanoseconds / 1_000n);\n}\n\nexport function toUnixNanoseconds(value: unknown): bigint {\n return getInstant(value).epochNanoseconds;\n}\n\n// SQL-oriented helpers. SQL date/time formats are simpler than the\n// network standards above — just 'YYYY-MM-DD' for dates, 'HH:MM:SS'\n// for times, 'YYYY-MM-DD HH:MM:SS' for datetimes. Delegating to\n// parse() with the right format strings keeps the validation surface\n// consistent.\nexport function parseSQL(input: string): unknown {\n const trimmed = input.trim();\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(trimmed)) {\n return parse('yyyy-MM-dd', trimmed);\n }\n if (/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(trimmed)) {\n return parse('yyyy-MM-dd HH:mm:ss', trimmed);\n }\n if (/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}/.test(trimmed)) {\n return parseISO(trimmed);\n }\n throw new FormatSyntaxError({ input, reason: 'not a recognized SQL date/time format' });\n}\n\nexport function formatSQL(value: unknown): string {\n // Detect what kind of Temporal value this is and pick the format.\n const v = value as { year?: number; hour?: number };\n if (typeof v?.hour === 'number') {\n return format(value as Parameters<typeof format>[0], 'yyyy-MM-dd HH:mm:ss');\n }\n return format(value as Parameters<typeof format>[0], 'yyyy-MM-dd');\n}","// Central configuration. Per-call options are the\n// default convention throughout this library (see formatDistance's\n// cutoffs precedent — explicitly NOT a global). This module provides\n// a typed ConfigOptions surface that callers can build once and pass\n// to any temporal-fmt function, plus a set of defaults that mirror\n// the existing per-call defaults.\n//\n// No global mutable state. The plan is explicit: \"No mysterious\n// mutable global state — this is a hard constraint, not a preference.\"\n// This module honors that: createConfig() returns an immutable config\n// object; there is no setConfig().\n\nimport { DEFAULT_LOCALE } from './tokens.js';\nimport type { NumberingSystem } from './numbering.js';\n\nexport interface TemporalFmtConfig {\n // BCP-47 locale tag. Default 'en-US'.\n locale: string;\n // Calendar identifier ('gregory', 'hebrew', etc.) or undefined to\n // use the locale's default.\n calendar?: string;\n // IANA timezone id ('America/New_York', etc.) or undefined to use\n // the system timezone.\n timezone?: string;\n // Numbering system. Default 'latn'.\n numberingSystem: NumberingSystem | string;\n // ISO week rules: 1 = Monday, 7 = Sunday. Default 1 (matches the\n // existing isoWeek.ts convention).\n firstDayOfWeek: 1 | 7;\n // Rounding mode for round()/roundDuration(). Default 'nearest'.\n roundingMode: 'nearest' | 'floor' | 'ceil' | 'trunc';\n // Disambiguation for ZonedDateTime construction during gaps/overlaps.\n // Default 'compatible' (Temporal's default).\n disambiguation: 'compatible' | 'earlier' | 'later' | 'reject';\n // Overflow mode for field construction (Feb 30 etc.).\n // Default 'reject' (matches parse()'s existing behavior).\n overflow: 'constrain' | 'reject';\n // Parse leniency. Default false (strict).\n parseLenient: boolean;\n // Duration zero-value display. Default false (omit zeros).\n durationShowZeroValues: boolean;\n}\n\nexport const DEFAULT_CONFIG: TemporalFmtConfig = {\n locale: DEFAULT_LOCALE,\n numberingSystem: 'latn',\n firstDayOfWeek: 1,\n roundingMode: 'nearest',\n disambiguation: 'compatible',\n overflow: 'reject',\n parseLenient: false,\n durationShowZeroValues: false,\n};\n\n// Creates a config object with the caller's overrides merged onto\n// the defaults. Returns a frozen object so callers can't mutate it\n// after the fact — same immutability convention as Temporal's own\n// options.\nexport function createConfig(overrides: Partial<TemporalFmtConfig> = {}): Readonly<TemporalFmtConfig> {\n const merged: TemporalFmtConfig = { ...DEFAULT_CONFIG, ...overrides };\n // Validate.\n if (typeof merged.locale !== 'string' || merged.locale.length === 0) {\n throw new Error(`temporal-fmt: config.locale must be a non-empty string (got ${String(merged.locale)}).`);\n }\n if (merged.firstDayOfWeek !== 1 && merged.firstDayOfWeek !== 7) {\n throw new Error(`temporal-fmt: config.firstDayOfWeek must be 1 (Monday) or 7 (Sunday) (got ${merged.firstDayOfWeek}).`);\n }\n if (!['nearest', 'floor', 'ceil', 'trunc'].includes(merged.roundingMode)) {\n throw new Error(`temporal-fmt: config.roundingMode \"${merged.roundingMode}\" is not recognized.`);\n }\n if (!['compatible', 'earlier', 'later', 'reject'].includes(merged.disambiguation)) {\n throw new Error(`temporal-fmt: config.disambiguation \"${merged.disambiguation}\" is not recognized.`);\n }\n if (!['constrain', 'reject'].includes(merged.overflow)) {\n throw new Error(`temporal-fmt: config.overflow \"${merged.overflow}\" is not recognized.`);\n }\n return Object.freeze(merged);\n}\n\n// Merges a per-call options object with a config. Per-call options take\n// precedence. Used by format()/parse()/etc. to fold a caller's config\n// into the per-call options they pass.\nexport function mergeWithConfig<T extends Record<string, unknown>>(\n config: Readonly<TemporalFmtConfig> | undefined,\n perCall: T,\n): T & { locale?: string; calendar?: string; timezone?: string; numberingSystem?: string; lenient?: boolean } {\n if (!config) return perCall;\n const result = { ...perCall } as T & { locale?: string; calendar?: string; timezone?: string; numberingSystem?: string; lenient?: boolean };\n // Only fill in fields the per-call options don't specify.\n if (result.locale === undefined) result.locale = config.locale;\n if (result.calendar === undefined && config.calendar !== undefined) result.calendar = config.calendar;\n if (result.timezone === undefined && config.timezone !== undefined) result.timezone = config.timezone;\n if (result.numberingSystem === undefined) result.numberingSystem = config.numberingSystem;\n if (result.lenient === undefined && config.parseLenient) result.lenient = true;\n return result;\n}","// Business calendar. Customizable weekend definitions, holiday set,\n// observed holidays, working hours, optional half days. The holiday\n// check is delegated to a holiday calendar (holidays.ts) so this\n// module stays focused on weekday-vs-weekend logic.\n\nimport { add } from './arithmetic.js';\nimport type { HolidayCalendar } from './holidays.js';\n\nexport interface BusinessCalendarOptions {\n // Default [6, 7] (Sat/Sun). ISO weekdays 1-7.\n weekend?: number[];\n // Holiday calendar to consult. Optional — if absent, only weekend\n // logic applies.\n holidays?: HolidayCalendar;\n // Working hours per weekday. 1=Mon..7=Sun. Default: 8 hours for\n // weekdays, 0 for weekend. Used by addBusinessDays() to compute\n // partial-day arithmetic.\n workingHours?: Record<number, number>;\n // Half days: weekdays where working hours are reduced. Default empty.\n halfDays?: number[];\n}\n\nexport interface BusinessCalendar {\n weekend: Set<number>;\n holidays?: HolidayCalendar;\n workingHours: Record<number, number>;\n halfDays: Set<number>;\n}\n\nexport function createBusinessCalendar(options: BusinessCalendarOptions = {}): BusinessCalendar {\n const weekend = new Set(options.weekend ?? [6, 7]);\n // Copy before filling defaults — writing the missing weekday entries\n // straight into options.workingHours mutated the caller's object\n // (their { 1: 6 } grew keys 2..7 as a side effect of \"creating\" a\n // calendar, and a shared object across calendars cross-contaminated\n // them with the first calendar's defaults).\n const workingHours: Record<number, number> = { ...(options.workingHours ?? {}) };\n for (let i = 1; i <= 7; i++) {\n if (workingHours[i] === undefined) {\n workingHours[i] = weekend.has(i) ? 0 : 8;\n }\n }\n return {\n weekend,\n holidays: options.holidays,\n workingHours,\n halfDays: new Set(options.halfDays ?? []),\n };\n}\n\nexport function isBusinessDay(cal: BusinessCalendar, value: unknown): boolean {\n const v = value as { dayOfWeek?: number; year?: number; month?: number; day?: number };\n // add() in arithmetic.ts doesn't update dayOfWeek (it returns a field\n // bag with whatever dayOfWeek the input had). Compute it from year/month/day\n // whenever those are present — more reliable than trusting the cached\n // dayOfWeek value.\n let dow = v.dayOfWeek;\n if (typeof v.year === 'number' && typeof v.month === 'number' && typeof v.day === 'number') {\n const d = new Date(Date.UTC(v.year, v.month - 1, v.day));\n const jsDow = d.getUTCDay(); // 0=Sun..6=Sat\n dow = jsDow === 0 ? 7 : jsDow; // 1=Mon..7=Sun\n }\n if (typeof dow !== 'number') {\n throw new Error('temporal-fmt: isBusinessDay() needs a value with dayOfWeek (or year/month/day to compute it).');\n }\n if (cal.weekend.has(dow)) return false;\n if (cal.holidays && cal.holidays.isHoliday(value)) return false;\n return true;\n}\n\nexport function nextBusinessDay(cal: BusinessCalendar, value: unknown): unknown {\n let candidate = add(value, 1, 'days');\n // Loop until we find a business day. Capped at 7 iterations since a\n // week is the natural upper bound for a Sat/Sun + holiday combo.\n for (let i = 0; i < 14; i++) {\n if (isBusinessDay(cal, candidate)) return candidate;\n candidate = add(candidate, 1, 'days');\n }\n throw new Error('temporal-fmt: nextBusinessDay() gave up after 14 days — likely a misconfigured calendar (e.g. all days are weekends or holidays).');\n}\n\nexport function previousBusinessDay(cal: BusinessCalendar, value: unknown): unknown {\n let candidate = add(value, -1, 'days');\n for (let i = 0; i < 14; i++) {\n if (isBusinessDay(cal, candidate)) return candidate;\n candidate = add(candidate, -1, 'days');\n }\n throw new Error('temporal-fmt: previousBusinessDay() gave up after 14 days — likely a misconfigured calendar.');\n}\n\nconst MAX_BUSINESS_DAY_TRAVERSAL = 100_000;\n\nfunction assertBusinessDayCount(days: number): void {\n if (!Number.isSafeInteger(days)) {\n throw new RangeError(\n `temporal-fmt: business-day count must be a finite safe integer (got ${days}).`,\n );\n }\n}\n\nfunction compareDateFields(a: unknown, b: unknown): number {\n const av = a as { year: number; month: number; day: number };\n const bv = b as { year: number; month: number; day: number };\n const ay = av.year * 10000 + av.month * 100 + av.day;\n const by = bv.year * 10000 + bv.month * 100 + bv.day;\n return ay - by;\n}\n\nexport function addBusinessDays(cal: BusinessCalendar, value: unknown, days: number): unknown {\n assertBusinessDayCount(days);\n if (days === 0) return value;\n const sign = days > 0 ? 1 : -1;\n const absDays = Math.abs(days);\n if (absDays > MAX_BUSINESS_DAY_TRAVERSAL) {\n throw new RangeError(\n `temporal-fmt: addBusinessDays() exceeded the ${MAX_BUSINESS_DAY_TRAVERSAL}-day limit.`,\n );\n }\n let candidate = value;\n for (let i = 0; i < absDays; i++) {\n candidate = sign > 0 ? nextBusinessDay(cal, candidate) : previousBusinessDay(cal, candidate);\n }\n return candidate;\n}\n\nexport function subtractBusinessDays(cal: BusinessCalendar, value: unknown, days: number): unknown {\n assertBusinessDayCount(days);\n return addBusinessDays(cal, value, -days);\n}\n\nexport function differenceInBusinessDays(cal: BusinessCalendar, a: unknown, b: unknown): number {\n const rawDirection = compareDateFields(b, a);\n if (rawDirection === 0) return 0;\n\n const direction = rawDirection > 0 ? 1 : -1;\n let candidate = a;\n let count = 0;\n let traversedDays = 0;\n\n while (compareDateFields(candidate, b) !== 0) {\n candidate = add(candidate, direction, 'days');\n traversedDays++;\n if (traversedDays > MAX_BUSINESS_DAY_TRAVERSAL) {\n throw new RangeError(\n `temporal-fmt: differenceInBusinessDays() exceeded the ${MAX_BUSINESS_DAY_TRAVERSAL}-day traversal limit.`,\n );\n }\n if (isBusinessDay(cal, candidate)) count += direction;\n }\n\n return count;\n}\n","// Holiday framework. Core provides the abstraction only —\n// country-specific holiday datasets stay out of core; those can be\n// separate ecosystem packages built on top of this. A holiday calendar\n// is a function from a date → boolean (\"is this a holiday?\") plus\n// iteration helpers (nextHoliday, previousHoliday, holidaysBetween).\n\nimport { add } from './arithmetic.js';\nimport { compare } from './comparison.js';\n\nexport interface HolidayCalendar {\n isHoliday(value: unknown): boolean;\n // Returns the list of holidays within [start, end] inclusive.\n holidaysBetween(start: unknown, end: unknown): unknown[];\n}\n\nexport interface HolidaySpec {\n // Month + day for fixed-date holidays (e.g. Jan 1 → New Year's).\n month?: number;\n day?: number;\n // For floating holidays: a function that takes a year and returns\n // the { month, day } of the holiday in that year. Used for \"last\n // Monday of May\" style rules.\n compute?: (year: number) => { month: number; day: number };\n // Optional name (for introspection / debugging).\n name?: string;\n}\n\n// Upper bound on the year range holidaysBetween() will walk. The loop\n// is year-granular with no input validation on the endpoints, so a\n// caller passing (say) year 1 to year 300000 makes it iterate — and\n// cache a holiday list — for every year in between; hostile or\n// accidental huge ranges used to hang the process and grow the\n// per-calendar cache without bound. 5,000 years matches the traversal\n// caps businessCalendar.ts and recurrence.ts already use for the same\n// class of \"walk it one step at a time\" APIs.\nconst MAX_HOLIDAY_YEAR_RANGE = 5_000;\n\nexport function createHolidayCalendar(specs: HolidaySpec[]): HolidayCalendar {\n // Pre-compute holidays for a year on demand, cache by year.\n const cache = new Map<number, Array<{ month: number; day: number; name?: string }>>();\n function forYear(year: number) {\n let list = cache.get(year);\n if (list) return list;\n list = specs.map((s) => {\n let md: { month: number; day: number };\n if (s.compute) {\n md = s.compute(year);\n } else {\n md = { month: s.month!, day: s.day! };\n }\n return { ...md, name: s.name };\n });\n cache.set(year, list);\n return list;\n }\n return {\n isHoliday(value: unknown) {\n const v = value as { year?: number; month?: number; day?: number };\n if (typeof v.year !== 'number' || typeof v.month !== 'number' || typeof v.day !== 'number') {\n throw new Error('temporal-fmt: isHoliday() needs a value with year/month/day.');\n }\n const list = forYear(v.year);\n return list.some((h) => h.month === v.month && h.day === v.day);\n },\n holidaysBetween(start: unknown, end: unknown) {\n const sv = start as { year: number; month: number; day: number };\n const ev = end as { year: number; month: number; day: number };\n if (typeof sv?.year !== 'number' || typeof ev?.year !== 'number') {\n throw new Error('temporal-fmt: holidaysBetween() needs start/end values with year/month/day.');\n }\n if (ev.year - sv.year > MAX_HOLIDAY_YEAR_RANGE) {\n throw new RangeError(\n `temporal-fmt: holidaysBetween() year range (${sv.year}–${ev.year}) exceeds the ` +\n `${MAX_HOLIDAY_YEAR_RANGE}-year limit. Split the query into smaller ranges.`\n );\n }\n const result: unknown[] = [];\n for (let y = sv.year; y <= ev.year; y++) {\n const list = forYear(y);\n for (const h of list) {\n const date = { year: y, month: h.month, day: h.day };\n if (compare(date, sv) >= 0 && compare(date, ev) <= 0) {\n result.push({ year: y, month: h.month, day: h.day });\n }\n }\n }\n return result;\n },\n };\n}\n\n// Returns the next holiday strictly after `value`. Returns undefined\n// if no holiday is registered within the next 5 years (sanity cap).\nexport function nextHoliday(cal: HolidayCalendar, value: unknown): unknown | undefined {\n let candidate = add(value, 1, 'days');\n for (let i = 0; i < 365 * 5; i++) {\n if (cal.isHoliday(candidate)) return candidate;\n candidate = add(candidate, 1, 'days');\n }\n return undefined;\n}\n\nexport function previousHoliday(cal: HolidayCalendar, value: unknown): unknown | undefined {\n let candidate = add(value, -1, 'days');\n for (let i = 0; i < 365 * 5; i++) {\n if (cal.isHoliday(candidate)) return candidate;\n candidate = add(candidate, -1, 'days');\n }\n return undefined;\n}\n\n// holidaysBetween is exposed as a HolidayCalendar method (see above);\n// this standalone helper delegates to it for ergonomic access.\nexport function holidaysBetween(cal: HolidayCalendar, start: unknown, end: unknown): unknown[] {\n return cal.holidaysBetween(start, end);\n}\n","// Extensibility. Controlled extensibility via\n// createFormatter({ tokens: ... }) rather than uncontrolled global\n// mutation. Custom tokens are passed at formatter-creation time;\n// built-in behavior stays deterministic regardless of what's registered.\n//\n// The existing registerLocaleVocab() is a global-registration escape\n// hatch for the locale-vocabulary case; createFormatter is the\n// per-formatter alternative for custom tokens.\n\nimport { type FormattedPart, type CompiledFormat } from './format.js';\nimport { TOKENS, type TemporalLike, type FormatOptions, DEFAULT_LOCALE } from './tokens.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\nimport { UnknownTokenError } from './errors.js';\n\nexport type TokenHandler = (t: TemporalLike, locale: string) => string;\nexport type TokenField = keyof TemporalLike;\n\nexport interface CustomToken {\n name: string;\n handler: TokenHandler;\n field: TokenField;\n}\n\nexport interface FormatterOptions {\n // Custom tokens to add (or override). Built-in tokens with the same\n // name are replaced by the custom one.\n tokens?: CustomToken[];\n // Default locale for this formatter. Callers can still override per-call.\n defaultLocale?: string;\n}\n\nexport interface Formatter {\n format(temporal: TemporalLike, formatStr: string, options?: FormatOptions): string;\n formatToParts(temporal: TemporalLike, formatStr: string, options?: FormatOptions): FormattedPart[];\n compileFormat(formatStr: string): CompiledFormat;\n}\n\nexport function createFormatter(options: FormatterOptions = {}): Formatter {\n // Build a merged token table: built-ins plus overrides.\n const mergedTokens: Array<[string, TokenHandler, TokenField]> = [...TOKENS];\n const customTokenNames = new Set<string>();\n for (const custom of options.tokens ?? []) {\n customTokenNames.add(custom.name);\n }\n // Replace existing tokens with the same name; append new ones.\n for (const custom of options.tokens ?? []) {\n const existingIdx = mergedTokens.findIndex(([name]) => name === custom.name);\n if (existingIdx >= 0) {\n mergedTokens[existingIdx] = [custom.name, custom.handler, custom.field];\n } else {\n mergedTokens.push([custom.name, custom.handler, custom.field]);\n }\n }\n // Sort longest-first for the greedy tokenizer.\n mergedTokens.sort((a, b) => b[0].length - a[0].length);\n const handlerByToken = new Map(mergedTokens.map(([name, handler, field]) => [name, { handler, field }]));\n const sortedTokenStrings = mergedTokens.map(([name]) => name);\n\n function customTokenize(formatStr: string) {\n const pieces: Array<{ kind: 'token' | 'literal'; value: string }> = [];\n let i = 0;\n while (i < formatStr.length) {\n const ch = formatStr[i];\n if (ch === \"'\") {\n // Quoted literal handling — same as tokenize.ts.\n if (formatStr[i + 1] === \"'\") {\n appendLiteral(pieces, \"'\");\n i += 2;\n continue;\n }\n let j = i + 1;\n let literal = '';\n let closed = false;\n while (j < formatStr.length) {\n if (formatStr[j] === \"'\") {\n if (formatStr[j + 1] === \"'\") {\n literal += \"'\";\n j += 2;\n continue;\n }\n closed = true;\n j += 1;\n break;\n }\n literal += formatStr[j]!;\n j += 1;\n }\n if (!closed) throw new Error(`temporal-fmt: unterminated quote in format string \"${formatStr}\"`);\n appendLiteral(pieces, literal);\n i = j;\n continue;\n }\n const match = sortedTokenStrings.find((tok) => formatStr.startsWith(tok, i));\n if (match) {\n // Overlong-run guard, same rule as tokenize.ts: a greedy match of N\n // chars followed by one more of the same letter (\"MMMMM\", \"ddddd\")\n // is not a valid token of any width — emitting it as \"token +\n // literal\" would silently splice an unrelated field onto this one,\n // exactly the misreading the main tokenizer rejects. Same\n // UnknownTokenError shape tokenize.ts throws.\n const runChar = match[match.length - 1];\n if (formatStr[i + match.length] === runChar) {\n let end = i + match.length;\n while (formatStr[end] === runChar) end += 1;\n throw new UnknownTokenError({\n token: formatStr.slice(i, end),\n format: formatStr,\n message:\n `temporal-fmt: \"${formatStr.slice(i, end)}\" in format string \"${formatStr}\" isn't a recognized token — ` +\n `did you mean \"${match}\"?`,\n });\n }\n pieces.push({ kind: 'token', value: match });\n i += match.length;\n continue;\n }\n appendLiteral(pieces, ch);\n i += 1;\n }\n return pieces;\n }\n\n function appendLiteral(pieces: Array<{ kind: 'token' | 'literal'; value: string }>, value: string): void {\n const last = pieces[pieces.length - 1];\n if (last && last.kind === 'literal') {\n last.value += value;\n } else {\n pieces.push({ kind: 'literal', value });\n }\n }\n\n const defaultLocale = options.defaultLocale ?? DEFAULT_LOCALE;\n\n return {\n format(temporal: TemporalLike, formatStr: string, opts: FormatOptions = {}) {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(`temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters (got ${formatStr.length}).`);\n }\n const locale = opts.locale ?? defaultLocale;\n const pieces = customTokenize(formatStr);\n let result = '';\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n result += piece.value;\n continue;\n }\n const handler = handlerByToken.get(piece.value);\n /* c8 ignore start @preserve -- unreachable: customTokenize only ever produces a\n `kind: 'token'` piece via sortedTokenStrings.find(...), and\n handlerByToken is built from that same mergedTokens array, so\n every token piece is guaranteed a handler entry. Guards against a\n future customTokenize change that decouples the two lookups. */\n if (!handler) throw new Error(`temporal-fmt: unknown token \"${piece.value}\"`);\n /* c8 ignore stop @preserve */\n if (temporal[handler.field] === undefined) {\n throw new Error(\n `temporal-fmt: token \"${piece.value}\" requires \"${String(handler.field)}\", which this Temporal object doesn't have.`\n );\n }\n result += handler.handler(temporal, locale);\n }\n return result;\n },\n formatToParts(temporal: TemporalLike, formatStr: string, opts: FormatOptions = {}) {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(`temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters (got ${formatStr.length}).`);\n }\n const locale = opts.locale ?? defaultLocale;\n const pieces = customTokenize(formatStr);\n const out: FormattedPart[] = [];\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n const last = out[out.length - 1];\n /* c8 ignore start @preserve -- unreachable: customTokenize's own\n appendLiteral() already merges adjacent literal chars/quoted\n spans into a single piece before this loop ever sees them, so\n two literal pieces are never adjacent here. Kept as a guard\n against a future customTokenize change that stops merging. */\n if (last && last.type === 'literal') last.value += piece.value;\n /* c8 ignore stop @preserve */\n else out.push({ type: 'literal', value: piece.value });\n continue;\n }\n const handler = handlerByToken.get(piece.value);\n /* c8 ignore start @preserve -- unreachable: customTokenize only emits\n kind:'token' pieces found in sortedTokenStrings, the same array\n handlerByToken is built from, so every token piece is guaranteed\n a handler entry. Guards against future decoupling of the two. */\n if (!handler) throw new Error(`temporal-fmt: unknown token \"${piece.value}\"`);\n /* c8 ignore stop @preserve */\n if (temporal[handler.field] === undefined) {\n throw new Error(`temporal-fmt: token \"${piece.value}\" requires \"${String(handler.field)}\".`);\n }\n out.push({ type: 'token', value: handler.handler(temporal, locale), token: piece.value });\n }\n return out;\n },\n compileFormat(formatStr: string): CompiledFormat {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(`temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters (got ${formatStr.length}).`);\n }\n const pieces = customTokenize(formatStr);\n return {\n formatStr,\n pieces: pieces.map((p) => p as { kind: 'token' | 'literal'; value: string }),\n format(temporal: TemporalLike, opts: FormatOptions = {}) {\n const locale = opts.locale ?? defaultLocale;\n let result = '';\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n result += piece.value;\n continue;\n }\n const handler = handlerByToken.get(piece.value);\n /* c8 ignore start @preserve -- unreachable, see the same guard's comment\n above in the un-compiled format(). */\n if (!handler) throw new Error(`temporal-fmt: unknown token \"${piece.value}\"`);\n /* c8 ignore stop @preserve */\n if (temporal[handler.field] === undefined) {\n throw new Error(`temporal-fmt: token \"${piece.value}\" requires \"${String(handler.field)}\".`);\n }\n result += handler.handler(temporal, locale);\n }\n return result;\n },\n formatToParts(temporal: TemporalLike, opts: FormatOptions = {}) {\n const locale = opts.locale ?? defaultLocale;\n const out: FormattedPart[] = [];\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n const last = out[out.length - 1];\n /* c8 ignore start @preserve -- unreachable, see the same guard's\n comment above in the un-compiled formatToParts. */\n if (last && last.type === 'literal') last.value += piece.value;\n /* c8 ignore stop @preserve */\n else out.push({ type: 'literal', value: piece.value });\n continue;\n }\n const handler = handlerByToken.get(piece.value);\n /* c8 ignore start @preserve -- unreachable, see the same guard's\n comment above in the un-compiled formatToParts. */\n if (!handler) throw new Error(`temporal-fmt: unknown token \"${piece.value}\"`);\n /* c8 ignore stop @preserve */\n if (temporal[handler.field] === undefined) {\n throw new Error(`temporal-fmt: token \"${piece.value}\" requires \"${String(handler.field)}\".`);\n }\n out.push({ type: 'token', value: handler.handler(temporal, locale), token: piece.value });\n }\n return out;\n },\n };\n },\n };\n}\n\n","// IDE tooling data exports. Provides structured data editor plugins can\n// consume for: token autocomplete, hover docs, inline diagnostics,\n// quick fixes, format preview, token conversion hints from\n// Day.js/date-fns, documentation links.\n//\n// This is the data layer only — an actual VS Code extension is out of\n// scope for this package. A separate package can build the extension\n// on top of these exports.\n\nimport { TOKEN_METADATA, ALL_TOKEN_NAMES } from './tokenMetadata.js';\nimport { analyzeFormat, listTokens } from './analyze.js';\nimport { format as builtinFormat } from './format.js';\n\nexport interface TokenAutocompleteEntry {\n label: string;\n detail: string;\n documentation: string;\n // Sort group — same-family tokens sort together in the autocomplete list.\n family: string;\n}\n\n// Token family grouping for autocomplete organization: year, month,\n// day, etc.\nfunction tokenFamily(name: string): string {\n if (/^y+$/.test(name)) return 'Year';\n if (/^[ML]+$/.test(name)) return 'Month';\n if (/^[decD]+$/.test(name)) return 'Day';\n if (/^[Ec]+$/.test(name)) return 'Weekday';\n if (/^[Qq]+$/.test(name)) return 'Quarter';\n if (/^[Gg]+$/.test(name)) return 'Era';\n if (/^[Hh]+$/.test(name)) return 'Hour';\n if (/^m+$/.test(name)) return 'Minute';\n if (/^s+$/.test(name)) return 'Second';\n if (/^S+$/.test(name)) return 'Fractional Second';\n if (name === 'a') return 'Day Period';\n if (name === 'zzz') return 'Time Zone';\n if (/^[Xx]+$/.test(name)) return 'UTC Offset';\n if (name === 'do') return 'Ordinal Day';\n if (name === 'ww' || name === 'RRRR') return 'ISO Week';\n return 'Other';\n}\n\nexport function getAutocompleteData(): TokenAutocompleteEntry[] {\n return ALL_TOKEN_NAMES.map((name) => {\n const meta = TOKEN_METADATA[name]!;\n return {\n label: name,\n detail: meta.meaning,\n documentation: [\n meta.meaning,\n ``,\n `Format-capable: ${meta.formatCapable}`,\n `Parse-capable: ${meta.parseCapable}`,\n `Locale-sensitive: ${meta.localeSensitive}`,\n `Calendar-sensitive: ${meta.calendarSensitive}`,\n `Timezone-sensitive: ${meta.timezoneSensitive}`,\n `Round-trip safe: ${meta.roundTripSafe}`,\n `Supported types: ${meta.supportedTypes.join(', ')}`,\n ].join('\\n'),\n family: tokenFamily(name),\n };\n });\n}\n\nexport interface TokenHoverDoc {\n signature: string;\n summary: string;\n details: string;\n examples?: string[];\n}\n\nexport function getHoverDocs(): Record<string, TokenHoverDoc> {\n const result: Record<string, TokenHoverDoc> = {};\n for (const name of ALL_TOKEN_NAMES) {\n const meta = TOKEN_METADATA[name]!;\n result[name] = {\n signature: name,\n summary: meta.meaning,\n details: [\n // every entry in TOKEN_METADATA currently has formatCapable:\n // true (verified: 51/51). The 'no' branch reflects real,\n // intended behavior for a future format-incapable token —\n // there's no such token today, so this isn't reachable data,\n // not dead logic. Every other field on this line has real\n // true/false variance across the token table and is exercised\n // by this same loop running over ALL_TOKEN_NAMES.\n /* c8 ignore next */\n `Format-capable: ${meta.formatCapable ? 'yes' : 'no'}`,\n `Parse-capable: ${meta.parseCapable ? 'yes' : 'no'}`,\n `Locale-sensitive: ${meta.localeSensitive ? 'yes' : 'no'}`,\n `Calendar-sensitive: ${meta.calendarSensitive ? 'yes' : 'no'}`,\n `Timezone-sensitive: ${meta.timezoneSensitive ? 'yes' : 'no'}`,\n `Round-trip safe: ${meta.roundTripSafe ? 'yes' : 'no'}`,\n `Supported types: ${meta.supportedTypes.join(', ')}`,\n ].join('\\n'),\n };\n }\n return result;\n}\n\n// Inline diagnostic data for a format string. Returns a list of issues\n// (warnings + errors) with position + message + suggested fix where\n// available. Mirrors analyzeFormat's warnings but adds the position\n// info an editor needs to draw squigglies.\nexport interface InlineDiagnostic {\n startColumn: number;\n endColumn: number;\n severity: 'error' | 'warning' | 'info';\n message: string;\n code: string;\n // Suggested replacement (for quick-fix). Empty when no quick fix exists.\n suggestion?: string;\n}\n\nexport function getInlineDiagnostics(formatStr: string): InlineDiagnostic[] {\n const analysis = analyzeFormat(formatStr);\n const diagnostics: InlineDiagnostic[] = [];\n for (const warning of analysis.warnings) {\n // Find the token that triggered the warning. analyzeFormat doesn't\n // currently surface which token caused which warning — we'd need\n // to extend it to track per-warning source positions. For now,\n // surface as a whole-string diagnostic.\n let message = warning.message;\n let suggestion: string | undefined;\n if (warning.code === 'TWELVE_HOUR_WITHOUT_A') {\n suggestion = 'Add an \"a\" token (e.g. \"h:mm a\") or use \"H:mm\" for 24-hour.';\n } else if (warning.code === 'MIXED_12_AND_24_HOUR') {\n suggestion = 'Pick one form: \"HH:mm\" for 24-hour or \"h:mm a\" for 12-hour.';\n } else if (warning.code === 'AMBIGUOUS_NUMERIC_RUN') {\n suggestion = 'Add a separator or use padded forms (e.g. \"MM\" instead of \"M\").';\n } else if (warning.code === 'FORMAT_ONLY_TOKEN') {\n suggestion = 'Use a parse-capable variant (e.g. \"d\" instead of \"do\").';\n }\n diagnostics.push({\n startColumn: 0,\n endColumn: formatStr.length,\n severity: 'warning',\n message,\n code: warning.code,\n suggestion,\n });\n }\n return diagnostics;\n}\n\n// Day.js / date-fns token conversion hints. Used by the IDE to suggest\n// the temporal-fmt equivalent when a user types a Day.js or date-fns\n// token. Pulls the translation tables from the codemod if available;\n// falls back to inline tables otherwise.\nexport interface TokenConversionHint {\n from: string;\n // null means \"real token in the source library, no temporal-fmt\n // equivalent\" — the codemod throws on these rather than treating\n // them as unrecognized text (see codemod.ts).\n to: string | null;\n notes?: string;\n}\n\n// Day.js → temporal-fmt mappings. Day.js uses Moment-style tokens:\n// `D`/`DD` are day-of-*month* here (unlike date-fns below, where the\n// same letters mean day-of-year). Assumes the AdvancedFormat plugin\n// for `Do`/`Q`/`k`/`kk`/`X`/`x` — see codemod.ts's doc comment for why.\nexport const DAYJS_TO_TEMPORAL_FMT: TokenConversionHint[] = [\n { from: 'YYYY', to: 'yyyy' },\n { from: 'YY', to: 'yy' },\n { from: 'MMMM', to: 'MMMM' },\n { from: 'MMM', to: 'MMM' },\n { from: 'MM', to: 'MM' },\n { from: 'M', to: 'M' },\n { from: 'DD', to: 'dd' },\n { from: 'D', to: 'd' },\n { from: 'Do', to: null, notes: 'Ordinal day (AdvancedFormat) — use temporal-fmt\\'s own \"do\" token instead.' },\n { from: 'dddd', to: 'EEEE' },\n { from: 'ddd', to: 'EEE' },\n { from: 'dd', to: null, notes: 'Min-name weekday (e.g. \"Tu\") — temporal-fmt has no equivalent width.' },\n { from: 'd', to: null, notes: 'Numeric weekday (0-6) — no temporal-fmt equivalent; not the same as \"d\" here, which is day-of-month.' },\n { from: 'HH', to: 'HH' },\n { from: 'H', to: 'H' },\n { from: 'hh', to: 'hh' },\n { from: 'h', to: 'h' },\n { from: 'kk', to: null, notes: 'Hour 1-24 (AdvancedFormat) — no temporal-fmt equivalent.' },\n { from: 'k', to: null, notes: 'Hour 1-24 (AdvancedFormat) — no temporal-fmt equivalent.' },\n { from: 'mm', to: 'mm' },\n { from: 'm', to: 'm' },\n { from: 'ss', to: 'ss' },\n { from: 's', to: 's' },\n { from: 'SSS', to: 'SSS' },\n { from: 'A', to: 'a', notes: 'Uppercase AM/PM in Day.js — temporal-fmt is always lowercase.' },\n { from: 'a', to: 'a' },\n { from: 'ZZ', to: 'XX', notes: 'Numeric UTC offset, no colon.' },\n { from: 'Z', to: 'XXX', notes: 'Numeric UTC offset with colon.' },\n { from: 'X', to: null, notes: 'Unix timestamp (seconds) — use fromUnixSeconds() instead.' },\n { from: 'x', to: null, notes: 'Unix timestamp (ms) — use fromUnixMilliseconds() instead.' },\n { from: 'Qo', to: null, notes: 'Ordinal quarter (AdvancedFormat) — no temporal-fmt equivalent.' },\n { from: 'Q', to: 'Q' },\n { from: 'Mo', to: null, notes: 'Ordinal month (AdvancedFormat) — no temporal-fmt equivalent.' },\n { from: 'ww', to: 'ww' },\n { from: 'wo', to: null, notes: 'Ordinal ISO week (AdvancedFormat) — no temporal-fmt equivalent.' },\n { from: 'w', to: null, notes: 'Unpadded ISO week — temporal-fmt\\'s \"ww\" is always 2-digit.' },\n { from: 'gggg', to: 'RRRR', notes: 'Week-numbering year, not the calendar year — same caveat as temporal-fmt\\'s RRRR.' },\n { from: 'L', to: null, notes: 'Localized date format (AdvancedFormat) — write the format string out explicitly.' },\n { from: 'LL', to: null, notes: 'Localized date format (AdvancedFormat) — write the format string out explicitly.' },\n { from: 'LLL', to: null, notes: 'Localized date format (AdvancedFormat) — write the format string out explicitly.' },\n { from: 'LLLL', to: null, notes: 'Localized date format (AdvancedFormat) — write the format string out explicitly.' },\n { from: 'LT', to: null, notes: 'Localized time format (AdvancedFormat) — write the format string out explicitly.' },\n { from: 'LTS', to: null, notes: 'Localized time format (AdvancedFormat) — write the format string out explicitly.' },\n];\n\n// date-fns → temporal-fmt mappings. date-fns already uses Unicode/LDML\n// -style tokens close to temporal-fmt's own vocabulary — most strings\n// pass through unchanged. The catch: `D`/`DD` here mean day-of-*year*\n// (same as temporal-fmt's `D`/`DD`), not day-of-month like Day.js's\n// `D`/`DD` above — don't reuse the Day.js table for this, they collide.\nexport const DATE_FNS_TO_TEMPORAL_FMT: TokenConversionHint[] = [\n { from: 'yyyy', to: 'yyyy' },\n { from: 'yy', to: 'yy' },\n { from: 'y', to: null, notes: 'Unpadded calendar year, opt-in via useAdditionalWeekYearTokens — temporal-fmt has no unpadded-year token; use \"yyyy\".' },\n { from: 'MMMM', to: 'MMMM' },\n { from: 'MMM', to: 'MMM' },\n { from: 'MM', to: 'MM' },\n { from: 'M', to: 'M' },\n { from: 'LLLL', to: 'LLLL' },\n { from: 'LLL', to: 'LLL' },\n { from: 'dd', to: 'dd' },\n { from: 'd', to: 'd' },\n { from: 'do', to: 'do' },\n { from: 'DDD', to: 'DDD' },\n { from: 'DD', to: 'DD' },\n { from: 'D', to: 'D', notes: 'Day-of-year, opt-in via useAdditionalDayOfYearTokens — matches temporal-fmt\\'s own \"D\" already.' },\n { from: 'EEEE', to: 'EEEE' },\n { from: 'EEE', to: 'EEE' },\n { from: 'eeee', to: null, notes: 'Locale-aware numeric weekday — no temporal-fmt equivalent.' },\n { from: 'cccc', to: 'cccc' },\n { from: 'ccc', to: 'ccc' },\n { from: 'HH', to: 'HH' },\n { from: 'H', to: 'H' },\n { from: 'hh', to: 'hh' },\n { from: 'h', to: 'h' },\n { from: 'mm', to: 'mm' },\n { from: 'm', to: 'm' },\n { from: 'ss', to: 'ss' },\n { from: 's', to: 's' },\n { from: 'SSS', to: 'SSS' },\n { from: 'a', to: 'a' },\n { from: 'aaa', to: 'a' },\n { from: 'XXX', to: 'XXX' },\n { from: 'XX', to: 'XX' },\n { from: 'X', to: 'X', notes: 'Opt-in via useAdditionalDayOfYearTokens-adjacent rules in date-fns v3+; matches temporal-fmt\\'s own \"X\" already.' },\n { from: 'xxx', to: 'xxx' },\n { from: 'xx', to: 'xx' },\n { from: 'x', to: 'x' },\n { from: 'zzzz', to: 'zzzz' },\n { from: 'zzz', to: 'zzz' },\n { from: 'z', to: 'z' },\n { from: 'QQQ', to: 'QQQ' },\n { from: 'Q', to: 'Q' },\n { from: 'GGGG', to: 'GGGG' },\n { from: 'GGG', to: null, notes: 'Abbreviated era — temporal-fmt only has \"G\" (short) and \"GGGG\" (long).' },\n { from: 'GG', to: null, notes: 'Abbreviated era — temporal-fmt only has \"G\" (short) and \"GGGG\" (long).' },\n { from: 'G', to: 'G' },\n { from: 'ww', to: 'ww' },\n { from: 'w', to: null, notes: 'Unpadded local week number — temporal-fmt\\'s \"ww\" is ISO-week and always 2-digit.' },\n { from: 'RRRR', to: 'RRRR' },\n { from: 'R', to: null, notes: 'Unpadded ISO week-numbering year — temporal-fmt\\'s \"RRRR\" is always 4-digit.' },\n { from: 'Y', to: null, notes: 'Week-numbering year (locale week rules), opt-in — no temporal-fmt equivalent; \"RRRR\" is ISO week-numbering, a different rule set.' },\n { from: 'PPPP', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n { from: 'PPP', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n { from: 'PP', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n { from: 'P', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n { from: 'pppp', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n { from: 'ppp', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n { from: 'pp', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n { from: 'p', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n];\n\n// Format preview — for a given format string and a sample Temporal\n// value, returns the formatted string. Editor plugins use this for\n// live preview as the user types.\nexport function previewFormat(formatStr: string, sample?: unknown): string {\n // Use a fixed sample date if none provided — 2026-08-04T15:45:30.\n // Picked because it exercises every common token: weekday is Tuesday,\n // month name has 5 chars, day is single-digit, hour is 12-hour-style,\n // minute/second both pad.\n const value = sample ?? {\n year: 2026, month: 8, day: 4, hour: 15, minute: 45, second: 30, millisecond: 123,\n dayOfWeek: 2, timeZoneId: 'UTC', offset: '+00:00', calendarId: 'iso8601',\n };\n return builtinFormat(value as Parameters<typeof builtinFormat>[0], formatStr, { locale: 'en-US' });\n}\n\n// Documentation links. Docs used to live under docs/ as one file per\n// token family; they're now consolidated into the root README's \"Token\n// reference\" section, which has no per-token anchors — so this points\n// at the section instead of a token-specific fragment.\nexport function getDocUrl(tokenName: string): string {\n void tokenName;\n return 'README.md#token-reference';\n}\n\n// Re-exports for callers that want everything IDE-related from one module.\nexport { listTokens, TOKEN_METADATA, ALL_TOKEN_NAMES };","// Day.js / date-fns format-string translation — backs the CLI's\n// `translate` subcommand. The mapping tables already live in\n// ideData.ts for the IDE tooling, so this module builds the actual\n// string translator on top of them rather than depending on anything\n// external.\n//\n// Scope: format *strings* only (`\"YYYY-MM-DD\"` -> `\"yyyy-MM-dd\"`), not\n// an AST codemod that rewrites call sites. Rewriting\n// `dayjs(x).format(fmt)` call expressions across a codebase is a\n// separate, bigger job — see `temporal-fmt-codemod` for that.\n\nimport { DAYJS_TO_TEMPORAL_FMT, DATE_FNS_TO_TEMPORAL_FMT, type TokenConversionHint } from './ideData.js';\n\ninterface SourcePiece {\n kind: 'token' | 'literal';\n value: string;\n}\n\n// Day.js and date-fns both escape literal text by wrapping it in\n// square brackets (`[MM]` stays literal \"MM\"), unlike temporal-fmt's\n// single-quote escaping. Splitting on that first keeps the token scan\n// below from matching inside an escaped span.\nfunction splitOnBrackets(source: string): SourcePiece[] {\n const pieces: SourcePiece[] = [];\n let i = 0;\n while (i < source.length) {\n if (source[i] === '[') {\n const end = source.indexOf(']', i + 1);\n if (end === -1) {\n pieces.push({ kind: 'token', value: source.slice(i) });\n break;\n }\n pieces.push({ kind: 'literal', value: source.slice(i + 1, end) });\n i = end + 1;\n } else {\n let j = i;\n while (j < source.length && source[j] !== '[') j += 1;\n pieces.push({ kind: 'token', value: source.slice(i, j) });\n i = j;\n }\n }\n return pieces;\n}\n\n// Splits a \"token\" span (the non-bracketed parts of the source string)\n// into runs of identical letters and everything else, greedy-longest\n// against the known token table first — same overall approach as\n// tokenize.ts, but here we're scanning the *source* library's\n// vocabulary rather than temporal-fmt's own.\nfunction splitIntoRuns(span: string, sortedFrom: string[]): SourcePiece[] {\n const pieces: SourcePiece[] = [];\n let i = 0;\n while (i < span.length) {\n const match = sortedFrom.find((tok) => span.startsWith(tok, i));\n if (match) {\n pieces.push({ kind: 'token', value: match });\n i += match.length;\n continue;\n }\n const last = pieces[pieces.length - 1];\n if (last && last.kind === 'literal') {\n last.value += span[i];\n } else {\n pieces.push({ kind: 'literal', value: span[i] });\n }\n i += 1;\n }\n return pieces;\n}\n\nfunction translate(source: string, table: TokenConversionHint[], sourceLibLabel: string): string {\n const byFrom = new Map(table.map((hint) => [hint.from, hint.to]));\n const sortedFrom = [...byFrom.keys()].sort((a, b) => b.length - a.length);\n\n const bracketPieces = splitOnBrackets(source);\n let out = '';\n for (const piece of bracketPieces) {\n if (piece.kind === 'literal') {\n // Re-escape for temporal-fmt's quote syntax; a literal quote\n // character inside the escaped span needs doubling.\n out += `'${piece.value.replace(/'/g, \"''\")}'`;\n continue;\n }\n for (const run of splitIntoRuns(piece.value, sortedFrom)) {\n if (run.kind === 'token') {\n const mapped = byFrom.get(run.value);\n if (mapped === undefined || mapped === null) {\n throw new Error(\n `temporal-fmt: \"${run.value}\" has no ${sourceLibLabel} -> temporal-fmt mapping ` +\n `(in format string \"${source}\"). Write the equivalent temporal-fmt token in by hand, ` +\n `or wrap it in brackets if it was meant as literal text.`\n );\n }\n out += mapped;\n } else if (/[a-zA-Z]/.test(run.value)) {\n // Unrecognized letters can't pass through unescaped — temporal-fmt\n // would read them as its own tokens. Quote the whole run.\n out += `'${run.value.replace(/'/g, \"''\")}'`;\n } else {\n out += run.value;\n }\n }\n }\n return out;\n}\n\n/**\n * Translates a Day.js format string to the equivalent temporal-fmt\n * token string.\n *\n * ```js\n * translateDayjsFormatString('YYYY-MM-DD HH:mm:ss'); // \"yyyy-MM-dd HH:mm:ss\"\n * translateDayjsFormatString('[Q]Q YYYY'); // \"'Q'Q yyyy\" (bracketed text stays literal)\n * ```\n *\n * Throws if the format string uses a Day.js token with no temporal-fmt\n * equivalent (`Do`, `Mo`, `Qo`, `k`, `kk`, `X`, `x`, the localized\n * `L`-family tokens) — these need to be rewritten by hand, since\n * there's no single temporal-fmt token that means the same thing.\n *\n * Note: `Do`/`Mo`/`Qo`/`k`/`kk`/`X`/`x` only have meaning in Day.js\n * once the `AdvancedFormat` (and, for `X`/`x`, base) plugins are\n * loaded — without them Day.js silently glues the parts together or\n * passes the letters through unrendered instead of erroring. This\n * function assumes the plugin is loaded, since that's the common case\n * for anyone who put these tokens in a format string on purpose.\n */\nexport function translateDayjsFormatString(formatStr: string): string {\n return translate(formatStr, DAYJS_TO_TEMPORAL_FMT, 'Day.js');\n}\n\n/**\n * Translates a date-fns format string to the equivalent temporal-fmt\n * token string. date-fns already uses Unicode-style tokens close to\n * temporal-fmt's own, so most strings pass through with only a case\n * change on the weekday tokens; the notable divergences are date-fns's\n * `D`/`DD` (day-of-year, matches temporal-fmt already) versus its `d`/\n * `dd` (day-of-month, also matches already) and the locale-dependent\n * `P`/`p` composite tokens, which have no single temporal-fmt token\n * and throw.\n */\nexport function translateDateFnsFormatString(formatStr: string): string {\n return translate(formatStr, DATE_FNS_TO_TEMPORAL_FMT, 'date-fns');\n}\n"],"mappings":"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","names":["readFields","value","label","obj","hasYear","hasMonth","hasDay","REFERENCE_YEAR","MS_PER_SECOND","MS_PER_MINUTE","MS_PER_HOUR","MS_PER_DAY","daysSinceReference","year","month","day","days","y","isGregorianLeapYear","dayOfYear","toEpochMs","fields","hour","minute","second","millisecond","DEFAULT_CUTOFFS","resolveCutoffs","user","merged","key","secondsMs","minutesMs","hoursMs","daysMs","monthsMs","rtfCache","MAX_RTF_CACHE_SIZE","getRtf","locale","numeric","canonicalLocaleKey","rtf","oldestKey","normalizeLocaleTag","err","InvalidLocaleError","formatDistance","date1","date2","options","fields1","fields2","diffMs","absMs","unitCutoffs","unit","maxMs","candidateUnit","divisor","unitToMs","rounded","DEFAULT_LOCALE","formatDistanceToNow","date","now","nowFields","MAX_REGISTERED_GRAMMARS","registeredGrammars","registerRelativeGrammar","grammar","existingIdx","g","tryRegisteredGrammar","language","input","reference","matcher","match","temporal","getTemporal","fields","listRegisteredGrammars","normalizeForMatch","s","levenshtein","a","b","prev","curr","j","i","cost","FUZZY_MAX_DISTANCE","MAX_RELATIVE_INPUT_LENGTH","MAX_RELATIVE_WORDS","buildEnglishFuzzyVocabulary","ENGLISH_WEEKDAYS","ENGLISH_MONTHS","ENGLISH_MONTH_SHORT","englishFuzzyVocabulary","getEnglishFuzzyVocabulary","fuzzyCorrectEnglish","normalized","vocabulary","words","changed","corrected","word","best","bestDist","candidate","dist","readYear","reference","readMonth","readDay","extractDayOfWeek","dow","nameAlternation","names","n","buildPlainDate","temporal","year","month","day","addDays","days","addUnits","count","unit","refDate","duration","weekdayOffset","rel","refDow","targetDow","diff","resolveToNextOccurrence","refYear","thisYear","err","weekdayIndexFromName","name","idx","monthIndexFromName","longNames","shortNames","longIdx","shortIdx","ENGLISH_GRAMMAR","_m","ctx","m","inPrefix","unitName","hasIn","hasAgo","sign","SPANISH_WEEKDAYS","SPANISH_MONTHS","SPANISH_MONTH_SHORT","SPANISH_GRAMMAR","relWord","weekdayName","unitWord","unitWordToEnglish","_ctx","FRENCH_WEEKDAYS","FRENCH_MONTHS","FRENCH_MONTH_SHORT","FRENCH_GRAMMAR","GERMAN_WEEKDAYS","GERMAN_MONTHS","GERMAN_MONTH_SHORT","GERMAN_GRAMMAR","adj","GRAMMARS","grammarForLocale","locale","lang","languageOf","w","parseRelative","input","referenceDate","options","reference","temporal","getTemporal","trimmed","MAX_RELATIVE_INPUT_LENGTH","normalized","normalizeForMatch","grammar","grammarForLocale","ctx","registered","tryRegisteredGrammar","languageOf","tryMatch","text","matcher","match","NO_MATCH","exactResult","ENGLISH_GRAMMAR","corrected","fuzzyCorrectEnglish","fuzzyResult","isObject","v","guardOrFalse","impl","value","hasMethod","name","hasTag","typeName","isPlainDate","isPlainTime","isPlainDateTime","isZonedDateTime","isInstant","isPlainYearMonth","isPlainMonthDay","isDuration","isTemporal","tag","describeValue","ctor","assertImpl","guard","expectedType","assertTemporal","assertInstant","assertPlainDate","assertPlainTime","assertPlainDateTime","assertZonedDateTime","assertPlainYearMonth","assertPlainMonthDay","assertDuration","TYPES_WITH","TOKEN_METADATA","ALL_TOKEN_NAMES","tokenizeFormat","formatStr","tokenize","listTokens","TOKENS","name","TOKEN_METADATA","tokenInfo","analyzeFormat","pieces","tokens","requiredFields","compatibleTypesSet","parseable","localeSensitive","calendarSensitive","timezoneSensitive","roundTripSafe","warnings","offset","unpaddedRun","flushRun","piece","metadata","handler","_handlerFor","t","stillCompatible","UNPADDED_NUMERIC_TOKENS","tokenNames","has12Hour","has24Hour","hasAPeriod","hasOffset","hasZzz","w","explainFormat","analysis","lines","isValidFormat","validateFormat","fieldForToken","token","parseISO","input","temporal","getTemporal","iso","offsetMatch","err","InvalidDateError","formatISO","value","v","FormatSyntaxError","parseRFC3339","formatRFC3339","s","parseRFC2822","ms","requireInstant","formatRFC2822","inst","formatRFC2822FromMs","parts","get","t","p","tzMatch","tz","sign","hours","minutes","hour","d","days","months","wd","dd","mon","yyyy","hh","mm","ss","parseHTTPDate","trimmed","formatHTTPDate","instant","getInstant","toUnixSeconds","fromUnixSeconds","seconds","fromUnixMilliseconds","fromUnixMicroseconds","µs","fromUnixNanoseconds","ns","toUnixMilliseconds","toUnixMicroseconds","epochNanoseconds","toUnixNanoseconds","parseSQL","parse","formatSQL","format","DEFAULT_CONFIG","DEFAULT_LOCALE","createConfig","overrides","merged","mergeWithConfig","config","perCall","result","createBusinessCalendar","options","weekend","workingHours","i","isBusinessDay","cal","value","v","dow","jsDow","nextBusinessDay","candidate","add","previousBusinessDay","MAX_BUSINESS_DAY_TRAVERSAL","assertBusinessDayCount","days","compareDateFields","a","b","av","bv","ay","by","addBusinessDays","sign","absDays","subtractBusinessDays","differenceInBusinessDays","rawDirection","direction","count","traversedDays","MAX_HOLIDAY_YEAR_RANGE","createHolidayCalendar","specs","cache","forYear","year","list","s","md","value","v","h","start","end","sv","ev","result","y","date","compare","nextHoliday","cal","candidate","add","i","previousHoliday","holidaysBetween","createFormatter","options","mergedTokens","TOKENS","customTokenNames","custom","existingIdx","name","a","b","handlerByToken","handler","field","sortedTokenStrings","customTokenize","formatStr","pieces","i","ch","appendLiteral","j","literal","closed","match","tok","runChar","end","UnknownTokenError","value","last","defaultLocale","DEFAULT_LOCALE","temporal","opts","locale","result","piece","out","p","tokenFamily","name","getAutocompleteData","ALL_TOKEN_NAMES","meta","TOKEN_METADATA","getHoverDocs","result","getInlineDiagnostics","formatStr","analysis","analyzeFormat","diagnostics","warning","message","suggestion","DAYJS_TO_TEMPORAL_FMT","DATE_FNS_TO_TEMPORAL_FMT","previewFormat","sample","format","getDocUrl","tokenName","splitOnBrackets","source","pieces","i","end","j","splitIntoRuns","span","sortedFrom","match","tok","last","translate","table","sourceLibLabel","byFrom","hint","a","b","bracketPieces","out","piece","run","mapped","translateDayjsFormatString","formatStr","DAYJS_TO_TEMPORAL_FMT","translateDateFnsFormatString","DATE_FNS_TO_TEMPORAL_FMT"]}
|
|
1
|
+
{"version":3,"sources":["../src/formatDistance.ts","../src/relativeGrammar.ts","../src/parseRelative.ts","../src/typeGuards.ts","../src/tokenMetadata.ts","../src/analyze.ts","../src/serialization.ts","../src/config.ts","../src/businessCalendar.ts","../src/holidays.ts","../src/extensibility.ts","../src/ideData.ts","../src/codemod.ts"],"sourcesContent":["import { DEFAULT_LOCALE, type FormatOptions } from './tokens.js';\nimport { dayOfYear, isGregorianLeapYear } from './isoWeek.js';\nimport { normalizeLocaleTag } from './localeVocab.js';\nimport { InvalidLocaleError } from './errors.js';\n\n// Reads date fields off a Temporal value in the same minimal-shape style\n// as the rest of the library (TemporalLike) — no Temporal factory needed.\n// Works for PlainDate, PlainDateTime, and ZonedDateTime (since they all\n// expose year/month/day). PlainTime has no date fields; formatDistance()\n// between two PlainTime values isn't really meaningful and isn't\n// supported — it'll throw below when the field read fails.\ninterface DateFieldView {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\nfunction readFields(value: unknown, label: string): DateFieldView {\n if (value === null || typeof value !== 'object') {\n throw new Error(\n `temporal-fmt: formatDistance expects Temporal values, got ${label} = ${String(value)}.`\n );\n }\n const obj = value as Record<string, unknown>;\n // Either year/month/day (a real date) or none of them (a PlainTime);\n // anything in between would be a malformed Temporal-like.\n const hasYear = typeof obj.year === 'number';\n const hasMonth = typeof obj.month === 'number';\n const hasDay = typeof obj.day === 'number';\n if (hasYear !== hasMonth || hasMonth !== hasDay) {\n throw new Error(\n `temporal-fmt: formatDistance got a ${label} with a partial date (some of year/month/day missing). ` +\n `Pass a full Temporal.PlainDate / PlainDateTime / ZonedDateTime.`\n );\n }\n return {\n year: hasYear ? (obj.year as number) : undefined,\n month: hasMonth ? (obj.month as number) : undefined,\n day: hasDay ? (obj.day as number) : undefined,\n hour: typeof obj.hour === 'number' ? (obj.hour as number) : undefined,\n minute: typeof obj.minute === 'number' ? (obj.minute as number) : undefined,\n second: typeof obj.second === 'number' ? (obj.second as number) : undefined,\n millisecond: typeof obj.millisecond === 'number' ? (obj.millisecond as number) : undefined,\n };\n}\n\n// Reference epoch for ms-since computation. Jan 1, 2000 UTC is the same\n// anchor isoWeek.ts uses for day-of-week arithmetic; reusing it keeps the\n// reasoning localized to one well-known reference date.\nconst REFERENCE_YEAR = 2000;\nconst MS_PER_SECOND = 1000;\nconst MS_PER_MINUTE = 60 * MS_PER_SECOND;\nconst MS_PER_HOUR = 60 * MS_PER_MINUTE;\nconst MS_PER_DAY = 24 * MS_PER_HOUR;\n\nfunction daysSinceReference(year: number, month: number, day: number): number {\n let days = 0;\n if (year >= REFERENCE_YEAR) {\n for (let y = REFERENCE_YEAR; y < year; y++) {\n days += isGregorianLeapYear(y) ? 366 : 365;\n }\n } else {\n for (let y = year; y < REFERENCE_YEAR; y++) {\n days -= isGregorianLeapYear(y) ? 366 : 365;\n }\n }\n days += dayOfYear(year, month, day) - 1;\n return days;\n}\n\nfunction toEpochMs(fields: DateFieldView): number {\n // A PlainDate has no time fields — treat as midnight. A PlainDateTime\n // has them all. Comparing two PlainDates is a day-resolution diff;\n // comparing two PlainDateTimes is millisecond-resolution. Mixing the\n // two (one PlainDate, one PlainDateTime) is allowed and just means the\n // PlainDate side is treated as midnight, which is what most callers\n // would intuitively expect (\"distance from this date to this moment\").\n if (fields.year === undefined || fields.month === undefined || fields.day === undefined) {\n throw new Error(\n `temporal-fmt: formatDistance needs a Temporal value with year/month/day fields ` +\n `(PlainDate, PlainDateTime, or ZonedDateTime). A PlainTime or other shape ` +\n `has no anchor date to diff against.`\n );\n }\n const days = daysSinceReference(fields.year, fields.month, fields.day);\n const hour = fields.hour ?? 0;\n const minute = fields.minute ?? 0;\n const second = fields.second ?? 0;\n const millisecond = fields.millisecond ?? 0;\n return days * MS_PER_DAY + hour * MS_PER_HOUR + minute * MS_PER_MINUTE + second * MS_PER_SECOND + millisecond;\n}\n\n// Unit selection cutoffs. Mirrors the rough thresholds date-fns uses,\n// trimmed to the units Intl.RelativeTimeFormat supports in every engine\n// (it accepts 'second' through 'year'; 'quarter' and 'week' support\n// varies, so we skip 'week' here — going days → months directly at the\n// 30-day boundary is simpler and avoids the engine-support cliff).\n//\n// |diff| < 60 s → seconds (\"30 seconds ago\")\n// |diff| < 60 min → minutes (\"12 minutes ago\")\n// |diff| < 24 h → hours (\"3 hours ago\")\n// |diff| < 30 d → days (\"5 days ago\")\n// |diff| < 365 d → months (\"2 months ago\")\n// otherwise → years (\"1 year ago\")\n//\n// 30 days is an approximation of a month — a calendar month is 28-31\n// days, so the boundary is inherently fuzzy. Same with 365 days for a\n// year. Documented as approximations, not exact calendar arithmetic.\n//\n// `cutoffs` on FormatDistanceOptions overrides individual boundaries\n// per call. DEFAULT_CUTOFFS holds the same numbers as the old hardcoded\n// UNIT_CUTOFFS so callers passing nothing see the same output as\n// before — verified byte-for-byte against the pre-change baseline.\nconst DEFAULT_CUTOFFS = {\n seconds: 60, // 60 s\n minutes: 60, // 60 min\n hours: 24, // 24 h\n days: 30, // 30 d\n months: 365, // 365 d (in days, since the months→years boundary is day-resolution)\n} as const;\n\ntype CutoffKey = keyof typeof DEFAULT_CUTOFFS;\n\n// Cutoffs the caller can override. Each value is in the unit's own\n// native scale (seconds for `seconds`, minutes for `minutes`, etc.) —\n// `months` is the exception: it's the day count that bounds the\n// months→years crossover, since \"months\" itself isn't a fixed number\n// of days. This mirrors how the original hardcoded table expressed\n// the same boundary (30 * MS_PER_DAY for days, 365 * MS_PER_DAY for\n// the months cap) and lets callers say \"treat anything under 90 days\n// as months\" rather than \"anything under 3 months as months\" (which\n// would require picking a definition of \"month\").\nexport interface DistanceCutoffs {\n seconds?: number;\n minutes?: number;\n hours?: number;\n days?: number;\n months?: number;\n}\n\n// Convert the user-facing cutoffs (per-unit numbers) into the ms\n// thresholds the matching loop needs. Validates each value is a\n// positive finite number, and that the boundaries are monotonically\n// non-decreasing in equivalent ms — without that, the smallest-bound\n// branch always wins and a later branch becomes unreachable, which\n// is never what the caller intended.\nfunction resolveCutoffs(user?: DistanceCutoffs): Array<{ maxMs: number; unit: Intl.RelativeTimeFormatUnit }> {\n const merged: Record<CutoffKey, number> = { ...DEFAULT_CUTOFFS, ...user };\n\n for (const key of Object.keys(merged) as CutoffKey[]) {\n const value = merged[key];\n if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) {\n throw new Error(\n `temporal-fmt: formatDistance cutoff \"${key}\" must be a positive finite number (got ${String(value)}).`\n );\n }\n }\n\n const secondsMs = merged.seconds * MS_PER_SECOND;\n const minutesMs = merged.minutes * MS_PER_MINUTE;\n const hoursMs = merged.hours * MS_PER_HOUR;\n const daysMs = merged.days * MS_PER_DAY;\n // `months` is in days — see DistanceCutoffs comment above.\n const monthsMs = merged.months * MS_PER_DAY;\n\n if (!(secondsMs <= minutesMs && minutesMs <= hoursMs && hoursMs <= daysMs && daysMs <= monthsMs)) {\n throw new Error(\n `temporal-fmt: formatDistance cutoffs must be monotonically non-decreasing in equivalent ms ` +\n `(seconds ≤ minutes ≤ hours ≤ days ≤ months). Got: seconds=${merged.seconds}s, ` +\n `minutes=${merged.minutes}min, hours=${merged.hours}h, days=${merged.days}d, months=${merged.months}d — ` +\n `pick a sequence where each boundary is at least as large as the one before it.`\n );\n }\n\n return [\n { maxMs: secondsMs, unit: 'second' },\n { maxMs: minutesMs, unit: 'minute' },\n { maxMs: hoursMs, unit: 'hour' },\n { maxMs: daysMs, unit: 'day' },\n { maxMs: monthsMs, unit: 'month' },\n ];\n}\n\nconst rtfCache = new Map<string, Intl.RelativeTimeFormat>();\nconst MAX_RTF_CACHE_SIZE = 100;\n\nfunction getRtf(locale: string, numeric: 'always' | 'auto'): Intl.RelativeTimeFormat {\n const key = `${canonicalLocaleKey(locale)}|${numeric}`;\n let rtf = rtfCache.get(key);\n if (rtf) return rtf;\n if (rtfCache.size >= MAX_RTF_CACHE_SIZE) {\n const oldestKey = rtfCache.keys().next().value;\n if (oldestKey !== undefined) rtfCache.delete(oldestKey);\n }\n try {\n rtf = new Intl.RelativeTimeFormat(normalizeLocaleTag(locale), { numeric });\n } catch (err) {\n // Malformed locale tags reach Intl as a bare RangeError; surface the\n // library's typed error instead. (Every failure mode of these\n // constructors with a string locale is a RangeError, so converting\n // unconditionally loses nothing — the original message is preserved\n // in `reason` either way.)\n throw new InvalidLocaleError({ actual: locale, reason: (err as Error).message });\n }\n rtfCache.set(key, rtf);\n return rtf;\n}\n\nfunction canonicalLocaleKey(locale: string): string {\n try {\n return new Intl.Locale(locale.replace(/_/g, '-')).toString().toLowerCase();\n } catch {\n return locale;\n }\n}\n\nexport interface FormatDistanceOptions extends FormatOptions {\n /**\n * 'auto' (default) lets Intl.RelativeTimeFormat use natural forms like\n * \"yesterday\"/\"tomorrow\"/\"now\" when the rounded value lands on ±1 or 0.\n * 'always' forces the strict \"1 day ago\"/\"in 1 day\"/\"in 0 seconds\" form.\n */\n numeric?: 'always' | 'auto';\n /**\n * Override the unit-selection boundaries (seconds→minutes,\n * minutes→hours, hours→days, days→months, months→years). Any\n * subset can be supplied; omitted boundaries fall back to the\n * defaults (60s, 60min, 24h, 30d, 365d). Values are in each\n * unit's native scale except `months`, which is in days — see\n * DistanceCutoffs. Throws descriptively on non-monotonic\n * boundaries or non-positive values, rather than producing\n * confusing output downstream.\n */\n cutoffs?: DistanceCutoffs;\n}\n\n/**\n * Returns a human-readable relative-time string describing `date1`\n * relative to `date2`, e.g. \"3 days ago\", \"in 2 hours\", \"now\". Delegates\n * unit names and pluralization to `Intl.RelativeTimeFormat` so the\n * output localizes the same way the rest of the library's locale-aware\n * tokens do.\n *\n * Convention: the result describes `date1`'s position relative to\n * `date2`. `formatDistance(now, threeDaysAgo)` → `\"3 days ago\"` (the\n * past date is described relative to now). `formatDistance(now, twoHoursFromNow)`\n * → `\"in 2 hours\"`. This matches the natural-language reading \"describe\n * the first date as if standing at the second one.\"\n *\n * Unit-selection cutoffs (seconds → minutes → hours → days → months →\n * years) and the rationale for each are documented in the README under\n * \"formatDistance\".\n *\n * @example\n * formatDistance(threeDaysAgo, today) // \"3 days ago\"\n * formatDistance(twoHoursFromNow, today) // \"in 2 hours\"\n * formatDistance(today, today) // \"now\"\n * formatDistance(futureDate, today, {locale:'fr-FR'}) // \"dans 2 jours\"\n */\nexport function formatDistance(\n date1: unknown,\n date2: unknown,\n options: FormatDistanceOptions = {},\n): string {\n const fields1 = readFields(date1, 'date1');\n const fields2 = readFields(date2, 'date2');\n\n // diff > 0: date1 is later than date2 → \"in X units\" (date1 is in\n // the future relative to date2). diff < 0: date1 is earlier than\n // date2 → \"X units ago\". This convention puts date1 in the\n // \"described\" role and date2 in the \"reference\" role, matching\n // natural-language reading: `formatDistance(threeDaysAgo, today)`\n // = \"describe threeDaysAgo as if standing at today\" = \"3 days ago\".\n const diffMs = toEpochMs(fields1) - toEpochMs(fields2);\n const absMs = Math.abs(diffMs);\n\n const unitCutoffs = resolveCutoffs(options.cutoffs);\n let unit: Intl.RelativeTimeFormatUnit = 'year';\n for (const { maxMs, unit: candidateUnit } of unitCutoffs) {\n if (absMs < maxMs) {\n unit = candidateUnit;\n break;\n }\n }\n\n const divisor = unitToMs(unit);\n const rounded = Math.round(diffMs / divisor);\n\n const numeric = options.numeric ?? 'auto';\n const locale = options.locale ?? DEFAULT_LOCALE;\n const rtf = getRtf(locale, numeric);\n return rtf.format(rounded, unit);\n}\n\n/**\n * Same as formatDistance(date, now), where \"now\" is read from the system\n * clock at call time. Convenience wrapper for the common \"how long ago\n * was this\" case, so the caller doesn't have to construct a reference\n * value themselves.\n *\n * Unlike formatRelativeToNow() (in relativeTime.ts), which only needs\n * calendar-day resolution, this reads the full wall-clock time (hour\n * through millisecond) off the system clock — formatDistance's unit\n * selection is ms-resolution, so a date-only \"now\" would misclassify\n * anything under 24 hours old (e.g. \"1 hour ago\" reading as \"in 23\n * hours\" against a midnight-truncated reference). See the test file\n * for a regression case covering exactly that.\n *\n * The reference is captured fresh on every call, not memoized — each\n * call reflects \"now\" at the moment it runs, same expectation\n * formatRelativeToNow() already sets.\n *\n * @example\n * formatDistanceToNow(threeHoursAgo) // \"3 hours ago\"\n * formatDistanceToNow(tomorrow) // \"in 1 day\" (auto: \"tomorrow\")\n */\nexport function formatDistanceToNow(\n date: unknown,\n options: FormatDistanceOptions = {},\n): string {\n const now = new Date();\n const nowFields = {\n year: now.getFullYear(),\n month: now.getMonth() + 1,\n day: now.getDate(),\n hour: now.getHours(),\n minute: now.getMinutes(),\n second: now.getSeconds(),\n millisecond: now.getMilliseconds(),\n };\n return formatDistance(date, nowFields, options);\n}\n\nfunction unitToMs(unit: Intl.RelativeTimeFormatUnit): number {\n switch (unit) {\n case 'second': return MS_PER_SECOND;\n case 'minute': return MS_PER_MINUTE;\n case 'hour': return MS_PER_HOUR;\n case 'day': return MS_PER_DAY;\n /* c8 ignore start @preserve -- unreachable: unitToMs is only called\n with `unit` values produced by formatDistance's cutoff loop above,\n which only ever yields 'second'/'minute'/'hour'/'day'/'month'\n (from resolveCutoffs' fixed array) or 'year' (the loop's fallback\n default). 'week' and 'quarter' were never wired into\n resolveCutoffs — formatDistance intentionally skips week-\n resolution output (see the comment above DEFAULT_CUTOFFS) — so\n neither can reach this switch. */\n case 'week': return 7 * MS_PER_DAY;\n /* c8 ignore stop @preserve */\n case 'month': return 30 * MS_PER_DAY;\n /* c8 ignore start @preserve -- unreachable, same reason as 'week'\n above: resolveCutoffs never produces 'quarter'. */\n case 'quarter': return 91 * MS_PER_DAY;\n /* c8 ignore stop @preserve */\n case 'year': return 365 * MS_PER_DAY;\n /* c8 ignore start @preserve -- unreachable: every unit\n resolveCutoffs can actually produce ('second' through 'month', or\n 'year' as the loop's fallback default) has an explicit case\n above, so this exhaustive-switch default can't fire at runtime.\n It exists so TS accepts the function as total — the compiler\n can't see through the cutoff-array iteration in formatDistance()\n to know the input is already narrowed. */\n default:\n throw new Error(`temporal-fmt: formatDistance hit unhandled unit \"${String(unit)}\".`);\n /* c8 ignore stop @preserve */\n }\n}","// Relative-grammar registration. Extends the existing\n// parseRelative.ts with an extension point for registering additional\n// grammars beyond the four built in (English, Spanish, French, German).\n//\n// The existing parseRelative() detects the language from the locale\n// option and dispatches to the matching grammar. registerRelativeGrammar()\n// lets a caller add a new language without modifying parseRelative.ts.\n//\n// Grammar shape: a list of matchers, each returning either a Temporal\n// field bag describing the resolved date or null. parseRelative tries\n// each matcher in order until one matches. This mirrors the ENGLISH/\n// SPANISH/FRENCH/GERMAN_GRAMMAR structure parseRelative already uses\n// internally.\n\nimport { getTemporal, type TemporalNamespace } from './temporalProvider.js';\n\nexport interface RelativeGrammarMatch {\n // The Temporal fields the matcher resolved. Used to construct a\n // PlainDate / PlainDateTime via Temporal.PlainDate.from().\n year?: number;\n month?: number;\n day?: number;\n // Optional: instead of computing fields directly, return a function\n // that takes the reference date and returns the resolved date. Used\n // for phrases like \"next Tuesday\" that depend on the reference's\n // weekday.\n resolve?: (reference: { year: number; month: number; day: number; dayOfWeek: number }) => { year: number; month: number; day: number };\n}\n\nexport interface RelativeGrammar {\n // Locale language subtag this grammar handles ('en', 'es', etc.).\n // Matched against the `locale` option's language subtag.\n language: string;\n // Matchers in priority order. First match wins.\n matchers: Array<(input: string) => RelativeGrammarMatch | null>;\n}\n\n// Cap on registered grammars. Replacement registration for an existing\n// language never grows the registry, so the cap only gates new languages —\n// the same convention registerLocaleVocab uses for custom vocabularies.\n// Without it, a caller looping registerRelativeGrammar() grows the array\n// (and the per-language scan in tryRegisteredGrammar) without bound.\nconst MAX_REGISTERED_GRAMMARS = 100;\n\nconst registeredGrammars: RelativeGrammar[] = [];\n\nexport function registerRelativeGrammar(grammar: RelativeGrammar): void {\n if (typeof grammar.language !== 'string' || grammar.language.length === 0) {\n throw new Error('temporal-fmt: registerRelativeGrammar requires a non-empty language string.');\n }\n if (!Array.isArray(grammar.matchers) || grammar.matchers.length === 0) {\n throw new Error('temporal-fmt: registerRelativeGrammar requires at least one matcher.');\n }\n // Replace any existing grammar for the same language.\n const existingIdx = registeredGrammars.findIndex((g) => g.language === grammar.language);\n if (existingIdx >= 0) {\n registeredGrammars[existingIdx] = grammar;\n } else {\n if (registeredGrammars.length >= MAX_REGISTERED_GRAMMARS) {\n throw new RangeError(`temporal-fmt: registerRelativeGrammar reached the ${MAX_REGISTERED_GRAMMARS}-grammar limit.`);\n }\n registeredGrammars.push(grammar);\n }\n}\n\n// Called by parseRelative() to try registered grammars before falling\n// back to the built-in ones. Returns the resolved Temporal.PlainDate or\n// null if no registered grammar matched.\nexport function tryRegisteredGrammar(\n language: string,\n input: string,\n reference: { year: number; month: number; day: number; dayOfWeek: number },\n): unknown | null {\n for (const grammar of registeredGrammars) {\n if (grammar.language !== language) continue;\n for (const matcher of grammar.matchers) {\n const match = matcher(input);\n if (match === null) continue;\n const temporal = getTemporal();\n if (match.resolve) {\n const fields = match.resolve(reference);\n return temporal.PlainDate.from(fields, { overflow: 'reject' });\n }\n return temporal.PlainDate.from(\n { year: match.year ?? reference.year, month: match.month ?? reference.month, day: match.day ?? reference.day },\n { overflow: 'reject' },\n );\n }\n }\n return null;\n}\n\n// Returns the list of registered languages (for introspection).\nexport function listRegisteredGrammars(): string[] {\n return registeredGrammars.map((g) => g.language);\n}\n\n// Suppress unused import — TemporalNamespace is referenced by the type\n// signature above (via the return type of tryRegisteredGrammar, which\n// is the result of temporal.PlainDate.from).\nvoid (undefined as unknown as TemporalNamespace);\n","import { getTemporal } from './temporalProvider.js';\nimport { type TemporalNamespace } from './temporalProvider.js';\nimport { tryRegisteredGrammar } from './relativeGrammar.js';\nimport { DEFAULT_LOCALE, type FormatOptions } from './tokens.js';\n\n// parseRelative resolves common relative-date phrases (\"next Tuesday\",\n// \"in 3 days\", \"March 5th\") against a reference date, returning a\n// Temporal.PlainDate. It's a different subsystem from the token-based\n// parse(): the input is free natural-language text, not a structurally-\n// typed format string, so this module owns its own grammar rather than\n// bolting a natural-language layer onto the existing tokenizer.\n//\n// Per-language grammars: each locale's grammar lives in its own\n// clearly-labeled section below (ENGLISH_GRAMMAR, SPANISH_GRAMMAR,\n// FRENCH_GRAMMAR, GERMAN_GRAMMAR). The vocabulary and phrase patterns\n// are NOT shared across languages — Spanish \"hace 2 semanas\" and\n// French \"il y a 2 semaines\" are different idioms and get their own\n// regexes. What IS shared is the matching engine (iterate matchers in\n// order, first match wins, throw on no match) and the resolution\n// helpers (addDays, addUnits, weekdayOffset, resolveToNextOccurrence).\n// Same approach the humanizing skill calls \"solve each recurring\n// problem once\": the matching strategy is shared, the per-language\n// vocabulary is not.\n//\n// Default locale (no `locale` option) uses English — matches the\n// pre-change behavior byte-for-byte. Passing `locale: 'es'`,\n// `locale: 'fr'`, or `locale: 'de'` (or any locale tag with that\n// language subtag) routes to the corresponding grammar. Unrecognized\n// languages fall back to English rather than throwing — a caller\n// passing `locale: 'it-IT'` still gets *some* result, just from the\n// English grammar. (We could throw instead; the current contract is\n// \"best effort.\" If the caller wanted Italian specifically, they'd\n// pass an Italian grammar via registerLocaleVocab-style extension —\n// not implemented here.)\n\n// Lowercase + expand German umlauts (ä→ae, ö→oe, ü→ue, ß→ss) + strip\n// remaining diacritics. Three things going on at once:\n//\n// 1. Lowercase — case-insensitive matching without forcing the\n// regex flag to do it (also keeps the captured groups lowercase\n// for the resolver's comparisons).\n// 2. Expand German umlaut transliterations. Germans without an\n// umlaut key write \"ä\" as \"ae\" — the standard transliteration.\n// Expanding \"ä\" → \"ae\" (before NFD stripping) means both \"März\"\n// and \"Maerz\" normalize to \"maerz\" and match the same pattern.\n// The reverse (ae → ä) would be wrong: \"Tage\" has \"ae\" as a\n// coincidence, not as an umlaut transliteration. Forward expansion\n// is unambiguous because the source string already has the\n// umlaut — the expansion only affects the matched form.\n// 3. Strip combining marks via NFD. \"Miércoles\" → \"Miercoles\",\n// \"février\" → \"fevrier\", \"août\" → \"aout\". Pairs with the umlaut\n// expansion above so all four languages' accented forms collapse\n// to one canonical unaccented form for matching.\n//\n// Both sides of the match — input string AND the weekday/month name\n// lists — get the same normalization applied, so this is symmetric.\nfunction normalizeForMatch(s: string): string {\n return s.toLowerCase()\n .replace(/ä/g, 'ae')\n .replace(/ö/g, 'oe')\n .replace(/ü/g, 'ue')\n .replace(/ß/g, 'ss')\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '');\n}\n\n// Standard Levenshtein edit distance (insert/delete/substitute, cost 1\n// each). Used only by the opt-in fuzzy layer below — the exact matcher\n// pass never calls this. Iterative DP over two rows, not the full\n// matrix, since only the previous row is ever needed.\nfunction levenshtein(a: string, b: string): number {\n /* c8 ignore start @preserve -- unreachable through the only call\n * site (fuzzyCorrectEnglish): `a` is always a word that already\n * failed the `vocabulary.includes(word)` exact-match check, so\n * a === b never holds against any `b` drawn from that same\n * vocabulary; and neither `a` (split from a non-empty normalized\n * string) nor `b` (a vocabulary entry) is ever empty. Kept as\n * general-purpose guards in case levenshtein() gets a second caller\n * later. */\n if (a === b) return 0;\n if (a.length === 0) return b.length;\n if (b.length === 0) return a.length;\n /* c8 ignore stop @preserve */\n let prev = new Array(b.length + 1);\n let curr = new Array(b.length + 1);\n for (let j = 0; j <= b.length; j++) prev[j] = j;\n for (let i = 1; i <= a.length; i++) {\n curr[0] = i;\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n curr[j] = Math.min(\n prev[j] + 1, // deletion\n curr[j - 1] + 1, // insertion\n prev[j - 1] + cost, // substitution\n );\n }\n [prev, curr] = [curr, prev];\n }\n return prev[b.length];\n}\n\n// Max edit distance a fuzzy correction is allowed to bridge. 2 covers\n// the common single-finger-slip and single-transposed-letter typo cases\n// (\"tommorow\" is distance 1 from \"tomorrow\"; \"tuesady\" is distance 2\n// from \"tuesday\" — a transposition costs 2 under simple Levenshtein,\n// which doesn't special-case adjacent-swap as a single edit) without\n// opening the door to correcting a word into something only vaguely\n// similar. Deliberately conservative — this is a typo-tolerance layer,\n// not a \"guess what they meant\" layer; the library's whole design\n// philosophy elsewhere (parse()'s strict-by-default ambiguity handling,\n// the lenient opt-in) is to bound how much guessing is allowed and make\n// the caller ask for it explicitly.\nconst FUZZY_MAX_DISTANCE = 2;\nconst MAX_RELATIVE_INPUT_LENGTH = 4096;\nconst MAX_RELATIVE_WORDS = 32;\n\n// English-only fuzzy vocabulary. Anything a matcher's regex treats as a\n// fixed keyword (not a captured number) belongs here — weekday names,\n// month names (long and short), and the marker words the matchers\n// switch on (today/tomorrow/yesterday/next/last/this/in/ago and the\n// unit words day/week/month/year). Numbers and ordinal suffixes are\n// deliberately excluded: \"5th\" vs \"5tj\" isn't a word-shaped typo this\n// layer is trying to solve, and correcting digits is a much easier way\n// to silently produce a wrong date than correcting a weekday name is.\n//\n// Scoped to English only for this pass — the other three grammars have\n// enough positional/multi-word-marker variation (French's \"il y a\",\n// Spanish's dual pre/post weekday-modifier shapes) that a single\n// word-substitution corrector isn't a good fit for all of them without\n// per-language tuning this change doesn't attempt. parseRelative()\n// throws a clear scope-limited error if { fuzzy: true } is combined\n// with a non-English locale, rather than silently no-op-ing.\nfunction buildEnglishFuzzyVocabulary(): string[] {\n return [\n ...ENGLISH_WEEKDAYS,\n ...ENGLISH_MONTHS,\n ...ENGLISH_MONTH_SHORT,\n 'today', 'tomorrow', 'yesterday',\n 'next', 'last', 'this',\n 'in', 'ago',\n 'day', 'days', 'week', 'weeks', 'month', 'months', 'year', 'years',\n ].map(normalizeForMatch);\n}\n\n// Lazily built and cached — the vocabulary is static per process, no\n// need to rebuild the normalized list on every fuzzy call.\nlet englishFuzzyVocabulary: readonly string[] | undefined;\nfunction getEnglishFuzzyVocabulary(): readonly string[] {\n if (!englishFuzzyVocabulary) englishFuzzyVocabulary = Object.freeze(buildEnglishFuzzyVocabulary());\n return englishFuzzyVocabulary;\n}\n\n// Attempts a word-level fuzzy correction of `normalized` against the\n// English vocabulary, returning a corrected string or undefined if no\n// correction was needed/possible. Tokenizes on whitespace; each token\n// that isn't already an exact vocabulary word (or a pure number/ordinal,\n// which passes through untouched) gets replaced with its closest\n// vocabulary match, if one exists within FUZZY_MAX_DISTANCE. If a token\n// has no sufficiently-close vocabulary match, it's left as-is — the\n// re-attempted exact match will then fail on that token same as before,\n// which is the correct outcome for \"this word isn't a typo of anything\n// we know, it's just not a phrase we support.\"\nfunction fuzzyCorrectEnglish(normalized: string): string | undefined {\n const vocabulary = getEnglishFuzzyVocabulary();\n const words = normalized.split(' ');\n if (normalized.length > MAX_RELATIVE_INPUT_LENGTH || words.length > MAX_RELATIVE_WORDS) {\n throw new RangeError(\n `temporal-fmt: parseRelative fuzzy input is too large (maximum ${MAX_RELATIVE_INPUT_LENGTH} characters and ${MAX_RELATIVE_WORDS} words).`,\n );\n }\n let changed = false;\n const corrected = words.map((word) => {\n // Pure digits, or digits with an ordinal suffix (st/nd/rd/th) —\n // never touched by fuzzy correction. See the vocabulary comment\n // above for why.\n if (/^\\d+(?:st|nd|rd|th)?$/.test(word)) return word;\n // Already an exact vocabulary word — nothing to correct.\n if (vocabulary.includes(word)) return word;\n\n let best: string | undefined;\n let bestDist = FUZZY_MAX_DISTANCE + 1;\n for (const candidate of vocabulary) {\n const dist = levenshtein(word, candidate);\n if (dist < bestDist) {\n bestDist = dist;\n best = candidate;\n }\n }\n if (best !== undefined && bestDist <= FUZZY_MAX_DISTANCE) {\n changed = true;\n return best;\n }\n return word;\n });\n\n return changed ? corrected.join(' ') : undefined;\n}\n\ninterface TemporalFieldBag {\n year?: number;\n month?: number;\n day?: number;\n dayOfWeek?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n}\n\nfunction readYear(reference: TemporalFieldBag): number {\n if (typeof reference.year !== 'number') {\n throw new Error('temporal-fmt: parseRelative reference date is missing year.');\n }\n return reference.year;\n}\nfunction readMonth(reference: TemporalFieldBag): number {\n if (typeof reference.month !== 'number') {\n throw new Error('temporal-fmt: parseRelative reference date is missing month.');\n }\n return reference.month;\n}\nfunction readDay(reference: TemporalFieldBag): number {\n if (typeof reference.day !== 'number') {\n throw new Error('temporal-fmt: parseRelative reference date is missing day.');\n }\n return reference.day;\n}\n\nfunction extractDayOfWeek(reference: TemporalFieldBag): number {\n const dow = reference.dayOfWeek;\n if (typeof dow !== 'number') {\n throw new Error(\n 'temporal-fmt: parseRelative needs a reference date exposing dayOfWeek (a Temporal.PlainDate / PlainDateTime / ZonedDateTime).'\n );\n }\n return dow;\n}\n\n// Build an alternation regex fragment from a name list, normalized for\n// matching. Longest-first so \"September\" wins over \"Sep\" in the same\n// match position. The caller is responsible for any wrapping groups\n// or anchors — this just produces the inner alternation.\nfunction nameAlternation(names: string[]): string {\n const normalized = names.map(normalizeForMatch);\n // Dedupe — some locales render the long and short form identically\n // (English \"May\" is the same in both MMMM and MMM lists). Keep both\n // in the alternation rather than deduping, since duplicates in a\n // regex alternation don't change behavior and the dedupe would just\n // be a micro-optimization.\n // Sort longest-first so a longer name wins over its own prefix.\n const sorted = [...normalized].sort((a, b) => b.length - a.length);\n // Escape regex metacharacters — names shouldn't contain any, but\n // belt-and-braces avoids a future \"M+1\" month name from breaking\n // the alternation silently.\n return sorted.map((n) => n.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')).join('|');\n}\n\n// Resolves to a PlainDate by adding `days` to the reference. Used for\n// weekday refs and the today/tomorrow/yesterday family.\nfunction buildPlainDate(temporal: { PlainDate: { from: (fields: Record<string, number>, options?: { overflow?: 'constrain' | 'reject' }) => unknown } }, year: number, month: number, day: number): unknown {\n return temporal.PlainDate.from({ year, month, day }, { overflow: 'reject' });\n}\n\nfunction addDays(\n temporal: { PlainDate: { from: (fields: Record<string, number>) => unknown } },\n reference: TemporalFieldBag,\n days: number,\n): unknown {\n // Build the reference as a real PlainDate so we can use Temporal's\n // own add() for date arithmetic — calendar-correct (handles month\n // boundaries, leap years, etc.) so we don't have to reimplement it.\n const refDate = temporal.PlainDate.from({\n year: readYear(reference),\n month: readMonth(reference),\n day: readDay(reference),\n }) as { add: (duration: Record<string, number>) => unknown };\n return refDate.add({ days });\n}\n\nfunction addUnits(\n temporal: { PlainDate: { from: (fields: Record<string, number>) => unknown } },\n reference: TemporalFieldBag,\n count: number,\n unit: 'day' | 'week' | 'month' | 'year',\n): unknown {\n const refDate = temporal.PlainDate.from({\n year: readYear(reference),\n month: readMonth(reference),\n day: readDay(reference),\n }) as { add: (duration: Record<string, number>) => unknown };\n const duration: Record<string, number> = {};\n if (unit === 'day') duration.days = count;\n if (unit === 'week') duration.weeks = count;\n if (unit === 'month') duration.months = count;\n if (unit === 'year') duration.years = count;\n return refDate.add(duration);\n}\n\n// \"next X\" — strictly future next occurrence. Said on a Tuesday:\n// \"next Tuesday\" = 7 days from now, not today. Rationale: \"this\n// Tuesday\" handles the same-week case, so \"next Tuesday\" staying\n// strictly-future gives the two phrases distinct, non-overlapping\n// meanings. Documented in README \"parseRelative\".\n//\n// \"last X\" — strictly past most recent occurrence. Symmetric to \"next\".\n//\n// \"this X\" — the X of the current ISO week (Mon..Sun). Can land on\n// today, past, or future depending on where in the week today falls.\n//\n// All three resolve the same way across the four supported languages\n// (en/es/fr/de): the equivalent idiom in each language maps to one of\n// these three rel words. The natural-language reading is consistent\n// — \"next Tuesday\" said on a Tuesday means next week's Tuesday in\n// every language we support.\nfunction weekdayOffset(rel: 'next' | 'last' | 'this', refDow: number, targetDow: number): number {\n // refDow and targetDow are both 1..7 (ISO Mon=1..Sun=7).\n if (rel === 'next') {\n let diff = targetDow - refDow;\n if (diff <= 0) diff += 7; // 0 (today) → 7, negative → wrap forward\n return diff; // 1..7\n }\n if (rel === 'last') {\n let diff = targetDow - refDow;\n if (diff >= 0) diff -= 7; // 0 (today) → -7, positive → wrap backward\n return diff; // -7..-1\n }\n // rel === 'this' — X of the current week. Can be today, past, or future.\n return targetDow - refDow; // -6..+6\n}\n\n// \"March 5th\" without a year → resolve to the next occurrence of that\n// month/day. If today is that date, return today. Otherwise, if it's\n// already past this year, return next year's occurrence.\n//\n// \"Next occurrence\" semantics: future-leaning. Documented in README\n// as the chosen behavior. The alternative (\"nearest in time, past or\n// future\") would mean \"March 5th\" said on March 6 returns yesterday —\n// counterintuitive for the typical \"next birthday\"/\"next deadline\"\n// use case this kind of phrase tends to drive.\nfunction resolveToNextOccurrence(\n temporal: {\n PlainDate: {\n from: (fields: Record<string, number>, options?: { overflow?: 'constrain' | 'reject' }) => unknown;\n compare?: (one: unknown, two: unknown) => number;\n };\n },\n reference: TemporalFieldBag,\n month: number,\n day: number,\n): unknown {\n const refYear = readYear(reference);\n const refDate = temporal.PlainDate.from({\n year: refYear,\n month: readMonth(reference),\n day: readDay(reference),\n });\n // PlainDate.compare is a static method on the namespace, not an\n // instance method — that's why it's called off temporal.PlainDate\n // rather than off an instance below. Checked outside the try/catch\n // below on purpose: that block's catch is scoped to Feb-29-style\n // overflow errors from from(), and silently retries with next year's\n // date. A missing-compare error thrown from inside that try would get\n // caught by the same handler and swallowed by that retry (next year's\n // from() usually succeeds), masking the real problem instead of\n // surfacing it.\n if (!temporal.PlainDate.compare) {\n throw new Error('temporal-fmt: parseRelative needs Temporal.PlainDate.compare to resolve month-day phrases; the active implementation does not expose it.');\n }\n // try this year first; if Feb 29 in a non-leap year, Temporal will\n // throw via overflow: 'reject' — fall through to next year.\n try {\n const thisYear = temporal.PlainDate.from({ year: refYear, month, day }, { overflow: 'reject' });\n // Returns -1 / 0 / 1.\n if (temporal.PlainDate.compare(thisYear, refDate) >= 0) {\n // today or in the future → use this year's occurrence\n return thisYear;\n }\n // already past this year → next year's occurrence\n return temporal.PlainDate.from({ year: refYear + 1, month, day }, { overflow: 'reject' });\n } catch (err) {\n // Feb 29 in a non-leap year, or similar. Try next year — if the\n // caller asked for \"Feb 29\" said in a non-leap year, next year may\n // also not be leap, in which case the inner from() will throw and\n // surface a clear error rather than silently landing on Feb 28.\n try {\n return temporal.PlainDate.from({ year: refYear + 1, month, day }, { overflow: 'reject' });\n } catch {\n throw new Error(\n `temporal-fmt: parseRelative can't resolve month ${month} day ${day} — ` +\n `it isn't a valid date in either ${refYear} or ${refYear + 1}. ` +\n `Original error: ${(err as Error).message}`\n );\n }\n }\n}\n\n// Each language provides a list of matchers. The shared engine\n// iterates them in order and returns the first match. A matcher is a\n// (regex, resolver) pair — the regex captures the structural pieces\n// (count, unit name, weekday name, etc.), the resolver turns them\n// into a Temporal.PlainDate using the shared helpers above.\ninterface ResolveContext {\n temporal: TemporalNamespace;\n reference: TemporalFieldBag;\n}\n\ninterface Matcher {\n pattern: RegExp;\n resolve: (match: RegExpMatchArray, ctx: ResolveContext) => unknown;\n}\n\ninterface RelativeDateGrammar {\n // Single-line description of supported phrase classes, included in\n // the \"doesn't recognize\" error so the caller knows what to try.\n supportedHint: string;\n // Ordered matchers; first match wins.\n matchers: Matcher[];\n}\n\nfunction weekdayIndexFromName(name: string, names: string[]): number {\n const normalized = normalizeForMatch(name);\n const idx = names.findIndex((n) => normalizeForMatch(n) === normalized);\n /* c8 ignore start @preserve -- unreachable: every caller passes a\n * name captured by nameAlternation(names), which builds its regex\n * alternation from this same list under the same normalizeForMatch\n * transform. The regex can't match anything findIndex() wouldn't\n * also find here. Defensive throw kept for the type checker and as\n * a tripwire if that invariant ever breaks. Ignore comment sits on\n * the `if` itself, not just the throw inside it — c8 tracks the\n * branch outcome (was the true side ever taken) separately from the\n * statements inside, so excluding only the inner throw still leaves\n * the branch itself flagged as uncovered. */\n /* c8 ignore next */\n if (idx < 0) {\n throw new Error(`temporal-fmt: parseRelative internal error — weekday \"${name}\" not in names list.`);\n }\n /* c8 ignore stop @preserve */\n return idx + 1;\n}\n\nfunction monthIndexFromName(name: string, longNames: string[], shortNames: string[] = []): number {\n const normalized = normalizeForMatch(name);\n const longIdx = longNames.findIndex((n) => normalizeForMatch(n) === normalized);\n if (longIdx >= 0) return longIdx + 1;\n const shortIdx = shortNames.findIndex((n) => normalizeForMatch(n) === normalized);\n /* c8 ignore next */\n if (shortIdx >= 0) return shortIdx + 1;\n /* c8 ignore start @preserve -- unreachable: every caller passes a name\n * captured by nameAlternation([...longNames, ...shortNames]), so the\n * regex alternation and these two findIndex() scans are built from\n * the same lists under the same normalizeForMatch transform. Kept as\n * a tripwire for the type checker in case that invariant ever breaks. */\n throw new Error(`temporal-fmt: parseRelative internal error — month \"${name}\" not in names list.`);\n /* c8 ignore stop @preserve */\n /* c8 ignore next -- defensive block is unreachable by construction. */\n}\n\n// English grammar — also the default when no locale is supplied. The\n// regexes here are the same ones the pre-change parseRelative() used\n// inline; they've just been pulled into a matcher list so the matching\n// engine can iterate them the same way it does for es/fr/de.\nconst ENGLISH_WEEKDAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];\nconst ENGLISH_MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];\nconst ENGLISH_MONTH_SHORT = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n\nconst ENGLISH_GRAMMAR: RelativeDateGrammar = {\n supportedHint: 'Supported: weekday refs (\"next Tuesday\"), day offsets (\"today\"/\"tomorrow\"/\"yesterday\"), unit offsets (\"in 3 days\", \"2 weeks ago\"), and month-day (\"March 5th\").',\n matchers: [\n // today / tomorrow / yesterday — exact match, most rigid shape.\n // Checked first because they're the most common phrase class.\n {\n pattern: /^today$/i,\n resolve: (_m, ctx) => buildPlainDate(ctx.temporal, readYear(ctx.reference), readMonth(ctx.reference), readDay(ctx.reference)),\n },\n {\n pattern: /^tomorrow$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, 1),\n },\n {\n pattern: /^yesterday$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, -1),\n },\n // weekday references: \"next/last/this Tuesday\". Capture the relative\n // word and the weekday name separately, then resolve via +7 / -7.\n {\n pattern: new RegExp(`^(next|last|this)\\\\s+(${nameAlternation(ENGLISH_WEEKDAYS)})$`, 'i'),\n resolve: (m, ctx) => {\n const rel = m[1]!.toLowerCase() as 'next' | 'last' | 'this';\n const targetDow = weekdayIndexFromName(m[2]!, ENGLISH_WEEKDAYS);\n const refDow = extractDayOfWeek(ctx.reference);\n return addDays(ctx.temporal, ctx.reference, weekdayOffset(rel, refDow, targetDow));\n },\n },\n // unit offsets: \"in 3 days\", \"2 weeks ago\", \"in 1 month\", \"1 year ago\".\n // Two shapes share this matcher — leading \"in\" (future) or trailing\n // \"ago\" (past). Both lead with <number> <unit>.\n {\n pattern: /^(in\\s+)?(\\d+)\\s+(day|week|month|year)s?(?:\\s+ago)?$/i,\n resolve: (m, ctx) => {\n const inPrefix = m[1];\n const count = m[2]!;\n const unitName = m[3]!.toLowerCase() as 'day' | 'week' | 'month' | 'year';\n // Disambiguate future vs past: \"in N units\" is always future; \"N\n // units ago\" is always past. A bare \"N units\" without either is\n // a sign error — throw, since neither direction is implied and\n // guessing is exactly what this library refuses to do.\n const hasIn = !!inPrefix;\n const hasAgo = /\\bago\\b/i.test(m[0]!);\n if (!hasIn && !hasAgo) {\n throw new Error(\n `temporal-fmt: parseRelative can't tell whether \"${m[0]}\" is past or future — ` +\n `use \"in ${count} ${unitName}s\" or \"${count} ${unitName}s ago\".`\n );\n }\n const sign = hasIn ? 1 : -1;\n return addUnits(ctx.temporal, ctx.reference, sign * Number(count), unitName);\n },\n },\n // month-day without year, e.g. \"March 5th\", \"March 5\", \"March 5, 2026\"\n // (year is ignored if present). The ordinal suffix is decorative —\n // strip it. The day-of-month is a 1- or 2-digit number.\n {\n pattern: new RegExp(`^(${nameAlternation([...ENGLISH_MONTHS, ...ENGLISH_MONTH_SHORT])})\\\\s+(\\\\d{1,2})(?:st|nd|rd|th)?(?:,?\\\\s*(\\\\d{4}))?$`, 'i'),\n resolve: (m, ctx) => {\n const month = monthIndexFromName(m[1]!, ENGLISH_MONTHS, ENGLISH_MONTH_SHORT);\n const day = Number(m[2]!);\n return resolveToNextOccurrence(ctx.temporal, ctx.reference, month, day);\n },\n },\n ],\n};\n\n// Spanish grammar. Distinct phrase shapes from English:\n// - \"hace 2 semanas\" (past unit offset) — distinct word \"hace\", not\n// the English \"X units ago\" suffix shape.\n// - \"5 de marzo\" — day-first, with required \"de\" between day and\n// month, opposite of English \"March 5\".\n// - \"el próximo lunes\" / \"lunes pasado\" — weekday ref has the relative\n// word sometimes as a prefix with article, sometimes as a suffix.\n//\n// All four phrase classes the English grammar supports have Spanish\n// equivalents here.\nconst SPANISH_WEEKDAYS = ['lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado', 'domingo'];\nconst SPANISH_MONTHS = ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'];\n// Spanish month abbreviations vary by region (\"set\" vs \"sept\" for\n// September). Sticking with the most common ICU form per locale.\nconst SPANISH_MONTH_SHORT = ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sept', 'oct', 'nov', 'dic'];\n\nconst SPANISH_GRAMMAR: RelativeDateGrammar = {\n supportedHint: 'Frases soportadas: referencias de día de la semana (\"el próximo lunes\", \"el lunes pasado\", \"este martes\"), offsets de día (\"hoy\"/\"mañana\"/\"ayer\"), offsets de unidad (\"en 3 días\", \"hace 2 semanas\"), y mes-día (\"5 de marzo\").',\n matchers: [\n {\n pattern: /^hoy$/i,\n resolve: (_m, ctx) => buildPlainDate(ctx.temporal, readYear(ctx.reference), readMonth(ctx.reference), readDay(ctx.reference)),\n },\n {\n pattern: /^ma[ñn]ana$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, 1),\n },\n {\n pattern: /^ayer$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, -1),\n },\n // weekday references. Spanish has three common shapes, all meaning\n // the same thing per rel word:\n // \"el próximo lunes\" / \"próximo lunes\" → next\n // \"el lunes próximo\" → next (suffix variant)\n // \"el lunes pasado\" / \"lunes pasado\" → last\n // \"este lunes\" → this\n // Capture the rel word from whichever shape matched, then resolve\n // the same way English does.\n {\n pattern: new RegExp(\n `^(?:el\\\\s+)?(?:(pr[oó]ximo|pasado)\\\\s+(${nameAlternation(SPANISH_WEEKDAYS)})|(${nameAlternation(SPANISH_WEEKDAYS)})\\\\s+(pr[oó]ximo|pasado)|este\\\\s+(${nameAlternation(SPANISH_WEEKDAYS)}))$`,\n 'i',\n ),\n resolve: (m, ctx) => {\n let relWord: string;\n let weekdayName: string;\n if (m[1] && m[2]) {\n // prefix variant: \"próximo lunes\" / \"pasado lunes\"\n relWord = m[1]!;\n weekdayName = m[2]!;\n } else if (m[3] && m[4]) {\n // suffix variant: \"lunes próximo\" / \"lunes pasado\"\n weekdayName = m[3]!;\n relWord = m[4]!;\n } else {\n // \"este lunes\"\n relWord = 'este';\n weekdayName = m[5]!;\n }\n const rel = normalizeForMatch(relWord) === 'proximo' ? 'next' : relWord.toLowerCase() === 'este' ? 'this' : 'last';\n const targetDow = weekdayIndexFromName(weekdayName, SPANISH_WEEKDAYS);\n const refDow = extractDayOfWeek(ctx.reference);\n return addDays(ctx.temporal, ctx.reference, weekdayOffset(rel, refDow, targetDow));\n },\n },\n // unit offsets. Spanish uses distinct markers:\n // \"en 3 días\" / \"dentro de 3 días\" → future\n // \"hace 2 semanas\" → past\n // Both shapes lead with the marker, unlike English where one\n // shape leads and the other trails.\n {\n pattern: new RegExp(\n `^(?:(en|dentro\\\\s+de)\\\\s+(\\\\d+)\\\\s+(d[ií]a|semana|mes|a[ñn]o)s?|(\\\\d+)\\\\s+(d[ií]a|semana|mes|a[ñn]o)s?\\\\s+(hace))$`,\n 'i',\n ),\n resolve: (m, ctx) => {\n let count: string;\n let unitWord: string;\n let sign: number;\n if (m[1] && m[2] && m[3]) {\n // future: \"en 3 días\" / \"dentro de 3 días\"\n count = m[2]!;\n unitWord = m[3]!;\n sign = 1;\n } else {\n // past: \"2 semanas hace\" — but the more natural Spanish is\n // \"hace 2 semanas\" (marker first). The regex above only\n // matches \"N units hace\"; that's a less common but\n // grammatical alternative. The primary past form \"hace N\n // unidades\" is matched by the next matcher.\n count = m[4]!;\n unitWord = m[5]!;\n sign = -1;\n }\n const unit = unitWordToEnglish(unitWord);\n return addUnits(ctx.temporal, ctx.reference, sign * Number(count), unit);\n },\n },\n // \"hace 2 semanas\" — the primary past-offset shape. Matcher kept\n // separate from the future \"en/dentro de\" matcher above because\n // Spanish word order differs between the two (marker-first for\n // past, marker-first for future too, but with different markers).\n {\n pattern: new RegExp(`^hace\\\\s+(\\\\d+)\\\\s+(d[ií]a|semana|mes|a[ñn]o)s?$`, 'i'),\n resolve: (m, ctx) => {\n const count = Number(m[1]!);\n const unit = unitWordToEnglish(m[2]!);\n return addUnits(ctx.temporal, ctx.reference, -count, unit);\n },\n },\n // bare \"N <unit>\" without \"en\" / \"hace\" — throw, since direction\n // is ambiguous. Matched AFTER the directional shapes so the\n // directional ones win when their marker is present.\n {\n pattern: new RegExp(`^(\\\\d+)\\\\s+(d[ií]a|semana|mes|a[ñn]o)s?$`, 'i'),\n resolve: (m, _ctx) => {\n throw new Error(\n `temporal-fmt: parseRelative no puede decidir si \"${m[0]}\" es pasado o futuro — ` +\n `usa \"en ${m[1]} ${m[2]}s\" o \"hace ${m[1]} ${m[2]}s\".`\n );\n },\n },\n // month-day: \"5 de marzo\" (day first), \"5 de marzo de 2026\" (year\n // ignored if present). Day is 1-2 digits, with optional trailing\n // \".\" (rare in Spanish but tolerated).\n {\n pattern: new RegExp(\n `^(\\\\d{1,2})\\\\.?\\\\s+de\\\\s+(${nameAlternation([...SPANISH_MONTHS, ...SPANISH_MONTH_SHORT])})(?:\\\\s+de\\\\s+(\\\\d{4}))?$`,\n 'i',\n ),\n resolve: (m, ctx) => {\n const day = Number(m[1]!);\n const month = monthIndexFromName(m[2]!, SPANISH_MONTHS, SPANISH_MONTH_SHORT);\n return resolveToNextOccurrence(ctx.temporal, ctx.reference, month, day);\n },\n },\n ],\n};\n\n// French grammar. Distinct from English/Spanish:\n// - \"il y a 2 semaines\" (past marker is a 3-word phrase, not a single word).\n// - \"mardi prochain\" — relative word is a SUFFIX on the weekday,\n// opposite of English \"next Tuesday\".\n// - \"5 mars\" — day-first, no \"de\" between day and month (unlike\n// Spanish's \"5 de marzo\").\nconst FRENCH_WEEKDAYS = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'];\nconst FRENCH_MONTHS = ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'];\nconst FRENCH_MONTH_SHORT = ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'];\n\nconst FRENCH_GRAMMAR: RelativeDateGrammar = {\n supportedHint: 'Phrases prises en charge : références de jour de la semaine (\"lundi prochain\", \"mardi dernier\", \"ce mercredi\"), décalages de jour (\"aujourd\\'hui\"/\"demain\"/\"hier\"), décalages d\\'unité (\"dans 3 jours\", \"il y a 2 semaines\"), et mois-jour (\"5 mars\").',\n matchers: [\n {\n pattern: /^aujourd'hui$/i,\n resolve: (_m, ctx) => buildPlainDate(ctx.temporal, readYear(ctx.reference), readMonth(ctx.reference), readDay(ctx.reference)),\n },\n {\n pattern: /^demain$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, 1),\n },\n {\n pattern: /^hier$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, -1),\n },\n // weekday references: \"lundi prochain\" (next), \"lundi dernier\"\n // (last), \"ce lundi\" (this). The relative word follows the\n // weekday for next/last, precedes it for this.\n {\n pattern: new RegExp(\n `^(?:(${nameAlternation(FRENCH_WEEKDAYS)})\\\\s+(prochain|dernier)|ce\\\\s+(${nameAlternation(FRENCH_WEEKDAYS)}))$`,\n 'i',\n ),\n resolve: (m, ctx) => {\n let rel: 'next' | 'last' | 'this';\n let weekdayName: string;\n if (m[1] && m[2]) {\n weekdayName = m[1]!;\n rel = m[2]!.toLowerCase() === 'prochain' ? 'next' : 'last';\n } else {\n rel = 'this';\n weekdayName = m[3]!;\n }\n const targetDow = weekdayIndexFromName(weekdayName, FRENCH_WEEKDAYS);\n const refDow = extractDayOfWeek(ctx.reference);\n return addDays(ctx.temporal, ctx.reference, weekdayOffset(rel, refDow, targetDow));\n },\n },\n // past: \"il y a 2 semaines\" — multi-word marker.\n {\n pattern: new RegExp(`^il\\\\s+y\\\\s+a\\\\s+(\\\\d+)\\\\s+(jour|semaine|mois|an|ann[eée]e)s?$`, 'i'),\n resolve: (m, ctx) => {\n const count = Number(m[1]!);\n const unit = unitWordToEnglish(m[2]!);\n return addUnits(ctx.temporal, ctx.reference, -count, unit);\n },\n },\n // future: \"dans 3 jours\"\n {\n pattern: new RegExp(`^dans\\\\s+(\\\\d+)\\\\s+(jour|semaine|mois|an|ann[eée]e)s?$`, 'i'),\n resolve: (m, ctx) => {\n const count = Number(m[1]!);\n const unit = unitWordToEnglish(m[2]!);\n return addUnits(ctx.temporal, ctx.reference, count, unit);\n },\n },\n // bare \"N <unit>\" without marker — throw.\n {\n pattern: new RegExp(`^(\\\\d+)\\\\s+(jour|semaine|mois|an|ann[eée]e)s?$`, 'i'),\n resolve: (m, _ctx) => {\n throw new Error(\n `temporal-fmt: parseRelative ne peut pas déterminer si \"${m[0]}\" est passé ou futur — ` +\n `utilisez \"dans ${m[1]} ${m[2]}s\" ou \"il y a ${m[1]} ${m[2]}s\".`\n );\n },\n },\n // month-day: \"5 mars\" (day first, no separator word). Year ignored.\n {\n pattern: new RegExp(\n `^(\\\\d{1,2})\\\\s+(${nameAlternation([...FRENCH_MONTHS, ...FRENCH_MONTH_SHORT])})(?:\\\\s+(\\\\d{4}))?$`,\n 'i',\n ),\n resolve: (m, ctx) => {\n const day = Number(m[1]!);\n const month = monthIndexFromName(m[2]!, FRENCH_MONTHS, FRENCH_MONTH_SHORT);\n return resolveToNextOccurrence(ctx.temporal, ctx.reference, month, day);\n },\n },\n ],\n};\n\n// German grammar. Distinct from the others:\n// - Unit words pluralize with -n in the dative after \"in\"/\"vor\":\n// \"in 3 Tagen\" (vs nominative \"3 Tage\"). The regex accepts both\n// since callers may not always get the case right, and accepting\n// both doesn't introduce ambiguity.\n// - \"nächsten Dienstag\" — relative word precedes weekday as a\n// declined adjective, with the weekday capitalized as a noun.\n// - \"5. März\" — day-first with a period after the day number,\n// matching German date convention.\nconst GERMAN_WEEKDAYS = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'];\nconst GERMAN_MONTHS = ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'];\nconst GERMAN_MONTH_SHORT = ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'];\n\nconst GERMAN_GRAMMAR: RelativeDateGrammar = {\n supportedHint: 'Unterstützte Phrasen: Wochentag-Bezüge (\"nächsten Dienstag\", \"letzten Freitag\", \"diesen Montag\"), Tages-Offsets (\"heute\"/\"morgen\"/\"gestern\"), Einheiten-Offsets (\"in 3 Tagen\", \"vor 2 Wochen\"), und Monat-Tag (\"5. März\").',\n matchers: [\n {\n pattern: /^heute$/i,\n resolve: (_m, ctx) => buildPlainDate(ctx.temporal, readYear(ctx.reference), readMonth(ctx.reference), readDay(ctx.reference)),\n },\n {\n pattern: /^morgen$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, 1),\n },\n {\n pattern: /^gestern$/i,\n resolve: (_m, ctx) => addDays(ctx.temporal, ctx.reference, -1),\n },\n // weekday references: \"nächsten Dienstag\" (next), \"letzten\n // Dienstag\" (last), \"diesen Dienstag\" (this). Adjective precedes\n // the weekday; case varies (nächsten/letzten/diesen all take the\n // weak-declension -en/-en/-en ending when no article, which is\n // convenient — one regex alternation covers all three.\n {\n pattern: new RegExp(`^(n(?:ae|a|ä)chsten|letzten|diesen)\\\\s+(${nameAlternation(GERMAN_WEEKDAYS)})$`, 'i'),\n resolve: (m, ctx) => {\n const adj = normalizeForMatch(m[1]!);\n const rel: 'next' | 'last' | 'this' = (adj === 'nachsten' || adj === 'naechsten') ? 'next' : adj === 'diesen' ? 'this' : 'last';\n const targetDow = weekdayIndexFromName(m[2]!, GERMAN_WEEKDAYS);\n const refDow = extractDayOfWeek(ctx.reference);\n return addDays(ctx.temporal, ctx.reference, weekdayOffset(rel, refDow, targetDow));\n },\n },\n // past: \"vor 2 Wochen\"\n {\n pattern: new RegExp(`^vor\\\\s+(\\\\d+)\\\\s+(Tag(?:e|n|en)?|Woche(?:n)?|Monat(?:e|n|en)?|Jahr(?:e|n|en)?)$`, 'i'),\n resolve: (m, ctx) => {\n const count = Number(m[1]!);\n const unit = unitWordToEnglish(m[2]!);\n return addUnits(ctx.temporal, ctx.reference, -count, unit);\n },\n },\n // future: \"in 3 Tagen\"\n {\n pattern: new RegExp(`^in\\\\s+(\\\\d+)\\\\s+(Tag(?:e|n|en)?|Woche(?:n)?|Monat(?:e|n|en)?|Jahr(?:e|n|en)?)$`, 'i'),\n resolve: (m, ctx) => {\n const count = Number(m[1]!);\n const unit = unitWordToEnglish(m[2]!);\n return addUnits(ctx.temporal, ctx.reference, count, unit);\n },\n },\n // bare \"N <unit>\" without \"in\" or \"vor\" — throw.\n {\n pattern: new RegExp(`^(\\\\d+)\\\\s+(Tag(?:e|n|en)?|Woche(?:n)?|Monat(?:e|n|en)?|Jahr(?:e|n|en)?)$`, 'i'),\n resolve: (m, _ctx) => {\n throw new Error(\n `temporal-fmt: parseRelative kann nicht erkennen, ob \"${m[0]}\" Vergangenheit oder Zukunft ist — ` +\n `verwende \"in ${m[1]} ${m[2]}\" oder \"vor ${m[1]} ${m[2]}\".`\n );\n },\n },\n // month-day: \"5. März\" (day-first with period). Year ignored.\n {\n pattern: new RegExp(\n `^(\\\\d{1,2})\\\\.?\\\\s+(${nameAlternation([...GERMAN_MONTHS, ...GERMAN_MONTH_SHORT, 'Maerz', 'Maer'])})(?:\\\\s+(\\\\d{4}))?$`,\n 'i',\n ),\n resolve: (m, ctx) => {\n const day = Number(m[1]!);\n const month = monthIndexFromName(m[2]!, GERMAN_MONTHS, GERMAN_MONTH_SHORT);\n return resolveToNextOccurrence(ctx.temporal, ctx.reference, month, day);\n },\n },\n ],\n};\n\nconst GRAMMARS: Record<string, RelativeDateGrammar> = {\n en: ENGLISH_GRAMMAR,\n es: SPANISH_GRAMMAR,\n fr: FRENCH_GRAMMAR,\n de: GERMAN_GRAMMAR,\n};\n\n// Pick a grammar for a locale. Falls back to English for languages we\n// don't have a grammar for (Italian, Portuguese, etc.) rather than\n// throwing — best-effort, matches how formatDistance treats unknown\n// locales (Intl.RelativeTimeFormat accepts them; here we fall back to\n// English so the call still succeeds with reasonable output).\nfunction grammarForLocale(locale: string | undefined): RelativeDateGrammar {\n if (!locale) return ENGLISH_GRAMMAR;\n try {\n // Intl.Locale requires BCP-47 hyphens — same normalization as the\n // other locale-handling code in this library.\n const tag = new Intl.Locale(locale.replace(/_/g, '-'));\n const lang = tag.language.toLowerCase();\n return GRAMMARS[lang] ?? ENGLISH_GRAMMAR;\n } catch {\n // Malformed locale tag — fall back to English. The actual Intl\n // call downstream will throw if the tag is genuinely unusable,\n // which is a better surface for that error than here.\n return ENGLISH_GRAMMAR;\n }\n}\n\n// Language subtag of a locale option, for dispatching to grammars\n// registered via registerRelativeGrammar(). Mirrors grammarForLocale's\n// normalization and fallback.\nfunction languageOf(locale: string | undefined): string {\n if (!locale) return 'en';\n try {\n return new Intl.Locale(locale.replace(/_/g, '-')).language.toLowerCase();\n } catch {\n return 'en';\n }\n}\n\n// Map a per-language unit word back to the English unit name the\n// shared addUnits() helper expects. Each language contributes its own\n// regex alternation of unit words; this function normalizes the\n// captured word back to a unit enum value.\nfunction unitWordToEnglish(word: string): 'day' | 'week' | 'month' | 'year' {\n const w = normalizeForMatch(word);\n // English\n /* c8 ignore next */\n if (w === 'day' || w === 'week' || w === 'month' || w === 'year') return w;\n // Spanish (accent-stripped)\n if (w === 'dia') return 'day';\n if (w === 'semana') return 'week';\n if (w === 'mes') return 'month';\n if (w === 'ano' || w === 'año') return 'year';\n // French\n if (w === 'jour') return 'day';\n if (w === 'semaine') return 'week';\n if (w === 'mois') return 'month';\n if (w === 'an' || w === 'annee') return 'year';\n // German\n if (w === 'tag' || w === 'tagen') return 'day';\n if (w === 'woche' || w === 'wochen') return 'week';\n if (w === 'monat' || w === 'monaten') return 'month';\n /* c8 ignore next */\n if (w === 'jahr' || w === 'jahren') return 'year';\n /* c8 ignore start @preserve -- unreachable: every caller passes a word\n * captured by a regex alternation built from exactly these unit-word\n * forms (day/week/month/year across en/es/fr/de), so the branches\n * above already cover every string that can reach this function.\n * Kept as a tripwire for the type checker in case a grammar adds a\n * unit word here without a matching regex update. */\n throw new Error(`temporal-fmt: parseRelative internal error — unrecognized unit word \"${word}\".`);\n /* c8 ignore stop @preserve */\n /* c8 ignore next -- defensive block is unreachable by construction. */\n}\n\n// Reference: kept exported for the unit tests that need it. The other\n// helpers above are not exported since tests only need to drive\n// parseRelative() through the public API + this one constant for the\n// Tuesday-on-Tuesday fixture.\nexport const WEEKDAY_NAMES = ENGLISH_WEEKDAYS;\nexport const MONTH_NAMES = ENGLISH_MONTHS;\n// Exported for the localeVocab-style stub-test pattern in case a future\n// test wants to verify a grammar's name list against Intl's actual\n// output for that locale — same pattern localeVocab.test.js uses to\n// catch a mismatch between what format() produces and what parse()\n// expects.\nexport const SPANISH_MONTH_NAMES = SPANISH_MONTHS;\nexport const FRENCH_MONTH_NAMES = FRENCH_MONTHS;\nexport const GERMAN_MONTH_NAMES = GERMAN_MONTHS;\nexport const SPANISH_WEEKDAY_NAMES = SPANISH_WEEKDAYS;\nexport const FRENCH_WEEKDAY_NAMES = FRENCH_WEEKDAYS;\nexport const GERMAN_WEEKDAY_NAMES = GERMAN_WEEKDAYS;\nvoid WEEKDAY_NAMES;\nvoid MONTH_NAMES;\n\nexport interface ParseRelativeOptions extends FormatOptions {\n /**\n * Opt-in typo tolerance. When the input doesn't match any phrase\n * exactly, retry after correcting individual words (weekday names,\n * month names, and marker words like \"next\"/\"ago\"/\"tomorrow\") that\n * are within a small edit distance of a known word — e.g.\n * \"tommorow\" → \"tomorrow\", \"next tuesady\" → \"next tuesday\". Numbers\n * are never touched.\n *\n * Off by default, matching this library's throw-rather-than-guess\n * philosophy elsewhere (parse()'s `lenient` option is the same shape\n * of opt-in). English only for this option currently — combining\n * `fuzzy: true` with a non-English `locale` throws rather than\n * silently skipping the fuzzy pass.\n *\n * If no correction produces a recognized phrase, throws the same\n * \"doesn't recognize\" error the exact pass would have thrown.\n */\n fuzzy?: boolean;\n}\n\n/**\n * Resolve common relative-date phrases against a reference date,\n * returning a Temporal.PlainDate. Supports English by default, plus\n * Spanish (es), French (fr), and German (de) via the `locale` option.\n *\n * Supported phrase classes (with examples per language):\n *\n * - weekday refs: \"next Tuesday\" / \"el próximo martes\" / \"mardi prochain\" / \"nächsten Dienstag\"\n * - day offsets: \"today\" / \"hoy\" / \"aujourd'hui\" / \"heute\" (and tomorrow/yesterday equivalents)\n * - unit offsets: \"in 3 days\" / \"en 3 días\" / \"dans 3 jours\" / \"in 3 Tagen\"\n * - month-day without year: \"March 5th\" / \"5 de marzo\" / \"5 mars\" / \"5. März\"\n *\n * Ambiguous-case handling is consistent across all four languages:\n * \"next X\" said on X (today is the named weekday) means 7 days from\n * now, not today. \"last X\" said on X means 7 days ago. See README\n * \"parseRelative\" for the documented behavior of each ambiguous case.\n *\n * Throws a descriptive error for any phrase it doesn't recognize in\n * the target language, rather than guessing. A bare \"5 days\" without\n * \"in\" or \"ago\" (or the per-language equivalent) throws with a message\n * pointing at the disambiguation options.\n *\n * Returns a Temporal.PlainDate for every supported phrase. Time-of-day\n * extensions like \"next Tuesday at 3pm\" aren't supported in this pass.\n */\nexport function parseRelative(\n input: string,\n referenceDate: unknown,\n options: ParseRelativeOptions = {},\n): unknown {\n const reference = referenceDate as TemporalFieldBag;\n const temporal = getTemporal();\n\n // Trim, collapse internal whitespace, strip diacritics, and lowercase.\n // Whitespace normalization is shared with the pre-change behavior;\n // diacritic stripping pairs with nameAlternation()'s normalization so\n // \"mi[eé]rcoles\" and \"miercoles\" both match the same pattern.\n // Lowercasing matches the case-insensitive regex flag explicitly so\n // the user's input never gets case-swapped on its way through the\n // matcher (the regexes are 'i'-flagged, but normalizing here keeps\n // the original-trimmed-string echo in error messages predictable).\n const trimmed = (input ?? '').trim().replace(/\\s+/g, ' ');\n if (trimmed.length === 0) {\n throw new Error('temporal-fmt: parseRelative got an empty input string.');\n }\n if (trimmed.length > MAX_RELATIVE_INPUT_LENGTH) {\n throw new RangeError(\n `temporal-fmt: parseRelative input is too large (maximum ${MAX_RELATIVE_INPUT_LENGTH} characters).`,\n );\n }\n // For error messages, keep the user's original spelling (with accents)\n // so the echo in the \"doesn't recognize\" error matches what they\n // typed. The matching itself uses the diacritic-stripped form so\n // \"mi[eé]rcoles\" / \"miercoles\" / \"MI[ÉE]RCOLES\" all match the same\n // pattern without forcing the user to remember the accent.\n const normalized = normalizeForMatch(trimmed);\n\n const grammar = grammarForLocale(options.locale);\n const ctx: ResolveContext = { temporal, reference };\n\n // Registered grammars (registerRelativeGrammar) take precedence over\n // the built-in ones for their language — that's the documented\n // contract in relativeGrammar.ts (\"try registered grammars before\n // falling back to the built-in ones\"). This wiring was missing\n // entirely before: registered grammars were stored and listed but\n // never consulted, so the extension point silently did nothing.\n // Returns null quickly when nothing is registered for the language.\n const registered = tryRegisteredGrammar(languageOf(options.locale), trimmed, {\n year: reference.year as number,\n month: reference.month as number,\n day: reference.day as number,\n dayOfWeek: reference.dayOfWeek as number,\n });\n if (registered !== null) {\n return registered;\n }\n\n const tryMatch = (text: string): unknown | typeof NO_MATCH => {\n for (const matcher of grammar.matchers) {\n const match = text.match(matcher.pattern);\n if (match) {\n return matcher.resolve(match, ctx);\n }\n }\n return NO_MATCH;\n };\n\n const exactResult = tryMatch(normalized);\n if (exactResult !== NO_MATCH) {\n return exactResult;\n }\n\n if (options.fuzzy) {\n // Fuzzy mode is English-only for this pass — see the vocabulary\n // comment above fuzzyCorrectEnglish for why the other three\n // grammars aren't covered. Fail loudly rather than silently\n // skipping the fuzzy attempt, so a caller relying on fuzzy mode\n // for, say, French input doesn't get a confusing \"doesn't\n // recognize\" error with no indication fuzzy matching never ran.\n if (grammar !== ENGLISH_GRAMMAR) {\n throw new Error(\n `temporal-fmt: parseRelative's { fuzzy: true } option currently only supports English. ` +\n `Pass no locale (or locale: 'en'), or omit { fuzzy: true } for this locale.`\n );\n }\n const corrected = fuzzyCorrectEnglish(normalized);\n if (corrected !== undefined) {\n const fuzzyResult = tryMatch(corrected);\n if (fuzzyResult !== NO_MATCH) {\n return fuzzyResult;\n }\n }\n }\n\n throw new Error(\n `temporal-fmt: parseRelative doesn't recognize \"${trimmed}\". ` +\n grammar.supportedHint\n );\n}\n\n// Sentinel distinguishing \"no matcher matched\" from a legitimate\n// resolve() return value of `undefined`/`null` (matchers can throw\n// their own errors, e.g. the ambiguous-direction case, but none\n// currently return a nullish PlainDate — this sentinel just makes the\n// \"no match\" case unambiguous regardless).\nconst NO_MATCH = Symbol('temporal-fmt: parseRelative no match');\n\n// DEFAULT_LOCALE is imported for the option's default-value documentation\n// above (no locale → English). The symbol itself isn't read at runtime\n// here, but the import keeps the dependency edge explicit so future\n// changes to the default-locale constant propagate here too.\nvoid DEFAULT_LOCALE;","// Type guards for Temporal values. The rest of this library works off the\n// duck-typed `TemporalLike` shape (year/month/day/hour/...) rather than\n// `instanceof Temporal.X`, because `instanceof` breaks across polyfill/\n// native boundaries — a polyfill's `Temporal.PlainDate` is a different\n// constructor from the native one, so a `value instanceof Temporal.PlainDate`\n// check would silently fail when the caller is using a polyfill while the\n// guard happens to be looking at native Temporal, or vice versa. Same\n// reasoning as tokens.ts's `intlSupportsNativeTemporal` probe: identity\n// checks don't survive the polyfill/native swap.\n//\n// These guards check structural shape instead: presence of the type-\n// discriminating method each Temporal type carries. Method presence is\n// part of the Temporal spec contract — every implementation, native or\n// polyfill, must expose the same methods on the same types — so it's a\n// stable signal without dragging in a Temporal namespace.\n//\n// Per-type discriminators (verified against @js-temporal/polyfill's\n// prototype method list, which matches the spec):\n//\n// PlainDate — `toPlainDateTime` + `withCalendar` + year/month/day,\n// no hour. (PlainDateTime also has `toPlainDateTime`'s\n// sibling `toPlainDate`/`toPlainTime`, but carries\n// hour — distinguished by time-field presence.)\n// PlainTime — no `toPlainDateTime`, no `withCalendar`. Has hour,\n// no year/month/day. (The only Temporal date/time type\n// that has neither `withCalendar` nor any `toPlainX`\n// method.)\n// PlainDateTime — `toPlainDate` + `withPlainTime` + year/month/day\n// AND hour. (`withPlainTime` is unique — only\n// PlainDateTime and ZonedDateTime carry it; ZonedDateTime\n// also carries `toInstant`, which PlainDateTime doesn't.)\n// ZonedDateTime — `toInstant` + `withTimeZone`. (Both are unique —\n// only ZonedDateTime carries `withTimeZone`.)\n// Instant — `toZonedDateTimeISO`, no `toInstant`. (Instant IS\n// the instant; the `toInstant` method belongs to\n// ZonedDateTime. `toZonedDateTimeISO` exists on\n// Instant and ZonedDateTime per the spec, but on\n// ZonedDateTime it's not exposed via the prototype\n// in either native or polyfill — only Instant has it\n// as a method. Verified by probing both.)\n// PlainYearMonth — `toPlainDate` (takes a day arg) + year/month,\n// no day. (PlainDate also has `toPlainDate`-shaped\n// methods but carries day; PlainMonthDay also has\n// `toPlainDate` but carries day, not year.)\n// PlainMonthDay — `toPlainDate` + month/day, no year. Plus: lacks\n// `add`/`subtract`/`until`/`since` (calendar arithmetic\n// doesn't apply to a month-day without a year).\n// Duration — `total` + `abs` + `negated`. (All three are unique\n// to Duration; no other Temporal type carries any of them.)\n\n// The shapes below intentionally mirror TemporalLike in tokens.ts but\n// stay loose enough to also match real Temporal objects (which carry\n// the spec methods the field-only TemporalLike doesn't).\ninterface TemporalInstance {\n toInstant?: () => unknown;\n toPlainDate?: (arg?: unknown) => unknown;\n toPlainDateTime?: (arg?: unknown) => unknown;\n toPlainTime?: () => unknown;\n toPlainYearMonth?: () => unknown;\n toPlainMonthDay?: () => unknown;\n toZonedDateTime?: (arg: unknown) => unknown;\n toZonedDateTimeISO?: (arg: unknown) => unknown;\n withCalendar?: (cal: unknown) => unknown;\n withPlainTime?: (t: unknown) => unknown;\n withTimeZone?: (z: unknown) => unknown;\n getTimeZoneTransition?: (opts: unknown) => unknown;\n startOfDay?: () => unknown;\n sign?: () => number;\n blank?: () => boolean;\n total?: (opts: unknown) => number;\n abs?: () => unknown;\n negated?: () => unknown;\n toString?: () => string;\n // Fields from TemporalLike — present on all date-carrying Temporal\n // types but absent on PlainTime (which has no calendar position).\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n calendarId?: string;\n timeZoneId?: string;\n // PlainMonthDay stores its month as `monthCode` (e.g. \"M08\"), not\n // as a numeric `month` field — without a year there's no way to\n // disambiguate which month a calendar-independent numeric month\n // refers to in leap-year-aware calendars, so the spec uses\n // `monthCode` instead. PlainMonthDay is the only Temporal type that\n // exposes `monthCode` without also exposing `month`.\n monthCode?: string;\n}\n\nfunction isObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null;\n}\n\n// Hostile-getter hardening: the structural guards below read properties\n// (year, hour, Symbol.toStringTag, ...) off arbitrary caller values. An\n// object with a throwing getter used to turn isPlainDate(obj) — a function\n// whose whole contract is returning a boolean — into an exception factory.\n// Every exported guard now runs through this wrapper: a throw during\n// probing means \"not one of ours\", not a crash. One shared catch (rather\n// than one per guard) keeps the coverage burden honest too.\nfunction guardOrFalse<T>(impl: (value: unknown) => value is T): (value: unknown) => value is T {\n return (value: unknown): value is T => {\n try {\n return impl(value);\n } catch {\n return false;\n }\n };\n}\n\nfunction hasMethod<T extends keyof TemporalInstance>(\n v: TemporalInstance,\n name: T,\n): boolean {\n return typeof v[name] === 'function';\n}\n\n// Symbol.toStringTag is the spec-mandated brand for Temporal types —\n// every Temporal instance carries a tag like \"Temporal.PlainDate\" via\n// this well-known symbol, regardless of whether it's native or polyfill.\n// Used by the per-type guards as a fast positive signal: a tag match\n// is sufficient, the structural fallback (field presence + method checks)\n// is only consulted when the tag isn't set (which can happen with\n// hand-built mock objects or partial implementations).\nfunction hasTag(value: unknown, typeName: string): boolean {\n if (!isObject(value)) return false;\n const tag = (value as { [Symbol.toStringTag]?: unknown })[Symbol.toStringTag];\n return tag === `Temporal.${typeName}`;\n}\n\nexport const isPlainDate: (value: unknown) => value is TemporalInstance = guardOrFalse(function isPlainDateImpl(value: unknown): value is TemporalInstance {\n if (hasTag(value, 'PlainDate')) return true;\n if (!isObject(value)) return false;\n const v = value as TemporalInstance;\n return typeof v.year === 'number'\n && typeof v.month === 'number'\n && typeof v.day === 'number'\n && typeof v.hour === 'undefined'\n && hasMethod(v, 'toPlainDateTime')\n && hasMethod(v, 'withCalendar');\n});\n\nexport const isPlainTime: (value: unknown) => value is TemporalInstance = guardOrFalse(function isPlainTimeImpl(value: unknown): value is TemporalInstance {\n if (hasTag(value, 'PlainTime')) return true;\n if (!isObject(value)) return false;\n const v = value as TemporalInstance;\n // PlainTime is the only Temporal type with `hour` but no `year` and\n // neither `withCalendar` nor any `toPlainX` method. That combination\n // is unique among the eight types.\n return typeof v.hour === 'number'\n && typeof v.year === 'undefined'\n && !hasMethod(v, 'withCalendar')\n && !hasMethod(v, 'toPlainDate')\n && !hasMethod(v, 'toPlainDateTime');\n});\n\nexport const isPlainDateTime: (value: unknown) => value is TemporalInstance = guardOrFalse(function isPlainDateTimeImpl(value: unknown): value is TemporalInstance {\n if (hasTag(value, 'PlainDateTime')) return true;\n if (!isObject(value)) return false;\n const v = value as TemporalInstance;\n // `withPlainTime` is on PlainDateTime and ZonedDateTime; ZonedDateTime\n // also carries `toInstant`. The combination \"has withPlainTime, no\n // toInstant\" uniquely identifies PlainDateTime.\n return typeof v.year === 'number'\n && typeof v.month === 'number'\n && typeof v.day === 'number'\n && typeof v.hour === 'number'\n && hasMethod(v, 'withPlainTime')\n && !hasMethod(v, 'toInstant');\n});\n\nexport const isZonedDateTime: (value: unknown) => value is TemporalInstance = guardOrFalse(function isZonedDateTimeImpl(value: unknown): value is TemporalInstance {\n if (hasTag(value, 'ZonedDateTime')) return true;\n if (!isObject(value)) return false;\n const v = value as TemporalInstance;\n // `withTimeZone` is unique to ZonedDateTime across every Temporal type.\n return typeof v.year === 'number'\n && typeof v.month === 'number'\n && typeof v.day === 'number'\n && typeof v.hour === 'number'\n && hasMethod(v, 'withTimeZone')\n && hasMethod(v, 'toInstant');\n});\n\nexport const isInstant: (value: unknown) => value is TemporalInstance = guardOrFalse(function isInstantImpl(value: unknown): value is TemporalInstance {\n if (hasTag(value, 'Instant')) return true;\n if (!isObject(value)) return false;\n // Instant carries `toZonedDateTimeISO` and no `toInstant` (it IS the\n // instant). It also has no year/month/day/hour fields — those are\n // only meaningful against a calendar and zone, which Instant alone\n // doesn't carry.\n const v = value as TemporalInstance;\n return hasMethod(v, 'toZonedDateTimeISO')\n && !hasMethod(v, 'toInstant')\n && typeof v.year === 'undefined';\n});\n\nexport const isPlainYearMonth: (value: unknown) => value is TemporalInstance = guardOrFalse(function isPlainYearMonthImpl(value: unknown): value is TemporalInstance {\n if (hasTag(value, 'PlainYearMonth')) return true;\n if (!isObject(value)) return false;\n const v = value as TemporalInstance;\n // Has year+month, no day, carries `toPlainDate` (used to attach a day).\n // PlainMonthDay also carries `toPlainDate` but has no `year` field.\n return typeof v.year === 'number'\n && typeof v.month === 'number'\n && typeof v.day === 'undefined'\n && hasMethod(v, 'toPlainDate');\n});\n\nexport const isPlainMonthDay: (value: unknown) => value is TemporalInstance = guardOrFalse(function isPlainMonthDayImpl(value: unknown): value is TemporalInstance {\n if (hasTag(value, 'PlainMonthDay')) return true;\n if (!isObject(value)) return false;\n const v = value as TemporalInstance;\n // PlainMonthDay has `day` and `monthCode` but no `year` and no numeric\n // `month`. The `monthCode` field is the discriminator — every other\n // Temporal type that has a month concept either exposes `month` (numeric,\n // calendar-aware) or doesn't expose months at all (PlainTime, Duration).\n return typeof v.year === 'undefined'\n && typeof v.month === 'undefined'\n && typeof v.day === 'number'\n && typeof v.monthCode === 'string'\n && hasMethod(v, 'toPlainDate');\n});\n\nexport const isDuration: (value: unknown) => value is Record<string, unknown> = guardOrFalse(function isDurationImpl(value: unknown): value is Record<string, unknown> {\n if (hasTag(value, 'Duration')) return true;\n if (!isObject(value)) return false;\n // `total` is unique to Duration across every Temporal type — no other\n // type carries it (verified by probing the prototype of each).\n // `abs` and `negated` are also Duration-only. Checking any one of\n // them is sufficient; checking `total` because it's the most semantically\n // distinctive (a Duration-specific operation no other type would\n // coincidentally need).\n const v = value as TemporalInstance;\n return hasMethod(v, 'total');\n});\n\n// Umbrella guard: any Temporal namespace member. Used by `assertTemporal`\n// below for the \"this needs to be some Temporal thing\" case. Two signals\n// checked in order:\n// 1. `Symbol.toStringTag` — every Temporal type brands itself as\n// `Temporal.X` via this well-known symbol. This is the spec-\n// mandated brand, present on native and polyfill instances alike.\n// 2. The discriminating-method fallback — covers any case where a\n// future/partial Temporal impl doesn't set the tag. Method\n// presence is part of the Temporal spec contract; combined with\n// `equals` + `with` (both present on every Temporal instance),\n// it's a reliable signal that doesn't rely on the toStringTag\n// being set.\nexport const isTemporal: (value: unknown) => value is TemporalInstance = guardOrFalse(function isTemporalImpl(value: unknown): value is TemporalInstance {\n if (!isObject(value)) return false;\n const tag = (value as { [Symbol.toStringTag]?: unknown })[Symbol.toStringTag];\n if (typeof tag === 'string' && tag.startsWith('Temporal.')) return true;\n const v = value as TemporalInstance;\n return hasMethod(v, 'toInstant')\n || hasMethod(v, 'toPlainDate')\n || hasMethod(v, 'toPlainDateTime')\n || hasMethod(v, 'toPlainTime')\n || hasMethod(v, 'toPlainYearMonth')\n || hasMethod(v, 'toPlainMonthDay')\n || hasMethod(v, 'toZonedDateTime')\n || hasMethod(v, 'toZonedDateTimeISO')\n || hasMethod(v, 'withCalendar')\n || hasMethod(v, 'withPlainTime')\n || hasMethod(v, 'withTimeZone')\n || hasMethod(v, 'total');\n});\n\n// Assertion helpers — throw descriptively rather than returning false.\n// Same convention as the rest of the library: descriptive thrown errors\n// instead of silent failures. The thrown Error carries a `valueType`\n// hint in the message so the caller can see what they actually passed.\nfunction describeValue(value: unknown): string {\n if (value === null) return 'null';\n if (Array.isArray(value)) return 'array';\n if (typeof value === 'object') {\n const ctor = (value as { constructor?: { name?: string } }).constructor;\n if (ctor && typeof ctor.name === 'string' && ctor.name !== 'Object') {\n return `instance of ${ctor.name}`;\n }\n return 'plain object';\n }\n return typeof value;\n}\n\nfunction assertImpl(value: unknown, guard: (v: unknown) => boolean, expectedType: string): void {\n if (!guard(value)) {\n throw new Error(\n `temporal-fmt: expected a Temporal.${expectedType}, got ${describeValue(value)}.`\n );\n }\n}\n\nexport function assertTemporal(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isTemporal, 'object (Instant, PlainDate, PlainTime, PlainDateTime, ZonedDateTime, Duration, PlainYearMonth, or PlainMonthDay)');\n}\nexport function assertInstant(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isInstant, 'Instant');\n}\nexport function assertPlainDate(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isPlainDate, 'PlainDate');\n}\nexport function assertPlainTime(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isPlainTime, 'PlainTime');\n}\nexport function assertPlainDateTime(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isPlainDateTime, 'PlainDateTime');\n}\nexport function assertZonedDateTime(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isZonedDateTime, 'ZonedDateTime');\n}\nexport function assertPlainYearMonth(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isPlainYearMonth, 'PlainYearMonth');\n}\nexport function assertPlainMonthDay(value: unknown): asserts value is TemporalInstance {\n assertImpl(value, isPlainMonthDay, 'PlainMonthDay');\n}\nexport function assertDuration(value: unknown): asserts value is Record<string, unknown> {\n assertImpl(value, isDuration, 'Duration');\n}","// Per-token metadata: the structured descriptor this module\n// asks for (meaning, format-capable?, parse-capable?, locale-sensitive?,\n// calendar-sensitive?, timezone-sensitive?, supported Temporal types,\n// round-trip-safe?). One table, kept in sync with TOKENS in tokens.ts\n// by tests (see test/tokenMetadata.test.js — every entry in TOKENS has\n// a metadata entry, and vice versa).\n//\n// This is the single source of truth that analyzeFormat() (section E)\n// and the ESLint plugin / codemod consume — never read the\n// TOKENS array directly for metadata; use TOKEN_METADATA here, or the\n// tokenInfo() / listTokens() wrappers in analyze.ts.\n\nimport type { TemporalLike } from './tokens.js';\n\nexport type TemporalType =\n | 'Instant'\n | 'PlainDate'\n | 'PlainTime'\n | 'PlainDateTime'\n | 'ZonedDateTime'\n | 'PlainYearMonth'\n | 'PlainMonthDay';\n\nexport interface TokenMetadata {\n // Short human-readable description of what the token represents.\n meaning: string;\n // True if format() accepts this token. Every token in TOKENS is\n // format-capable by construction; this flag exists so the table is\n // self-describing for callers (the codemod) that work with token\n // families including format-only tokens from other libraries.\n formatCapable: boolean;\n // True if parse() accepts this token. False for `do`, `ww`, `RRRR`\n // — see FORMAT_ONLY_TOKENS in pattern.ts.\n parseCapable: boolean;\n // True if the output depends on locale (resolves via Intl or\n // custom vocab). MMMM/MMM/EEEE/EEE/a are true; everything else is\n // numeric ASCII and locale-independent.\n localeSensitive: boolean;\n // True if the output depends on the calendar (gregory, hebrew,\n // etc.). Locale-aware tokens inherit calendar sensitivity from\n // the Intl path (a hebrew PlainDate's month name depends on the\n // hebrew calendar). Year/month/day numeric tokens are calendar-\n // sensitive in principle (a Hebrew year/month renders differently\n // than a Gregorian one) but stay ISO-numeric on the format side\n // because tokens.ts reads straight off TemporalLike fields, which\n // are already calendar-specific by the time format() sees them.\n calendarSensitive: boolean;\n // True if the token requires a timeZoneId or offset field — i.e.\n // only ZonedDateTime supports it. zzz and the six offset tokens\n // (X/XX/XXX/x/xx/xxx) are timezone-sensitive.\n timezoneSensitive: boolean;\n // Which Temporal types can supply the field this token needs.\n // PlainTime can't supply year; PlainDate can't supply hour; only\n // ZonedDateTime carries timeZoneId/offset.\n supportedTypes: TemporalType[];\n // True if format(x, fmt) → parse(fmt, output) round-trips back to\n // a value equal to x. False when the format is fundamentally lossy:\n // `do` (ordinal suffix isn't structurally parseable), `ww`/`RRRR`\n // (week + weekday alone can't reconstruct a date without an extra\n // disambiguator), `yy` (two-digit year loses century — strptime\n // heuristic resolves it, but the heuristic isn't symmetric with\n // how `yy` formats BCE years, so round-trip only works for years\n // where 00-68/69-99 lands back on the same century).\n roundTripSafe: boolean;\n}\n\n// Helper: which Temporal types carry each field. Centralized here so\n// the supportedTypes arrays below stay short and the table is easy to\n// audit. Mirrors the field checks in tokens.ts (handler third tuple\n// element).\nconst TYPES_WITH: Record<string, TemporalType[]> = {\n year: ['PlainDate', 'PlainDateTime', 'ZonedDateTime', 'PlainYearMonth'],\n month: ['PlainDate', 'PlainDateTime', 'ZonedDateTime', 'PlainYearMonth', 'PlainMonthDay'],\n day: ['PlainDate', 'PlainDateTime', 'ZonedDateTime', 'PlainMonthDay'],\n hour: ['PlainTime', 'PlainDateTime', 'ZonedDateTime', 'Instant'],\n minute: ['PlainTime', 'PlainDateTime', 'ZonedDateTime', 'Instant'],\n second: ['PlainTime', 'PlainDateTime', 'ZonedDateTime', 'Instant'],\n millisecond: ['PlainTime', 'PlainDateTime', 'ZonedDateTime', 'Instant'],\n dayOfWeek: ['PlainDate', 'PlainDateTime', 'ZonedDateTime'],\n timeZoneId: ['ZonedDateTime'],\n offset: ['ZonedDateTime'],\n};\n\n// Every token in TOKENS gets an entry here. Adding a token to TOKENS\n// without adding one here makes test/tokenMetadata.test.js fail.\nexport const TOKEN_METADATA: Record<string, TokenMetadata> = {\n yyyy: {\n meaning: 'Four-digit year (preserves sign for BCE; no truncation).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.year, roundTripSafe: true,\n },\n yy: {\n meaning: 'Two-digit year (year % 100). Throws on negative years.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.year, roundTripSafe: false,\n },\n y: {\n meaning: 'Unpadded year, any width (preserves sign for BCE; no truncation, no minimum digits). Cannot sit directly next to another digit-reading token or a literal starting with a digit — there would be no way to tell where it ends.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.year, roundTripSafe: true,\n },\n MMMM: {\n meaning: 'Long month name (locale-aware, e.g. \"January\", \"janvier\").',\n formatCapable: true, parseCapable: true, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n MMM: {\n meaning: 'Short month name (locale-aware, e.g. \"Jan\", \"janv.\").',\n formatCapable: true, parseCapable: true, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n MM: {\n meaning: 'Two-digit month (01-12, zero-padded).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n M: {\n meaning: 'One- or two-digit month (1-12, no padding).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n dd: {\n meaning: 'Two-digit day-of-month (01-31, zero-padded).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.day, roundTripSafe: true,\n },\n d: {\n meaning: 'One- or two-digit day-of-month (1-31, no padding).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.day, roundTripSafe: true,\n },\n EEEE: {\n meaning: 'Long weekday name (locale-aware, e.g. \"Monday\", \"lundi\"). Parse cross-checks against the parsed date.',\n formatCapable: true, parseCapable: true, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.dayOfWeek, roundTripSafe: true,\n },\n EEE: {\n meaning: 'Short weekday name (locale-aware, e.g. \"Mon\", \"lun.\"). Parse cross-checks against the parsed date.',\n formatCapable: true, parseCapable: true, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.dayOfWeek, roundTripSafe: true,\n },\n HH: {\n meaning: 'Two-digit hour, 24-hour clock (00-23, zero-padded).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.hour, roundTripSafe: true,\n },\n H: {\n meaning: 'One- or two-digit hour, 24-hour clock (0-23, no padding).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.hour, roundTripSafe: true,\n },\n hh: {\n meaning: 'Two-digit hour, 12-hour clock (01-12, zero-padded). Requires `a` token on parse.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.hour, roundTripSafe: true,\n },\n h: {\n meaning: 'One- or two-digit hour, 12-hour clock (1-12, no padding). Requires `a` token on parse.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.hour, roundTripSafe: true,\n },\n mm: {\n meaning: 'Two-digit minute (00-59, zero-padded).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.minute, roundTripSafe: true,\n },\n m: {\n meaning: 'One- or two-digit minute (0-59, no padding).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.minute, roundTripSafe: true,\n },\n ss: {\n meaning: 'Two-digit second (00-59, zero-padded).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.second, roundTripSafe: true,\n },\n s: {\n meaning: 'One- or two-digit second (0-59, no padding).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.second, roundTripSafe: true,\n },\n S: {\n meaning: 'Fractional second, 1 digit (tenths of a second).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SS: {\n meaning: 'Fractional second, 2 digits (hundredths of a second).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SSS: {\n meaning: 'Fractional second, 3 digits (milliseconds).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SSSS: {\n meaning: 'Fractional second, 4 digits (tens of microseconds).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SSSSS: {\n meaning: 'Fractional second, 5 digits (hundred-thousandths of a second).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SSSSSS: {\n meaning: 'Fractional second, 6 digits (microseconds).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SSSSSSS: {\n meaning: 'Fractional second, 7 digits (tens of nanoseconds).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SSSSSSSS: {\n meaning: 'Fractional second, 8 digits (hundred-millionths of a second).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n SSSSSSSSS: {\n meaning: 'Fractional second, 9 digits (nanoseconds).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.millisecond, roundTripSafe: true,\n },\n a: {\n meaning: 'Day period (locale-aware: \"AM\"/\"PM\", \"午前\"/\"午後\", etc.). Required alongside 12-hour tokens on parse.',\n formatCapable: true, parseCapable: true, localeSensitive: true, calendarSensitive: false, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.hour, roundTripSafe: true,\n },\n zzz: {\n meaning: 'IANA time zone id (e.g. \"America/New_York\") or fixed offset (\"+05:30\"). Requires full date+time on parse.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.timeZoneId, roundTripSafe: true,\n },\n X: {\n meaning: 'Numeric UTC offset, short (Z for UTC, ±HH[MM] otherwise). Minutes omitted when zero.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.offset, roundTripSafe: true,\n },\n XX: {\n meaning: 'Numeric UTC offset, no colon (Z for UTC, ±HHMM otherwise).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.offset, roundTripSafe: true,\n },\n XXX: {\n meaning: 'Numeric UTC offset, with colon (Z for UTC, ±HH:MM otherwise).',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.offset, roundTripSafe: true,\n },\n x: {\n meaning: 'Numeric UTC offset, short, never Z (always ±HH[MM]). Lowercase variant of X.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.offset, roundTripSafe: true,\n },\n xx: {\n meaning: 'Numeric UTC offset, no colon, never Z (always ±HHMM). Lowercase variant of XX.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.offset, roundTripSafe: true,\n },\n xxx: {\n meaning: 'Numeric UTC offset, with colon, never Z (always ±HH:MM). Lowercase variant of XXX.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.offset, roundTripSafe: true,\n },\n do: {\n meaning: 'Ordinal day-of-month with English suffix (\"1st\", \"2nd\", \"3rd\", \"4th\", ... 21st, 22nd, ...). Format-only — not parseable.',\n formatCapable: true, parseCapable: false, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.day, roundTripSafe: false,\n },\n Q: {\n meaning: 'Quarter as a digit (1-4). Derived from month.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n QQQ: {\n meaning: 'Quarter with \"Q\" prefix (\"Q1\"..\"Q4\"). Derived from month.',\n formatCapable: true, parseCapable: true, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n ww: {\n meaning: 'ISO 8601 week number (01-53). Format-only — week alone can\\'t reconstruct a date.',\n formatCapable: true, parseCapable: false, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.dayOfWeek, roundTripSafe: false,\n },\n RRRR: {\n meaning: 'ISO 8601 week-numbering year (4-digit, may differ from calendar year at year boundaries). Format-only.',\n formatCapable: true, parseCapable: false, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.dayOfWeek, roundTripSafe: false,\n },\n D: {\n meaning: 'Day of year, unpadded (1-366). Format-only — parsing requires resolving against a year.',\n formatCapable: true, parseCapable: false, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.day, roundTripSafe: false,\n },\n DD: {\n meaning: 'Day of year, 2-digit minimum (01-366). Format-only.',\n formatCapable: true, parseCapable: false, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.day, roundTripSafe: false,\n },\n DDD: {\n meaning: 'Day of year, 3-digit zero-padded (001-366). Format-only.',\n formatCapable: true, parseCapable: false, localeSensitive: false, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.day, roundTripSafe: false,\n },\n LLLL: {\n meaning: 'Stand-alone long month name (nominative case in Slavic locales). Identical to MMMM in most locales.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n LLL: {\n meaning: 'Stand-alone short month name. Identical to MMM in most locales.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.month, roundTripSafe: true,\n },\n cccc: {\n meaning: 'Stand-alone long weekday name. Identical to EEEE in most locales.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.dayOfWeek, roundTripSafe: true,\n },\n ccc: {\n meaning: 'Stand-alone short weekday name. Identical to EEE in most locales.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.dayOfWeek, roundTripSafe: true,\n },\n GGGG: {\n meaning: 'Long era name (locale-aware, e.g. \"Anno Domini\"/\"Before Christ\"). Format-only.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.year, roundTripSafe: false,\n },\n G: {\n meaning: 'Short era name (locale-aware, e.g. \"AD\"/\"BC\"). Format-only.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: true, timezoneSensitive: false,\n supportedTypes: TYPES_WITH.year, roundTripSafe: false,\n },\n zzzz: {\n meaning: 'Localized long timezone name (e.g. \"Eastern Standard Time\"). Format-only.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.timeZoneId, roundTripSafe: false,\n },\n z: {\n meaning: 'Localized short timezone name (e.g. \"EST\"). Format-only.',\n formatCapable: true, parseCapable: false, localeSensitive: true, calendarSensitive: false, timezoneSensitive: true,\n supportedTypes: TYPES_WITH.timeZoneId, roundTripSafe: false,\n },\n\n};\n\nexport const ALL_TOKEN_NAMES: string[] = Object.keys(TOKEN_METADATA);","// Format-string analysis and introspection. Single source of truth for\n// \"what does this format string need / accept / produce\" — consumed by\n// the ESLint plugin and the codemod\n// so they don't each carry their own token table that drifts out of\n// sync with the runtime. Everything here reads from TOKENS in\n// tokens.ts and TOKEN_METADATA in tokenMetadata.ts, so adding a token\n// to those two tables automatically makes it visible to analyze()\n// without touching this file.\n\nimport { TOKENS, type TemporalLike } from './tokens.js';\nimport { TOKEN_METADATA, type TokenMetadata, type TemporalType } from './tokenMetadata.js';\nimport { tokenize, type Piece } from './tokenize.js';\nimport { _handlerFor } from './format.js';\nimport { UNPADDED_NUMERIC_TOKENS, FORMAT_ONLY_TOKENS } from './pattern.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\n\n// Re-exported so callers can import everything analyzer-related from a\n// single entry point — analyze.ts is the introspection surface.\nexport type { TokenMetadata, TemporalType } from './tokenMetadata.js';\nexport type { Piece } from './tokenize.js';\n\n// tokenizeFormat is the same tokenize() the runtime uses, exposed\n// under a name that signals \"this is the introspection entry point.\"\n// Same implementation, different name — callers reading analyze.ts\n// see a coherent API surface rather than having to know that the\n// runtime tokenizer is the right thing to call.\nexport function tokenizeFormat(formatStr: string): Piece[] {\n return tokenize(formatStr);\n}\n\n// listTokens: every token the runtime recognizes, with metadata. Used\n// by IDE autocomplete data (section AC) and the codemod's \"can this\n// source-library token be translated?\" lookup (section Z).\nexport function listTokens(): Array<{ name: string; metadata: TokenMetadata }> {\n return TOKENS.map(([name]) => ({ name, metadata: TOKEN_METADATA[name]! }));\n}\n\n// tokenInfo: one token's metadata. Returns undefined for unknown\n// tokens rather than throwing — callers (autocomplete, hover docs)\n// want a sentinel, not an exception, when a user types a partial token.\nexport function tokenInfo(name: string): TokenMetadata | undefined {\n return TOKEN_METADATA[name];\n}\n\nexport interface AnalyzedToken {\n name: string;\n // Position in the format string, 0-indexed. Useful for IDE diagnostics\n // that highlight a specific token.\n position: number;\n metadata: TokenMetadata;\n}\n\nexport interface FormatAnalysis {\n // Every token in the format string, in order, with metadata.\n tokens: AnalyzedToken[];\n // Fields (year/month/day/hour/...) any token in this format string\n // reads off the input. Lets a caller statically check \"does this\n // format string need a field PlainDate doesn't have?\"\n requiredFields: string[];\n // Temporal types that can supply every required field. The intersection\n // across all tokens — a format string with both `yyyy` (needs year)\n // and `HH` (needs hour) is compatible only with types carrying both,\n // i.e. PlainDateTime/ZonedDateTime.\n compatibleTypes: TemporalType[];\n // Can parse() accept this format string? False when any token is\n // format-only (do/ww/RRRR per FORMAT_ONLY_TOKENS in pattern.ts).\n parseable: boolean;\n // Does the format string contain any locale-aware token (MMMM/MMM/\n // EEEE/EEE/a)? True means the output depends on the locale option\n // and a registered custom vocab can override the result.\n localeSensitive: boolean;\n // Does the format string contain any calendar-sensitive token?\n // Almost every date/weekday token is, since its output depends on\n // the object's calendar (a hebrew PlainDate's \"MMMM\" is a hebrew\n // month name). Pure-time tokens (HH/mm/ss) are not.\n calendarSensitive: boolean;\n // Does the format string contain zzz or any offset token? If yes,\n // only ZonedDateTime can supply the field.\n timezoneSensitive: boolean;\n // Does the format string contain a run of 2+ adjacent unpadded\n // numeric tokens with no literal between them (Md, dM, Hms, ...)?\n // Such runs can be ambiguous at parse time — strict mode throws,\n // lenient mode picks one split via the documented heuristic.\n ambiguous: boolean;\n // Does format(x, fmt) → parse(fmt, output) round-trip? False when\n // any token is format-only OR when yy is used (century loss).\n roundTripSafe: boolean;\n // Non-fatal issues found during analysis. Each carries a `code`\n // the IDE plugin / CLI can switch on. Empty for clean format strings.\n warnings: Array<{ code: string; message: string }>;\n}\n\nexport function analyzeFormat(formatStr: string): FormatAnalysis {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`\n );\n }\n const pieces = tokenize(formatStr);\n const tokens: AnalyzedToken[] = [];\n const requiredFields = new Set<string>();\n const compatibleTypesSet = new Set<TemporalType>();\n let parseable = true;\n let localeSensitive = false;\n let calendarSensitive = false;\n let timezoneSensitive = false;\n let roundTripSafe = true;\n const warnings: Array<{ code: string; message: string }> = [];\n\n // Walk pieces, building up the analysis. Position is computed per\n // token piece (literals count toward offset but don't appear in the\n // tokens array).\n let offset = 0;\n const unpaddedRun: string[] = [];\n const flushRun = () => {\n if (unpaddedRun.length >= 2) {\n warnings.push({\n code: 'AMBIGUOUS_NUMERIC_RUN',\n message: `Adjacent unpadded numeric tokens \"${unpaddedRun.join('')}\" with no separator can be ambiguous to parse. Add a separator or use the padded form (e.g. \"MM\" instead of \"M\").`,\n });\n }\n unpaddedRun.length = 0;\n };\n\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n offset += piece.value.length;\n flushRun();\n continue;\n }\n const metadata = TOKEN_METADATA[piece.value];\n // Dead by construction, confirmed via listTokens(): every token in\n // TOKENS has a matching TOKEN_METADATA entry (51/51), and tokenize()\n // already throws on any string that isn't in TOKENS before this loop\n // ever runs. Kept as a guard against the two tables drifting apart.\n /* c8 ignore start */\n if (!metadata) {\n warnings.push({\n code: 'UNKNOWN_TOKEN_NO_METADATA',\n message: `Token \"${piece.value}\" is recognized by the tokenizer but has no metadata entry in tokenMetadata.ts — this is a bug in temporal-fmt.`,\n });\n offset += piece.value.length;\n continue;\n }\n /* c8 ignore stop */\n tokens.push({ name: piece.value, position: offset, metadata });\n\n // Required fields: read off the handler map (the source of truth\n // for \"what field does this token need\"). Falls back to the\n // metadata's supportedTypes-derived field set if the handler isn't\n // found, which also shouldn't happen.\n const handler = _handlerFor(piece.value);\n if (handler) {\n requiredFields.add(handler.field as string);\n }\n\n // compatibleTypes: intersect every token's supportedTypes. The\n // first token seeds the set; subsequent tokens narrow it.\n if (tokens.length === 1) {\n for (const t of metadata.supportedTypes) compatibleTypesSet.add(t);\n } else {\n const stillCompatible = new Set<TemporalType>();\n for (const t of compatibleTypesSet) {\n if (metadata.supportedTypes.includes(t)) stillCompatible.add(t);\n }\n compatibleTypesSet.clear();\n for (const t of stillCompatible) compatibleTypesSet.add(t);\n }\n\n if (!metadata.parseCapable) {\n parseable = false;\n warnings.push({\n code: 'FORMAT_ONLY_TOKEN',\n message: `Token \"${piece.value}\" is format-only — it can't be parsed back into a value. Use a parse-capable variant (e.g. \"d\" instead of \"do\") if you need round-trip.`,\n });\n }\n if (metadata.localeSensitive) localeSensitive = true;\n if (metadata.calendarSensitive) calendarSensitive = true;\n if (metadata.timezoneSensitive) timezoneSensitive = true;\n if (!metadata.roundTripSafe) roundTripSafe = false;\n\n // Track runs of adjacent unpadded numeric tokens — same definition\n // as parsePattern.ts uses (UNPADDED_NUMERIC_TOKENS). A literal\n // between tokens breaks the run; this is checked by the flushRun\n // call above.\n if (UNPADDED_NUMERIC_TOKENS.has(piece.value)) {\n unpaddedRun.push(piece.value);\n } else {\n flushRun();\n }\n\n offset += piece.value.length;\n }\n flushRun();\n\n // Cross-token checks the runtime parse() performs. Mirroring them\n // here lets the ESLint plugin flag them statically without having\n // to re-derive the logic.\n const tokenNames = tokens.map((t) => t.name);\n const has12Hour = tokenNames.some((t) => t === 'hh' || t === 'h');\n const has24Hour = tokenNames.some((t) => t === 'HH' || t === 'H');\n const hasAPeriod = tokenNames.some((t) => t === 'a');\n if (has12Hour && !hasAPeriod) {\n warnings.push({\n code: 'TWELVE_HOUR_WITHOUT_A',\n message: '12-hour token (\"hh\"/\"h\") used without an \"a\" (AM/PM) token — parse() can\\'t tell AM from PM and throws at runtime.',\n });\n }\n if (has12Hour && has24Hour) {\n warnings.push({\n code: 'MIXED_12_AND_24_HOUR',\n message: 'Mixing 24-hour and 12-hour tokens — parse() refuses to guess which is authoritative and throws at runtime.',\n });\n }\n\n const hasOffset = tokenNames.some((t) => t === 'X' || t === 'XX' || t === 'XXX' || t === 'x' || t === 'xx' || t === 'xxx');\n const hasZzz = tokenNames.some((t) => t === 'zzz');\n if (hasOffset && hasZzz) {\n warnings.push({\n code: 'ZZZ_WITH_OFFSET_TOKEN',\n message: 'Format string has both \"zzz\" and an offset token — parse() cross-checks them and throws if the parsed offset disagrees with the zone\\'s actual offset.',\n });\n }\n if (hasOffset && !requiredFields.has('year')) {\n warnings.push({\n code: 'OFFSET_WITHOUT_FULL_DATE',\n message: 'Offset token used without a full date — parse() needs a complete date and time to build a ZonedDateTime and throws at runtime otherwise.',\n });\n }\n\n return {\n tokens,\n requiredFields: [...requiredFields].sort(),\n compatibleTypes: [...compatibleTypesSet].sort(),\n parseable,\n localeSensitive,\n calendarSensitive,\n timezoneSensitive,\n // Ambiguous iff at least one warning fired about an ambiguous run.\n ambiguous: warnings.some((w) => w.code === 'AMBIGUOUS_NUMERIC_RUN'),\n roundTripSafe: roundTripSafe && parseable,\n warnings,\n };\n}\n\n// explainFormat: human-readable rendering of analyzeFormat's output.\n// Used by the CLI (section AD) for `temporal-fmt inspect <fmt>` and by\n// the IDE for hover docs on a format string. Plain prose, no JSON —\n// callers wanting machine-readable output should call analyzeFormat()\n// directly.\nexport function explainFormat(formatStr: string): string {\n const analysis = analyzeFormat(formatStr);\n const lines: string[] = [];\n lines.push(`Format string: \"${formatStr}\"`);\n lines.push(`Tokens (${analysis.tokens.length}):`);\n for (const t of analysis.tokens) {\n lines.push(` ${t.name} @${t.position} — ${t.metadata.meaning}`);\n }\n if (analysis.requiredFields.length > 0) {\n lines.push(`Required fields: ${analysis.requiredFields.join(', ')}`);\n }\n if (analysis.compatibleTypes.length > 0) {\n lines.push(`Compatible Temporal types: ${analysis.compatibleTypes.join(', ')}`);\n }\n lines.push(`Parseable: ${analysis.parseable ? 'yes' : 'no'}`);\n lines.push(`Locale-sensitive: ${analysis.localeSensitive ? 'yes' : 'no'}`);\n lines.push(`Calendar-sensitive: ${analysis.calendarSensitive ? 'yes' : 'no'}`);\n lines.push(`Timezone-sensitive: ${analysis.timezoneSensitive ? 'yes' : 'no'}`);\n lines.push(`Ambiguous: ${analysis.ambiguous ? 'yes' : 'no'}`);\n lines.push(`Round-trip safe: ${analysis.roundTripSafe ? 'yes' : 'no'}`);\n if (analysis.warnings.length > 0) {\n lines.push('Warnings:');\n for (const w of analysis.warnings) {\n lines.push(` [${w.code}] ${w.message}`);\n }\n }\n return lines.join('\\n');\n}\n\n// isValidFormat: true iff tokenize() accepts the string without\n// throwing. Distinct from analyzeFormat's `parseable` flag — a format\n// string can be valid (tokenizes cleanly) but not parseable (contains\n// a format-only token like `do`). Both checks are exposed since callers\n// want different things: validity for \"will format() throw\", parseability\n// for \"will parse() throw\".\nexport function isValidFormat(formatStr: string): boolean {\n if (formatStr.length > MAX_FORMAT_LENGTH) return false;\n try {\n tokenize(formatStr);\n return true;\n } catch {\n return false;\n }\n}\n\n// validateFormat: throws on invalid format strings instead of\n// returning a boolean. Mirrors the existing strict-validation\n// convention (descriptive thrown errors, never silent failures).\n// Returns the analysis for callers who want both — validate-then-use.\nexport function validateFormat(formatStr: string): FormatAnalysis {\n const analysis = analyzeFormat(formatStr);\n return analysis;\n}\n\n// Exported for callers that want to query the token table without\n// touching internals. Kept here rather than re-exported from\n// tokenMetadata.ts so this module is the single import for \"anything\n// analyzer-related.\"\nexport { TOKEN_METADATA, ALL_TOKEN_NAMES } from './tokenMetadata.js';\n\n// Re-export FORMAT_ONLY_TOKENS so callers don't have to import from\n// pattern.ts (which is a lower-level module they shouldn't need to\n// know about).\nexport { FORMAT_ONLY_TOKENS } from './pattern.js';\n\n// Used by callers that need to look up which field a token requires —\n// e.g. the ESLint plugin's \"type mismatch\" check (section Y) wants to\n// answer \"does the type the caller passed to format() carry this\n// field?\" without having to actually call format() and catch the\n// thrown error. Mirrors the same lookup format.ts does internally.\nexport function fieldForToken(token: string): keyof TemporalLike | undefined {\n return _handlerFor(token)?.field;\n}","// Serialization / interop helpers. Standardized\n// parse/format pairs for ISO 8601, RFC 3339, RFC 2822, HTTP-date,\n// plus epoch conversions to/from unix seconds/ms/µs/ns.\n//\n// All of these wrap the existing parse()/format() surface rather than\n// reimplementing the formats — same convention as the rest of the\n// library (one tokenizer, one parser, one constructor path). The\n// standard-format helpers are essentially pre-baked format strings\n// with the right tokens, plus stricter input validation where the\n// standard demands it (e.g. RFC 3339 requires UTC-offset-only zones,\n// not named IANA zones).\n\nimport { parse } from './parse.js';\nimport { format } from './format.js';\nimport { getTemporal, type TemporalNamespace } from './temporalProvider.js';\nimport { FormatSyntaxError, InvalidDateError } from './errors.js';\n\n// Build a Temporal instance from a field bag. Used by the parse helpers\n// to construct PlainDate / PlainDateTime / ZonedDateTime / Instant from\n// the fields the standard format carries. Throws on construction errors\n// (Feb 30, etc.) wrapped in InvalidDateError so callers get the typed\n// error surface.\nfunction constructFromFields(fields: Record<string, unknown>, kind: 'PlainDate' | 'PlainDateTime' | 'ZonedDateTime' | 'Instant'): unknown {\n const temporal = getTemporal();\n try {\n switch (kind) {\n case 'PlainDate':\n return temporal.PlainDate.from(fields as Record<string, number | string | undefined>, { overflow: 'reject' });\n case 'PlainDateTime':\n return temporal.PlainDateTime.from(fields as Record<string, number | string | undefined>, { overflow: 'reject' });\n case 'ZonedDateTime':\n return temporal.ZonedDateTime.from(fields as Record<string, number | string | undefined>, { overflow: 'reject' });\n case 'Instant': {\n // Instant.from takes an ISO string, not a field bag. Build the\n // ISO string ourselves and parse it.\n const iso = buildISOFromFields(fields);\n if (!temporal.Instant) {\n throw new Error('temporal-fmt: Temporal.Instant is not available in this implementation.');\n }\n return temporal.Instant.from(iso);\n }\n }\n } catch (err) {\n throw new InvalidDateError({ input: JSON.stringify(fields), reason: (err as Error).message });\n }\n}\n\nfunction buildISOFromFields(fields: Record<string, unknown>): string {\n const y = String(fields.year).padStart(4, '0');\n const m = String(fields.month).padStart(2, '0');\n const d = String(fields.day).padStart(2, '0');\n const h = fields.hour !== undefined ? `T${String(fields.hour).padStart(2, '0')}` : '';\n const min = fields.minute !== undefined ? `:${String(fields.minute).padStart(2, '0')}` : '';\n const sec = fields.second !== undefined ? `:${String(fields.second).padStart(2, '0')}` : '';\n const frac = fields.millisecond !== undefined && (fields.millisecond as number) > 0\n ? `.${String(fields.millisecond).padStart(3, '0')}`\n : '';\n const tz = typeof fields.timeZone === 'string' ? fields.timeZone : 'Z';\n return `${y}-${m}-${d}${h}${min}${sec}${frac}${tz}`;\n}\n\n// ISO 8601 is the most permissive of the standards here — accepts\n// calendar dates, week dates, ordinal dates, times with optional\n// fractional seconds, timezone offsets or 'Z'. Delegates to\n// Temporal's own ISO parsing (which is ISO 8601-compliant) by\n// constructing from the raw ISO string.\n\nexport function parseISO(input: string): unknown {\n const temporal = getTemporal();\n // Detect what kind of Temporal object the ISO string describes.\n // ISO 8601 strings have a date part, optional time part, optional\n // timezone. We dispatch to the right Temporal constructor based on\n // which parts are present.\n try {\n if (/^\\d{4}-\\d{2}-\\d{2}T/.test(input) || /T\\d{2}:\\d{2}/.test(input)) {\n // Has a time component.\n if (/[zZ]$/.test(input) || /[+-]\\d{2}:?\\d{2}$/.test(input)) {\n // ZonedDateTime. Temporal.ZonedDateTime.from accepts ISO with\n // a zone bracket (e.g. \"2026-08-04T15:45:30[UTC]\") but rejects\n // a bare offset with no bracket. For \"Z\" suffix, expand to\n // \"+00:00[UTC]\"; for a numeric offset, append that same offset\n // as the bracket (e.g. \"+05:30\" → \"+05:30[+05:30]\").\n let iso = input;\n if (/[zZ]$/.test(iso)) {\n iso = iso.slice(0, -1) + '+00:00[UTC]';\n } else {\n const offsetMatch = /([+-]\\d{2}:?\\d{2})$/.exec(iso);\n if (offsetMatch) {\n iso = `${iso}[${offsetMatch[1]}]`;\n }\n }\n return temporal.ZonedDateTime.from(iso as unknown as Record<string, number | string | undefined>, { overflow: 'reject' });\n }\n return temporal.PlainDateTime.from(input as unknown as Record<string, number | string | undefined>, { overflow: 'reject' });\n }\n if (/^\\d{4}-\\d{2}-\\d{2}/.test(input)) {\n return temporal.PlainDate.from(input as unknown as Record<string, number | string | undefined>, { overflow: 'reject' });\n }\n if (/^\\d{2}:\\d{2}/.test(input)) {\n return temporal.PlainTime.from(input as unknown as Record<string, number | string | undefined>);\n }\n throw new Error(`temporal-fmt: parseISO(\"${input}\") doesn't look like an ISO 8601 string.`);\n } catch (err) {\n throw new InvalidDateError({ input, reason: (err as Error).message });\n }\n}\n\nexport function formatISO(value: unknown): string {\n // Temporal objects expose toString() which produces ISO 8601 output\n // by spec. So formatting IS just toString().\n const v = value as { toString?: () => string };\n if (typeof v?.toString !== 'function') {\n throw new FormatSyntaxError({ reason: `formatISO() expects a Temporal value with toString(), got ${typeof value}.` });\n }\n return v.toString();\n}\n\n// RFC 3339 is a profile of ISO 8601 used in network protocols (HTTP,\n// JSON-RPC, etc.). Stricter than ISO 8601: requires full date+time,\n// requires seconds, requires UTC offset or 'Z', disallows IANA zone\n// names. Delegates to parseISO then validates the constraints.\n\nexport function parseRFC3339(input: string): unknown {\n // RFC 3339 grammar (https://www.rfc-editor.org/rfc/rfc3339#section-5.6):\n // date-fullyear = 4DIGIT\n // date-month = 2DIGIT ; 01-12\n // date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31\n // time-hour = 2DIGIT ; 00-23\n // time-minute = 2DIGIT ; 00-59\n // time-second = 2DIGIT ; 00-58, 00-59, 00-60 (leap second)\n // time-secfrac = \".\" 1*DIGIT\n // time-numoffset = (\"+\" / \"-\") time-hour \":\" time-minute\n // time-offset = \"Z\" / time-numoffset\n // partial-time = time-hour \":\" time-minute \":\" time-second [time-secfrac]\n // full-date = date-fullyear \"-\" date-month \"-\" date-mday\n // full-time = partial-time time-offset\n // date-time = full-date \"T\" full-time\n const re = /^(\\d{4})-(\\d{2})-(\\d{2})[Tt](\\d{2}):(\\d{2}):(\\d{2})(\\.\\d+)?([Zz]|[+-]\\d{2}:\\d{2})$/;\n const m = re.exec(input);\n if (!m) {\n throw new FormatSyntaxError({ input, reason: 'does not match RFC 3339 date-time grammar' });\n }\n // Construct via parseISO with the same expansion for bare Z.\n const iso = input.replace(/[tT]/, 'T').replace(/[zZ]$/, '+00:00[UTC]');\n return parseISO(iso);\n}\n\nexport function formatRFC3339(value: unknown): string {\n // RFC 3339 output is ISO 8601 with a UTC offset. toString() on a\n // ZonedDateTime produces this shape; we just verify the result looks\n // like RFC 3339 and pass it through.\n const s = formatISO(value);\n if (!/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})$/.test(s)) {\n throw new FormatSyntaxError({ input: s, reason: 'value did not produce RFC 3339-compliant output' });\n }\n return s;\n}\n\n// RFC 2822 date-time (used in email Message-ID headers, etc.). Format:\n// day-of-week, day month year hour:minute:second zone\n// e.g. \"Mon, 04 Aug 2026 15:45:30 +0000\"\n// JS Date can parse this natively, so we use Date.parse and convert\n// to a Temporal.Instant. (Date.parse's RFC 2822 support is universal\n// across engines, unlike its ISO 8601 support which varies.)\n\nexport function parseRFC2822(input: string): unknown {\n // Strict shape pre-check: Date.parse is far more permissive than RFC 2822\n // (it happily accepts ISO 8601 and other dialects), so without this gate\n // parseRFC2822(\"2026-08-04\") would succeed despite not being an RFC 2822\n // date at all. The regex mirrors RFC 2822 §3.3's date-time grammar:\n // optional day-of-week, 1-2 digit day, month name, 2-4 digit year (the\n // obsolete two-digit form included), time with optional seconds, and a\n // zone that is either a numeric ±HHMM offset or an alphabetic zone name.\n const RFC2822_SHAPE =\n /^(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\\s+)?\\d{1,2}\\s+(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\\s+\\d{2,4}\\s+\\d{2}:\\d{2}(?::\\d{2})?\\s+(?:[+-]\\d{4}|[A-Za-z]{1,5})$/;\n if (!RFC2822_SHAPE.test(input.trim())) {\n throw new FormatSyntaxError({ input, reason: 'not a valid RFC 2822 date' });\n }\n const ms = Date.parse(input);\n if (Number.isNaN(ms)) {\n throw new FormatSyntaxError({ input, reason: 'not a valid RFC 2822 date' });\n }\n return requireInstant().fromEpochMilliseconds(ms);\n}\n\nexport function formatRFC2822(value: unknown): string {\n // Format using format() with the right tokens, then construct via\n // the value's epoch ms. RFC 2822 requires a fixed offset, not an\n // IANA zone, so we read the value's offset directly.\n const v = value as { toEpochMilliseconds?: () => number; epochMilliseconds?: number; toInstant?: () => { epochMilliseconds: number } };\n let ms: number | undefined;\n if (typeof v?.toEpochMilliseconds === 'function') {\n ms = v.toEpochMilliseconds();\n } else if (typeof v?.epochMilliseconds === 'number') {\n // Temporal.Instant exposes epochMilliseconds as a property.\n ms = v.epochMilliseconds;\n } else if (typeof v?.toInstant === 'function') {\n // ZonedDateTime.toInstant() → Instant.\n const inst = v.toInstant();\n if (typeof (inst as { epochMilliseconds?: number }).epochMilliseconds === 'number') {\n ms = (inst as { epochMilliseconds: number }).epochMilliseconds;\n }\n }\n if (ms === undefined) {\n throw new FormatSyntaxError({ reason: `formatRFC2822() expects a value with epochMilliseconds, toEpochMilliseconds(), or toInstant(), got ${typeof value}.` });\n }\n return formatRFC2822FromMs(ms);\n}\n\nfunction formatRFC2822FromMs(ms: number): string {\n // Use Intl.DateTimeFormat with the en-US POSIX locale and the rfc822\n // format option. Modern Node ships Intl with this option; if not\n // available, fall back to manual formatting.\n try {\n const fmt = new Intl.DateTimeFormat('en-US', {\n weekday: 'short', day: '2-digit', month: 'short', year: 'numeric',\n hour: '2-digit', minute: '2-digit', second: '2-digit',\n timeZone: 'UTC', timeZoneName: 'shortOffset',\n hour12: false,\n });\n const parts = fmt.formatToParts(new Date(ms));\n /* c8 ignore start -- every part type get() is called with (weekday,\n day, month, year, hour, minute, second, timeZoneName) is always\n present given the fixed options above, so the ?? '' fallback\n can't fire without a different Intl implementation. */\n const get = (t: string) => parts.find((p) => p.type === t)?.value ?? '';\n /* c8 ignore stop */\n const tzRaw = get('timeZoneName');\n // Intl's shortOffset returns \"GMT+0\", \"GMT-8\", \"GMT+5:30\", etc.\n // RFC 2822 wants \"+0000\", \"-0800\", \"+0530\". Parse and reformat.\n const tzMatch = tzRaw?.match(/GMT([+-])(\\d+)(?::(\\d+))?/);\n let tz: string;\n if (tzMatch) {\n const sign = tzMatch[1]!;\n const hours = tzMatch[2]!.padStart(2, '0');\n const minutes = (tzMatch[3] ?? '0').padStart(2, '0');\n tz = `${sign}${hours}${minutes}`;\n /* c8 ignore start @preserve -- timeZone is hardcoded to 'UTC' above,\n which always resolves cleanly, so shortOffset always returns a\n parseable \"GMT+0\"-shaped string in this environment's ICU. This\n branch only guards against an ICU build whose shortOffset output\n doesn't match the regex; can't trigger it without mocking Intl.\n The ignore starts before the closing brace of the if-block so it\n covers the whole else-branch node c8 tracks as a single unit. */\n } else {\n tz = '+0000';\n }\n /* c8 ignore stop @preserve */\n let hour = get('hour');\n /* c8 ignore start @preserve -- hour12:false with a fixed UTC zone\n never yields \"24\" in this environment's ICU (midnight formats as\n \"00\"). Some ICU versions/locales are documented to emit \"24\" for\n hour12:false, so this stays as a defensive normalization; not\n reachable here without mocking Intl.DateTimeFormat's output. */\n if (hour === '24') hour = '00';\n /* c8 ignore stop @preserve */\n return `${get('weekday')}, ${get('day')} ${get('month')} ${get('year')} ${hour}:${get('minute')}:${get('second')} ${tz}`;\n /* c8 ignore start @preserve -- Intl.DateTimeFormat is constructed\n above with a literal, always-valid timeZone: 'UTC' and no other\n user input reaches the constructor or formatToParts call, so this\n catch can't be triggered through the public API in a normal Intl\n environment (e.g. Node with full-icu). Kept as a genuine fallback\n for runtimes with a broken or absent Intl implementation. */\n } catch {\n // Fallback: hand-rolled RFC 2822 format via Date's UTC methods.\n const d = new Date(ms);\n const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n const wd = days[d.getUTCDay()];\n const dd = String(d.getUTCDate()).padStart(2, '0');\n const mon = months[d.getUTCMonth()]!;\n const yyyy = d.getUTCFullYear();\n const hh = String(d.getUTCHours()).padStart(2, '0');\n const mm = String(d.getUTCMinutes()).padStart(2, '0');\n const ss = String(d.getUTCSeconds()).padStart(2, '0');\n return `${wd}, ${dd} ${mon} ${yyyy} ${hh}:${mm}:${ss} +0000`;\n }\n /* c8 ignore stop @preserve */\n}\n\n// RFC 7231 defines three formats: IMF-fixdate, RFC 850, asctime.\n// The canonical format is IMF-fixdate (RFC 2822-like with required\n// seconds and UTC-only). Delegates to Date.parse for parsing and to\n// formatRFC2822 for formatting (they're nearly identical).\n\nexport function parseHTTPDate(input: string): unknown {\n const trimmed = input.trim();\n const ms = Date.parse(trimmed);\n if (Number.isNaN(ms)) {\n throw new FormatSyntaxError({ input, reason: 'not a valid HTTP-date' });\n }\n return requireInstant().fromEpochMilliseconds(ms);\n}\n\nexport function formatHTTPDate(value: unknown): string {\n // IMF-fixdate format: \"Sun, 06 Nov 1994 08:49:37 GMT\"\n const instant = (value as { toInstant?: () => { epochMilliseconds: number } })?.toInstant?.()\n ?? (value as { epochMilliseconds?: number });\n const ms = typeof instant === 'object' && instant !== null && 'epochMilliseconds' in instant\n ? (instant as { epochMilliseconds: number }).epochMilliseconds\n : (() => { throw new FormatSyntaxError({ reason: `formatHTTPDate() expects an Instant or ZonedDateTime, got ${typeof value}.` }); })();\n const d = new Date(ms);\n const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n const wd = days[d.getUTCDay()];\n const dd = String(d.getUTCDate()).padStart(2, '0');\n const mon = months[d.getUTCMonth()]!;\n const yyyy = d.getUTCFullYear();\n const hh = String(d.getUTCHours()).padStart(2, '0');\n const mm = String(d.getUTCMinutes()).padStart(2, '0');\n const ss = String(d.getUTCSeconds()).padStart(2, '0');\n return `${wd}, ${dd} ${mon} ${yyyy} ${hh}:${mm}:${ss} GMT`;\n}\n\n// All epoch conversions go through Temporal.Instant, which has spec\n// methods for each epoch granularity. Wrapped here for the\n// temporal-fmt surface so callers don't have to import Temporal\n// directly.\n\nfunction getInstant(value: unknown): { epochMilliseconds: number; epochNanoseconds: bigint } {\n const v = value as { toInstant?: () => { epochMilliseconds: number; epochNanoseconds: bigint }; epochMilliseconds?: number; epochNanoseconds?: bigint };\n if (typeof v?.toInstant === 'function') {\n const inst = v.toInstant();\n // Prefer the instant's own epochNanoseconds when present — same\n // precision reasoning as below, since toInstant() can return a\n // real Temporal.Instant carrying both fields.\n if (typeof (inst as { epochNanoseconds?: bigint }).epochNanoseconds === 'bigint') {\n return { epochMilliseconds: inst.epochMilliseconds, epochNanoseconds: (inst as { epochNanoseconds: bigint }).epochNanoseconds };\n }\n return { epochMilliseconds: inst.epochMilliseconds, epochNanoseconds: BigInt(inst.epochMilliseconds) * 1_000_000n };\n }\n // Check epochNanoseconds before epochMilliseconds: a real\n // Temporal.Instant exposes both, and epochMilliseconds is truncated\n // to millisecond precision. Deriving epochNanoseconds by scaling\n // epochMilliseconds back up would silently drop sub-ms precision\n // that was available on the object all along.\n if (typeof v?.epochNanoseconds === 'bigint') {\n return { epochMilliseconds: Number(v.epochNanoseconds / 1_000_000n), epochNanoseconds: v.epochNanoseconds };\n }\n if (typeof v?.epochMilliseconds === 'number') {\n return { epochMilliseconds: v.epochMilliseconds, epochNanoseconds: BigInt(v.epochMilliseconds) * 1_000_000n };\n }\n throw new FormatSyntaxError({ reason: `expected an Instant or ZonedDateTime, got ${typeof value}.` });\n}\n\nfunction requireInstant(): NonNullable<TemporalNamespace['Instant']> {\n const t = getTemporal().Instant;\n if (!t) throw new Error('temporal-fmt: Temporal.Instant is not available in this implementation.');\n return t;\n}\n\nexport function toUnixSeconds(value: unknown): number {\n return getInstant(value).epochMilliseconds / 1000;\n}\n\nexport function fromUnixSeconds(seconds: number): unknown {\n return requireInstant().fromEpochMilliseconds(seconds * 1000);\n}\n\nexport function fromUnixMilliseconds(ms: number): unknown {\n return requireInstant().fromEpochMilliseconds(ms);\n}\n\nexport function fromUnixMicroseconds(µs: number): unknown {\n // Temporal.Instant has no fromEpochMicroseconds in the spec — only\n // fromEpochMilliseconds and fromEpochNanoseconds. Convert via ns.\n return requireInstant().fromEpochNanoseconds(BigInt(µs) * 1_000n);\n}\n\nexport function fromUnixNanoseconds(ns: bigint): unknown {\n return requireInstant().fromEpochNanoseconds(ns);\n}\n\nexport function toUnixMilliseconds(value: unknown): number {\n return getInstant(value).epochMilliseconds;\n}\n\nexport function toUnixMicroseconds(value: unknown): number {\n const { epochNanoseconds } = getInstant(value);\n return Number(epochNanoseconds / 1_000n);\n}\n\nexport function toUnixNanoseconds(value: unknown): bigint {\n return getInstant(value).epochNanoseconds;\n}\n\n// SQL-oriented helpers. SQL date/time formats are simpler than the\n// network standards above — just 'YYYY-MM-DD' for dates, 'HH:MM:SS'\n// for times, 'YYYY-MM-DD HH:MM:SS' for datetimes. Delegating to\n// parse() with the right format strings keeps the validation surface\n// consistent.\nexport function parseSQL(input: string): unknown {\n const trimmed = input.trim();\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(trimmed)) {\n return parse('yyyy-MM-dd', trimmed);\n }\n if (/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(trimmed)) {\n return parse('yyyy-MM-dd HH:mm:ss', trimmed);\n }\n if (/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}/.test(trimmed)) {\n return parseISO(trimmed);\n }\n throw new FormatSyntaxError({ input, reason: 'not a recognized SQL date/time format' });\n}\n\nexport function formatSQL(value: unknown): string {\n // Detect what kind of Temporal value this is and pick the format.\n const v = value as { year?: number; hour?: number };\n if (typeof v?.hour === 'number') {\n return format(value as Parameters<typeof format>[0], 'yyyy-MM-dd HH:mm:ss');\n }\n return format(value as Parameters<typeof format>[0], 'yyyy-MM-dd');\n}","// Central configuration. Per-call options are the\n// default convention throughout this library (see formatDistance's\n// cutoffs precedent — explicitly NOT a global). This module provides\n// a typed ConfigOptions surface that callers can build once and pass\n// to any temporal-fmt function, plus a set of defaults that mirror\n// the existing per-call defaults.\n//\n// No global mutable state. The plan is explicit: \"No mysterious\n// mutable global state — this is a hard constraint, not a preference.\"\n// This module honors that: createConfig() returns an immutable config\n// object; there is no setConfig().\n\nimport { DEFAULT_LOCALE } from './tokens.js';\nimport type { NumberingSystem } from './numbering.js';\n\nexport interface TemporalFmtConfig {\n // BCP-47 locale tag. Default 'en-US'.\n locale: string;\n // Calendar identifier ('gregory', 'hebrew', etc.) or undefined to\n // use the locale's default.\n calendar?: string;\n // IANA timezone id ('America/New_York', etc.) or undefined to use\n // the system timezone.\n timezone?: string;\n // Numbering system. Default 'latn'.\n numberingSystem: NumberingSystem | string;\n // ISO week rules: 1 = Monday, 7 = Sunday. Default 1 (matches the\n // existing isoWeek.ts convention).\n firstDayOfWeek: 1 | 7;\n // Rounding mode for round()/roundDuration(). Default 'nearest'.\n roundingMode: 'nearest' | 'floor' | 'ceil' | 'trunc';\n // Disambiguation for ZonedDateTime construction during gaps/overlaps.\n // Default 'compatible' (Temporal's default).\n disambiguation: 'compatible' | 'earlier' | 'later' | 'reject';\n // Overflow mode for field construction (Feb 30 etc.).\n // Default 'reject' (matches parse()'s existing behavior).\n overflow: 'constrain' | 'reject';\n // Parse leniency. Default false (strict).\n parseLenient: boolean;\n // Duration zero-value display. Default false (omit zeros).\n durationShowZeroValues: boolean;\n}\n\nexport const DEFAULT_CONFIG: TemporalFmtConfig = {\n locale: DEFAULT_LOCALE,\n numberingSystem: 'latn',\n firstDayOfWeek: 1,\n roundingMode: 'nearest',\n disambiguation: 'compatible',\n overflow: 'reject',\n parseLenient: false,\n durationShowZeroValues: false,\n};\n\n// Creates a config object with the caller's overrides merged onto\n// the defaults. Returns a frozen object so callers can't mutate it\n// after the fact — same immutability convention as Temporal's own\n// options.\nexport function createConfig(overrides: Partial<TemporalFmtConfig> = {}): Readonly<TemporalFmtConfig> {\n const merged: TemporalFmtConfig = { ...DEFAULT_CONFIG, ...overrides };\n // Validate.\n if (typeof merged.locale !== 'string' || merged.locale.length === 0) {\n throw new Error(`temporal-fmt: config.locale must be a non-empty string (got ${String(merged.locale)}).`);\n }\n if (merged.firstDayOfWeek !== 1 && merged.firstDayOfWeek !== 7) {\n throw new Error(`temporal-fmt: config.firstDayOfWeek must be 1 (Monday) or 7 (Sunday) (got ${merged.firstDayOfWeek}).`);\n }\n if (!['nearest', 'floor', 'ceil', 'trunc'].includes(merged.roundingMode)) {\n throw new Error(`temporal-fmt: config.roundingMode \"${merged.roundingMode}\" is not recognized.`);\n }\n if (!['compatible', 'earlier', 'later', 'reject'].includes(merged.disambiguation)) {\n throw new Error(`temporal-fmt: config.disambiguation \"${merged.disambiguation}\" is not recognized.`);\n }\n if (!['constrain', 'reject'].includes(merged.overflow)) {\n throw new Error(`temporal-fmt: config.overflow \"${merged.overflow}\" is not recognized.`);\n }\n return Object.freeze(merged);\n}\n\n// Merges a per-call options object with a config. Per-call options take\n// precedence. Used by format()/parse()/etc. to fold a caller's config\n// into the per-call options they pass.\nexport function mergeWithConfig<T extends Record<string, unknown>>(\n config: Readonly<TemporalFmtConfig> | undefined,\n perCall: T,\n): T & { locale?: string; calendar?: string; timezone?: string; numberingSystem?: string; lenient?: boolean } {\n if (!config) return perCall;\n const result = { ...perCall } as T & { locale?: string; calendar?: string; timezone?: string; numberingSystem?: string; lenient?: boolean };\n // Only fill in fields the per-call options don't specify.\n if (result.locale === undefined) result.locale = config.locale;\n if (result.calendar === undefined && config.calendar !== undefined) result.calendar = config.calendar;\n if (result.timezone === undefined && config.timezone !== undefined) result.timezone = config.timezone;\n if (result.numberingSystem === undefined) result.numberingSystem = config.numberingSystem;\n if (result.lenient === undefined && config.parseLenient) result.lenient = true;\n return result;\n}","// Business calendar. Customizable weekend definitions, holiday set,\n// observed holidays, working hours, optional half days. The holiday\n// check is delegated to a holiday calendar (holidays.ts) so this\n// module stays focused on weekday-vs-weekend logic.\n\nimport { add } from './arithmetic.js';\nimport type { HolidayCalendar } from './holidays.js';\n\nexport interface BusinessCalendarOptions {\n // Default [6, 7] (Sat/Sun). ISO weekdays 1-7.\n weekend?: number[];\n // Holiday calendar to consult. Optional — if absent, only weekend\n // logic applies.\n holidays?: HolidayCalendar;\n // Working hours per weekday. 1=Mon..7=Sun. Default: 8 hours for\n // weekdays, 0 for weekend. Used by addBusinessDays() to compute\n // partial-day arithmetic.\n workingHours?: Record<number, number>;\n // Half days: weekdays where working hours are reduced. Default empty.\n halfDays?: number[];\n}\n\nexport interface BusinessCalendar {\n weekend: Set<number>;\n holidays?: HolidayCalendar;\n workingHours: Record<number, number>;\n halfDays: Set<number>;\n}\n\nexport function createBusinessCalendar(options: BusinessCalendarOptions = {}): BusinessCalendar {\n const weekend = new Set(options.weekend ?? [6, 7]);\n // Copy before filling defaults — writing the missing weekday entries\n // straight into options.workingHours mutated the caller's object\n // (their { 1: 6 } grew keys 2..7 as a side effect of \"creating\" a\n // calendar, and a shared object across calendars cross-contaminated\n // them with the first calendar's defaults).\n const workingHours: Record<number, number> = { ...(options.workingHours ?? {}) };\n for (let i = 1; i <= 7; i++) {\n if (workingHours[i] === undefined) {\n workingHours[i] = weekend.has(i) ? 0 : 8;\n }\n }\n return {\n weekend,\n holidays: options.holidays,\n workingHours,\n halfDays: new Set(options.halfDays ?? []),\n };\n}\n\nexport function isBusinessDay(cal: BusinessCalendar, value: unknown): boolean {\n const v = value as { dayOfWeek?: number; year?: number; month?: number; day?: number };\n // add() in arithmetic.ts doesn't update dayOfWeek (it returns a field\n // bag with whatever dayOfWeek the input had). Compute it from year/month/day\n // whenever those are present — more reliable than trusting the cached\n // dayOfWeek value.\n let dow = v.dayOfWeek;\n if (typeof v.year === 'number' && typeof v.month === 'number' && typeof v.day === 'number') {\n const d = new Date(Date.UTC(v.year, v.month - 1, v.day));\n const jsDow = d.getUTCDay(); // 0=Sun..6=Sat\n dow = jsDow === 0 ? 7 : jsDow; // 1=Mon..7=Sun\n }\n if (typeof dow !== 'number') {\n throw new Error('temporal-fmt: isBusinessDay() needs a value with dayOfWeek (or year/month/day to compute it).');\n }\n if (cal.weekend.has(dow)) return false;\n if (cal.holidays && cal.holidays.isHoliday(value)) return false;\n return true;\n}\n\nexport function nextBusinessDay(cal: BusinessCalendar, value: unknown): unknown {\n let candidate = add(value, 1, 'days');\n // Loop until we find a business day. Capped at 7 iterations since a\n // week is the natural upper bound for a Sat/Sun + holiday combo.\n for (let i = 0; i < 14; i++) {\n if (isBusinessDay(cal, candidate)) return candidate;\n candidate = add(candidate, 1, 'days');\n }\n throw new Error('temporal-fmt: nextBusinessDay() gave up after 14 days — likely a misconfigured calendar (e.g. all days are weekends or holidays).');\n}\n\nexport function previousBusinessDay(cal: BusinessCalendar, value: unknown): unknown {\n let candidate = add(value, -1, 'days');\n for (let i = 0; i < 14; i++) {\n if (isBusinessDay(cal, candidate)) return candidate;\n candidate = add(candidate, -1, 'days');\n }\n throw new Error('temporal-fmt: previousBusinessDay() gave up after 14 days — likely a misconfigured calendar.');\n}\n\nconst MAX_BUSINESS_DAY_TRAVERSAL = 100_000;\n\nfunction assertBusinessDayCount(days: number): void {\n if (!Number.isSafeInteger(days)) {\n throw new RangeError(\n `temporal-fmt: business-day count must be a finite safe integer (got ${days}).`,\n );\n }\n}\n\nfunction compareDateFields(a: unknown, b: unknown): number {\n const av = a as { year: number; month: number; day: number };\n const bv = b as { year: number; month: number; day: number };\n const ay = av.year * 10000 + av.month * 100 + av.day;\n const by = bv.year * 10000 + bv.month * 100 + bv.day;\n return ay - by;\n}\n\nexport function addBusinessDays(cal: BusinessCalendar, value: unknown, days: number): unknown {\n assertBusinessDayCount(days);\n if (days === 0) return value;\n const sign = days > 0 ? 1 : -1;\n const absDays = Math.abs(days);\n if (absDays > MAX_BUSINESS_DAY_TRAVERSAL) {\n throw new RangeError(\n `temporal-fmt: addBusinessDays() exceeded the ${MAX_BUSINESS_DAY_TRAVERSAL}-day limit.`,\n );\n }\n let candidate = value;\n for (let i = 0; i < absDays; i++) {\n candidate = sign > 0 ? nextBusinessDay(cal, candidate) : previousBusinessDay(cal, candidate);\n }\n return candidate;\n}\n\nexport function subtractBusinessDays(cal: BusinessCalendar, value: unknown, days: number): unknown {\n assertBusinessDayCount(days);\n return addBusinessDays(cal, value, -days);\n}\n\nexport function differenceInBusinessDays(cal: BusinessCalendar, a: unknown, b: unknown): number {\n const rawDirection = compareDateFields(b, a);\n if (rawDirection === 0) return 0;\n\n const direction = rawDirection > 0 ? 1 : -1;\n let candidate = a;\n let count = 0;\n let traversedDays = 0;\n\n while (compareDateFields(candidate, b) !== 0) {\n candidate = add(candidate, direction, 'days');\n traversedDays++;\n if (traversedDays > MAX_BUSINESS_DAY_TRAVERSAL) {\n throw new RangeError(\n `temporal-fmt: differenceInBusinessDays() exceeded the ${MAX_BUSINESS_DAY_TRAVERSAL}-day traversal limit.`,\n );\n }\n if (isBusinessDay(cal, candidate)) count += direction;\n }\n\n return count;\n}\n","// Holiday framework. Core provides the abstraction only —\n// country-specific holiday datasets stay out of core; those can be\n// separate ecosystem packages built on top of this. A holiday calendar\n// is a function from a date → boolean (\"is this a holiday?\") plus\n// iteration helpers (nextHoliday, previousHoliday, holidaysBetween).\n\nimport { add } from './arithmetic.js';\nimport { compare } from './comparison.js';\n\nexport interface HolidayCalendar {\n isHoliday(value: unknown): boolean;\n // Returns the list of holidays within [start, end] inclusive.\n holidaysBetween(start: unknown, end: unknown): unknown[];\n}\n\nexport interface HolidaySpec {\n // Month + day for fixed-date holidays (e.g. Jan 1 → New Year's).\n month?: number;\n day?: number;\n // For floating holidays: a function that takes a year and returns\n // the { month, day } of the holiday in that year. Used for \"last\n // Monday of May\" style rules.\n compute?: (year: number) => { month: number; day: number };\n // Optional name (for introspection / debugging).\n name?: string;\n}\n\n// Upper bound on the year range holidaysBetween() will walk. The loop\n// is year-granular with no input validation on the endpoints, so a\n// caller passing (say) year 1 to year 300000 makes it iterate — and\n// cache a holiday list — for every year in between; hostile or\n// accidental huge ranges used to hang the process and grow the\n// per-calendar cache without bound. 5,000 years matches the traversal\n// caps businessCalendar.ts and recurrence.ts already use for the same\n// class of \"walk it one step at a time\" APIs.\nconst MAX_HOLIDAY_YEAR_RANGE = 5_000;\n\nexport function createHolidayCalendar(specs: HolidaySpec[]): HolidayCalendar {\n // Pre-compute holidays for a year on demand, cache by year.\n const cache = new Map<number, Array<{ month: number; day: number; name?: string }>>();\n function forYear(year: number) {\n let list = cache.get(year);\n if (list) return list;\n list = specs.map((s) => {\n let md: { month: number; day: number };\n if (s.compute) {\n md = s.compute(year);\n } else {\n md = { month: s.month!, day: s.day! };\n }\n return { ...md, name: s.name };\n });\n cache.set(year, list);\n return list;\n }\n return {\n isHoliday(value: unknown) {\n const v = value as { year?: number; month?: number; day?: number };\n if (typeof v.year !== 'number' || typeof v.month !== 'number' || typeof v.day !== 'number') {\n throw new Error('temporal-fmt: isHoliday() needs a value with year/month/day.');\n }\n const list = forYear(v.year);\n return list.some((h) => h.month === v.month && h.day === v.day);\n },\n holidaysBetween(start: unknown, end: unknown) {\n const sv = start as { year: number; month: number; day: number };\n const ev = end as { year: number; month: number; day: number };\n if (typeof sv?.year !== 'number' || typeof ev?.year !== 'number') {\n throw new Error('temporal-fmt: holidaysBetween() needs start/end values with year/month/day.');\n }\n if (ev.year - sv.year > MAX_HOLIDAY_YEAR_RANGE) {\n throw new RangeError(\n `temporal-fmt: holidaysBetween() year range (${sv.year}–${ev.year}) exceeds the ` +\n `${MAX_HOLIDAY_YEAR_RANGE}-year limit. Split the query into smaller ranges.`\n );\n }\n const result: unknown[] = [];\n for (let y = sv.year; y <= ev.year; y++) {\n const list = forYear(y);\n for (const h of list) {\n const date = { year: y, month: h.month, day: h.day };\n if (compare(date, sv) >= 0 && compare(date, ev) <= 0) {\n result.push({ year: y, month: h.month, day: h.day });\n }\n }\n }\n return result;\n },\n };\n}\n\n// Returns the next holiday strictly after `value`. Returns undefined\n// if no holiday is registered within the next 5 years (sanity cap).\nexport function nextHoliday(cal: HolidayCalendar, value: unknown): unknown | undefined {\n let candidate = add(value, 1, 'days');\n for (let i = 0; i < 365 * 5; i++) {\n if (cal.isHoliday(candidate)) return candidate;\n candidate = add(candidate, 1, 'days');\n }\n return undefined;\n}\n\nexport function previousHoliday(cal: HolidayCalendar, value: unknown): unknown | undefined {\n let candidate = add(value, -1, 'days');\n for (let i = 0; i < 365 * 5; i++) {\n if (cal.isHoliday(candidate)) return candidate;\n candidate = add(candidate, -1, 'days');\n }\n return undefined;\n}\n\n// holidaysBetween is exposed as a HolidayCalendar method (see above);\n// this standalone helper delegates to it for ergonomic access.\nexport function holidaysBetween(cal: HolidayCalendar, start: unknown, end: unknown): unknown[] {\n return cal.holidaysBetween(start, end);\n}\n","// Extensibility. Controlled extensibility via\n// createFormatter({ tokens: ... }) rather than uncontrolled global\n// mutation. Custom tokens are passed at formatter-creation time;\n// built-in behavior stays deterministic regardless of what's registered.\n//\n// The existing registerLocaleVocab() is a global-registration escape\n// hatch for the locale-vocabulary case; createFormatter is the\n// per-formatter alternative for custom tokens.\n\nimport { type FormattedPart, type CompiledFormat } from './format.js';\nimport { TOKENS, type TemporalLike, type FormatOptions, DEFAULT_LOCALE } from './tokens.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\nimport { UnknownTokenError } from './errors.js';\n\nexport type TokenHandler = (t: TemporalLike, locale: string) => string;\nexport type TokenField = keyof TemporalLike;\n\nexport interface CustomToken {\n name: string;\n handler: TokenHandler;\n field: TokenField;\n}\n\nexport interface FormatterOptions {\n // Custom tokens to add (or override). Built-in tokens with the same\n // name are replaced by the custom one.\n tokens?: CustomToken[];\n // Default locale for this formatter. Callers can still override per-call.\n defaultLocale?: string;\n}\n\nexport interface Formatter {\n format(temporal: TemporalLike, formatStr: string, options?: FormatOptions): string;\n formatToParts(temporal: TemporalLike, formatStr: string, options?: FormatOptions): FormattedPart[];\n compileFormat(formatStr: string): CompiledFormat;\n}\n\nexport function createFormatter(options: FormatterOptions = {}): Formatter {\n // Build a merged token table: built-ins plus overrides.\n const mergedTokens: Array<[string, TokenHandler, TokenField]> = [...TOKENS];\n const customTokenNames = new Set<string>();\n for (const custom of options.tokens ?? []) {\n customTokenNames.add(custom.name);\n }\n // Replace existing tokens with the same name; append new ones.\n for (const custom of options.tokens ?? []) {\n const existingIdx = mergedTokens.findIndex(([name]) => name === custom.name);\n if (existingIdx >= 0) {\n mergedTokens[existingIdx] = [custom.name, custom.handler, custom.field];\n } else {\n mergedTokens.push([custom.name, custom.handler, custom.field]);\n }\n }\n // Sort longest-first for the greedy tokenizer.\n mergedTokens.sort((a, b) => b[0].length - a[0].length);\n const handlerByToken = new Map(mergedTokens.map(([name, handler, field]) => [name, { handler, field }]));\n const sortedTokenStrings = mergedTokens.map(([name]) => name);\n\n function customTokenize(formatStr: string) {\n const pieces: Array<{ kind: 'token' | 'literal'; value: string }> = [];\n let i = 0;\n while (i < formatStr.length) {\n const ch = formatStr[i];\n if (ch === \"'\") {\n // Quoted literal handling — same as tokenize.ts.\n if (formatStr[i + 1] === \"'\") {\n appendLiteral(pieces, \"'\");\n i += 2;\n continue;\n }\n let j = i + 1;\n let literal = '';\n let closed = false;\n while (j < formatStr.length) {\n if (formatStr[j] === \"'\") {\n if (formatStr[j + 1] === \"'\") {\n literal += \"'\";\n j += 2;\n continue;\n }\n closed = true;\n j += 1;\n break;\n }\n literal += formatStr[j]!;\n j += 1;\n }\n if (!closed) throw new Error(`temporal-fmt: unterminated quote in format string \"${formatStr}\"`);\n appendLiteral(pieces, literal);\n i = j;\n continue;\n }\n const match = sortedTokenStrings.find((tok) => formatStr.startsWith(tok, i));\n if (match) {\n // Overlong-run guard, same rule as tokenize.ts: a greedy match of N\n // chars followed by one more of the same letter (\"MMMMM\", \"ddddd\")\n // is not a valid token of any width — emitting it as \"token +\n // literal\" would silently splice an unrelated field onto this one,\n // exactly the misreading the main tokenizer rejects. Same\n // UnknownTokenError shape tokenize.ts throws.\n const runChar = match[match.length - 1];\n if (formatStr[i + match.length] === runChar) {\n let end = i + match.length;\n while (formatStr[end] === runChar) end += 1;\n throw new UnknownTokenError({\n token: formatStr.slice(i, end),\n format: formatStr,\n message:\n `temporal-fmt: \"${formatStr.slice(i, end)}\" in format string \"${formatStr}\" isn't a recognized token — ` +\n `did you mean \"${match}\"?`,\n });\n }\n pieces.push({ kind: 'token', value: match });\n i += match.length;\n continue;\n }\n appendLiteral(pieces, ch);\n i += 1;\n }\n return pieces;\n }\n\n function appendLiteral(pieces: Array<{ kind: 'token' | 'literal'; value: string }>, value: string): void {\n const last = pieces[pieces.length - 1];\n if (last && last.kind === 'literal') {\n last.value += value;\n } else {\n pieces.push({ kind: 'literal', value });\n }\n }\n\n const defaultLocale = options.defaultLocale ?? DEFAULT_LOCALE;\n\n return {\n format(temporal: TemporalLike, formatStr: string, opts: FormatOptions = {}) {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(`temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters (got ${formatStr.length}).`);\n }\n const locale = opts.locale ?? defaultLocale;\n const pieces = customTokenize(formatStr);\n let result = '';\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n result += piece.value;\n continue;\n }\n const handler = handlerByToken.get(piece.value);\n /* c8 ignore start @preserve -- unreachable: customTokenize only ever produces a\n `kind: 'token'` piece via sortedTokenStrings.find(...), and\n handlerByToken is built from that same mergedTokens array, so\n every token piece is guaranteed a handler entry. Guards against a\n future customTokenize change that decouples the two lookups. */\n if (!handler) throw new Error(`temporal-fmt: unknown token \"${piece.value}\"`);\n /* c8 ignore stop @preserve */\n if (temporal[handler.field] === undefined) {\n throw new Error(\n `temporal-fmt: token \"${piece.value}\" requires \"${String(handler.field)}\", which this Temporal object doesn't have.`\n );\n }\n result += handler.handler(temporal, locale);\n }\n return result;\n },\n formatToParts(temporal: TemporalLike, formatStr: string, opts: FormatOptions = {}) {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(`temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters (got ${formatStr.length}).`);\n }\n const locale = opts.locale ?? defaultLocale;\n const pieces = customTokenize(formatStr);\n const out: FormattedPart[] = [];\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n const last = out[out.length - 1];\n /* c8 ignore start @preserve -- unreachable: customTokenize's own\n appendLiteral() already merges adjacent literal chars/quoted\n spans into a single piece before this loop ever sees them, so\n two literal pieces are never adjacent here. Kept as a guard\n against a future customTokenize change that stops merging. */\n if (last && last.type === 'literal') last.value += piece.value;\n /* c8 ignore stop @preserve */\n else out.push({ type: 'literal', value: piece.value });\n continue;\n }\n const handler = handlerByToken.get(piece.value);\n /* c8 ignore start @preserve -- unreachable: customTokenize only emits\n kind:'token' pieces found in sortedTokenStrings, the same array\n handlerByToken is built from, so every token piece is guaranteed\n a handler entry. Guards against future decoupling of the two. */\n if (!handler) throw new Error(`temporal-fmt: unknown token \"${piece.value}\"`);\n /* c8 ignore stop @preserve */\n if (temporal[handler.field] === undefined) {\n throw new Error(`temporal-fmt: token \"${piece.value}\" requires \"${String(handler.field)}\".`);\n }\n out.push({ type: 'token', value: handler.handler(temporal, locale), token: piece.value });\n }\n return out;\n },\n compileFormat(formatStr: string): CompiledFormat {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(`temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters (got ${formatStr.length}).`);\n }\n const pieces = customTokenize(formatStr);\n return {\n formatStr,\n pieces: pieces.map((p) => p as { kind: 'token' | 'literal'; value: string }),\n format(temporal: TemporalLike, opts: FormatOptions = {}) {\n const locale = opts.locale ?? defaultLocale;\n let result = '';\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n result += piece.value;\n continue;\n }\n const handler = handlerByToken.get(piece.value);\n /* c8 ignore start @preserve -- unreachable, see the same guard's comment\n above in the un-compiled format(). */\n if (!handler) throw new Error(`temporal-fmt: unknown token \"${piece.value}\"`);\n /* c8 ignore stop @preserve */\n if (temporal[handler.field] === undefined) {\n throw new Error(`temporal-fmt: token \"${piece.value}\" requires \"${String(handler.field)}\".`);\n }\n result += handler.handler(temporal, locale);\n }\n return result;\n },\n formatToParts(temporal: TemporalLike, opts: FormatOptions = {}) {\n const locale = opts.locale ?? defaultLocale;\n const out: FormattedPart[] = [];\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n const last = out[out.length - 1];\n /* c8 ignore start @preserve -- unreachable, see the same guard's\n comment above in the un-compiled formatToParts. */\n if (last && last.type === 'literal') last.value += piece.value;\n /* c8 ignore stop @preserve */\n else out.push({ type: 'literal', value: piece.value });\n continue;\n }\n const handler = handlerByToken.get(piece.value);\n /* c8 ignore start @preserve -- unreachable, see the same guard's\n comment above in the un-compiled formatToParts. */\n if (!handler) throw new Error(`temporal-fmt: unknown token \"${piece.value}\"`);\n /* c8 ignore stop @preserve */\n if (temporal[handler.field] === undefined) {\n throw new Error(`temporal-fmt: token \"${piece.value}\" requires \"${String(handler.field)}\".`);\n }\n out.push({ type: 'token', value: handler.handler(temporal, locale), token: piece.value });\n }\n return out;\n },\n };\n },\n };\n}\n\n","// IDE tooling data exports. Provides structured data editor plugins can\n// consume for: token autocomplete, hover docs, inline diagnostics,\n// quick fixes, format preview, token conversion hints from\n// Day.js/date-fns, documentation links.\n//\n// This is the data layer only — an actual VS Code extension is out of\n// scope for this package. A separate package can build the extension\n// on top of these exports.\n\nimport { TOKEN_METADATA, ALL_TOKEN_NAMES } from './tokenMetadata.js';\nimport { analyzeFormat, listTokens } from './analyze.js';\nimport { format as builtinFormat } from './format.js';\n\nexport interface TokenAutocompleteEntry {\n label: string;\n detail: string;\n documentation: string;\n // Sort group — same-family tokens sort together in the autocomplete list.\n family: string;\n}\n\n// Token family grouping for autocomplete organization: year, month,\n// day, etc.\nfunction tokenFamily(name: string): string {\n if (/^y+$/.test(name)) return 'Year';\n if (/^[ML]+$/.test(name)) return 'Month';\n if (/^[decD]+$/.test(name)) return 'Day';\n if (/^[Ec]+$/.test(name)) return 'Weekday';\n if (/^[Qq]+$/.test(name)) return 'Quarter';\n if (/^[Gg]+$/.test(name)) return 'Era';\n if (/^[Hh]+$/.test(name)) return 'Hour';\n if (/^m+$/.test(name)) return 'Minute';\n if (/^s+$/.test(name)) return 'Second';\n if (/^S+$/.test(name)) return 'Fractional Second';\n if (name === 'a') return 'Day Period';\n if (name === 'zzz') return 'Time Zone';\n if (/^[Xx]+$/.test(name)) return 'UTC Offset';\n if (name === 'do') return 'Ordinal Day';\n if (name === 'ww' || name === 'RRRR') return 'ISO Week';\n return 'Other';\n}\n\nexport function getAutocompleteData(): TokenAutocompleteEntry[] {\n return ALL_TOKEN_NAMES.map((name) => {\n const meta = TOKEN_METADATA[name]!;\n return {\n label: name,\n detail: meta.meaning,\n documentation: [\n meta.meaning,\n ``,\n `Format-capable: ${meta.formatCapable}`,\n `Parse-capable: ${meta.parseCapable}`,\n `Locale-sensitive: ${meta.localeSensitive}`,\n `Calendar-sensitive: ${meta.calendarSensitive}`,\n `Timezone-sensitive: ${meta.timezoneSensitive}`,\n `Round-trip safe: ${meta.roundTripSafe}`,\n `Supported types: ${meta.supportedTypes.join(', ')}`,\n ].join('\\n'),\n family: tokenFamily(name),\n };\n });\n}\n\nexport interface TokenHoverDoc {\n signature: string;\n summary: string;\n details: string;\n examples?: string[];\n}\n\nexport function getHoverDocs(): Record<string, TokenHoverDoc> {\n const result: Record<string, TokenHoverDoc> = {};\n for (const name of ALL_TOKEN_NAMES) {\n const meta = TOKEN_METADATA[name]!;\n result[name] = {\n signature: name,\n summary: meta.meaning,\n details: [\n // every entry in TOKEN_METADATA currently has formatCapable:\n // true (verified: 51/51). The 'no' branch reflects real,\n // intended behavior for a future format-incapable token —\n // there's no such token today, so this isn't reachable data,\n // not dead logic. Every other field on this line has real\n // true/false variance across the token table and is exercised\n // by this same loop running over ALL_TOKEN_NAMES.\n /* c8 ignore next */\n `Format-capable: ${meta.formatCapable ? 'yes' : 'no'}`,\n `Parse-capable: ${meta.parseCapable ? 'yes' : 'no'}`,\n `Locale-sensitive: ${meta.localeSensitive ? 'yes' : 'no'}`,\n `Calendar-sensitive: ${meta.calendarSensitive ? 'yes' : 'no'}`,\n `Timezone-sensitive: ${meta.timezoneSensitive ? 'yes' : 'no'}`,\n `Round-trip safe: ${meta.roundTripSafe ? 'yes' : 'no'}`,\n `Supported types: ${meta.supportedTypes.join(', ')}`,\n ].join('\\n'),\n };\n }\n return result;\n}\n\n// Inline diagnostic data for a format string. Returns a list of issues\n// (warnings + errors) with position + message + suggested fix where\n// available. Mirrors analyzeFormat's warnings but adds the position\n// info an editor needs to draw squigglies.\nexport interface InlineDiagnostic {\n startColumn: number;\n endColumn: number;\n severity: 'error' | 'warning' | 'info';\n message: string;\n code: string;\n // Suggested replacement (for quick-fix). Empty when no quick fix exists.\n suggestion?: string;\n}\n\nexport function getInlineDiagnostics(formatStr: string): InlineDiagnostic[] {\n const analysis = analyzeFormat(formatStr);\n const diagnostics: InlineDiagnostic[] = [];\n for (const warning of analysis.warnings) {\n // Find the token that triggered the warning. analyzeFormat doesn't\n // currently surface which token caused which warning — we'd need\n // to extend it to track per-warning source positions. For now,\n // surface as a whole-string diagnostic.\n let message = warning.message;\n let suggestion: string | undefined;\n if (warning.code === 'TWELVE_HOUR_WITHOUT_A') {\n suggestion = 'Add an \"a\" token (e.g. \"h:mm a\") or use \"H:mm\" for 24-hour.';\n } else if (warning.code === 'MIXED_12_AND_24_HOUR') {\n suggestion = 'Pick one form: \"HH:mm\" for 24-hour or \"h:mm a\" for 12-hour.';\n } else if (warning.code === 'AMBIGUOUS_NUMERIC_RUN') {\n suggestion = 'Add a separator or use padded forms (e.g. \"MM\" instead of \"M\").';\n } else if (warning.code === 'FORMAT_ONLY_TOKEN') {\n suggestion = 'Use a parse-capable variant (e.g. \"d\" instead of \"do\").';\n }\n diagnostics.push({\n startColumn: 0,\n endColumn: formatStr.length,\n severity: 'warning',\n message,\n code: warning.code,\n suggestion,\n });\n }\n return diagnostics;\n}\n\n// Day.js / date-fns token conversion hints. Used by the IDE to suggest\n// the temporal-fmt equivalent when a user types a Day.js or date-fns\n// token. Pulls the translation tables from the codemod if available;\n// falls back to inline tables otherwise.\nexport interface TokenConversionHint {\n from: string;\n // null means \"real token in the source library, no temporal-fmt\n // equivalent\" — the codemod throws on these rather than treating\n // them as unrecognized text (see codemod.ts).\n to: string | null;\n notes?: string;\n}\n\n// Day.js → temporal-fmt mappings. Day.js uses Moment-style tokens:\n// `D`/`DD` are day-of-*month* here (unlike date-fns below, where the\n// same letters mean day-of-year). Assumes the AdvancedFormat plugin\n// for `Do`/`Q`/`k`/`kk`/`X`/`x` — see codemod.ts's doc comment for why.\nexport const DAYJS_TO_TEMPORAL_FMT: TokenConversionHint[] = [\n { from: 'YYYY', to: 'yyyy' },\n { from: 'YY', to: 'yy' },\n { from: 'MMMM', to: 'MMMM' },\n { from: 'MMM', to: 'MMM' },\n { from: 'MM', to: 'MM' },\n { from: 'M', to: 'M' },\n { from: 'DD', to: 'dd' },\n { from: 'D', to: 'd' },\n { from: 'Do', to: null, notes: 'Ordinal day (AdvancedFormat) — use temporal-fmt\\'s own \"do\" token instead.' },\n { from: 'dddd', to: 'EEEE' },\n { from: 'ddd', to: 'EEE' },\n { from: 'dd', to: null, notes: 'Min-name weekday (e.g. \"Tu\") — temporal-fmt has no equivalent width.' },\n { from: 'd', to: null, notes: 'Numeric weekday (0-6) — no temporal-fmt equivalent; not the same as \"d\" here, which is day-of-month.' },\n { from: 'HH', to: 'HH' },\n { from: 'H', to: 'H' },\n { from: 'hh', to: 'hh' },\n { from: 'h', to: 'h' },\n { from: 'kk', to: null, notes: 'Hour 1-24 (AdvancedFormat) — no temporal-fmt equivalent.' },\n { from: 'k', to: null, notes: 'Hour 1-24 (AdvancedFormat) — no temporal-fmt equivalent.' },\n { from: 'mm', to: 'mm' },\n { from: 'm', to: 'm' },\n { from: 'ss', to: 'ss' },\n { from: 's', to: 's' },\n { from: 'SSS', to: 'SSS' },\n { from: 'A', to: 'a', notes: 'Uppercase AM/PM in Day.js — temporal-fmt is always lowercase.' },\n { from: 'a', to: 'a' },\n { from: 'ZZ', to: 'XX', notes: 'Numeric UTC offset, no colon.' },\n { from: 'Z', to: 'XXX', notes: 'Numeric UTC offset with colon.' },\n { from: 'X', to: null, notes: 'Unix timestamp (seconds) — use fromUnixSeconds() instead.' },\n { from: 'x', to: null, notes: 'Unix timestamp (ms) — use fromUnixMilliseconds() instead.' },\n { from: 'Qo', to: null, notes: 'Ordinal quarter (AdvancedFormat) — no temporal-fmt equivalent.' },\n { from: 'Q', to: 'Q' },\n { from: 'Mo', to: null, notes: 'Ordinal month (AdvancedFormat) — no temporal-fmt equivalent.' },\n { from: 'ww', to: 'ww' },\n { from: 'wo', to: null, notes: 'Ordinal ISO week (AdvancedFormat) — no temporal-fmt equivalent.' },\n { from: 'w', to: null, notes: 'Unpadded ISO week — temporal-fmt\\'s \"ww\" is always 2-digit.' },\n { from: 'gggg', to: 'RRRR', notes: 'Week-numbering year, not the calendar year — same caveat as temporal-fmt\\'s RRRR.' },\n { from: 'L', to: null, notes: 'Localized date format (AdvancedFormat) — write the format string out explicitly.' },\n { from: 'LL', to: null, notes: 'Localized date format (AdvancedFormat) — write the format string out explicitly.' },\n { from: 'LLL', to: null, notes: 'Localized date format (AdvancedFormat) — write the format string out explicitly.' },\n { from: 'LLLL', to: null, notes: 'Localized date format (AdvancedFormat) — write the format string out explicitly.' },\n { from: 'LT', to: null, notes: 'Localized time format (AdvancedFormat) — write the format string out explicitly.' },\n { from: 'LTS', to: null, notes: 'Localized time format (AdvancedFormat) — write the format string out explicitly.' },\n];\n\n// date-fns → temporal-fmt mappings. date-fns already uses Unicode/LDML\n// -style tokens close to temporal-fmt's own vocabulary — most strings\n// pass through unchanged. The catch: `D`/`DD` here mean day-of-*year*\n// (same as temporal-fmt's `D`/`DD`), not day-of-month like Day.js's\n// `D`/`DD` above — don't reuse the Day.js table for this, they collide.\nexport const DATE_FNS_TO_TEMPORAL_FMT: TokenConversionHint[] = [\n { from: 'yyyy', to: 'yyyy' },\n { from: 'yy', to: 'yy' },\n { from: 'y', to: null, notes: 'Unpadded calendar year, opt-in via useAdditionalWeekYearTokens — temporal-fmt has no unpadded-year token; use \"yyyy\".' },\n { from: 'MMMM', to: 'MMMM' },\n { from: 'MMM', to: 'MMM' },\n { from: 'MM', to: 'MM' },\n { from: 'M', to: 'M' },\n { from: 'LLLL', to: 'LLLL' },\n { from: 'LLL', to: 'LLL' },\n { from: 'dd', to: 'dd' },\n { from: 'd', to: 'd' },\n { from: 'do', to: 'do' },\n { from: 'DDD', to: 'DDD' },\n { from: 'DD', to: 'DD' },\n { from: 'D', to: 'D', notes: 'Day-of-year, opt-in via useAdditionalDayOfYearTokens — matches temporal-fmt\\'s own \"D\" already.' },\n { from: 'EEEE', to: 'EEEE' },\n { from: 'EEE', to: 'EEE' },\n { from: 'eeee', to: null, notes: 'Locale-aware numeric weekday — no temporal-fmt equivalent.' },\n { from: 'cccc', to: 'cccc' },\n { from: 'ccc', to: 'ccc' },\n { from: 'HH', to: 'HH' },\n { from: 'H', to: 'H' },\n { from: 'hh', to: 'hh' },\n { from: 'h', to: 'h' },\n { from: 'mm', to: 'mm' },\n { from: 'm', to: 'm' },\n { from: 'ss', to: 'ss' },\n { from: 's', to: 's' },\n { from: 'SSS', to: 'SSS' },\n { from: 'a', to: 'a' },\n { from: 'aaa', to: 'a' },\n { from: 'XXX', to: 'XXX' },\n { from: 'XX', to: 'XX' },\n { from: 'X', to: 'X', notes: 'Opt-in via useAdditionalDayOfYearTokens-adjacent rules in date-fns v3+; matches temporal-fmt\\'s own \"X\" already.' },\n { from: 'xxx', to: 'xxx' },\n { from: 'xx', to: 'xx' },\n { from: 'x', to: 'x' },\n { from: 'zzzz', to: 'zzzz' },\n { from: 'zzz', to: 'zzz' },\n { from: 'z', to: 'z' },\n { from: 'QQQ', to: 'QQQ' },\n { from: 'Q', to: 'Q' },\n { from: 'GGGG', to: 'GGGG' },\n { from: 'GGG', to: null, notes: 'Abbreviated era — temporal-fmt only has \"G\" (short) and \"GGGG\" (long).' },\n { from: 'GG', to: null, notes: 'Abbreviated era — temporal-fmt only has \"G\" (short) and \"GGGG\" (long).' },\n { from: 'G', to: 'G' },\n { from: 'ww', to: 'ww' },\n { from: 'w', to: null, notes: 'Unpadded local week number — temporal-fmt\\'s \"ww\" is ISO-week and always 2-digit.' },\n { from: 'RRRR', to: 'RRRR' },\n { from: 'R', to: null, notes: 'Unpadded ISO week-numbering year — temporal-fmt\\'s \"RRRR\" is always 4-digit.' },\n { from: 'Y', to: null, notes: 'Week-numbering year (locale week rules), opt-in — no temporal-fmt equivalent; \"RRRR\" is ISO week-numbering, a different rule set.' },\n { from: 'PPPP', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n { from: 'PPP', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n { from: 'PP', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n { from: 'P', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n { from: 'pppp', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n { from: 'ppp', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n { from: 'pp', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n { from: 'p', to: null, notes: 'Localized composite format — write the format string out explicitly.' },\n];\n\n// Format preview — for a given format string and a sample Temporal\n// value, returns the formatted string. Editor plugins use this for\n// live preview as the user types.\nexport function previewFormat(formatStr: string, sample?: unknown): string {\n // Use a fixed sample date if none provided — 2026-08-04T15:45:30.\n // Picked because it exercises every common token: weekday is Tuesday,\n // month name has 5 chars, day is single-digit, hour is 12-hour-style,\n // minute/second both pad.\n const value = sample ?? {\n year: 2026, month: 8, day: 4, hour: 15, minute: 45, second: 30, millisecond: 123,\n dayOfWeek: 2, timeZoneId: 'UTC', offset: '+00:00', calendarId: 'iso8601',\n };\n return builtinFormat(value as Parameters<typeof builtinFormat>[0], formatStr, { locale: 'en-US' });\n}\n\n// Documentation links. Docs used to live under docs/ as one file per\n// token family; they're now consolidated into the root README's \"Token\n// reference\" section, which has no per-token anchors — so this points\n// at the section instead of a token-specific fragment.\nexport function getDocUrl(tokenName: string): string {\n void tokenName;\n return 'README.md#token-reference';\n}\n\n// Re-exports for callers that want everything IDE-related from one module.\nexport { listTokens, TOKEN_METADATA, ALL_TOKEN_NAMES };","// Day.js / date-fns format-string translation — backs the CLI's\n// `translate` subcommand. The mapping tables already live in\n// ideData.ts for the IDE tooling, so this module builds the actual\n// string translator on top of them rather than depending on anything\n// external.\n//\n// Scope: format *strings* only (`\"YYYY-MM-DD\"` -> `\"yyyy-MM-dd\"`), not\n// an AST codemod that rewrites call sites. Rewriting\n// `dayjs(x).format(fmt)` call expressions across a codebase is a\n// separate, bigger job — see `temporal-fmt-codemod` for that.\n\nimport { DAYJS_TO_TEMPORAL_FMT, DATE_FNS_TO_TEMPORAL_FMT, type TokenConversionHint } from './ideData.js';\n\ninterface SourcePiece {\n kind: 'token' | 'literal';\n value: string;\n}\n\n// Day.js and date-fns both escape literal text by wrapping it in\n// square brackets (`[MM]` stays literal \"MM\"), unlike temporal-fmt's\n// single-quote escaping. Splitting on that first keeps the token scan\n// below from matching inside an escaped span.\nfunction splitOnBrackets(source: string): SourcePiece[] {\n const pieces: SourcePiece[] = [];\n let i = 0;\n while (i < source.length) {\n if (source[i] === '[') {\n const end = source.indexOf(']', i + 1);\n if (end === -1) {\n pieces.push({ kind: 'token', value: source.slice(i) });\n break;\n }\n pieces.push({ kind: 'literal', value: source.slice(i + 1, end) });\n i = end + 1;\n } else {\n let j = i;\n while (j < source.length && source[j] !== '[') j += 1;\n pieces.push({ kind: 'token', value: source.slice(i, j) });\n i = j;\n }\n }\n return pieces;\n}\n\n// Splits a \"token\" span (the non-bracketed parts of the source string)\n// into runs of identical letters and everything else, greedy-longest\n// against the known token table first — same overall approach as\n// tokenize.ts, but here we're scanning the *source* library's\n// vocabulary rather than temporal-fmt's own.\nfunction splitIntoRuns(span: string, sortedFrom: string[]): SourcePiece[] {\n const pieces: SourcePiece[] = [];\n let i = 0;\n while (i < span.length) {\n const match = sortedFrom.find((tok) => span.startsWith(tok, i));\n if (match) {\n pieces.push({ kind: 'token', value: match });\n i += match.length;\n continue;\n }\n const last = pieces[pieces.length - 1];\n if (last && last.kind === 'literal') {\n last.value += span[i];\n } else {\n pieces.push({ kind: 'literal', value: span[i] });\n }\n i += 1;\n }\n return pieces;\n}\n\nfunction translate(source: string, table: TokenConversionHint[], sourceLibLabel: string): string {\n const byFrom = new Map(table.map((hint) => [hint.from, hint.to]));\n const sortedFrom = [...byFrom.keys()].sort((a, b) => b.length - a.length);\n\n const bracketPieces = splitOnBrackets(source);\n let out = '';\n for (const piece of bracketPieces) {\n if (piece.kind === 'literal') {\n // Re-escape for temporal-fmt's quote syntax; a literal quote\n // character inside the escaped span needs doubling.\n out += `'${piece.value.replace(/'/g, \"''\")}'`;\n continue;\n }\n for (const run of splitIntoRuns(piece.value, sortedFrom)) {\n if (run.kind === 'token') {\n const mapped = byFrom.get(run.value);\n if (mapped === undefined || mapped === null) {\n throw new Error(\n `temporal-fmt: \"${run.value}\" has no ${sourceLibLabel} -> temporal-fmt mapping ` +\n `(in format string \"${source}\"). Write the equivalent temporal-fmt token in by hand, ` +\n `or wrap it in brackets if it was meant as literal text.`\n );\n }\n out += mapped;\n } else if (/[a-zA-Z]/.test(run.value)) {\n // Unrecognized letters can't pass through unescaped — temporal-fmt\n // would read them as its own tokens. Quote the whole run.\n out += `'${run.value.replace(/'/g, \"''\")}'`;\n } else {\n out += run.value;\n }\n }\n }\n return out;\n}\n\n/**\n * Translates a Day.js format string to the equivalent temporal-fmt\n * token string.\n *\n * ```js\n * translateDayjsFormatString('YYYY-MM-DD HH:mm:ss'); // \"yyyy-MM-dd HH:mm:ss\"\n * translateDayjsFormatString('[Q]Q YYYY'); // \"'Q'Q yyyy\" (bracketed text stays literal)\n * ```\n *\n * Throws if the format string uses a Day.js token with no temporal-fmt\n * equivalent (`Do`, `Mo`, `Qo`, `k`, `kk`, `X`, `x`, the localized\n * `L`-family tokens) — these need to be rewritten by hand, since\n * there's no single temporal-fmt token that means the same thing.\n *\n * Note: `Do`/`Mo`/`Qo`/`k`/`kk`/`X`/`x` only have meaning in Day.js\n * once the `AdvancedFormat` (and, for `X`/`x`, base) plugins are\n * loaded — without them Day.js silently glues the parts together or\n * passes the letters through unrendered instead of erroring. This\n * function assumes the plugin is loaded, since that's the common case\n * for anyone who put these tokens in a format string on purpose.\n */\nexport function translateDayjsFormatString(formatStr: string): string {\n return translate(formatStr, DAYJS_TO_TEMPORAL_FMT, 'Day.js');\n}\n\n/**\n * Translates a date-fns format string to the equivalent temporal-fmt\n * token string. date-fns already uses Unicode-style tokens close to\n * temporal-fmt's own, so most strings pass through with only a case\n * change on the weekday tokens; the notable divergences are date-fns's\n * `D`/`DD` (day-of-year, matches temporal-fmt already) versus its `d`/\n * `dd` (day-of-month, also matches already) and the locale-dependent\n * `P`/`p` composite tokens, which have no single temporal-fmt token\n * and throw.\n */\nexport function translateDateFnsFormatString(formatStr: string): string {\n return translate(formatStr, DATE_FNS_TO_TEMPORAL_FMT, 'date-fns');\n}\n"],"mappings":"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","names":["readFields","value","label","obj","hasYear","hasMonth","hasDay","REFERENCE_YEAR","MS_PER_SECOND","MS_PER_MINUTE","MS_PER_HOUR","MS_PER_DAY","daysSinceReference","year","month","day","days","y","isGregorianLeapYear","dayOfYear","toEpochMs","fields","hour","minute","second","millisecond","DEFAULT_CUTOFFS","resolveCutoffs","user","merged","key","secondsMs","minutesMs","hoursMs","daysMs","monthsMs","rtfCache","MAX_RTF_CACHE_SIZE","getRtf","locale","numeric","canonicalLocaleKey","rtf","oldestKey","normalizeLocaleTag","err","InvalidLocaleError","formatDistance","date1","date2","options","fields1","fields2","diffMs","absMs","unitCutoffs","unit","maxMs","candidateUnit","divisor","unitToMs","rounded","DEFAULT_LOCALE","formatDistanceToNow","date","now","nowFields","MAX_REGISTERED_GRAMMARS","registeredGrammars","registerRelativeGrammar","grammar","existingIdx","g","tryRegisteredGrammar","language","input","reference","matcher","match","temporal","getTemporal","fields","listRegisteredGrammars","normalizeForMatch","s","levenshtein","a","b","prev","curr","j","i","cost","FUZZY_MAX_DISTANCE","MAX_RELATIVE_INPUT_LENGTH","MAX_RELATIVE_WORDS","buildEnglishFuzzyVocabulary","ENGLISH_WEEKDAYS","ENGLISH_MONTHS","ENGLISH_MONTH_SHORT","englishFuzzyVocabulary","getEnglishFuzzyVocabulary","fuzzyCorrectEnglish","normalized","vocabulary","words","changed","corrected","word","best","bestDist","candidate","dist","readYear","reference","readMonth","readDay","extractDayOfWeek","dow","nameAlternation","names","n","buildPlainDate","temporal","year","month","day","addDays","days","addUnits","count","unit","refDate","duration","weekdayOffset","rel","refDow","targetDow","diff","resolveToNextOccurrence","refYear","thisYear","err","weekdayIndexFromName","name","idx","monthIndexFromName","longNames","shortNames","longIdx","shortIdx","ENGLISH_GRAMMAR","_m","ctx","m","inPrefix","unitName","hasIn","hasAgo","sign","SPANISH_WEEKDAYS","SPANISH_MONTHS","SPANISH_MONTH_SHORT","SPANISH_GRAMMAR","relWord","weekdayName","unitWord","unitWordToEnglish","_ctx","FRENCH_WEEKDAYS","FRENCH_MONTHS","FRENCH_MONTH_SHORT","FRENCH_GRAMMAR","GERMAN_WEEKDAYS","GERMAN_MONTHS","GERMAN_MONTH_SHORT","GERMAN_GRAMMAR","adj","GRAMMARS","grammarForLocale","locale","lang","languageOf","w","parseRelative","input","referenceDate","options","reference","temporal","getTemporal","trimmed","MAX_RELATIVE_INPUT_LENGTH","normalized","normalizeForMatch","grammar","grammarForLocale","ctx","registered","tryRegisteredGrammar","languageOf","tryMatch","text","matcher","match","NO_MATCH","exactResult","ENGLISH_GRAMMAR","corrected","fuzzyCorrectEnglish","fuzzyResult","isObject","v","guardOrFalse","impl","value","hasMethod","name","hasTag","typeName","isPlainDate","isPlainTime","isPlainDateTime","isZonedDateTime","isInstant","isPlainYearMonth","isPlainMonthDay","isDuration","isTemporal","tag","describeValue","ctor","assertImpl","guard","expectedType","assertTemporal","assertInstant","assertPlainDate","assertPlainTime","assertPlainDateTime","assertZonedDateTime","assertPlainYearMonth","assertPlainMonthDay","assertDuration","TYPES_WITH","TOKEN_METADATA","ALL_TOKEN_NAMES","tokenizeFormat","formatStr","tokenize","listTokens","TOKENS","name","TOKEN_METADATA","tokenInfo","analyzeFormat","pieces","tokens","requiredFields","compatibleTypesSet","parseable","localeSensitive","calendarSensitive","timezoneSensitive","roundTripSafe","warnings","offset","unpaddedRun","flushRun","piece","metadata","handler","_handlerFor","t","stillCompatible","UNPADDED_NUMERIC_TOKENS","tokenNames","has12Hour","has24Hour","hasAPeriod","hasOffset","hasZzz","w","explainFormat","analysis","lines","isValidFormat","validateFormat","fieldForToken","token","parseISO","input","temporal","getTemporal","iso","offsetMatch","err","InvalidDateError","formatISO","value","v","FormatSyntaxError","parseRFC3339","formatRFC3339","s","parseRFC2822","ms","requireInstant","formatRFC2822","inst","formatRFC2822FromMs","parts","get","t","p","tzMatch","tz","sign","hours","minutes","hour","d","days","months","wd","dd","mon","yyyy","hh","mm","ss","parseHTTPDate","trimmed","formatHTTPDate","instant","getInstant","toUnixSeconds","fromUnixSeconds","seconds","fromUnixMilliseconds","fromUnixMicroseconds","µs","fromUnixNanoseconds","ns","toUnixMilliseconds","toUnixMicroseconds","epochNanoseconds","toUnixNanoseconds","parseSQL","parse","formatSQL","format","DEFAULT_CONFIG","DEFAULT_LOCALE","createConfig","overrides","merged","mergeWithConfig","config","perCall","result","createBusinessCalendar","options","weekend","workingHours","i","isBusinessDay","cal","value","v","dow","jsDow","nextBusinessDay","candidate","add","previousBusinessDay","MAX_BUSINESS_DAY_TRAVERSAL","assertBusinessDayCount","days","compareDateFields","a","b","av","bv","ay","by","addBusinessDays","sign","absDays","subtractBusinessDays","differenceInBusinessDays","rawDirection","direction","count","traversedDays","MAX_HOLIDAY_YEAR_RANGE","createHolidayCalendar","specs","cache","forYear","year","list","s","md","value","v","h","start","end","sv","ev","result","y","date","compare","nextHoliday","cal","candidate","add","i","previousHoliday","holidaysBetween","createFormatter","options","mergedTokens","TOKENS","customTokenNames","custom","existingIdx","name","a","b","handlerByToken","handler","field","sortedTokenStrings","customTokenize","formatStr","pieces","i","ch","appendLiteral","j","literal","closed","match","tok","runChar","end","UnknownTokenError","value","last","defaultLocale","DEFAULT_LOCALE","temporal","opts","locale","result","piece","out","p","tokenFamily","name","getAutocompleteData","ALL_TOKEN_NAMES","meta","TOKEN_METADATA","getHoverDocs","result","getInlineDiagnostics","formatStr","analysis","analyzeFormat","diagnostics","warning","message","suggestion","DAYJS_TO_TEMPORAL_FMT","DATE_FNS_TO_TEMPORAL_FMT","previewFormat","sample","format","getDocUrl","tokenName","splitOnBrackets","source","pieces","i","end","j","splitIntoRuns","span","sortedFrom","match","tok","last","translate","table","sourceLibLabel","byFrom","hint","a","b","bracketPieces","out","piece","run","mapped","translateDayjsFormatString","formatStr","DAYJS_TO_TEMPORAL_FMT","translateDateFnsFormatString","DATE_FNS_TO_TEMPORAL_FMT"]}
|