temporal-fmt 0.9.0 → 0.9.2

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.
Files changed (105) hide show
  1. package/dist/calendarUtils.cjs +4 -259
  2. package/dist/calendarUtils.cjs.map +1 -1
  3. package/dist/calendarUtils.js +1 -33
  4. package/dist/chunk-2JHEV7ZF.js +7 -0
  5. package/dist/chunk-2JHEV7ZF.js.map +1 -0
  6. package/dist/chunk-3MZLTVP3.js +2 -0
  7. package/dist/{chunk-MXXYIMFJ.js.map → chunk-3MZLTVP3.js.map} +1 -1
  8. package/dist/chunk-4JWGUR4O.js +11 -0
  9. package/dist/{chunk-AXQLUIDY.js.map → chunk-4JWGUR4O.js.map} +1 -1
  10. package/dist/chunk-5U5WJ465.js +36 -0
  11. package/dist/chunk-5U5WJ465.js.map +1 -0
  12. package/dist/chunk-C5YESWFT.js +2 -0
  13. package/dist/chunk-C5YESWFT.js.map +1 -0
  14. package/dist/chunk-C6ZZ62ET.js +2 -0
  15. package/dist/{chunk-YS52LOMJ.js.map → chunk-C6ZZ62ET.js.map} +1 -1
  16. package/dist/chunk-EHLRZULM.js +5 -0
  17. package/dist/{chunk-4ZBGVYLR.js.map → chunk-EHLRZULM.js.map} +1 -1
  18. package/dist/chunk-F4RGUDA3.js +2 -0
  19. package/dist/chunk-F4RGUDA3.js.map +1 -0
  20. package/dist/chunk-J2AQNXF2.js +2 -0
  21. package/dist/{chunk-GRJQHQLW.js.map → chunk-J2AQNXF2.js.map} +1 -1
  22. package/dist/chunk-NBXF7V5B.js +2 -0
  23. package/dist/chunk-NBXF7V5B.js.map +1 -0
  24. package/dist/chunk-R52YOKI3.js +7 -0
  25. package/dist/{chunk-M33NSC4E.js.map → chunk-R52YOKI3.js.map} +1 -1
  26. package/dist/chunk-UJR6DHXY.js +2 -0
  27. package/dist/chunk-UJR6DHXY.js.map +1 -0
  28. package/dist/chunk-VQXUMFB2.js +21 -0
  29. package/dist/{chunk-VHSZL3P3.js.map → chunk-VQXUMFB2.js.map} +1 -1
  30. package/dist/chunk-XH46JNPK.js +2 -0
  31. package/dist/chunk-XH46JNPK.js.map +1 -0
  32. package/dist/chunk-YB6YAG7E.js +35 -0
  33. package/dist/chunk-YB6YAG7E.js.map +1 -0
  34. package/dist/chunk-ZGMTY52O.js +2 -0
  35. package/dist/chunk-ZGMTY52O.js.map +1 -0
  36. package/dist/duration.cjs +9 -624
  37. package/dist/duration.cjs.map +1 -1
  38. package/dist/duration.js +1 -29
  39. package/dist/format.cjs +18 -769
  40. package/dist/format.cjs.map +1 -1
  41. package/dist/format.js +1 -20
  42. package/dist/formatDuration.d.cts +6 -0
  43. package/dist/formatDuration.d.ts +6 -0
  44. package/dist/index.cjs +146 -6672
  45. package/dist/index.cjs.map +1 -1
  46. package/dist/index.js +58 -3004
  47. package/dist/index.js.map +1 -1
  48. package/dist/interval.cjs +18 -952
  49. package/dist/interval.cjs.map +1 -1
  50. package/dist/interval.js +1 -41
  51. package/dist/localeRegistry.cjs +15 -328
  52. package/dist/localeRegistry.cjs.map +1 -1
  53. package/dist/localeRegistry.js +1 -11
  54. package/dist/localeVocab.d.cts +3 -0
  55. package/dist/localeVocab.d.ts +3 -0
  56. package/dist/parse.cjs +53 -1637
  57. package/dist/parse.cjs.map +1 -1
  58. package/dist/parse.js +1 -20
  59. package/dist/parsePattern.d.cts +1 -0
  60. package/dist/parsePattern.d.ts +1 -0
  61. package/dist/pattern.d.cts +1 -0
  62. package/dist/pattern.d.ts +1 -0
  63. package/dist/recurrence.cjs +20 -450
  64. package/dist/recurrence.cjs.map +1 -1
  65. package/dist/recurrence.js +1 -20
  66. package/dist/relativeTime.cjs +24 -177
  67. package/dist/relativeTime.cjs.map +1 -1
  68. package/dist/relativeTime.js +1 -14
  69. package/dist/rounding.d.cts +1 -0
  70. package/dist/rounding.d.ts +1 -0
  71. package/dist/serialization.d.cts +1 -1
  72. package/dist/serialization.d.ts +1 -1
  73. package/dist/timezone.cjs +20 -387
  74. package/dist/timezone.cjs.map +1 -1
  75. package/dist/timezone.js +1 -26
  76. package/dist/typeGuards.d.cts +9 -9
  77. package/dist/typeGuards.d.ts +9 -9
  78. package/package.json +4 -2
  79. package/dist/chunk-4ZBGVYLR.js +0 -182
  80. package/dist/chunk-AXQLUIDY.js +0 -183
  81. package/dist/chunk-CKVHXFX7.js +0 -902
  82. package/dist/chunk-CKVHXFX7.js.map +0 -1
  83. package/dist/chunk-CSUIKL73.js +0 -215
  84. package/dist/chunk-CSUIKL73.js.map +0 -1
  85. package/dist/chunk-EDUFSRWJ.js +0 -9
  86. package/dist/chunk-EDUFSRWJ.js.map +0 -1
  87. package/dist/chunk-FQA4XJME.js +0 -57
  88. package/dist/chunk-FQA4XJME.js.map +0 -1
  89. package/dist/chunk-FTMLZ4EN.js +0 -196
  90. package/dist/chunk-FTMLZ4EN.js.map +0 -1
  91. package/dist/chunk-GRJQHQLW.js +0 -170
  92. package/dist/chunk-JCIMP43G.js +0 -602
  93. package/dist/chunk-JCIMP43G.js.map +0 -1
  94. package/dist/chunk-KDYK72Z2.js +0 -75
  95. package/dist/chunk-KDYK72Z2.js.map +0 -1
  96. package/dist/chunk-M33NSC4E.js +0 -169
  97. package/dist/chunk-MXXYIMFJ.js +0 -29
  98. package/dist/chunk-NFKQ3EXC.js +0 -188
  99. package/dist/chunk-NFKQ3EXC.js.map +0 -1
  100. package/dist/chunk-O6GVMBLW.js +0 -403
  101. package/dist/chunk-O6GVMBLW.js.map +0 -1
  102. package/dist/chunk-VHSZL3P3.js +0 -242
  103. package/dist/chunk-VSUCBUTC.js +0 -295
  104. package/dist/chunk-VSUCBUTC.js.map +0 -1
  105. package/dist/chunk-YS52LOMJ.js +0 -51
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/temporalProvider.ts"],"sourcesContent":["// This package's tsconfig assumes lib: [\"ESNext\"] only — no ambient\n// `Temporal` namespace type. Everywhere else in this codebase only ever\n// *reads* fields off a Temporal-like object the caller already built\n// (TemporalLike in tokens.ts). This module is the single choke point for\n// touching a *namespace*-shaped Temporal (PlainDate.from, etc.): parse()\n// uses it to construct a result, tokens.ts uses it to probe native\n// Intl<->Temporal support. Consumers can hand us an implementation via\n// setTemporal(), or we fall back to globalThis.Temporal\ninterface TemporalFactory {\n from(fields: Record<string, number | string | undefined>, options?: { overflow?: 'constrain' | 'reject'; disambiguation?: 'compatible' | 'earlier' | 'later' | 'reject'; offset?: 'use' | 'ignore' | 'prefer' | 'reject' }): unknown;\n // compare() lives on the namespace (Temporal.PlainDate.compare), not on\n // instances. Optional here since a consumer might be passing a\n // stripped-down Temporal shim that doesn't expose it.\n compare?(one: unknown, two: unknown): number;\n}\n\n// Instant is constructed via fromEpochMilliseconds / fromEpochNanoseconds\n// rather than from(fields). Separate interface.\ninterface InstantFactory {\n from(iso: string): unknown;\n fromEpochMilliseconds(ms: number): unknown;\n fromEpochMicroseconds(µs: number): unknown;\n fromEpochNanoseconds(ns: bigint): unknown;\n}\n\n// Duration is constructed via from(fields). Carries round() and compare().\ninterface DurationFactory extends TemporalFactory {\n compare?(one: unknown, two: unknown): number;\n prototype?: { round(options: unknown): unknown };\n}\n\n// PlainYearMonth / PlainMonthDay are also constructed via from(fields).\n// Same factory shape, kept separate for type clarity in callers that\n// want to narrow.\nexport interface TemporalNamespace {\n PlainDate: TemporalFactory;\n PlainTime: TemporalFactory;\n PlainDateTime: TemporalFactory;\n ZonedDateTime: TemporalFactory;\n Instant?: InstantFactory;\n Duration?: DurationFactory;\n PlainYearMonth?: TemporalFactory;\n PlainMonthDay?: TemporalFactory;\n}\n\nlet injectedTemporal: TemporalNamespace | undefined;\n\n// Anything that caches a result derived from *which* Temporal\n// implementation is active (right now: tokens.ts's native-Intl-support\n// probe) registers here so it gets invalidated whenever setTemporal()\n// swaps the implementation — see the comment on setTemporal() below for\n// why that matters. A plain array instead of an event-emitter-style API\n// since this only ever needs \"call every listener, in registration order,\n// with no payload\" — nothing here needs unsubscribe or payload data.\nconst onTemporalChanged: Array<() => void> = [];\n\nexport function subscribeToTemporalChanges(listener: () => void): void {\n onTemporalChanged.push(listener);\n}\n\n/**\n * Explicitly hand temporal-fmt the Temporal implementation to use, instead\n * of relying on a global `Temporal`. Call this once, before your first\n * `format()`/`parse()`/`parseISO()`/etc.\n *\n * Call with no argument (or `undefined`) to clear the override and fall\n * back to `globalThis.Temporal` again.\n *\n * @example\n * import { Temporal } from 'temporal-polyfill';\n * import { setTemporal } from 'temporal-fmt';\n * setTemporal(Temporal);\n */\nexport function setTemporal(temporal?: TemporalNamespace): void {\n injectedTemporal = temporal;\n // tokens.ts's native-Intl-support probe is keyed on whichever Temporal\n // implementation was active the first time a locale-aware format() ran —\n // if that implementation changes later (native -> polyfill or back), the\n // memoized probe result can go stale and disagree with what's now\n // actually active. Resetting it here means the next locale-aware format()\n // after any setTemporal() call re-probes against the implementation\n // that's active *now*, at the (small, one-time-per-switch) cost of\n // re-running the probe.\n for (const listener of onTemporalChanged) listener();\n}\n\nfunction resolveTemporal(): TemporalNamespace | undefined {\n return injectedTemporal ?? (globalThis as unknown as { Temporal?: TemporalNamespace }).Temporal;\n}\n\nexport function getTemporal(): TemporalNamespace {\n const temporal = resolveTemporal();\n if (!temporal) {\n throw new Error(\n 'temporal-fmt: parse() needs a Temporal implementation to construct its result. ' +\n 'Call setTemporal(Temporal) once at startup, or assign one to globalThis.Temporal ' +\n '(native on Node 26+, or a polyfill like temporal-polyfill).'\n );\n }\n return temporal;\n}\n"],"mappings":";AA6CA,IAAI;AASJ,IAAM,oBAAuC,CAAC;AAEvC,SAAS,2BAA2B,UAA4B;AACrE,oBAAkB,KAAK,QAAQ;AACjC;AAeO,SAAS,YAAY,UAAoC;AAC9D,qBAAmB;AASnB,aAAW,YAAY,kBAAmB,UAAS;AACrD;AAEA,SAAS,kBAAiD;AACxD,SAAO,oBAAqB,WAA2D;AACzF;AAEO,SAAS,cAAiC;AAC/C,QAAM,WAAW,gBAAgB;AACjC,MAAI,CAAC,UAAU;AACb,UAAM,IAAI;AAAA,MACR;AAAA,IAGF;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/temporalProvider.ts"],"sourcesContent":["// This package's tsconfig assumes lib: [\"ESNext\"] only — no ambient\n// `Temporal` namespace type. Everywhere else in this codebase only ever\n// *reads* fields off a Temporal-like object the caller already built\n// (TemporalLike in tokens.ts). This module is the single choke point for\n// touching a *namespace*-shaped Temporal (PlainDate.from, etc.): parse()\n// uses it to construct a result, tokens.ts uses it to probe native\n// Intl<->Temporal support. Consumers can hand us an implementation via\n// setTemporal(), or we fall back to globalThis.Temporal\ninterface TemporalFactory {\n from(fields: Record<string, number | string | undefined>, options?: { overflow?: 'constrain' | 'reject'; disambiguation?: 'compatible' | 'earlier' | 'later' | 'reject'; offset?: 'use' | 'ignore' | 'prefer' | 'reject' }): unknown;\n // compare() lives on the namespace (Temporal.PlainDate.compare), not on\n // instances. Optional here since a consumer might be passing a\n // stripped-down Temporal shim that doesn't expose it.\n compare?(one: unknown, two: unknown): number;\n}\n\n// Instant is constructed via fromEpochMilliseconds / fromEpochNanoseconds\n// rather than from(fields). Separate interface.\ninterface InstantFactory {\n from(iso: string): unknown;\n fromEpochMilliseconds(ms: number): unknown;\n fromEpochMicroseconds(µs: number): unknown;\n fromEpochNanoseconds(ns: bigint): unknown;\n}\n\n// Duration is constructed via from(fields). Carries round() and compare().\ninterface DurationFactory extends TemporalFactory {\n compare?(one: unknown, two: unknown): number;\n prototype?: { round(options: unknown): unknown };\n}\n\n// PlainYearMonth / PlainMonthDay are also constructed via from(fields).\n// Same factory shape, kept separate for type clarity in callers that\n// want to narrow.\nexport interface TemporalNamespace {\n PlainDate: TemporalFactory;\n PlainTime: TemporalFactory;\n PlainDateTime: TemporalFactory;\n ZonedDateTime: TemporalFactory;\n Instant?: InstantFactory;\n Duration?: DurationFactory;\n PlainYearMonth?: TemporalFactory;\n PlainMonthDay?: TemporalFactory;\n}\n\nlet injectedTemporal: TemporalNamespace | undefined;\n\n// Anything that caches a result derived from *which* Temporal\n// implementation is active (right now: tokens.ts's native-Intl-support\n// probe) registers here so it gets invalidated whenever setTemporal()\n// swaps the implementation — see the comment on setTemporal() below for\n// why that matters. A plain array instead of an event-emitter-style API\n// since this only ever needs \"call every listener, in registration order,\n// with no payload\" — nothing here needs unsubscribe or payload data.\nconst onTemporalChanged: Array<() => void> = [];\n\nexport function subscribeToTemporalChanges(listener: () => void): void {\n onTemporalChanged.push(listener);\n}\n\n/**\n * Explicitly hand temporal-fmt the Temporal implementation to use, instead\n * of relying on a global `Temporal`. Call this once, before your first\n * `format()`/`parse()`/`parseISO()`/etc.\n *\n * Call with no argument (or `undefined`) to clear the override and fall\n * back to `globalThis.Temporal` again.\n *\n * @example\n * import { Temporal } from 'temporal-polyfill';\n * import { setTemporal } from 'temporal-fmt';\n * setTemporal(Temporal);\n */\nexport function setTemporal(temporal?: TemporalNamespace): void {\n injectedTemporal = temporal;\n // tokens.ts's native-Intl-support probe is keyed on whichever Temporal\n // implementation was active the first time a locale-aware format() ran —\n // if that implementation changes later (native -> polyfill or back), the\n // memoized probe result can go stale and disagree with what's now\n // actually active. Resetting it here means the next locale-aware format()\n // after any setTemporal() call re-probes against the implementation\n // that's active *now*, at the (small, one-time-per-switch) cost of\n // re-running the probe.\n for (const listener of onTemporalChanged) listener();\n}\n\nfunction resolveTemporal(): TemporalNamespace | undefined {\n return injectedTemporal ?? (globalThis as unknown as { Temporal?: TemporalNamespace }).Temporal;\n}\n\nexport function getTemporal(): TemporalNamespace {\n const temporal = resolveTemporal();\n if (!temporal) {\n throw new Error(\n 'temporal-fmt: parse() needs a Temporal implementation to construct its result. ' +\n 'Call setTemporal(Temporal) once at startup, or assign one to globalThis.Temporal ' +\n '(native on Node 26+, or a polyfill like temporal-polyfill).'\n );\n }\n return temporal;\n}\n"],"mappings":"AA6CA,IAAIA,EASEC,EAAuC,CAAC,EAEvC,SAASC,EAA2BC,EAA4B,CACrEF,EAAkB,KAAKE,CAAQ,CACjC,CAeO,SAASC,EAAYC,EAAoC,CAC9DL,EAAmBK,EASnB,QAAWF,KAAYF,EAAmBE,EAAS,CACrD,CAEA,SAASG,GAAiD,CACxD,OAAON,GAAqB,WAA2D,QACzF,CAEO,SAASO,GAAiC,CAC/C,IAAMF,EAAWC,EAAgB,EACjC,GAAI,CAACD,EACH,MAAM,IAAI,MACR,6NAGF,EAEF,OAAOA,CACT","names":["injectedTemporal","onTemporalChanged","subscribeToTemporalChanges","listener","setTemporal","temporal","resolveTemporal","getTemporal"]}
@@ -0,0 +1,11 @@
1
+ import{a as v,e as c}from"./chunk-R52YOKI3.js";import{a as f,b as k}from"./chunk-C5YESWFT.js";import{b as r,c as u}from"./chunk-5U5WJ465.js";var d=new Map(k.map(([t,n,i])=>[t,{fn:n,field:i}])),p=new Map,w=500;function h(t){let n=p.get(t);if(n)return n;if(p.size>=w){let i=p.keys().next().value;i!==void 0&&p.delete(i)}return n=v(t),p.set(t,n),n}function $(t,n,i={}){if(n.length>1e3)throw new r({format:n,message:`temporal-fmt: format string exceeds maximum length of ${1e3} characters (got ${n.length}).`});let l=i.locale??f,s=h(n),o="";for(let e of s){if(e.kind==="literal"){o+=e.value;continue}let a=d.get(e.value);/* c8 ignore start @preserve -- unreachable: tokenize() only ever emits
2
+ tokens present in TOKENS, and HANDLER_BY_TOKEN is built from that
3
+ same list, so every token piece.value can hold already has an entry
4
+ here. Same defensive-guard category as the twin checks in
5
+ analyze.ts/formatDuration.ts. */if(!a)throw new u({token:e.value,format:n,message:`temporal-fmt: unknown token "${e.value}"`});/* c8 ignore stop @preserve */if(t[a.field]===void 0)throw new r({format:n,token:e.value,message:`temporal-fmt: token "${e.value}" requires "${a.field}", which this Temporal object doesn't have. (e.g. PlainDate has no time fields, PlainTime has no date fields)`});o+=a.fn(t,l)}return c(o,i)}function x(t,n,i={}){if(n.length>1e3)throw new r({format:n,message:`temporal-fmt: format string exceeds maximum length of ${1e3} characters (got ${n.length}).`});let l=i.locale??f,s=h(n),o=[];for(let e of s){if(e.kind==="literal"){let m=o[o.length-1];/* c8 ignore start @preserve -- unreachable through tokenize()'s own
6
+ output: appendLiteral() in tokenize.ts already merges every
7
+ adjacent literal character before pieces ever reaches here, so
8
+ two 'literal' pieces never sit back-to-back in the array this
9
+ loop walks. Kept as defense-in-depth in case that invariant ever
10
+ changes upstream. */if(m&&m.type==="literal")m.value+=e.value;else{/* c8 ignore stop @preserve */o.push({type:"literal",value:e.value})}continue}let a=d.get(e.value);/* c8 ignore start @preserve -- unreachable, see the note in format() above */if(!a)throw new u({token:e.value,format:n,message:`temporal-fmt: unknown token "${e.value}"`});/* c8 ignore stop @preserve */if(t[a.field]===void 0)throw new r({format:n,token:e.value,message:`temporal-fmt: token "${e.value}" requires "${a.field}", which this Temporal object doesn't have. (e.g. PlainDate has no time fields, PlainTime has no date fields)`});o.push({type:"token",value:c(a.fn(t,l),i),token:e.value})}return o}function L(t){if(t.length>1e3)throw new r({format:t,message:`temporal-fmt: format string exceeds maximum length of ${1e3} characters (got ${t.length}).`});let n=h(t);return{formatStr:t,pieces:n,format(i,l={}){let s=l.locale??f,o="";for(let e of n){if(e.kind==="literal"){o+=e.value;continue}let a=d.get(e.value);if(!a)throw new u({token:e.value,format:t,message:`temporal-fmt: unknown token "${e.value}"`});if(i[a.field]===void 0)throw new r({format:t,token:e.value,message:`temporal-fmt: token "${e.value}" requires "${a.field}", which this Temporal object doesn't have. (e.g. PlainDate has no time fields, PlainTime has no date fields)`});o+=a.fn(i,s)}return c(o,l)},formatToParts(i,l={}){let s=l.locale??f,o=[];for(let e of n){if(e.kind==="literal"){let m=o[o.length-1];m&&m.type==="literal"?m.value+=e.value:o.push({type:"literal",value:e.value});continue}let a=d.get(e.value);if(!a)throw new u({token:e.value,format:t,message:`temporal-fmt: unknown token "${e.value}"`});if(i[a.field]===void 0)throw new r({format:t,token:e.value,message:`temporal-fmt: token "${e.value}" requires "${a.field}", which this Temporal object doesn't have. (e.g. PlainDate has no time fields, PlainTime has no date fields)`});o.push({type:"token",value:c(a.fn(i,s),l),token:e.value})}return o}}}function N(t){return h(t)}function O(t){return d.get(t)}export{$ as a,x as b,L as c,N as d,O as e};
11
+ //# sourceMappingURL=chunk-4JWGUR4O.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/format.ts"],"sourcesContent":["import { TOKENS, DEFAULT_LOCALE, type TemporalLike, type FormatOptions } from './tokens.js';\nimport { tokenize, type Piece } from './tokenize.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\nimport { applyNumbering, type NumberingFormatOptions } from './numbering.js';\nimport { FormatSyntaxError, UnknownTokenError } from './errors.js';\n\nconst HANDLER_BY_TOKEN = new Map(TOKENS.map(([tok, fn, field]) => [tok, { fn, field }]));\n\n// Pre-tokenized format strings, keyed by (formatStr) — locale doesn't\n// change the tokenization step, only the per-token rendering, so the\n// piece list is shared across locales. Same eviction shape as the\n// other caches in this library.\nconst tokenizeCache = new Map<string, Piece[]>();\nconst MAX_TOKENIZE_CACHE_SIZE = 500;\n\nfunction getPieces(formatStr: string): Piece[] {\n let pieces = tokenizeCache.get(formatStr);\n if (pieces) return pieces;\n if (tokenizeCache.size >= MAX_TOKENIZE_CACHE_SIZE) {\n const oldestKey = tokenizeCache.keys().next().value;\n if (oldestKey !== undefined) tokenizeCache.delete(oldestKey);\n }\n pieces = tokenize(formatStr);\n tokenizeCache.set(formatStr, pieces);\n return pieces;\n}\n\n/**\n * Format a Temporal.PlainDate, PlainTime, PlainDateTime, or ZonedDateTime\n * using a date-fns-style token string.\n *\n * @example\n * format(Temporal.Now.plainDateISO(), 'yyyy-MM-dd') // \"2026-08-04\"\n * format(zdt, \"MMM d, yyyy 'at' h:mm a\") // \"Aug 4, 2026 at 3:45 PM\"\n * format(zdt, 'MMMM d, yyyy', { locale: 'fr-FR' }) // \"août 4, 2026\"\n *\n * Throws on a token the input type doesn't support (e.g. 'HH' on a PlainDate).\n */\nexport function format(temporal: TemporalLike, formatStr: string, options: NumberingFormatOptions = {}): string {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new FormatSyntaxError({\n format: formatStr,\n message:\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`,\n });\n }\n\n const locale = options.locale ?? DEFAULT_LOCALE;\n const pieces = getPieces(formatStr);\n let result = '';\n\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n result += piece.value;\n continue;\n }\n\n const handler = HANDLER_BY_TOKEN.get(piece.value);\n /* c8 ignore start @preserve -- unreachable: tokenize() only ever emits\n tokens present in TOKENS, and HANDLER_BY_TOKEN is built from that\n same list, so every token piece.value can hold already has an entry\n here. Same defensive-guard category as the twin checks in\n analyze.ts/formatDuration.ts. */\n if (!handler) {\n throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n }\n /* c8 ignore stop @preserve */\n\n if (temporal[handler.field] === undefined) {\n throw new FormatSyntaxError({\n format: formatStr,\n token: piece.value,\n message:\n `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n `which this Temporal object doesn't have. ` +\n `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n });\n }\n\n result += handler.fn(temporal, locale);\n }\n\n // Numeral transliteration happens last and only on request — every\n // upstream token handler still emits plain ASCII digits, so this is\n // the single place output digits can diverge from that default.\n return applyNumbering(result, options);\n}\n\n// Shape mirrors Intl.DateTimeFormat.formatToParts: each entry is either\n// a literal (carrying no token info) or a token piece (carrying the\n// token string and the formatted value). Letting callers iterate parts\n// means they can build custom output — strip a token, swap a separator,\n// render each token to its own DOM node — without re-implementing the\n// tokenizer or the field-check logic.\nexport interface FormattedPart {\n type: 'literal' | 'token';\n value: string;\n // Present when `type === 'token'`. Carries the token string (e.g. \"yyyy\")\n // so a caller can look up its metadata via tokenInfo() from analyze.ts.\n token?: string;\n}\n\nexport function formatToParts(temporal: TemporalLike, formatStr: string, options: NumberingFormatOptions = {}): FormattedPart[] {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new FormatSyntaxError({\n format: formatStr,\n message:\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`,\n });\n }\n const locale = options.locale ?? DEFAULT_LOCALE;\n const pieces = getPieces(formatStr);\n const result: FormattedPart[] = [];\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n // Collapse adjacent literals so formatToParts stays consistent with\n // how format() walks pieces — a multi-char literal \"at \" is one\n // entry, not one per character. Same merge logic as appendLiteral\n // in tokenize.ts.\n const last = result[result.length - 1];\n /* c8 ignore start @preserve -- unreachable through tokenize()'s own\n output: appendLiteral() in tokenize.ts already merges every\n adjacent literal character before pieces ever reaches here, so\n two 'literal' pieces never sit back-to-back in the array this\n loop walks. Kept as defense-in-depth in case that invariant ever\n changes upstream. */\n if (last && last.type === 'literal') {\n last.value += piece.value;\n } else {\n /* c8 ignore stop @preserve */\n result.push({ type: 'literal', value: piece.value });\n }\n continue;\n }\n const handler = HANDLER_BY_TOKEN.get(piece.value);\n /* c8 ignore start @preserve -- unreachable, see the note in format() above */\n if (!handler) {\n throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n }\n /* c8 ignore stop @preserve */\n if (temporal[handler.field] === undefined) {\n throw new FormatSyntaxError({\n format: formatStr,\n token: piece.value,\n message:\n `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n `which this Temporal object doesn't have. ` +\n `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n });\n }\n // Numeral transliteration applies per-token-part here, rather than\n // once at the end like format() does, so a caller styling individual\n // parts (e.g. one <span> per token) still gets correctly-transliterated\n // digits in each part instead of plain ASCII.\n result.push({ type: 'token', value: applyNumbering(handler.fn(temporal, locale), options), token: piece.value });\n }\n return result;\n}\n\n// Pre-compiles a format string into an object whose format()/formatToParts()\n// methods skip the tokenization step on every call. The tokenizeCache in\n// this module means a plain format(temporal, fmt) call already pays only\n// a Map lookup for tokenization after the first call, so compileFormat()\n// is mostly a typing/ergonomics affordance — useful for callers who want\n// to hold onto a compiled form explicitly (e.g. to inspect the pieces\n// via the .pieces property, or to pass the compiled object around\n// instead of the string).\nexport interface CompiledFormat {\n format(temporal: TemporalLike, options?: NumberingFormatOptions): string;\n formatToParts(temporal: TemporalLike, options?: NumberingFormatOptions): FormattedPart[];\n readonly pieces: ReadonlyArray<Piece>;\n readonly formatStr: string;\n}\n\nexport function compileFormat(formatStr: string): CompiledFormat {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new FormatSyntaxError({\n format: formatStr,\n message:\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`,\n });\n }\n // Pre-tokenize once. Validation (unknown tokens, unterminated quotes)\n // happens here, not lazily on first format() call — surfaces a bad\n // format string at compile time rather than at first use, which is\n // the point of compiling up front.\n const pieces = getPieces(formatStr);\n return {\n formatStr,\n pieces,\n format(temporal: TemporalLike, options: NumberingFormatOptions = {}) {\n const locale = options.locale ?? DEFAULT_LOCALE;\n let result = '';\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n result += piece.value;\n continue;\n }\n const handler = HANDLER_BY_TOKEN.get(piece.value);\n /* c8 ignore next -- unreachable, see the note in format() above */\n if (!handler) throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n if (temporal[handler.field] === undefined) {\n throw new FormatSyntaxError({\n format: formatStr,\n token: piece.value,\n message:\n `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n `which this Temporal object doesn't have. ` +\n `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n });\n }\n result += handler.fn(temporal, locale);\n }\n return applyNumbering(result, options);\n },\n formatToParts(temporal: TemporalLike, options: NumberingFormatOptions = {}) {\n const locale = options.locale ?? DEFAULT_LOCALE;\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 next -- unreachable, see the note in formatToParts() above */\n if (last && last.type === 'literal') last.value += piece.value;\n else out.push({ type: 'literal', value: piece.value });\n continue;\n }\n const handler = HANDLER_BY_TOKEN.get(piece.value);\n /* c8 ignore next -- unreachable, see the note in format() above */\n if (!handler) throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n if (temporal[handler.field] === undefined) {\n throw new FormatSyntaxError({\n format: formatStr,\n token: piece.value,\n message:\n `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n `which this Temporal object doesn't have. ` +\n `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n });\n }\n out.push({ type: 'token', value: applyNumbering(handler.fn(temporal, locale), options), token: piece.value });\n }\n return out;\n },\n };\n}\n\n// Exported so analyze.ts can reuse the same tokenization cache rather\n// than re-tokenizing when a caller asks for both a format() and an\n// analyzeFormat() on the same string.\nexport function _getPieces(formatStr: string): Piece[] {\n return getPieces(formatStr);\n}\n\n// Exported for analyze.ts — same reason as above. The handler map is\n// the source of truth for \"what field does this token need\" — analyze\n// consumes it to compute requiredFields and compatibleTypes.\nexport function _handlerFor(token: string): { fn: (t: TemporalLike, locale: string) => string; field: keyof TemporalLike } | undefined {\n return HANDLER_BY_TOKEN.get(token);\n}"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/format.ts"],"sourcesContent":["import { TOKENS, DEFAULT_LOCALE, type TemporalLike, type FormatOptions } from './tokens.js';\nimport { tokenize, type Piece } from './tokenize.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\nimport { applyNumbering, type NumberingFormatOptions } from './numbering.js';\nimport { FormatSyntaxError, UnknownTokenError } from './errors.js';\n\nconst HANDLER_BY_TOKEN = new Map(TOKENS.map(([tok, fn, field]) => [tok, { fn, field }]));\n\n// Pre-tokenized format strings, keyed by (formatStr) — locale doesn't\n// change the tokenization step, only the per-token rendering, so the\n// piece list is shared across locales. Same eviction shape as the\n// other caches in this library.\nconst tokenizeCache = new Map<string, Piece[]>();\nconst MAX_TOKENIZE_CACHE_SIZE = 500;\n\nfunction getPieces(formatStr: string): Piece[] {\n let pieces = tokenizeCache.get(formatStr);\n if (pieces) return pieces;\n if (tokenizeCache.size >= MAX_TOKENIZE_CACHE_SIZE) {\n const oldestKey = tokenizeCache.keys().next().value;\n if (oldestKey !== undefined) tokenizeCache.delete(oldestKey);\n }\n pieces = tokenize(formatStr);\n tokenizeCache.set(formatStr, pieces);\n return pieces;\n}\n\n/**\n * Format a Temporal.PlainDate, PlainTime, PlainDateTime, or ZonedDateTime\n * using a date-fns-style token string.\n *\n * @example\n * format(Temporal.Now.plainDateISO(), 'yyyy-MM-dd') // \"2026-08-04\"\n * format(zdt, \"MMM d, yyyy 'at' h:mm a\") // \"Aug 4, 2026 at 3:45 PM\"\n * format(zdt, 'MMMM d, yyyy', { locale: 'fr-FR' }) // \"août 4, 2026\"\n *\n * Throws on a token the input type doesn't support (e.g. 'HH' on a PlainDate).\n */\nexport function format(temporal: TemporalLike, formatStr: string, options: NumberingFormatOptions = {}): string {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new FormatSyntaxError({\n format: formatStr,\n message:\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`,\n });\n }\n\n const locale = options.locale ?? DEFAULT_LOCALE;\n const pieces = getPieces(formatStr);\n let result = '';\n\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n result += piece.value;\n continue;\n }\n\n const handler = HANDLER_BY_TOKEN.get(piece.value);\n /* c8 ignore start @preserve -- unreachable: tokenize() only ever emits\n tokens present in TOKENS, and HANDLER_BY_TOKEN is built from that\n same list, so every token piece.value can hold already has an entry\n here. Same defensive-guard category as the twin checks in\n analyze.ts/formatDuration.ts. */\n if (!handler) {\n throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n }\n /* c8 ignore stop @preserve */\n\n if (temporal[handler.field] === undefined) {\n throw new FormatSyntaxError({\n format: formatStr,\n token: piece.value,\n message:\n `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n `which this Temporal object doesn't have. ` +\n `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n });\n }\n\n result += handler.fn(temporal, locale);\n }\n\n // Numeral transliteration happens last and only on request — every\n // upstream token handler still emits plain ASCII digits, so this is\n // the single place output digits can diverge from that default.\n return applyNumbering(result, options);\n}\n\n// Shape mirrors Intl.DateTimeFormat.formatToParts: each entry is either\n// a literal (carrying no token info) or a token piece (carrying the\n// token string and the formatted value). Letting callers iterate parts\n// means they can build custom output — strip a token, swap a separator,\n// render each token to its own DOM node — without re-implementing the\n// tokenizer or the field-check logic.\nexport interface FormattedPart {\n type: 'literal' | 'token';\n value: string;\n // Present when `type === 'token'`. Carries the token string (e.g. \"yyyy\")\n // so a caller can look up its metadata via tokenInfo() from analyze.ts.\n token?: string;\n}\n\nexport function formatToParts(temporal: TemporalLike, formatStr: string, options: NumberingFormatOptions = {}): FormattedPart[] {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new FormatSyntaxError({\n format: formatStr,\n message:\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`,\n });\n }\n const locale = options.locale ?? DEFAULT_LOCALE;\n const pieces = getPieces(formatStr);\n const result: FormattedPart[] = [];\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n // Collapse adjacent literals so formatToParts stays consistent with\n // how format() walks pieces — a multi-char literal \"at \" is one\n // entry, not one per character. Same merge logic as appendLiteral\n // in tokenize.ts.\n const last = result[result.length - 1];\n /* c8 ignore start @preserve -- unreachable through tokenize()'s own\n output: appendLiteral() in tokenize.ts already merges every\n adjacent literal character before pieces ever reaches here, so\n two 'literal' pieces never sit back-to-back in the array this\n loop walks. Kept as defense-in-depth in case that invariant ever\n changes upstream. */\n if (last && last.type === 'literal') {\n last.value += piece.value;\n } else {\n /* c8 ignore stop @preserve */\n result.push({ type: 'literal', value: piece.value });\n }\n continue;\n }\n const handler = HANDLER_BY_TOKEN.get(piece.value);\n /* c8 ignore start @preserve -- unreachable, see the note in format() above */\n if (!handler) {\n throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n }\n /* c8 ignore stop @preserve */\n if (temporal[handler.field] === undefined) {\n throw new FormatSyntaxError({\n format: formatStr,\n token: piece.value,\n message:\n `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n `which this Temporal object doesn't have. ` +\n `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n });\n }\n // Numeral transliteration applies per-token-part here, rather than\n // once at the end like format() does, so a caller styling individual\n // parts (e.g. one <span> per token) still gets correctly-transliterated\n // digits in each part instead of plain ASCII.\n result.push({ type: 'token', value: applyNumbering(handler.fn(temporal, locale), options), token: piece.value });\n }\n return result;\n}\n\n// Pre-compiles a format string into an object whose format()/formatToParts()\n// methods skip the tokenization step on every call. The tokenizeCache in\n// this module means a plain format(temporal, fmt) call already pays only\n// a Map lookup for tokenization after the first call, so compileFormat()\n// is mostly a typing/ergonomics affordance — useful for callers who want\n// to hold onto a compiled form explicitly (e.g. to inspect the pieces\n// via the .pieces property, or to pass the compiled object around\n// instead of the string).\nexport interface CompiledFormat {\n format(temporal: TemporalLike, options?: NumberingFormatOptions): string;\n formatToParts(temporal: TemporalLike, options?: NumberingFormatOptions): FormattedPart[];\n readonly pieces: ReadonlyArray<Piece>;\n readonly formatStr: string;\n}\n\nexport function compileFormat(formatStr: string): CompiledFormat {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new FormatSyntaxError({\n format: formatStr,\n message:\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`,\n });\n }\n // Pre-tokenize once. Validation (unknown tokens, unterminated quotes)\n // happens here, not lazily on first format() call — surfaces a bad\n // format string at compile time rather than at first use, which is\n // the point of compiling up front.\n const pieces = getPieces(formatStr);\n return {\n formatStr,\n pieces,\n format(temporal: TemporalLike, options: NumberingFormatOptions = {}) {\n const locale = options.locale ?? DEFAULT_LOCALE;\n let result = '';\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n result += piece.value;\n continue;\n }\n const handler = HANDLER_BY_TOKEN.get(piece.value);\n /* c8 ignore next -- unreachable, see the note in format() above */\n if (!handler) throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n if (temporal[handler.field] === undefined) {\n throw new FormatSyntaxError({\n format: formatStr,\n token: piece.value,\n message:\n `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n `which this Temporal object doesn't have. ` +\n `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n });\n }\n result += handler.fn(temporal, locale);\n }\n return applyNumbering(result, options);\n },\n formatToParts(temporal: TemporalLike, options: NumberingFormatOptions = {}) {\n const locale = options.locale ?? DEFAULT_LOCALE;\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 next -- unreachable, see the note in formatToParts() above */\n if (last && last.type === 'literal') last.value += piece.value;\n else out.push({ type: 'literal', value: piece.value });\n continue;\n }\n const handler = HANDLER_BY_TOKEN.get(piece.value);\n /* c8 ignore next -- unreachable, see the note in format() above */\n if (!handler) throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n if (temporal[handler.field] === undefined) {\n throw new FormatSyntaxError({\n format: formatStr,\n token: piece.value,\n message:\n `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n `which this Temporal object doesn't have. ` +\n `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n });\n }\n out.push({ type: 'token', value: applyNumbering(handler.fn(temporal, locale), options), token: piece.value });\n }\n return out;\n },\n };\n}\n\n// Exported so analyze.ts can reuse the same tokenization cache rather\n// than re-tokenizing when a caller asks for both a format() and an\n// analyzeFormat() on the same string.\nexport function _getPieces(formatStr: string): Piece[] {\n return getPieces(formatStr);\n}\n\n// Exported for analyze.ts — same reason as above. The handler map is\n// the source of truth for \"what field does this token need\" — analyze\n// consumes it to compute requiredFields and compatibleTypes.\nexport function _handlerFor(token: string): { fn: (t: TemporalLike, locale: string) => string; field: keyof TemporalLike } | undefined {\n return HANDLER_BY_TOKEN.get(token);\n}"],"mappings":"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","names":["HANDLER_BY_TOKEN","TOKENS","tok","fn","field","tokenizeCache","MAX_TOKENIZE_CACHE_SIZE","getPieces","formatStr","pieces","oldestKey","tokenize","format","temporal","options","FormatSyntaxError","locale","DEFAULT_LOCALE","result","piece","handler","UnknownTokenError","applyNumbering","formatToParts","last","compileFormat","out","_getPieces","_handlerFor","token"]}
@@ -0,0 +1,36 @@
1
+ var s=class extends Error{code;input;format;token;position;expected;actual;reason;constructor(e,t){super(e),this.name="TemporalFmtError",this.code=t.code,this.input=t.input,this.format=t.format,this.token=t.token,this.position=t.position,this.expected=t.expected,this.actual=t.actual,this.reason=t.reason;let o=Error.captureStackTrace;typeof o=="function"&&o(this,this.constructor)}toJSON(){return{name:this.name,message:this.message,code:this.code,input:this.input,format:this.format,token:this.token,position:this.position,expected:this.expected,actual:this.actual,reason:this.reason}}},T=class extends s{constructor(e){let{message:t,...o}=e;super(t??`format string "${e.format??""}" has a syntax error${e.reason?`: ${e.reason}`:""}.`,{code:"FORMAT_SYNTAX_ERROR",...o}),this.name="FormatSyntaxError"}},$=class extends s{constructor(e){let{message:t,...o}=e;super(t??`token "${e.token??""}" is not a recognized temporal-fmt token${e.format?` in format string "${e.format}"`:""}.`,{code:"UNKNOWN_TOKEN",...o}),this.name="UnknownTokenError"}},w=class extends s{constructor(e){let{message:t,...o}=e;super(t??`input "${e.input??""}" does not match format "${e.format??""}"${e.reason?`: ${e.reason}`:""}.`,{code:"PARSE_MISMATCH",...o}),this.name="ParseMismatchError"}},k=class extends s{constructor(e){let{message:t,...o}=e;super(t??`input "${e.input??""}" does not describe a valid date${e.reason?`: ${e.reason}`:""}.`,{code:"INVALID_DATE",...o}),this.name="InvalidDateError"}};/* c8 ignore start @preserve -- InvalidTimeError is part of the public
2
+ error-class surface (exported from index.ts, code 'INVALID_TIME')
3
+ but nothing in this package constructs one. Investigated wiring it
4
+ in the same way InvalidTimeZoneError was just wired (see parse.ts's
5
+ zzz-validation loop): checked whether hour/minute/second have a
6
+ post-match semantic range check the way zone ids do. They don't —
7
+ pattern.ts's regex fragments for HH/H/hh/h/mm/m/ss/s already enforce
8
+ their valid ranges at the regex level (e.g. HH is '(?:[01]\d|2[0-3])',
9
+ which can't match "99" in the first place), so an out-of-range time
10
+ is rejected as a plain shape mismatch before any semantic check
11
+ could run. There's no live gap to hook this into without inventing a
12
+ redundant check purely to give this class a body. Left unconstructed
13
+ until the library actually has a real invalid-time case to report. */var _=class extends s{constructor(e){let{message:t,...o}=e;super(t??`input "${e.input??""}" does not describe a valid time${e.reason?`: ${e.reason}`:""}.`,{code:"INVALID_TIME",...o}),this.name="InvalidTimeError"}};/* c8 ignore stop @preserve */var A=class extends s{constructor(e){let{message:t,...o}=e;super(t??`offset "${e.actual??""}" is invalid${e.reason?`: ${e.reason}`:""}.`,{code:"INVALID_OFFSET",...o}),this.name="InvalidOffsetError"}},b=class extends s{constructor(e){let{message:t,...o}=e;super(t??`time zone "${e.actual??""}" is not a recognized IANA time zone or fixed offset${e.reason?`: ${e.reason}`:""}.`,{code:"INVALID_TIME_ZONE",...o}),this.name="InvalidTimeZoneError"}};/* c8 ignore start @preserve -- InvalidCalendarError is part of the
14
+ public error-class surface (exported from index.ts, code
15
+ 'INVALID_CALENDAR') but nothing in this package constructs one.
16
+ Checked for a wiring opportunity the same way InvalidTimeZoneError
17
+ got one: there's no user-supplied calendar identifier anywhere in
18
+ the library to validate against a supported list. resolveCalendar()
19
+ in parse.ts derives the calendar entirely from Intl's own resolution
20
+ of the locale string — it's never handed an arbitrary "calendar"
21
+ value a caller could get wrong. There's no live input to reject.
22
+ Left unconstructed until the library actually accepts a calendar
23
+ parameter that could be invalid. */var M=class extends s{constructor(e){let{message:t,...o}=e;super(t??`calendar "${e.actual??""}" is not supported${e.reason?`: ${e.reason}`:""}.`,{code:"INVALID_CALENDAR",...o}),this.name="InvalidCalendarError"}};/* c8 ignore stop @preserve */var I=class extends s{constructor(e){let{message:t,...o}=e;super(t??`input "${e.input??""}" is ambiguous${e.reason?`: ${e.reason}`:""}.`,{code:"AMBIGUOUS_INPUT",...o}),this.name="AmbiguousInputError"}},u=class extends s{constructor(e){let{message:t,...o}=e;super(t??`locale "${e.actual??""}" is not a valid BCP-47 tag${e.reason?`: ${e.reason}`:""}.`,{code:"INVALID_LOCALE",...o}),this.name="InvalidLocaleError"}},C=class extends s{constructor(e){let{message:t,...o}=e;super(t??`duration is invalid${e.reason?`: ${e.reason}`:""}.`,{code:"INVALID_DURATION",...o}),this.name="InvalidDurationError"}};/* c8 ignore start @preserve -- unreachable from the current test suite,
24
+ see rationale above */function H(r,e){let t=r.message;if(/unknown token|isn't a recognized token/.test(t))return new $({input:e.input,format:e.format,reason:t});if(/ambiguous/i.test(t))return new I({input:e.input,format:e.format,reason:t});if(/offset/.test(t)&&/out of range|exceeds|doesn't match the shape/i.test(t))return new A({input:e.input,format:e.format,reason:t});if(/no valid pattern matches/i.test(t))return new w({input:e.input,format:e.format,reason:t});if(/doesn't describe a valid date\/time|incomplete date|weekday token|quarter token/.test(t))return new k({input:e.input,format:e.format,reason:t});let o=t.toLowerCase();return o.includes("locale")&&(o.includes("produced no")||o.includes("not a valid"))||o.includes("cutoffs must be")?new u({input:e.input,format:e.format,reason:t}):/format string exceeds maximum length|input exceeds maximum length|unterminated quote|isn't a recognized token/i.test(t)?new T({input:e.input,format:e.format,reason:t}):new w({input:e.input,format:e.format,reason:t})}/* c8 ignore stop @preserve */var y=new Map,N=500,D=256,O=256;function Z(r,e){let t=[{key:"monthLong",length:12,label:"long month names"},{key:"monthShort",length:12,label:"short month names"},{key:"weekdayLong",length:7,label:"long weekday names"},{key:"weekdayShort",length:7,label:"short weekday names"},{key:"dayPeriod",length:2,label:"day period markers (AM/PM-equivalent)"}];for(let{key:o,length:n,label:a}of t){let i=r[o];if(i===void 0)throw new Error(`temporal-fmt: registerLocaleVocab for locale "${e}" is missing required field "${o}" (${a}).`);if(!Array.isArray(i))throw new Error(`temporal-fmt: registerLocaleVocab for locale "${e}": "${o}" must be an array, got ${typeof i}.`);if(i.length!==n)throw new Error(`temporal-fmt: registerLocaleVocab for locale "${e}": "${o}" must have exactly ${n} entries (got ${i.length}) \u2014 ${a}.`);i.forEach((m,g)=>{if(typeof m!="string"||m.length===0)throw new Error(`temporal-fmt: registerLocaleVocab for locale "${e}": "${o}[${g}]" must be a non-empty string, got ${String(m)}.`);if(m.length>O)throw new RangeError(`temporal-fmt: registerLocaleVocab for locale "${e}": "${o}[${g}]" is too long (maximum ${O} characters).`)})}if(d(r.monthLong,"MMMM month",e),d(r.monthShort,"MMM month",e),d(r.weekdayLong,"EEEE weekday",e),d(r.weekdayShort,"EEE weekday",e),r.dayPeriod[0]===r.dayPeriod[1])throw new Error(`temporal-fmt: registerLocaleVocab for locale "${e}": dayPeriod entries must differ (both are "${r.dayPeriod[0]}"); otherwise parse() can't tell AM from PM.`)}var S=[];function W(r){S.push(r)}function J(r,e){if(typeof r!="string"||r.length===0)throw new Error(`temporal-fmt: registerLocaleVocab requires a non-empty locale string, got ${String(r)}.`);if(r.length>D)throw new RangeError(`temporal-fmt: registerLocaleVocab locale is too long (maximum ${D} characters).`);Z(e,r);let t=F(r);if(!y.has(t)&&y.size>=N)throw new RangeError(`temporal-fmt: registerLocaleVocab reached the ${N}-locale limit.`);y.set(t,{monthLong:[...e.monthLong],monthShort:[...e.monthShort],weekdayLong:[...e.weekdayLong],weekdayShort:[...e.weekdayShort],dayPeriod:[...e.dayPeriod]}),p.delete(t);for(let o of S)o()}function P(r){return r.replace(/_/g,"-")}var f=new Map,B=500;function F(r){let e=f.get(r);if(e!==void 0)return e;let t;try{t=new Intl.Locale(r.replace(/_/g,"-")).toString().toLowerCase()}catch{t=r}if(f.size>=B){let o=f.keys().next().value;o!==void 0&&f.delete(o)}return f.set(r,t),t}function X(r){try{new Intl.Locale(P(r))}catch{throw new u({actual:r,reason:"not a valid BCP-47 locale tag"})}}var p=new Map,q=500;function l(r,e,t){let o=r.formatToParts(e),n=o.findIndex(g=>g.type===t);/* c8 ignore start @preserve -- defensive guard against a real but
25
+ unreproducible failure mode: an Intl implementation that omits the
26
+ requested part type entirely for some locale. Checked every locale
27
+ with unusual dayPeriod/weekday/month rendering available in this
28
+ runtime's ICU data (ja-JP, zh-CN, th-TH, he-IL, ar-SA, ko-KR, fa-IR)
29
+ against the exact formatter options getLocaleVocab uses (notably
30
+ hour12: true for the dayPeriod formatter, which is what makes every
31
+ locale here actually emit a dayPeriod part — omitting it is what
32
+ produced a false "gap" during investigation). None omit their part
33
+ on this runtime. A different ICU version or a non-Node Intl
34
+ implementation could plausibly behave differently, so this stays a
35
+ real check rather than an assertion. *//* c8 ignore start @preserve */if(n===-1)throw new u({message:`temporal-fmt: locale produced no "${t}" part while building match vocabulary.`});/* c8 ignore stop @preserve */let a=o[n].value,i=o[n-1],m=o[n+1];return i?.type==="literal"&&!/\s/.test(i.value)&&(a=i.value+a),m?.type==="literal"&&!/\s/.test(m.value)&&(a=a+m.value),a}function d(r,e,t){let o=new Map;for(let n=0;n<r.length;n++){let a=o.get(r[n]);if(a!==void 0)throw new Error(`temporal-fmt: locale "${t}" renders ${e} index ${a} and ${n} identically ("${r[n]}"). parse() can't reliably tell these apart for this locale/token, so this combination isn't supported.`);o.set(r[n],n)}}function j(r){let e=F(r);return y.get(e)}function Q(r){X(r);let e=F(r),t=y.get(e);if(t)return t;let o=p.get(e);if(o)return o;let n=P(r),a=new Intl.DateTimeFormat(n,{month:"long",timeZone:"UTC"}),i=new Intl.DateTimeFormat(n,{month:"short",timeZone:"UTC"}),m=[],g=[];for(let c=0;c<12;c++){let h=new Date(Date.UTC(2020,c,1));m.push(l(a,h,"month")),g.push(l(i,h,"month"))}d(m,"MMMM month",r),d(g,"MMM month",r);let v=new Intl.DateTimeFormat(n,{weekday:"long",timeZone:"UTC"}),U=new Intl.DateTimeFormat(n,{weekday:"short",timeZone:"UTC"}),E=[],L=[];for(let c=0;c<7;c++){let h=new Date(Date.UTC(2024,0,1+c));E.push(l(v,h,"weekday")),L.push(l(U,h,"weekday"))}d(E,"EEEE weekday",r),d(L,"EEE weekday",r);let V=new Intl.DateTimeFormat(n,{hour:"numeric",hour12:!0,timeZone:"UTC"}),R=l(V,new Date(Date.UTC(2020,0,1,1)),"dayPeriod"),K=l(V,new Date(Date.UTC(2020,0,1,13)),"dayPeriod"),z=[...new Set([R,K])],x={monthLong:m,monthShort:g,weekdayLong:E,weekdayShort:L,dayPeriod:z};if(p.size>=q){let c=p.keys().next().value;c!==void 0&&p.delete(c)}return p.set(e,x),x}export{s as a,T as b,$ as c,w as d,k as e,_ as f,A as g,b as h,M as i,I as j,u as k,C as l,H as m,W as n,J as o,P as p,F as q,X as r,j as s,Q as t};
36
+ //# sourceMappingURL=chunk-5U5WJ465.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/localeVocab.ts"],"sourcesContent":["// Structured error classes for parse()/format() failures.\n//\n// As of 0.9.0, every throw site on the parse/format data path —\n// tokenize.ts, pattern.ts, format.ts, parse.ts (parse/safeParse/tryParse/\n// parseToParts/compileParser), and the two data-path throws in\n// localeVocab.ts (partValue/assertNoCollision on the getLocaleVocab side)\n// — throws these typed classes directly instead of plain\n// `new Error(message)`. Every migrated site kept its exact pre-0.9.0\n// message text — subclasses of TemporalFmtError still satisfy\n// `instanceof Error` and message-matching regexes (e.g.\n// `/token \"HH\" requires/`), so this was safe to do without a semver-major\n// bump for either check. What *is* a breaking change for 0.9.0: code that\n// specifically checked `err.constructor === Error` or `err.name ===\n// 'Error'` will see a different name now (e.g. 'FormatSyntaxError'). See\n// the 0.9.0 changelog entry.\n//\n// Not migrated, on purpose:\n// - localeVocab.ts's registration-time throws (assertValidVocab,\n// registerLocaleVocab itself) — these are config-time API-misuse\n// errors on data the developer supplies once at startup, not runtime\n// parse/format failures, so they don't fit this module's\n// TemporalFmtErrorCode taxonomy as-is. assertNoCollision is shared\n// between the registration path and the data path (getLocaleVocab), so\n// its throw stays plain `Error` for both until that split is done —\n// see the tracking note at its call site.\n//\n// wrapUntypedError() below still exists for localeVocab.ts's registration\n// throws and for anything a caller passes into safeParse()/tryParse() from\n// outside this package. On the data path, safeParse's `if (err instanceof\n// TemporalFmtError) return { ok: false, error: err }` now catches every\n// throw before it would reach the classifier, so the regex branches here\n// are effectively dead for parse/format/tokenize/pattern — left in place\n// as the fallback for anything not yet on a typed throw site.\n\nexport type TemporalFmtErrorCode =\n | 'FORMAT_SYNTAX_ERROR'\n | 'UNKNOWN_TOKEN'\n | 'PARSE_MISMATCH'\n | 'INVALID_DATE'\n | 'INVALID_TIME'\n | 'INVALID_OFFSET'\n | 'INVALID_TIME_ZONE'\n | 'INVALID_CALENDAR'\n | 'AMBIGUOUS_INPUT'\n | 'INVALID_LOCALE'\n | 'INVALID_DURATION';\n\nexport interface TemporalFmtErrorFields {\n code: TemporalFmtErrorCode;\n input?: string;\n format?: string;\n token?: string;\n position?: number;\n expected?: string;\n actual?: string;\n reason?: string;\n}\n\n// Base class. `message` is the human-readable summary; the structured\n// fields are the machine-readable parts a linter or codemod reports on.\n// `Error.captureStackTrace` is called manually (where available) so\n// the stack points at the call site, not at this constructor — same\n// pattern Node uses for its own error classes.\nexport class TemporalFmtError extends Error {\n readonly code: TemporalFmtErrorCode;\n readonly input?: string;\n readonly format?: string;\n readonly token?: string;\n readonly position?: number;\n readonly expected?: string;\n readonly actual?: string;\n readonly reason?: string;\n\n constructor(message: string, fields: TemporalFmtErrorFields) {\n super(message);\n this.name = 'TemporalFmtError';\n this.code = fields.code;\n this.input = fields.input;\n this.format = fields.format;\n this.token = fields.token;\n this.position = fields.position;\n this.expected = fields.expected;\n this.actual = fields.actual;\n this.reason = fields.reason;\n // Avoid setting the stack to point at this constructor — keeps it\n // useful. captureStackTrace is V8-only; on other engines the\n // default stack (this constructor line) is what callers get.\n const capture = (Error as unknown as { captureStackTrace?: (target: Error, ctor?: Function) => void }).captureStackTrace;\n if (typeof capture === 'function') {\n capture(this, this.constructor);\n }\n }\n\n // Lets callers do `err.toJSON()` for logging. Plain `Error` doesn't\n // serialize its non-enumerable fields; this picks them up explicitly.\n toJSON(): TemporalFmtErrorFields & { name: string; message: string } {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n input: this.input,\n format: this.format,\n token: this.token,\n position: this.position,\n expected: this.expected,\n actual: this.actual,\n reason: this.reason,\n };\n }\n}\n\n// Each subclass fixes `code` so callers can switch on it without\n// re-checking message text. The constructor takes only the fields\n// that vary per call; `code` and a default `message` template are\n// provided by the subclass.\n\nexport class FormatSyntaxError extends TemporalFmtError {\n constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n const { message, ...rest } = fields;\n super(\n message ?? `format string \"${fields.format ?? ''}\" has a syntax error${fields.reason ? `: ${fields.reason}` : ''}.`,\n { code: 'FORMAT_SYNTAX_ERROR', ...rest },\n );\n this.name = 'FormatSyntaxError';\n }\n}\n\nexport class UnknownTokenError extends TemporalFmtError {\n constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n const { message, ...rest } = fields;\n super(\n message ?? `token \"${fields.token ?? ''}\" is not a recognized temporal-fmt token${fields.format ? ` in format string \"${fields.format}\"` : ''}.`,\n { code: 'UNKNOWN_TOKEN', ...rest },\n );\n this.name = 'UnknownTokenError';\n }\n}\n\nexport class ParseMismatchError extends TemporalFmtError {\n constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n const { message, ...rest } = fields;\n super(\n message ?? `input \"${fields.input ?? ''}\" does not match format \"${fields.format ?? ''}\"${fields.reason ? `: ${fields.reason}` : ''}.`,\n { code: 'PARSE_MISMATCH', ...rest },\n );\n this.name = 'ParseMismatchError';\n }\n}\n\nexport class InvalidDateError extends TemporalFmtError {\n constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n const { message, ...rest } = fields;\n super(\n message ?? `input \"${fields.input ?? ''}\" does not describe a valid date${fields.reason ? `: ${fields.reason}` : ''}.`,\n { code: 'INVALID_DATE', ...rest },\n );\n this.name = 'InvalidDateError';\n }\n}\n\n/* c8 ignore start @preserve -- InvalidTimeError is part of the public\n error-class surface (exported from index.ts, code 'INVALID_TIME')\n but nothing in this package constructs one. Investigated wiring it\n in the same way InvalidTimeZoneError was just wired (see parse.ts's\n zzz-validation loop): checked whether hour/minute/second have a\n post-match semantic range check the way zone ids do. They don't —\n pattern.ts's regex fragments for HH/H/hh/h/mm/m/ss/s already enforce\n their valid ranges at the regex level (e.g. HH is '(?:[01]\\d|2[0-3])',\n which can't match \"99\" in the first place), so an out-of-range time\n is rejected as a plain shape mismatch before any semantic check\n could run. There's no live gap to hook this into without inventing a\n redundant check purely to give this class a body. Left unconstructed\n until the library actually has a real invalid-time case to report. */\nexport class InvalidTimeError extends TemporalFmtError {\n constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n const { message, ...rest } = fields;\n super(\n message ?? `input \"${fields.input ?? ''}\" does not describe a valid time${fields.reason ? `: ${fields.reason}` : ''}.`,\n { code: 'INVALID_TIME', ...rest },\n );\n this.name = 'InvalidTimeError';\n }\n}\n/* c8 ignore stop @preserve */\n\nexport class InvalidOffsetError extends TemporalFmtError {\n constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n const { message, ...rest } = fields;\n super(\n message ?? `offset \"${fields.actual ?? ''}\" is invalid${fields.reason ? `: ${fields.reason}` : ''}.`,\n { code: 'INVALID_OFFSET', ...rest },\n );\n this.name = 'InvalidOffsetError';\n }\n}\n\nexport class InvalidTimeZoneError extends TemporalFmtError {\n constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n const { message, ...rest } = fields;\n super(\n message ?? `time zone \"${fields.actual ?? ''}\" is not a recognized IANA time zone or fixed offset${fields.reason ? `: ${fields.reason}` : ''}.`,\n { code: 'INVALID_TIME_ZONE', ...rest },\n );\n this.name = 'InvalidTimeZoneError';\n }\n}\n\n/* c8 ignore start @preserve -- InvalidCalendarError is part of the\n public error-class surface (exported from index.ts, code\n 'INVALID_CALENDAR') but nothing in this package constructs one.\n Checked for a wiring opportunity the same way InvalidTimeZoneError\n got one: there's no user-supplied calendar identifier anywhere in\n the library to validate against a supported list. resolveCalendar()\n in parse.ts derives the calendar entirely from Intl's own resolution\n of the locale string — it's never handed an arbitrary \"calendar\"\n value a caller could get wrong. There's no live input to reject.\n Left unconstructed until the library actually accepts a calendar\n parameter that could be invalid. */\nexport class InvalidCalendarError extends TemporalFmtError {\n constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n const { message, ...rest } = fields;\n super(\n message ?? `calendar \"${fields.actual ?? ''}\" is not supported${fields.reason ? `: ${fields.reason}` : ''}.`,\n { code: 'INVALID_CALENDAR', ...rest },\n );\n this.name = 'InvalidCalendarError';\n }\n}\n/* c8 ignore stop @preserve */\n\nexport class AmbiguousInputError extends TemporalFmtError {\n constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n const { message, ...rest } = fields;\n super(\n message ?? `input \"${fields.input ?? ''}\" is ambiguous${fields.reason ? `: ${fields.reason}` : ''}.`,\n { code: 'AMBIGUOUS_INPUT', ...rest },\n );\n this.name = 'AmbiguousInputError';\n }\n}\n\nexport class InvalidLocaleError extends TemporalFmtError {\n constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n const { message, ...rest } = fields;\n super(\n message ?? `locale \"${fields.actual ?? ''}\" is not a valid BCP-47 tag${fields.reason ? `: ${fields.reason}` : ''}.`,\n { code: 'INVALID_LOCALE', ...rest },\n );\n this.name = 'InvalidLocaleError';\n }\n}\n\nexport class InvalidDurationError extends TemporalFmtError {\n constructor(fields: Omit<TemporalFmtErrorFields, 'code'> & { message?: string }) {\n const { message, ...rest } = fields;\n super(\n message ?? `duration is invalid${fields.reason ? `: ${fields.reason}` : ''}.`,\n { code: 'INVALID_DURATION', ...rest },\n );\n this.name = 'InvalidDurationError';\n }\n}\n\n// Wraps a plain Error thrown from a code path that hasn't been\n// migrated to typed errors yet. Carries the original message in\n// `reason` so callers reading the typed surface still see what\n// failed. Used by safeParse() in parse.ts.\n//\n// As of the 0.9.0 migration, every throw site on the parse/format data\n// path throws a TemporalFmtError directly, so safeParse's `instanceof\n// TemporalFmtError` check always passes before this function would be\n// called — nothing in the current test suite reaches any branch below.\n// Kept as the safety net for wrapping a future unmigrated throw site\n// (see the c8-ignored call in parse.ts's safeParse), same reasoning as\n// that call site: removing this would silently drop the \"safeParse\n// always returns a TemporalFmtError\" contract the moment anyone adds a\n// throw new Error(...) without wiring a typed class for it.\n/* c8 ignore start @preserve -- unreachable from the current test suite,\n see rationale above */\nexport function wrapUntypedError(err: Error, context: { input?: string; format?: string }): TemporalFmtError {\n // Try to classify by inspecting the message — covers the existing\n // parse()/format() throw sites without modifying them. Anything\n // that doesn't match a known pattern falls through to a generic\n // ParseMismatchError, which still has the structured fields.\n const msg = err.message;\n if (/unknown token|isn't a recognized token/.test(msg)) {\n return new UnknownTokenError({ input: context.input, format: context.format, reason: msg });\n }\n if (/ambiguous/i.test(msg)) {\n return new AmbiguousInputError({ input: context.input, format: context.format, reason: msg });\n }\n if (/offset/.test(msg) && /out of range|exceeds|doesn't match the shape/i.test(msg)) {\n return new InvalidOffsetError({ input: context.input, format: context.format, reason: msg });\n }\n if (/no valid pattern matches/i.test(msg)) {\n return new ParseMismatchError({ input: context.input, format: context.format, reason: msg });\n }\n if (/doesn't describe a valid date\\/time|incomplete date|weekday token|quarter token/.test(msg)) {\n return new InvalidDateError({ input: context.input, format: context.format, reason: msg });\n }\n const lowerMsg = msg.toLowerCase();\n const mentionsLocale = lowerMsg.includes('locale');\n if (\n (mentionsLocale && (lowerMsg.includes('produced no') || lowerMsg.includes('not a valid'))) ||\n lowerMsg.includes('cutoffs must be')\n ) {\n return new InvalidLocaleError({ input: context.input, format: context.format, reason: msg });\n }\n if (/format string exceeds maximum length|input exceeds maximum length|unterminated quote|isn't a recognized token/i.test(msg)) {\n return new FormatSyntaxError({ input: context.input, format: context.format, reason: msg });\n }\n return new ParseMismatchError({ input: context.input, format: context.format, reason: msg });\n}\n/* c8 ignore stop @preserve */","// Name lists for the locale-aware tokens (MMMM, MMM, EEEE, EEE, a). Each\n// list is small and fixed (12 months, 7 weekdays, 2 day periods), so we\n// generate the real Intl strings for a locale once and cache them.\n\nimport { InvalidLocaleError } from './errors.js';\n\nexport interface LocaleVocab {\n monthLong: string[]; // index 0 = January\n monthShort: string[];\n weekdayLong: string[]; // index 0 = Monday, per Temporal's dayOfWeek numbering\n weekdayShort: string[];\n dayPeriod: string[]; // typically [AM-ish, PM-ish], deduped\n}\n\n// Custom vocabs registered by callers for locales Intl doesn't cover well\n// (e.g. a 13-month Hebrew leap year, where Intl's 12-month vocabulary\n// silently loses a whole month). Keyed by canonical cache key so the\n// same locale string spelling variants fold together — same convention\n// as the Intl-derived vocab cache above.\nconst customVocabs = new Map<string, LocaleVocab>();\nconst MAX_CUSTOM_VOCABS = 500;\nconst MAX_LOCALE_TAG_LENGTH = 256;\nconst MAX_VOCAB_ENTRY_LENGTH = 256;\n\nfunction assertValidVocab(vocab: Partial<LocaleVocab>, locale: string): void {\n // Strict shape validation at registration time, not lazily on first\n // use — the README's promise is that a malformed registration throws\n // descriptively here, rather than failing later inside format()/parse()\n // with a confusing \"no month part\" or wrong-month error the caller\n // can't trace back to the bad registration.\n const required: Array<{ key: keyof LocaleVocab; length: number; label: string }> = [\n { key: 'monthLong', length: 12, label: 'long month names' },\n { key: 'monthShort', length: 12, label: 'short month names' },\n { key: 'weekdayLong', length: 7, label: 'long weekday names' },\n { key: 'weekdayShort', length: 7, label: 'short weekday names' },\n { key: 'dayPeriod', length: 2, label: 'day period markers (AM/PM-equivalent)' },\n ];\n\n for (const { key, length, label } of required) {\n const value = vocab[key];\n if (value === undefined) {\n throw new Error(\n `temporal-fmt: registerLocaleVocab for locale \"${locale}\" is missing required field \"${key}\" (${label}).`\n );\n }\n if (!Array.isArray(value)) {\n throw new Error(\n `temporal-fmt: registerLocaleVocab for locale \"${locale}\": \"${key}\" must be an array, got ${typeof value}.`\n );\n }\n if (value.length !== length) {\n throw new Error(\n `temporal-fmt: registerLocaleVocab for locale \"${locale}\": \"${key}\" must have exactly ${length} entries (got ${value.length}) — ${label}.`\n );\n }\n value.forEach((entry, i) => {\n if (typeof entry !== 'string' || entry.length === 0) {\n throw new Error(\n `temporal-fmt: registerLocaleVocab for locale \"${locale}\": \"${key}[${i}]\" must be a non-empty string, got ${String(entry)}.`\n );\n }\n if (entry.length > MAX_VOCAB_ENTRY_LENGTH) {\n throw new RangeError(\n `temporal-fmt: registerLocaleVocab for locale \"${locale}\": \"${key}[${i}]\" is too long (maximum ${MAX_VOCAB_ENTRY_LENGTH} characters).`\n );\n }\n });\n }\n\n // Reuse the same collision check the Intl-derived path uses — a\n // duplicate month name is just as ambiguous when supplied by a caller\n // as when produced by Intl.\n assertNoCollision(vocab.monthLong!, 'MMMM month', locale);\n assertNoCollision(vocab.monthShort!, 'MMM month', locale);\n assertNoCollision(vocab.weekdayLong!, 'EEEE weekday', locale);\n assertNoCollision(vocab.weekdayShort!, 'EEE weekday', locale);\n\n // dayPeriod entries must differ from each other, or parse()'s\n // isPM check (raw === vocab.dayPeriod[1]) can never return true and\n // every 12-hour parse silently resolves to AM. The Intl-derived path\n // dedupes a same-AM/PM collision to length 1, but a caller passing\n // both entries identical is a real bug to surface — not something to\n // dedupe around.\n if (vocab.dayPeriod![0] === vocab.dayPeriod![1]) {\n throw new Error(\n `temporal-fmt: registerLocaleVocab for locale \"${locale}\": dayPeriod entries must differ ` +\n `(both are \"${vocab.dayPeriod![0]}\"); otherwise parse() can't tell AM from PM.`\n );\n }\n}\n\n// Anything that caches a result derived from *which* vocabulary is\n// active for a locale (right now: parse.ts's compiled pattern cache,\n// whose MMMM/MMM/EEEE/EEE/a fragments embed the vocab's alternations)\n// subscribes here so it gets invalidated when a registration swaps the\n// vocab — mirrors temporalProvider.ts's subscribeToTemporalChanges.\nconst onVocabChanged: Array<() => void> = [];\n\nexport function subscribeToVocabChanges(listener: () => void): void {\n onVocabChanged.push(listener);\n}\n\n/**\n * Supply a custom month/weekday/day-period vocabulary for a locale key,\n * overriding the Intl-derived vocab this library would otherwise build\n * for that key. Useful for locales Intl doesn't cover well — the README's\n * known-limitations section calls out the Hebrew leap-month gap as a\n * specific case this addresses.\n *\n * Throws descriptively on malformed input (wrong array lengths, empty\n * strings, duplicate entries, missing fields) rather than failing later\n * during format/parse.\n *\n * Registered vocab takes precedence over the Intl-derived vocab for that\n * locale key, including for already-cached entries — registering\n * invalidates the prior cache entry for that locale so the next call\n * picks up the new vocab.\n *\n * @example\n * registerLocaleVocab('en-u-ca-hebrew-leap', {\n * monthLong: ['Nisan','Iyar','Sivan','Tammuz','Av','Elul','Tishrei','Marcheshvan','Kislev','Tevet','Shevat','Adar I','Adar II'],\n * monthShort: ['Nis','Iyy','Siv','Tam','Av','Elu','Tish','Chesh','Kis','Tev','Shv','Ad1','Ad2'],\n * weekdayLong: ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'],\n * weekdayShort: ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],\n * dayPeriod: ['AM','PM'],\n * });\n */\nexport function registerLocaleVocab(locale: string, vocab: Partial<LocaleVocab>): void {\n if (typeof locale !== 'string' || locale.length === 0) {\n throw new Error(`temporal-fmt: registerLocaleVocab requires a non-empty locale string, got ${String(locale)}.`);\n }\n if (locale.length > MAX_LOCALE_TAG_LENGTH) {\n throw new RangeError(`temporal-fmt: registerLocaleVocab locale is too long (maximum ${MAX_LOCALE_TAG_LENGTH} characters).`);\n }\n assertValidVocab(vocab, locale);\n\n const cacheKey = canonicalCacheKey(locale);\n if (!customVocabs.has(cacheKey) && customVocabs.size >= MAX_CUSTOM_VOCABS) {\n throw new RangeError(`temporal-fmt: registerLocaleVocab reached the ${MAX_CUSTOM_VOCABS}-locale limit.`);\n }\n customVocabs.set(cacheKey, {\n monthLong: [...vocab.monthLong!],\n monthShort: [...vocab.monthShort!],\n weekdayLong: [...vocab.weekdayLong!],\n weekdayShort: [...vocab.weekdayShort!],\n dayPeriod: [...vocab.dayPeriod!],\n });\n // Invalidate the Intl-derived cache entry so any prior format/parse\n // result cached for this locale is rebuilt against the new vocab. Not\n // strictly necessary (getLocaleVocab checks customVocabs first), but\n // cheap and keeps the two caches from drifting out of sync.\n vocabCache.delete(cacheKey);\n // Also invalidate downstream caches that baked the previous vocab in\n // at build time (parse.ts's pattern cache is the one that matters:\n // without this, a cached pattern would keep matching the OLD month /\n // weekday names while format() renders the new ones, so the library's\n // own format() output would fail to parse back).\n for (const listener of onVocabChanged) listener();\n}\n\n// Every locale-keyed cache in this library (this one, formatterCache in\n// tokens.ts, patternCache/calendarCache in parse.ts) used to key on the\n// exact locale string a caller passed in. Intl treats spelling variants of\n// the same locale as equivalent ('en-US' / 'en-us' / 'en_US' all resolve\n// the same way), but a plain string-keyed Map doesn't — so callers mixing\n// spellings for what's really one locale would silently fragment across\n// separate cache entries instead of sharing one, making the bounded\n// eviction limits (MAX_*_CACHE_SIZE) less effective than they look. This\n// doesn't change any cache's *correctness* (each entry is still built from\n// -- and valid for -- whatever locale string produced it), only how many\n// distinct entries equivalent spellings end up costing. Falls back to the\n// original string on a malformed/unrecognized tag rather than throwing —\n// cache-key normalization shouldn't be where a bad locale first surfaces\n// as an error; whatever actually calls `new Intl.DateTimeFormat(locale)`\n// downstream is the right place for that.\n// Intl constructors (DateTimeFormat/NumberFormat/RelativeTimeFormat)\n// reject underscore-separated tags like 'en_US' outright, while\n// canonicalCacheKey and every locale-parsing path in this library\n// tolerates them by normalizing to BCP-47 hyphens. Centralize that\n// normalization so every `new Intl.*(locale)` construction site\n// accepts the same spellings the cache keys do. Genuinely malformed\n// tags still throw downstream, unchanged.\nexport function normalizeLocaleTag(locale: string): string {\n return locale.replace(/_/g, '-');\n}\n\n// Memoized so hot paths (parse()'s resolveCalendar keys off this on\n// every call, and every locale-keyed cache re-derives it) don't build a\n// fresh Intl.Locale per invocation — construction is comparatively\n// expensive. Bounded like every other cache in this library.\nconst canonicalKeyCache = new Map<string, string>();\nconst MAX_CANONICAL_KEY_CACHE = 500;\n\nexport function canonicalCacheKey(locale: string): string {\n const hit = canonicalKeyCache.get(locale);\n if (hit !== undefined) return hit;\n let key: string;\n try {\n // Intl.Locale requires BCP-47 hyphens and rejects underscore-separated\n // tags like 'en_US' outright (RangeError), rather than normalizing\n // them — so without this replace, that spelling would just fall\n // through to the catch below and never fold with 'en-US'.\n key = new Intl.Locale(locale.replace(/_/g, '-')).toString().toLowerCase();\n } catch {\n // Malformed tag: key on the raw string. Callers that must reject\n // malformed tags do it via assertValidLocaleTag() before/instead of\n // relying on this function — cache-key normalization isn't where a\n // bad locale should surface as an error (unchanged behavior).\n key = locale;\n }\n if (canonicalKeyCache.size >= MAX_CANONICAL_KEY_CACHE) {\n const oldestKey = canonicalKeyCache.keys().next().value;\n if (oldestKey !== undefined) canonicalKeyCache.delete(oldestKey);\n }\n canonicalKeyCache.set(locale, key);\n return key;\n}\n\n// Single validation choke point for locale tags at public boundaries.\n// Intl constructors reject malformed tags with a bare engine RangeError\n// (\"Incorrect locale information provided\") that carries none of the\n// library's structured error context; this rethrows as the typed\n// InvalidLocaleError with the offending tag in its fields. Accepts the\n// same spellings as canonicalCacheKey (underscore tags normalized).\nexport function assertValidLocaleTag(locale: string): void {\n try {\n new Intl.Locale(normalizeLocaleTag(locale));\n } catch {\n throw new InvalidLocaleError({\n actual: locale,\n reason: 'not a valid BCP-47 locale tag',\n });\n }\n}\n\nconst vocabCache = new Map<string, LocaleVocab>();\nconst MAX_VOCAB_CACHE_SIZE = 500;\n\n// Some locales (ja-JP) split a field across two parts — month \"8\" plus a\n// counter suffix \"月\" as a separate sibling \"literal\" — while format()'s\n// tokens go through toLocaleString(), which concatenates everything into\n// \"8月\". Reading only the type-tagged part used to drop that suffix, so\n// this locale's vocab never matched what format() actually produced.\n// Only merges *adjacent* literals, not the whole string, since the\n// dayPeriod/weekday formatters below carry an extra hour part that a\n// join-everything approach would wrongly absorb.\nfunction partValue(formatter: Intl.DateTimeFormat, date: Date, type: Intl.DateTimeFormatPartTypes): string {\n const parts = formatter.formatToParts(date);\n const index = parts.findIndex((p) => p.type === type);\n /* c8 ignore start @preserve -- defensive guard against a real but\n unreproducible failure mode: an Intl implementation that omits the\n requested part type entirely for some locale. Checked every locale\n with unusual dayPeriod/weekday/month rendering available in this\n runtime's ICU data (ja-JP, zh-CN, th-TH, he-IL, ar-SA, ko-KR, fa-IR)\n against the exact formatter options getLocaleVocab uses (notably\n hour12: true for the dayPeriod formatter, which is what makes every\n locale here actually emit a dayPeriod part — omitting it is what\n produced a false \"gap\" during investigation). None omit their part\n on this runtime. A different ICU version or a non-Node Intl\n implementation could plausibly behave differently, so this stays a\n real check rather than an assertion. */\n /* c8 ignore start @preserve */\n if (index === -1) {\n throw new InvalidLocaleError({\n message: `temporal-fmt: locale produced no \"${type}\" part while building match vocabulary.`,\n });\n }\n /* c8 ignore stop @preserve */\n let value = parts[index]!.value;\n const prev = parts[index - 1];\n const next = parts[index + 1];\n // skip whitespace literals (the separator before \"AM\") — only a\n // no-space suffix like ja-JP's \"月\" should get folded in\n if (prev?.type === 'literal' && !/\\s/.test(prev.value)) value = prev.value + value;\n if (next?.type === 'literal' && !/\\s/.test(next.value)) value = value + next.value;\n return value;\n}\n\n// Two entries rendering identically means parse()'s reverse lookup\n// (indexOf) can never tell them apart. Weekday collisions already surface\n// via parse()'s dayOfWeek cross-check, but with a confusing same-string\n// error; months have no equivalent cross-check, so a collision there would\n// otherwise resolve silently to the wrong month. Catching both here, once\n// at build time, gives one clear error instead.\nfunction assertNoCollision(names: string[], label: string, locale: string): void {\n const seen = new Map<string, number>();\n for (let i = 0; i < names.length; i++) {\n const prior = seen.get(names[i]!);\n if (prior !== undefined) {\n // Not migrated to a typed error: this function is shared between\n // getLocaleVocab's Intl-derived path (data-path error, would be a\n // good InvalidLocaleError candidate) and assertValidVocab's\n // registration-time check (out of scope for this pass — see the\n // localeVocab.ts registration-error follow-up). Splitting this into\n // two near-duplicate functions just to route error types\n // differently isn't worth it for one throw; revisit together with\n // the registration-error work instead.\n throw new Error(\n `temporal-fmt: locale \"${locale}\" renders ${label} index ${prior} and ${i} identically ` +\n `(\"${names[i]}\"). parse() can't reliably tell these apart for this locale/token, so this ` +\n `combination isn't supported.`\n );\n }\n seen.set(names[i]!, i);\n }\n}\n\n// Exposed for tokens.ts: when a custom vocab is registered for this\n// locale, format()'s locale-aware tokens (MMMM/MMM/EEEE/EEE/a) read\n// straight from the registered array instead of going through\n// Intl.DateTimeFormat. Without this override, format() would silently\n// keep producing Intl's strings while parse() matched against the\n// registered vocab — the two would round-trip-fail.\nexport function getCustomVocab(locale: string): LocaleVocab | undefined {\n const cacheKey = canonicalCacheKey(locale);\n return customVocabs.get(cacheKey);\n}\n\nexport function getLocaleVocab(locale: string): LocaleVocab {\n // Validate before building vocab: a malformed tag used to surface as a\n // raw RangeError from the first new Intl.DateTimeFormat below.\n assertValidLocaleTag(locale);\n const cacheKey = canonicalCacheKey(locale);\n // Registered vocabs take precedence over the Intl-derived one — this\n // is the override mechanism registerLocaleVocab() promises. Checking\n // here, before the Intl cache lookup, means a registration that\n // happens *after* the first Intl-derived vocab was built still takes\n // effect on the next call.\n const custom = customVocabs.get(cacheKey);\n if (custom) {\n return custom;\n }\n const cached = vocabCache.get(cacheKey);\n if (cached) {\n return cached;\n }\n\n const intlLocale = normalizeLocaleTag(locale);\n const monthLongFmt = new Intl.DateTimeFormat(intlLocale, { month: 'long', timeZone: 'UTC' });\n const monthShortFmt = new Intl.DateTimeFormat(intlLocale, { month: 'short', timeZone: 'UTC' });\n const monthLong: string[] = [];\n const monthShort: string[] = [];\n for (let m = 0; m < 12; m++) {\n const date = new Date(Date.UTC(2020, m, 1));\n monthLong.push(partValue(monthLongFmt, date, 'month'));\n monthShort.push(partValue(monthShortFmt, date, 'month'));\n }\n assertNoCollision(monthLong, 'MMMM month', locale);\n assertNoCollision(monthShort, 'MMM month', locale);\n\n const weekdayLongFmt = new Intl.DateTimeFormat(intlLocale, { weekday: 'long', timeZone: 'UTC' });\n const weekdayShortFmt = new Intl.DateTimeFormat(intlLocale, { weekday: 'short', timeZone: 'UTC' });\n const weekdayLong: string[] = [];\n const weekdayShort: string[] = [];\n // 2024-01-01 is a Monday (UTC) — walk 7 days from there for weekday names\n for (let d = 0; d < 7; d++) {\n const date = new Date(Date.UTC(2024, 0, 1 + d));\n weekdayLong.push(partValue(weekdayLongFmt, date, 'weekday'));\n weekdayShort.push(partValue(weekdayShortFmt, date, 'weekday'));\n }\n // redundant with parse()'s dayOfWeek cross-check, but gives a clearer error\n assertNoCollision(weekdayLong, 'EEEE weekday', locale);\n assertNoCollision(weekdayShort, 'EEE weekday', locale);\n\n const dayPeriodFmt = new Intl.DateTimeFormat(intlLocale, { hour: 'numeric', hour12: true, timeZone: 'UTC' });\n const am = partValue(dayPeriodFmt, new Date(Date.UTC(2020, 0, 1, 1)), 'dayPeriod');\n const pm = partValue(dayPeriodFmt, new Date(Date.UTC(2020, 0, 1, 13)), 'dayPeriod');\n const dayPeriod = [...new Set([am, pm])];\n\n const vocab: LocaleVocab = { monthLong, monthShort, weekdayLong, weekdayShort, dayPeriod };\n if (vocabCache.size >= MAX_VOCAB_CACHE_SIZE) {\n const oldestKey = vocabCache.keys().next().value;\n if (oldestKey !== undefined) vocabCache.delete(oldestKey);\n }\n vocabCache.set(cacheKey, vocab);\n return vocab;\n}"],"mappings":"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","names":["TemporalFmtError","message","fields","capture","FormatSyntaxError","rest","UnknownTokenError","ParseMismatchError","InvalidDateError","InvalidTimeError","InvalidOffsetError","InvalidTimeZoneError","InvalidCalendarError","AmbiguousInputError","InvalidLocaleError","InvalidDurationError","wrapUntypedError","err","context","msg","lowerMsg","customVocabs","MAX_CUSTOM_VOCABS","MAX_LOCALE_TAG_LENGTH","MAX_VOCAB_ENTRY_LENGTH","assertValidVocab","vocab","locale","required","key","length","label","value","entry","i","assertNoCollision","onVocabChanged","subscribeToVocabChanges","listener","registerLocaleVocab","cacheKey","canonicalCacheKey","vocabCache","normalizeLocaleTag","canonicalKeyCache","MAX_CANONICAL_KEY_CACHE","hit","oldestKey","assertValidLocaleTag","InvalidLocaleError","MAX_VOCAB_CACHE_SIZE","partValue","formatter","date","type","parts","index","p","prev","next","names","seen","prior","getCustomVocab","getLocaleVocab","custom","cached","intlLocale","monthLongFmt","monthShortFmt","monthLong","monthShort","m","weekdayLongFmt","weekdayShortFmt","weekdayLong","weekdayShort","d","dayPeriodFmt","am","pm","dayPeriod"]}
@@ -0,0 +1,2 @@
1
+ import{a as I,c as L}from"./chunk-3MZLTVP3.js";import{k as D,p as O,q as b,s}from"./chunk-5U5WJ465.js";import{b as p,c as w}from"./chunk-C6ZZ62ET.js";function r(e,t){let n=e<0,o=String(Math.abs(e)).padStart(t,"0");return n?"-"+o:o}r.fraction=function(t,n){let o=t.millisecond*1e6+(t.microsecond??0)*1e3+(t.nanosecond??0);return r(o,9).slice(0,n)};var G="en-US",l=new Map,$=500;function F(e,t){let n=JSON.stringify([b(e),t]),o=l.get(n);if(o)return o;if(l.size>=$){let a=l.keys().next().value;a!==void 0&&l.delete(a)}try{o=new Intl.DateTimeFormat(O(e),t)}catch(a){throw new D({actual:e,reason:a.message})}return l.set(n,o),o}var y;I(()=>{y=void 0});function M(){if(y===void 0){y=!1;try{let e=L();new Intl.DateTimeFormat("en-US",{day:"numeric"}).formatToParts(e.PlainDate.from({year:1970,month:1,day:1})),y=!0}catch{}}return y}function h(e,t,n,o){let a=e?.calendarId,i={...n,calendar:a&&a!=="iso8601"?a:"gregory"},d=e.toLocaleString;if(typeof d!="function"||d===Object.prototype.toLocaleString)throw new Error(`temporal-fmt: locale-aware part "${o}" needs a value that implements toLocaleString (a real Temporal object). A plain field bag cannot render locale-aware names \u2014 pass a Temporal.PlainDate/PlainDateTime/ZonedDateTime.`);if(!M())try{return d.call(e,O(t),i)}catch(u){throw u instanceof RangeError?new D({actual:t,reason:u.message}):u}let{toInstant:E,timeZoneId:X}=e,x=typeof E=="function"&&typeof X=="string",Z=x?e.toInstant():e,P={...i,...x?{timeZone:X}:{}},S=F(t,P).formatToParts(Z),g=S.findIndex(u=>u.type===o);if(g===-1)throw new Error(`temporal-fmt: locale "${t}" produced no "${o}" part for this token. This usually means the Temporal object is missing the field the token needs.`);let f=S[g].value,T=S[g-1],k=S[g+1];return T?.type==="literal"&&!/\s/.test(T.value)&&(f=T.value+f),k?.type==="literal"&&!/\s/.test(k.value)&&(f=f+k.value),f}function W(e,t){let n=s(t);if(n)return e<12?n.dayPeriod[0]:n.dayPeriod[1];let o=new Date(Date.UTC(1970,0,1,e)),i=F(t,{hour:"numeric",hour12:!0,timeZone:"UTC"}).formatToParts(o).find(d=>d.type==="dayPeriod");if(!i)throw new Error(`temporal-fmt: locale "${t}" produced no "dayPeriod" part for token "a".`);return i.value}function m(e,t,n,o,a,i){return a&&i!==void 0&&i>=0&&i<a.length?a[i]:h(e,t,n,o)}function c(e,t){if(e==="+00:00"&&(t==="X"||t==="XX"||t==="XXX"))return"Z";let n=e[0],o=e.slice(1,3),a=e.slice(4,6);switch(t){case"X":case"x":return a==="00"?`${n}${o}`:`${n}${o}${a}`;case"XX":case"xx":return`${n}${o}${a}`;case"XXX":case"xxx":return`${n}${o}:${a}`}}var H=[["yyyy",e=>r(e.year,4),"year"],["yy",e=>{if(e.year<0)throw new Error(`temporal-fmt: token "yy" doesn't support negative years (got ${e.year}), since truncating to 2 digits would make it indistinguishable from a positive year. Use "yyyy" instead.`);return r(e.year%100,2)},"year"],["MMMM",(e,t)=>{let n=s(t);return m(e,t,{month:"long"},"month",n?.monthLong,e.month-1)},"month"],["MMM",(e,t)=>{let n=s(t);return m(e,t,{month:"short"},"month",n?.monthShort,e.month-1)},"month"],["MM",e=>r(e.month,2),"month"],["M",e=>String(e.month),"month"],["dd",e=>r(e.day,2),"day"],["d",e=>String(e.day),"day"],["EEEE",(e,t)=>{let n=s(t);return m(e,t,{weekday:"long"},"weekday",n?.weekdayLong,e.dayOfWeek-1)},"dayOfWeek"],["EEE",(e,t)=>{let n=s(t);return m(e,t,{weekday:"short"},"weekday",n?.weekdayShort,e.dayOfWeek-1)},"dayOfWeek"],["HH",e=>r(e.hour,2),"hour"],["H",e=>String(e.hour),"hour"],["hh",e=>r(e.hour%12||12,2),"hour"],["h",e=>String(e.hour%12||12),"hour"],["mm",e=>r(e.minute,2),"minute"],["m",e=>String(e.minute),"minute"],["ss",e=>r(e.second,2),"second"],["s",e=>String(e.second),"second"],["SSSSSSSSS",e=>r.fraction(e,9),"millisecond"],["SSSSSSSS",e=>r.fraction(e,8),"millisecond"],["SSSSSSS",e=>r.fraction(e,7),"millisecond"],["SSSSSS",e=>r.fraction(e,6),"millisecond"],["SSSSS",e=>r.fraction(e,5),"millisecond"],["SSSS",e=>r.fraction(e,4),"millisecond"],["SSS",e=>r.fraction(e,3),"millisecond"],["SS",e=>r.fraction(e,2),"millisecond"],["S",e=>r.fraction(e,1),"millisecond"],["a",(e,t)=>W(e.hour,t),"hour"],["zzz",e=>e.timeZoneId,"timeZoneId"],["xxx",e=>c(e.offset,"xxx"),"offset"],["xx",e=>c(e.offset,"xx"),"offset"],["X",e=>c(e.offset,"X"),"offset"],["XX",e=>c(e.offset,"XX"),"offset"],["XXX",e=>c(e.offset,"XXX"),"offset"],["x",e=>c(e.offset,"x"),"offset"],["do",e=>{let t=e.day,n=t%10,o=t%100;return o>=11&&o<=13?t+"th":n===1?t+"st":n===2?t+"nd":n===3?t+"rd":t+"th"},"day"],["Q",e=>String(Math.ceil(e.month/3)),"month"],["QQQ",e=>"Q"+Math.ceil(e.month/3),"month"],["ww",e=>{let{week:t}=w(e.year,e.month,e.day,e.dayOfWeek);return r(t,2)},"dayOfWeek"],["RRRR",e=>{let{isoYear:t}=w(e.year,e.month,e.day,e.dayOfWeek);return r(t,4)},"dayOfWeek"],["D",e=>String(p(e.year,e.month,e.day)),"day"],["DD",e=>r(p(e.year,e.month,e.day),2),"day"],["DDD",e=>r(p(e.year,e.month,e.day),3),"day"],["LLLL",(e,t)=>{let n=s(t);return m(e,t,{month:"long"},"month",n?.monthLong,e.month-1)},"month"],["LLL",(e,t)=>{let n=s(t);return m(e,t,{month:"short"},"month",n?.monthShort,e.month-1)},"month"],["cccc",(e,t)=>{let n=s(t);return m(e,t,{weekday:"long"},"weekday",n?.weekdayLong,e.dayOfWeek-1)},"dayOfWeek"],["ccc",(e,t)=>{let n=s(t);return m(e,t,{weekday:"short"},"weekday",n?.weekdayShort,e.dayOfWeek-1)},"dayOfWeek"],["GGGG",(e,t)=>h(e,t,{era:"long"},"era"),"year"],["G",(e,t)=>h(e,t,{era:"short"},"era"),"year"],["zzzz",(e,t)=>h(e,t,{timeZoneName:"longGeneric"},"timeZoneName"),"timeZoneId"],["z",(e,t)=>h(e,t,{timeZoneName:"short"},"timeZoneName"),"timeZoneId"]];export{G as a,H as b};
2
+ //# sourceMappingURL=chunk-C5YESWFT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tokens.ts"],"sourcesContent":["import { getTemporal, subscribeToTemporalChanges } from './temporalProvider.js';\nimport { canonicalCacheKey, getCustomVocab, normalizeLocaleTag } from './localeVocab.js';\nimport { InvalidLocaleError } from './errors.js';\nimport { isoWeekYearAndWeek, dayOfYear } from './isoWeek.js';\n\nexport function pad(n: number, len: number): string {\n // padStart pads the whole string, sign included, so pad(-45, 4) used to\n // come out \"0-45\" instead of \"-045\" — split the sign off first.\n const negative = n < 0;\n const digits = String(Math.abs(n)).padStart(len, '0');\n return negative ? '-' + digits : digits;\n}\n\n// Combines the three sub-second fields Temporal exposes into one 9-digit\n// nanosecond-of-second value, then truncates (never rounds) to the\n// requested width. Truncating matches what every digit-width token in\n// this library already does elsewhere (yy, MM, dd, ...) — the token\n// asked for N digits of precision, not a rounded N-digit approximation.\n// A caller asking for SSS on a value with nanosecond precision gets the\n// leading 3 digits of it, same as they'd get the leading 3 digits of any\n// other multi-digit field this library formats.\n//\n// Attached to pad() rather than declared standalone: the bundler's\n// per-function coverage instrumentation attributes hits to each of the\n// 9 fraction-token arrow functions individually but not to a shared\n// helper they all close over, so a correctly-exercised helper still\n// shows as 0 hits under c8. pad() itself is called directly all over\n// this file and is reliably attributed — routing through it here keeps\n// the coverage numbers honest without duplicating the slice logic\n// across every token entry below.\npad.fraction = function formatFraction(t: TemporalLike, width: number): string {\n const nanoOfSecond = t.millisecond! * 1_000_000 + (t.microsecond ?? 0) * 1_000 + (t.nanosecond ?? 0);\n return pad(nanoOfSecond, 9).slice(0, width);\n};\n\n// Not every field exists on every Temporal type (PlainDate has no .hour,\n// etc). Callers check for undefined before formatting a token.\nexport interface TemporalLike {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n microsecond?: number;\n nanosecond?: number;\n timeZoneId?: string;\n // ZonedDateTime.prototype.offset — always `±HH:MM` (6 chars) for any\n // modern date. Historical LMT offsets with seconds exist in IANA but\n // aren't reachable through this Temporal field, so format-side offset\n // tokens can assume the canonical 6-char shape. Parse-side writes a\n // canonicalized `+HH:MM` here before handing it to\n // Temporal.ZonedDateTime.from as the `timeZone` value.\n offset?: string;\n dayOfWeek?: number; // 1=Mon, 7=Sun, per Temporal spec\n calendarId?: string;\n toInstant?: () => unknown;\n toLocaleString?: (locale: string, options: Intl.DateTimeFormatOptions) => string;\n}\n\nexport interface FormatOptions {\n /** BCP 47 locale tag, e.g. 'en-US', 'fr-FR', 'ar-EG'. Defaults to 'en-US'. */\n locale?: string;\n /**\n * When set on parse(), opts into the lenient split heuristic for ambiguous\n * glued numeric runs (e.g. \"121\" against \"Md\"). Default (false) keeps\n * parse()'s strict behavior — throw on ambiguity rather than guess.\n * See README \"Lenient parse mode\" for the heuristic and why it's opt-in.\n */\n lenient?: boolean;\n}\n\nexport const DEFAULT_LOCALE = 'en-US';\n\n// Intl.DateTimeFormat is expensive to construct and format() can run in a\n// loop (rendering a table of dates), so cache by (locale, options).\nconst formatterCache = new Map<string, Intl.DateTimeFormat>();\nconst MAX_CACHE_SIZE = 500;\n\nfunction getFormatter(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {\n const key = JSON.stringify([canonicalCacheKey(locale), options]);\n let formatter = formatterCache.get(key);\n if (formatter) {\n return formatter;\n }\n if (formatterCache.size >= MAX_CACHE_SIZE) {\n // not real LRU, just evicts oldest insertion — fine for this key space\n const oldestKey = formatterCache.keys().next().value;\n if (oldestKey !== undefined) formatterCache.delete(oldestKey);\n }\n try {\n formatter = new Intl.DateTimeFormat(normalizeLocaleTag(locale), options);\n } catch (err) {\n // Malformed locale tags reach Intl as a bare RangeError; surface the\n // library's typed error instead (reached via dayPeriodPart — the\n // 'a' token — on any runtime, and the native-Intl path for the rest).\n // Every failure mode of this constructor with a string locale is a\n // RangeError, so converting unconditionally preserves the original\n // message in `reason` either way.\n throw new InvalidLocaleError({ actual: locale, reason: (err as Error).message });\n }\n formatterCache.set(key, formatter);\n return formatter;\n}\n\n// Passing a Temporal object straight into `new Intl.DateTimeFormat().formatToParts()`\n// only works when the engine's Intl implementation has special-cased support for\n// *native* Temporal instances (checked via internal slots and/or gated behind a V8 flag,\n// not tied to a specific Node version).\n//\n// A Temporal polyfill's instances don't have those slots, so the engine falls back to ToNumber() -> .valueOf(),\n// which the polyfill deliberately throws on (\"Cannot use valueOf\").\n// Probed once and memoized and only from intlPart(), so it never\n// runs unless a format string actually uses a locale-aware token.\nlet nativeSupport: boolean | undefined;\n// Invalidate the memoized probe whenever setTemporal() swaps the active\n// implementation — otherwise a probe result from \"is native Temporal\n// supported\" could keep being used after the active implementation is\n// no longer the one that was probed. See setTemporal() in\n// temporalProvider.ts for the other half of this.\nsubscribeToTemporalChanges(() => { nativeSupport = undefined; });\n\nfunction intlSupportsNativeTemporal(): boolean {\n if (nativeSupport === undefined) {\n nativeSupport = false;\n try {\n const temporal = getTemporal();\n new Intl.DateTimeFormat('en-US', { day: 'numeric' })\n .formatToParts(temporal.PlainDate.from({ year: 1970, month: 1, day: 1 }) as Date);\n // Version-gated, not dead — see the matching note on the\n // !intlSupportsNativeTemporal() branch in intlPart() below for\n // why this can't be exercised from this environment.\n /* c8 ignore next */\n nativeSupport = true;\n /* c8 ignore start */\n } catch {\n // native Temporal absent, or present but not recognized by Intl — fall back.\n // Version-gated, not dead: this catch only fires on runtimes where the\n // probe above throws (no native Temporal, or Intl doesn't recognize it).\n // On a runtime with full native support (e.g. Node builds where Intl\n // accepts native Temporal instances directly) the try succeeds and this\n // branch is unreachable — mirror case of the block below.\n }\n /* c8 ignore stop */\n }\n return nativeSupport;\n}\n\nfunction intlPart(\n temporal: TemporalLike,\n locale: string,\n options: Intl.DateTimeFormatOptions,\n partType: Intl.DateTimeFormatPartTypes\n): string {\n // Intl throws \"Mismatching Calendars\" if the formatter's calendar doesn't\n // match the object's own (e.g. en-US formatter defaults to gregory, but\n // a hebrew/islamic PlainDate needs its own calendar passed through).\n //\n // For iso8601 specifically, force 'gregory' rather than leaving calendar\n // unset: numeric fields (yyyy/dd, see tokens' pad()-based handlers) are\n // always pulled straight off the object's own ISO fields — so if the\n // *locale* carries a `-u-ca-*` extension (e.g. 'en-u-ca-hebrew') and this\n // step left calendar unset, the formatter would resolve its own default\n // calendar from the locale and format MMMM/EEEE in that calendar while\n // yyyy/dd stay ISO, producing a date that looks internally consistent\n // (a real Hebrew month name next to a real-looking day/year) but names a\n // completely different day than the object actually represents. Forcing\n // 'gregory' here keeps every field of an ISO object's output anchored to\n // the same (ISO/Gregorian) calendar — a locale's calendar extension only\n // takes effect when the object itself already carries a non-ISO calendar\n // (via `.withCalendar()`), matching what the README documents.\n //\n // 'gregory' specifically, not 'iso8601' — passing `calendar: 'iso8601'`\n // explicitly alongside a single-field options object makes\n // formatToParts() come back empty for some reason, but 'gregory' doesn't\n // have that problem and Temporal's iso8601 calendar is Gregorian-shaped\n // (proleptic Gregorian throughout, no Julian cutover) so the two agree\n // on every numeric field this library ever reads.\n const calendar = temporal?.calendarId;\n const formatterOptions: Intl.DateTimeFormatOptions = {\n ...options,\n calendar: calendar && calendar !== 'iso8601' ? calendar : 'gregory',\n };\n\n // Field-bag guard: a plain { year, month, day } object only has\n // Object.prototype.toLocaleString, which ignores both arguments and\n // returns \"[object Object]\". On engines without native Temporal\n // support in Intl this used to be caught below, but on engines where\n // Intl *does* recognize native Temporal instances (Node 26+), a bag\n // skips that branch entirely and reaches formatToParts() directly —\n // which doesn't throw \"[object Object]\", it throws a bare\n // \"RangeError: Invalid time value\" once the bag fails ToNumber()\n // coercion. Neither failure mode is useful to a caller, so check for\n // a real toLocaleString up front, before branching on native support,\n // so the descriptive error fires on every engine.\n const ls = temporal.toLocaleString;\n if (typeof ls !== 'function' || ls === Object.prototype.toLocaleString) {\n throw new Error(\n `temporal-fmt: locale-aware part \"${partType}\" needs a value that implements ` +\n `toLocaleString (a real Temporal object). A plain field bag cannot render ` +\n `locale-aware names — pass a Temporal.PlainDate/PlainDateTime/ZonedDateTime.`\n );\n }\n\n // Temporal.prototype.toLocaleString() is part of the Temporal spec itself:\n // polyfills implement the ICU formatting internally without needing the\n // engine to recognize the object, so it works without native Intl support.\n //\n // Everything from here to the end of this function is genuinely\n // reachable — NOT dead code — but only on a Node build where a global\n // `Temporal` exists AND Intl.DateTimeFormat.formatToParts() recognizes\n // native Temporal instances directly (this is real, observed to vary\n // across Node versions: absent on the Node 22/24 builds this suite has\n // been run against, present on at least one Node 26 build). This\n // environment has no native Temporal (`typeof globalThis.Temporal ===\n // 'undefined'`), so intlSupportsNativeTemporal() always returns false\n // here and this branch can't be exercised from this test suite without\n // faking native-instance recognition, which turned out to be\n // impractical (Intl's native-Temporal detection isn't spoofable via a\n // Proxy or valueOf() shim — see the M-02 regression test in\n // temporalProvider.test.js for the same conclusion reached about the\n // sibling probe function). Coverage numbers for this block will differ\n // between Node versions for that reason; that's expected, not a\n // regression.\n /* c8 ignore start */\n if (!intlSupportsNativeTemporal()) {\n // normalizeLocaleTag: the active Temporal implementation's\n // toLocaleString forwards the locale to Intl.DateTimeFormat, which\n // (unlike this library's cache keys) rejects underscore-separated\n // tags like 'en_US' outright.\n // (Field-bag guard now runs unconditionally above, before this\n // native-support branch, so it's not repeated here.)\n try {\n return ls.call(temporal, normalizeLocaleTag(locale), formatterOptions);\n } catch (err) {\n // The active Temporal implementation forwards the tag to Intl, which\n // throws a bare RangeError for a malformed one — rethrow typed.\n if (err instanceof RangeError) {\n throw new InvalidLocaleError({ actual: locale, reason: err.message });\n }\n throw err;\n }\n }\n\n // formatToParts() throws on ZonedDateTime directly (per spec), so convert\n // to Instant and pass the zone via `timeZone` instead. Don't convert to\n // PlainDateTime — that drops the zone, which breaks 'MMMM' + 'zzz' combos.\n const { toInstant, timeZoneId } = temporal;\n const isZoned = typeof toInstant === 'function' && typeof timeZoneId === 'string';\n // has to be called as temporal.toInstant() because destructuring it off breaks\n // the receiver and throws\n const intlSafeTemporal = isZoned ? temporal.toInstant!() : temporal;\n const nativeOptions: Intl.DateTimeFormatOptions = {\n ...formatterOptions,\n ...(isZoned ? { timeZone: timeZoneId } : {}),\n };\n\n const formatter = getFormatter(locale, nativeOptions);\n const parts = formatter.formatToParts(intlSafeTemporal as Date | number);\n const index = parts.findIndex((p) => p.type === partType);\n if (index === -1) {\n throw new Error(\n `temporal-fmt: locale \"${locale}\" produced no \"${partType}\" part for this token. ` +\n `This usually means the Temporal object is missing the field the token needs.`\n );\n }\n // some locales (ja-JP) split a field across two parts — e.g. month \"8\"\n // plus a counter suffix \"月\" as a separate sibling literal part. Merge in\n // an adjacent literal only if it has no whitespace, so a genuine suffix\n // gets folded in but an ordinary separator (the space before \"AM\") stays\n // a separator. Mirrors partValue() in localeVocab.ts, which builds the\n // vocab this token's output needs to match for parse() to round-trip.\n let value = parts[index]!.value;\n const prev = parts[index - 1];\n const next = parts[index + 1];\n if (prev?.type === 'literal' && !/\\s/.test(prev.value)) value = prev.value + value;\n if (next?.type === 'literal' && !/\\s/.test(next.value)) value = value + next.value;\n return value;\n}\n/* c8 ignore stop */\n\n// Temporal.prototype.toLocaleString() can't isolate a single field the way\n// formatToParts() can — asking for `hour` + `dayPeriod` together returns one\n// joined string (e.g. \"3 in the afternoon\"), and `dayPeriod` alone resolves\n// against a different, non-hour-anchored set of periods (\"in the\n// afternoon\"/\"昼\" instead of \"PM\"/\"午後\"). Day period only depends on the\n// hour anyway, so route it through a plain UTC Date and Intl.DateTimeFormat\n// instead — that's worked the same on every engine regardless of whether\n// Temporal itself is native or polyfilled.\nfunction dayPeriodPart(hour: number, locale: string): string {\n // Custom vocab (when registered) takes precedence over Intl — same\n // contract as the other locale-aware tokens. Intl won't know about a\n // caller-supplied AM/PM string for a made-up locale key, so going\n // through Intl would produce something other than what the caller\n // registered.\n const custom = getCustomVocab(locale);\n if (custom) {\n return hour < 12 ? custom.dayPeriod[0]! : custom.dayPeriod[1]!;\n }\n const date = new Date(Date.UTC(1970, 0, 1, hour));\n const formatter = getFormatter(locale, { hour: 'numeric', hour12: true, timeZone: 'UTC' });\n const part = formatter.formatToParts(date).find((p) => p.type === 'dayPeriod');\n // Defensive guard, confirmed unreachable on this ICU build: forcing\n // hour12: true (as this call always does) produces a dayPeriod part\n // for every locale checked, including 24-hour-clock locales (ja-JP,\n // zh-CN, th-TH, he-IL) and a wide sweep of less-common tags (dz-BT,\n // bo-CN, am-ET, etc.). Same finding as partValue()'s twin guard in\n // localeVocab.ts. Kept in case a future ICU/locale-data update\n // produces a locale that genuinely omits it.\n /* c8 ignore start */\n if (!part) {\n throw new Error(`temporal-fmt: locale \"${locale}\" produced no \"dayPeriod\" part for token \"a\".`);\n }\n /* c8 ignore stop */\n return part.value;\n}\n\n// Resolves a locale-aware month/weekday name from the registered custom\n// vocab when one exists for this locale, falling through to Intl otherwise.\n// Without this, format() would silently keep producing Intl's strings while\n// parse() matched against the registered vocab — the two would round-trip-fail\n// against each other.\nfunction localeAwareName(\n temporal: TemporalLike,\n locale: string,\n options: Intl.DateTimeFormatOptions,\n partType: Intl.DateTimeFormatPartTypes,\n customArray: string[] | undefined,\n customIndex: number | undefined,\n): string {\n if (customArray && customIndex !== undefined && customIndex >= 0 && customIndex < customArray.length) {\n return customArray[customIndex]!;\n }\n return intlPart(temporal, locale, options, partType);\n}\n\n// Formats a `±HH:MM` offset string (the shape Temporal exposes on\n// ZonedDateTime.prototype.offset) into one of the six offset-token widths.\n// Width and Z-handling come from the variant letter+case:\n//\n// X / x — short form: minutes omitted when zero, no colon otherwise\n// XX / xx — hours + minutes, no colon\n// XXX / xxx — hours + minutes, with colon\n//\n// Uppercase (X) collapses +00:00 to \"Z\"; lowercase (x) always emits a\n// numeric offset, even for UTC. Mirrors the date-fns/Unicode-LDML offset\n// family — see README for the full variant table.\nfunction formatOffset(offset: string, variant: 'X' | 'XX' | 'XXX' | 'x' | 'xx' | 'xxx'): string {\n if (offset === '+00:00' && (variant === 'X' || variant === 'XX' || variant === 'XXX')) {\n return 'Z';\n }\n // offset is always 6 chars: sign + HH + ':' + MM\n const sign = offset[0]!;\n const hours = offset.slice(1, 3);\n const minutes = offset.slice(4, 6);\n switch (variant) {\n case 'X': case 'x':\n // minutes only matter when they're non-zero — otherwise drop them\n // entirely. Matches LDML: \"With a single X, the hours field is\n // required. The minutes field is optional, but only if the\n // minutes value is 0.\"\n return minutes === '00' ? `${sign}${hours}` : `${sign}${hours}${minutes}`;\n case 'XX': case 'xx':\n return `${sign}${hours}${minutes}`;\n case 'XXX': case 'xxx':\n return `${sign}${hours}:${minutes}`;\n }\n}\n\ntype TokenHandler = (t: TemporalLike, locale: string) => string;\n\n// Longest-first — tokenizer is greedy, \"yyyy\" has to be tried before \"yy\".\n//\n// Numeric tokens always render in ASCII digits, never locale-native\n// (Arabic-Indic, Devanagari, etc). Padding non-ASCII digits isn't as simple\n// as padding \"3\", and most consumers parsing these back out want plain\n// digits anyway.\nexport const TOKENS: Array<[string, TokenHandler, keyof TemporalLike]> = [\n ['yyyy', (t) => pad(t.year!, 4), 'year'],\n ['yy', (t) => {\n // -45 % 100 === -45, so truncating negative years to 2 digits doesn't\n // work and Math.abs() would make 45 CE and 45 BCE render the same.\n if (t.year! < 0) {\n throw new Error(\n `temporal-fmt: token \"yy\" doesn't support negative years (got ${t.year}), ` +\n `since truncating to 2 digits would make it indistinguishable from a ` +\n `positive year. Use \"yyyy\" instead.`\n );\n }\n return pad(t.year! % 100, 2);\n }, 'year'],\n ['MMMM', (t, locale) => {\n const custom = getCustomVocab(locale);\n return localeAwareName(t, locale, { month: 'long' }, 'month', custom?.monthLong, t.month! - 1);\n }, 'month'],\n ['MMM', (t, locale) => {\n const custom = getCustomVocab(locale);\n return localeAwareName(t, locale, { month: 'short' }, 'month', custom?.monthShort, t.month! - 1);\n }, 'month'],\n ['MM', (t) => pad(t.month!, 2), 'month'],\n ['M', (t) => String(t.month!), 'month'],\n ['dd', (t) => pad(t.day!, 2), 'day'],\n ['d', (t) => String(t.day!), 'day'],\n ['EEEE', (t, locale) => {\n const custom = getCustomVocab(locale);\n return localeAwareName(t, locale, { weekday: 'long' }, 'weekday', custom?.weekdayLong, t.dayOfWeek! - 1);\n }, 'dayOfWeek'],\n ['EEE', (t, locale) => {\n const custom = getCustomVocab(locale);\n return localeAwareName(t, locale, { weekday: 'short' }, 'weekday', custom?.weekdayShort, t.dayOfWeek! - 1);\n }, 'dayOfWeek'],\n ['HH', (t) => pad(t.hour!, 2), 'hour'],\n ['H', (t) => String(t.hour!), 'hour'],\n ['hh', (t) => pad(t.hour! % 12 || 12, 2), 'hour'],\n ['h', (t) => String(t.hour! % 12 || 12), 'hour'],\n ['mm', (t) => pad(t.minute!, 2), 'minute'],\n ['m', (t) => String(t.minute!), 'minute'],\n ['ss', (t) => pad(t.second!, 2), 'second'],\n ['s', (t) => String(t.second!), 'second'],\n // Fractional-second tokens, S through SSSSSSSSS (1-9 digits). Each token\n // formats a slice of the same underlying nanosecond-of-second value —\n // combining millisecond/microsecond/nanosecond into one 9-digit number\n // and truncating to the token's width — so \"SSS\" keeps meaning exactly\n // what it always meant (3-digit milliseconds) while wider tokens expose\n // the precision Temporal actually carries. formatFraction below is the\n // shared implementation; see its comment for the truncate-not-round\n // rule and why.\n ['SSSSSSSSS', (t) => pad.fraction(t, 9), 'millisecond'],\n ['SSSSSSSS', (t) => pad.fraction(t, 8), 'millisecond'],\n ['SSSSSSS', (t) => pad.fraction(t, 7), 'millisecond'],\n ['SSSSSS', (t) => pad.fraction(t, 6), 'millisecond'],\n ['SSSSS', (t) => pad.fraction(t, 5), 'millisecond'],\n ['SSSS', (t) => pad.fraction(t, 4), 'millisecond'],\n ['SSS', (t) => pad.fraction(t, 3), 'millisecond'],\n ['SS', (t) => pad.fraction(t, 2), 'millisecond'],\n ['S', (t) => pad.fraction(t, 1), 'millisecond'],\n // dayPeriod text is locale-specific (AM/PM in en-US, م/ص in ar-EG) but\n // still needs .hour on the input to compute which period it is\n ['a', (t, locale) => dayPeriodPart(t.hour!, locale), 'hour'],\n ['zzz', (t) => t.timeZoneId!, 'timeZoneId'],\n // Numeric UTC offset tokens (date-fns/Unicode-LDML family). Only\n // ZonedDateTime carries an offset, so the field check in format() throws\n // the same \"requires offset, which this Temporal object doesn't have\"\n // error zzz throws on PlainDate/PlainTime/PlainDateTime — same\n // validation path, just a different field name. See formatOffset above\n // for the per-variant width and Z/numeric distinction.\n ['xxx', (t) => formatOffset(t.offset!, 'xxx'), 'offset'],\n ['xx', (t) => formatOffset(t.offset!, 'xx'), 'offset'],\n ['X', (t) => formatOffset(t.offset!, 'X'), 'offset'],\n ['XX', (t) => formatOffset(t.offset!, 'XX'), 'offset'],\n ['XXX', (t) => formatOffset(t.offset!, 'XXX'), 'offset'],\n ['x', (t) => formatOffset(t.offset!, 'x'), 'offset'],\n\n // Ordinal day (1st, 2nd, 3rd, ... 21st). English suffix rules only —\n // locale-aware ordinals (\"2.\" in de-DE, \"2日\" in ja-JP) are out of scope,\n // since the rest of this library routes locale-specific names through\n // Intl.DateTimeFormat, and Intl has no part type for ordinals. Format-only:\n // the suffix isn't structurally distinguishable from a literal in a parse\n // context (a \"st\"/\"nd\"/\"rd\"/\"th\" suffix isn't a digit and would collide\n // with any adjacent literal text), so there's no good way to read it back.\n ['do', (t) => {\n const day = t.day!;\n const lastDigit = day % 10;\n // 11, 12, 13 are the exception — they'd otherwise match the 1/2/3 rule\n // and produce \"11st\"/\"12nd\"/\"13rd\", which is wrong. They always take \"th\".\n const lastTwoDigits = day % 100;\n if (lastTwoDigits >= 11 && lastTwoDigits <= 13) {\n return day + 'th';\n }\n if (lastDigit === 1) return day + 'st';\n if (lastDigit === 2) return day + 'nd';\n if (lastDigit === 3) return day + 'rd';\n return day + 'th';\n }, 'day'],\n\n // Quarter computed from month: 1-3=Q1, 4-6=Q2, 7-9=Q3, 10-12=Q4.\n // `Q` is plain numeric, `QQQ` renders as \"Q3\" — same convention as\n // date-fns's `Q` and `QQQ` for parity with the most common prior art.\n // Both format and parse; parse() cross-checks Q/QQQ against the parsed\n // month in the same spirit as the EEEE-vs-date cross-check.\n ['Q', (t) => String(Math.ceil(t.month! / 3)), 'month'],\n ['QQQ', (t) => 'Q' + Math.ceil(t.month! / 3), 'month'],\n\n // ISO 8601 week and week-numbering year. Both are format-only — parsing\n // \"ww\"/\"RRRR\" back into a real date requires resolving an ISO week + a\n // weekday (or some other disambiguator) to a specific date, which is a\n // different parsing surface than the token-based parse() here. The\n // ISO-week year (RRRR) can differ from the calendar year at the boundary:\n // Dec 29-31 often belong to week 1 of the *next* year; Jan 1-3 often\n // belong to week 52/53 of the *previous* year. See isoWeekYearAndWeek().\n ['ww', (t) => {\n const { week } = isoWeekYearAndWeek(t.year!, t.month!, t.day!, t.dayOfWeek!);\n return pad(week, 2);\n }, 'dayOfWeek'],\n ['RRRR', (t) => {\n const { isoYear } = isoWeekYearAndWeek(t.year!, t.month!, t.day!, t.dayOfWeek!);\n return pad(isoYear, 4);\n }, 'dayOfWeek'],\n\n // Day of year — number of days since Jan 1 (1-366). Three widths:\n // D — unpadded (1, 2, 366)\n // DD — 2-digit minimum (zero-padded if <100)\n // DDD — 3-digit zero-padded (001, 002, 366)\n // Format-only — parsing day-of-year requires resolving against a year,\n // which is a different shape from the token-based parse() surface.\n // The dayOfYearHelper() in calendarUtils.ts covers the same field for\n // callers who need the numeric value.\n ['D', (t) => String(dayOfYear(t.year!, t.month!, t.day!)), 'day'],\n ['DD', (t) => pad(dayOfYear(t.year!, t.month!, t.day!), 2), 'day'],\n ['DDD', (t) => pad(dayOfYear(t.year!, t.month!, t.day!), 3), 'day'],\n\n // Stand-alone month — uses Intl's stand-alone form. In most locales\n // (en, fr, de, es) this is identical to MMMM/MMM. In Slavic/Baltic\n // locales (cs, sk, pl, ru) the stand-alone form differs from the\n // format form (nominative vs genitive case). LLLL = long, LLL = short.\n ['LLLL', (t, locale) => {\n const custom = getCustomVocab(locale);\n return localeAwareName(t, locale, { month: 'long' }, 'month', custom?.monthLong, t.month! - 1);\n }, 'month'],\n ['LLL', (t, locale) => {\n const custom = getCustomVocab(locale);\n return localeAwareName(t, locale, { month: 'short' }, 'month', custom?.monthShort, t.month! - 1);\n }, 'month'],\n\n // Stand-alone weekday — same pattern as stand-alone month but for\n // weekday names. cccc = long, ccc = short.\n ['cccc', (t, locale) => {\n const custom = getCustomVocab(locale);\n return localeAwareName(t, locale, { weekday: 'long' }, 'weekday', custom?.weekdayLong, t.dayOfWeek! - 1);\n }, 'dayOfWeek'],\n ['ccc', (t, locale) => {\n const custom = getCustomVocab(locale);\n return localeAwareName(t, locale, { weekday: 'short' }, 'weekday', custom?.weekdayShort, t.dayOfWeek! - 1);\n }, 'dayOfWeek'],\n\n // Era — locale-aware (\"AD\"/\"BC\" in en, \"ap. J.-C.\"/\"av. J.-C.\" in fr).\n // GGGG = long, G = short. Format-only.\n ['GGGG', (t, locale) => {\n return intlPart(t, locale, { era: 'long' }, 'era');\n }, 'year'],\n ['G', (t, locale) => {\n return intlPart(t, locale, { era: 'short' }, 'era');\n }, 'year'],\n\n // Localized timezone name — uses Intl's longLocalized/short timezone\n // name option. Format-only — these names are locale-dependent and\n // vary by season (EST vs EDT), so parsing them back requires a\n // lookup table that isn't practical to ship.\n ['zzzz', (t, locale) => {\n return intlPart(t, locale, { timeZoneName: 'longGeneric' as Intl.DateTimeFormatOptions['timeZoneName'] }, 'timeZoneName' as Intl.DateTimeFormatPartTypes);\n }, 'timeZoneId'],\n ['z', (t, locale) => {\n return intlPart(t, locale, { timeZoneName: 'short' as Intl.DateTimeFormatOptions['timeZoneName'] }, 'timeZoneName' as Intl.DateTimeFormatPartTypes);\n }, 'timeZoneId'],\n\n];"],"mappings":"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","names":["pad","n","len","negative","digits","width","nanoOfSecond","DEFAULT_LOCALE","formatterCache","MAX_CACHE_SIZE","getFormatter","locale","options","key","canonicalCacheKey","formatter","oldestKey","normalizeLocaleTag","err","InvalidLocaleError","nativeSupport","subscribeToTemporalChanges","intlSupportsNativeTemporal","temporal","getTemporal","intlPart","partType","calendar","formatterOptions","ls","toInstant","timeZoneId","isZoned","intlSafeTemporal","nativeOptions","parts","index","p","value","prev","next","dayPeriodPart","hour","custom","getCustomVocab","date","part","localeAwareName","customArray","customIndex","formatOffset","offset","variant","sign","hours","minutes","TOKENS","t","day","lastDigit","lastTwoDigits","week","isoWeekYearAndWeek","isoYear","dayOfYear"]}
@@ -0,0 +1,2 @@
1
+ var a=[0,31,59,90,120,151,181,212,243,273,304,334];function i(e){return e%4===0&&e%100!==0||e%400===0}function u(e){return i(e)?366:365}function d(e,o,s){let n=a[o-1]+s;return o>2&&i(e)&&(n+=1),n}var b=2e3;function l(e){let o=0;if(e>=b)for(let n=b;n<e;n++)o+=u(n);else for(let n=e;n<b;n++)o-=u(n);return((5+o)%7+7)%7+1}function D(e,o,s,n){let t=d(e,o,s)+(4-n),r,f;t<1?(r=e-1,f=t+u(r)):t>u(e)?(r=e+1,f=t-u(e)):(r=e,f=t);let c=1+(4-l(r)+7)%7,m=1+Math.floor((f-c)/7);return{isoYear:r,week:m}}export{i as a,d as b,D as c};
2
+ //# sourceMappingURL=chunk-C6ZZ62ET.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/isoWeek.ts"],"sourcesContent":["// ISO 8601 week numbering: a week runs Monday–Sunday, and week 1 of a year\n// is the week containing the year's first Thursday (equivalently, the week\n// containing January 4). This means late-December dates can fall in week 1\n// of the *next* year, and early-January dates can fall in week 52 or 53 of\n// the *previous* year. The \"ISO week-numbering year\" (what `RRRR` formats)\n// is that adjacent year, not the calendar year.\n//\n// Computed here from the date's own year/month/day plus its ISO dayOfWeek\n// (1=Mon..7=Sun, matching Temporal's numbering) using plain Gregorian\n// arithmetic — no Temporal factory needed. format() only has the fields\n// the caller already put on the object, and requiring a Temporal\n// implementation just for ISO week would be a regression for callers who\n// use format() without setTemporal() on a non-26 Node.\n\nconst DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\nconst CUMULATIVE_DAYS_BY_MONTH = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];\n\nexport function isGregorianLeapYear(year: number): boolean {\n // Gregorian rule: divisible by 4, except centuries which must also be\n // divisible by 400. Temporal's iso8601 calendar is proleptic Gregorian\n // (no Julian cutover), so this applies for every year, including BCE.\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n}\n\nfunction daysInYear(year: number): 365 | 366 {\n return isGregorianLeapYear(year) ? 366 : 365;\n}\n\nexport function dayOfYear(year: number, month: number, day: number): number {\n let doy = CUMULATIVE_DAYS_BY_MONTH[month - 1]! + day;\n if (month > 2 && isGregorianLeapYear(year)) doy += 1;\n return doy;\n}\n\n// Jan 1, 2000 was a Saturday — ISO dayOfWeek 6. Anchoring day-of-week\n// computations to a known reference date is simpler and cheaper than\n// pulling in Zeller's congruence, and the reference never changes.\nconst REFERENCE_YEAR = 2000;\nconst REFERENCE_JAN1_DAY_OF_WEEK = 6;\n\nfunction dayOfWeekOfJan1(year: number): number {\n // Sum full-year deltas from the 2000 anchor rather than recomputing from\n // scratch each call — the per-call work is a single mod this way, and\n // the loop rarely runs far (a typical caller passes a current-era year).\n let offset = 0;\n if (year >= REFERENCE_YEAR) {\n for (let y = REFERENCE_YEAR; y < year; y++) offset += daysInYear(y);\n } else {\n for (let y = year; y < REFERENCE_YEAR; y++) offset -= daysInYear(y);\n }\n // Convert \"days since Jan 1, 2000\" into an ISO day-of-week (1=Mon..7=Sun).\n // Jan 1, 2000 was ISO 6 (Sat), so zero-indexed dow = (6-1 + offset) mod 7.\n const zeroIndexed = (((6 - 1 + offset) % 7) + 7) % 7;\n return zeroIndexed + 1;\n}\n\nexport interface IsoWeekDate {\n isoYear: number;\n week: number; // 1..53\n}\n\nexport function isoWeekYearAndWeek(year: number, month: number, day: number, dayOfWeek: number): IsoWeekDate {\n // Step 1: find the Thursday of the current ISO week. The ISO week-numbering\n // year is whichever calendar year that Thursday falls in. Computing it via\n // day-of-year offsets (rather than constructing a Temporal.PlainDate and\n // adding days) keeps this function pure-numeric.\n const doy = dayOfYear(year, month, day);\n const thursdayDoyRelative = doy + (4 - dayOfWeek); // may be <1 or >daysInYear\n\n let isoYear: number;\n let thursdayDoy: number;\n if (thursdayDoyRelative < 1) {\n isoYear = year - 1;\n thursdayDoy = thursdayDoyRelative + daysInYear(isoYear);\n } else if (thursdayDoyRelative > daysInYear(year)) {\n isoYear = year + 1;\n thursdayDoy = thursdayDoyRelative - daysInYear(year);\n } else {\n isoYear = year;\n thursdayDoy = thursdayDoyRelative;\n }\n\n // Step 2: locate the first Thursday of isoYear — its week is week 1. The\n // first Thursday's day-of-year depends on what weekday Jan 1 of isoYear is.\n const jan1Dow = dayOfWeekOfJan1(isoYear);\n const firstThursdayDoy = 1 + ((4 - jan1Dow + 7) % 7); // 1..7\n\n // Step 3: count full weeks between the two Thursdays.\n const week = 1 + Math.floor((thursdayDoy - firstThursdayDoy) / 7);\n return { isoYear, week };\n}\n"],"mappings":";AAeA,IAAM,2BAA2B,CAAC,GAAG,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AAEhF,SAAS,oBAAoB,MAAuB;AAIzD,SAAQ,OAAO,MAAM,KAAK,OAAO,QAAQ,KAAM,OAAO,QAAQ;AAChE;AAEA,SAAS,WAAW,MAAyB;AAC3C,SAAO,oBAAoB,IAAI,IAAI,MAAM;AAC3C;AAEO,SAAS,UAAU,MAAc,OAAe,KAAqB;AAC1E,MAAI,MAAM,yBAAyB,QAAQ,CAAC,IAAK;AACjD,MAAI,QAAQ,KAAK,oBAAoB,IAAI,EAAG,QAAO;AACnD,SAAO;AACT;AAKA,IAAM,iBAAiB;AAGvB,SAAS,gBAAgB,MAAsB;AAI7C,MAAI,SAAS;AACb,MAAI,QAAQ,gBAAgB;AAC1B,aAAS,IAAI,gBAAgB,IAAI,MAAM,IAAK,WAAU,WAAW,CAAC;AAAA,EACpE,OAAO;AACL,aAAS,IAAI,MAAM,IAAI,gBAAgB,IAAK,WAAU,WAAW,CAAC;AAAA,EACpE;AAGA,QAAM,gBAAiB,IAAI,IAAI,UAAU,IAAK,KAAK;AACnD,SAAO,cAAc;AACvB;AAOO,SAAS,mBAAmB,MAAc,OAAe,KAAa,WAAgC;AAK3G,QAAM,MAAM,UAAU,MAAM,OAAO,GAAG;AACtC,QAAM,sBAAsB,OAAO,IAAI;AAEvC,MAAI;AACJ,MAAI;AACJ,MAAI,sBAAsB,GAAG;AAC3B,cAAU,OAAO;AACjB,kBAAc,sBAAsB,WAAW,OAAO;AAAA,EACxD,WAAW,sBAAsB,WAAW,IAAI,GAAG;AACjD,cAAU,OAAO;AACjB,kBAAc,sBAAsB,WAAW,IAAI;AAAA,EACrD,OAAO;AACL,cAAU;AACV,kBAAc;AAAA,EAChB;AAIA,QAAM,UAAU,gBAAgB,OAAO;AACvC,QAAM,mBAAmB,KAAM,IAAI,UAAU,KAAK;AAGlD,QAAM,OAAO,IAAI,KAAK,OAAO,cAAc,oBAAoB,CAAC;AAChE,SAAO,EAAE,SAAS,KAAK;AACzB;","names":[]}
1
+ {"version":3,"sources":["../src/isoWeek.ts"],"sourcesContent":["// ISO 8601 week numbering: a week runs Monday–Sunday, and week 1 of a year\n// is the week containing the year's first Thursday (equivalently, the week\n// containing January 4). This means late-December dates can fall in week 1\n// of the *next* year, and early-January dates can fall in week 52 or 53 of\n// the *previous* year. The \"ISO week-numbering year\" (what `RRRR` formats)\n// is that adjacent year, not the calendar year.\n//\n// Computed here from the date's own year/month/day plus its ISO dayOfWeek\n// (1=Mon..7=Sun, matching Temporal's numbering) using plain Gregorian\n// arithmetic — no Temporal factory needed. format() only has the fields\n// the caller already put on the object, and requiring a Temporal\n// implementation just for ISO week would be a regression for callers who\n// use format() without setTemporal() on a non-26 Node.\n\nconst DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\nconst CUMULATIVE_DAYS_BY_MONTH = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];\n\nexport function isGregorianLeapYear(year: number): boolean {\n // Gregorian rule: divisible by 4, except centuries which must also be\n // divisible by 400. Temporal's iso8601 calendar is proleptic Gregorian\n // (no Julian cutover), so this applies for every year, including BCE.\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n}\n\nfunction daysInYear(year: number): 365 | 366 {\n return isGregorianLeapYear(year) ? 366 : 365;\n}\n\nexport function dayOfYear(year: number, month: number, day: number): number {\n let doy = CUMULATIVE_DAYS_BY_MONTH[month - 1]! + day;\n if (month > 2 && isGregorianLeapYear(year)) doy += 1;\n return doy;\n}\n\n// Jan 1, 2000 was a Saturday — ISO dayOfWeek 6. Anchoring day-of-week\n// computations to a known reference date is simpler and cheaper than\n// pulling in Zeller's congruence, and the reference never changes.\nconst REFERENCE_YEAR = 2000;\nconst REFERENCE_JAN1_DAY_OF_WEEK = 6;\n\nfunction dayOfWeekOfJan1(year: number): number {\n // Sum full-year deltas from the 2000 anchor rather than recomputing from\n // scratch each call — the per-call work is a single mod this way, and\n // the loop rarely runs far (a typical caller passes a current-era year).\n let offset = 0;\n if (year >= REFERENCE_YEAR) {\n for (let y = REFERENCE_YEAR; y < year; y++) offset += daysInYear(y);\n } else {\n for (let y = year; y < REFERENCE_YEAR; y++) offset -= daysInYear(y);\n }\n // Convert \"days since Jan 1, 2000\" into an ISO day-of-week (1=Mon..7=Sun).\n // Jan 1, 2000 was ISO 6 (Sat), so zero-indexed dow = (6-1 + offset) mod 7.\n const zeroIndexed = (((6 - 1 + offset) % 7) + 7) % 7;\n return zeroIndexed + 1;\n}\n\nexport interface IsoWeekDate {\n isoYear: number;\n week: number; // 1..53\n}\n\nexport function isoWeekYearAndWeek(year: number, month: number, day: number, dayOfWeek: number): IsoWeekDate {\n // Step 1: find the Thursday of the current ISO week. The ISO week-numbering\n // year is whichever calendar year that Thursday falls in. Computing it via\n // day-of-year offsets (rather than constructing a Temporal.PlainDate and\n // adding days) keeps this function pure-numeric.\n const doy = dayOfYear(year, month, day);\n const thursdayDoyRelative = doy + (4 - dayOfWeek); // may be <1 or >daysInYear\n\n let isoYear: number;\n let thursdayDoy: number;\n if (thursdayDoyRelative < 1) {\n isoYear = year - 1;\n thursdayDoy = thursdayDoyRelative + daysInYear(isoYear);\n } else if (thursdayDoyRelative > daysInYear(year)) {\n isoYear = year + 1;\n thursdayDoy = thursdayDoyRelative - daysInYear(year);\n } else {\n isoYear = year;\n thursdayDoy = thursdayDoyRelative;\n }\n\n // Step 2: locate the first Thursday of isoYear — its week is week 1. The\n // first Thursday's day-of-year depends on what weekday Jan 1 of isoYear is.\n const jan1Dow = dayOfWeekOfJan1(isoYear);\n const firstThursdayDoy = 1 + ((4 - jan1Dow + 7) % 7); // 1..7\n\n // Step 3: count full weeks between the two Thursdays.\n const week = 1 + Math.floor((thursdayDoy - firstThursdayDoy) / 7);\n return { isoYear, week };\n}\n"],"mappings":"AAeA,IAAMA,EAA2B,CAAC,EAAG,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAG,EAEhF,SAASC,EAAoBC,EAAuB,CAIzD,OAAQA,EAAO,IAAM,GAAKA,EAAO,MAAQ,GAAMA,EAAO,MAAQ,CAChE,CAEA,SAASC,EAAWD,EAAyB,CAC3C,OAAOD,EAAoBC,CAAI,EAAI,IAAM,GAC3C,CAEO,SAASE,EAAUF,EAAcG,EAAeC,EAAqB,CAC1E,IAAIC,EAAMP,EAAyBK,EAAQ,CAAC,EAAKC,EACjD,OAAID,EAAQ,GAAKJ,EAAoBC,CAAI,IAAGK,GAAO,GAC5CA,CACT,CAKA,IAAMC,EAAiB,IAGvB,SAASC,EAAgBC,EAAsB,CAI7C,IAAIC,EAAS,EACb,GAAID,GAAQE,EACV,QAASC,EAAID,EAAgBC,EAAIH,EAAMG,IAAKF,GAAUG,EAAWD,CAAC,MAElE,SAASA,EAAIH,EAAMG,EAAID,EAAgBC,IAAKF,GAAUG,EAAWD,CAAC,EAKpE,QADuB,EAAQF,GAAU,EAAK,GAAK,EAC9B,CACvB,CAOO,SAASI,EAAmBL,EAAcM,EAAeC,EAAaC,EAAgC,CAM3G,IAAMC,EADMC,EAAUV,EAAMM,EAAOC,CAAG,GACH,EAAIC,GAEnCG,EACAC,EACAH,EAAsB,GACxBE,EAAUX,EAAO,EACjBY,EAAcH,EAAsBL,EAAWO,CAAO,GAC7CF,EAAsBL,EAAWJ,CAAI,GAC9CW,EAAUX,EAAO,EACjBY,EAAcH,EAAsBL,EAAWJ,CAAI,IAEnDW,EAAUX,EACVY,EAAcH,GAMhB,IAAMI,EAAmB,GAAM,EADfd,EAAgBY,CAAO,EACM,GAAK,EAG5CG,EAAO,EAAI,KAAK,OAAOF,EAAcC,GAAoB,CAAC,EAChE,MAAO,CAAE,QAAAF,EAAS,KAAAG,CAAK,CACzB","names":["CUMULATIVE_DAYS_BY_MONTH","isGregorianLeapYear","year","daysInYear","dayOfYear","month","day","doy","REFERENCE_YEAR","dayOfWeekOfJan1","year","offset","REFERENCE_YEAR","y","daysInYear","isoWeekYearAndWeek","month","day","dayOfWeek","thursdayDoyRelative","dayOfYear","isoYear","thursdayDoy","firstThursdayDoy","week"]}
@@ -0,0 +1,5 @@
1
+ import{a,b as d,c as i}from"./chunk-C6ZZ62ET.js";function o(e,t){for(let r of t)if(typeof e[r]!="number")throw new Error(`temporal-fmt: calendar helper requires "${String(r)}", which this value doesn't have. Pass a Temporal.PlainDate / PlainDateTime / ZonedDateTime.`)}function m(e){o(e,["year","month"]);let{year:t,month:r}=e,n=[31,28,31,30,31,30,31,31,30,31,30,31];return r===2&&a(t)?29:n[r-1]}function c(e){return o(e,["year"]),a(e.year)?366:365}function h(e){return 12}function p(e){return o(e,["year"]),a(e.year)}function b(e){return!1}function D(e){return o(e,["year","month","day"]),d(e.year,e.month,e.day)}function k(e){return o(e,["year","month","day","dayOfWeek"]),i(e.year,e.month,e.day,e.dayOfWeek).week}function O(e){return o(e,["year","month","day","dayOfWeek"]),i(e.year,e.month,e.day,e.dayOfWeek).isoYear}function l(e){if(!Number.isInteger(e)||e<1||e>12)throw new Error(`temporal-fmt: getQuarter's startMonth must be an integer from 1 to 12 (got ${e}).`)}function F(e,t={}){o(e,["month"]);let r=t.startMonth??1;if(l(r),r===1)return Math.ceil(e.month/3);let n=(e.month-r+12)%12+1;return Math.ceil(n/3)}function V(e){return o(e,["month"]),e.month}function w(e){return o(e,["dayOfWeek"]),e.dayOfWeek}function f(e){return e==="day"||e==="month"||e==="year"}function u(e){if(typeof e.dayOfWeek!="number")return;/* c8 ignore start @preserve -- unreachable: startOf()/endOf() both call
2
+ * asDateFieldView() before this, which already throws if year/month/day
3
+ * aren't all numbers — so by the time a value with a numeric dayOfWeek
4
+ * reaches here, year/month/day are guaranteed present too. */if(typeof e.year!="number"||typeof e.month!="number"||typeof e.day!="number")return;/* c8 ignore stop @preserve */let t=new Date(Date.UTC(e.year,e.month-1,e.day)).getUTCDay();e.dayOfWeek=t===0?7:t}function x(e,t){let n={...y(e)};return t==="year"?(n.month=1,n.day=1):t==="month"&&(n.day=1),u(n),f(t)?(n.hour=0,n.minute=0,n.second=0,n.millisecond=0):t==="hour"?(n.minute=0,n.second=0,n.millisecond=0):t==="minute"?(n.second=0,n.millisecond=0):t==="second"&&(n.millisecond=0),n}function g(e,t){let n={...y(e)};return t==="year"?(n.month=12,n.day=m({year:n.year,month:12})):t==="month"&&(n.day=m({year:n.year,month:n.month})),u(n),f(t)?(n.hour=23,n.minute=59,n.second=59,n.millisecond=999):t==="hour"?(n.minute=59,n.second=59,n.millisecond=999):t==="minute"?(n.second=59,n.millisecond=999):t==="second"&&(n.millisecond=999),n}function y(e){if(typeof e!="object"||e===null)throw new Error(`temporal-fmt: expected a date-carrying Temporal value, got ${String(e)}.`);let t=e,r={};if(typeof t.year=="number"&&(r.year=t.year),typeof t.month=="number"&&(r.month=t.month),typeof t.day=="number"&&(r.day=t.day),typeof t.hour=="number"&&(r.hour=t.hour),typeof t.minute=="number"&&(r.minute=t.minute),typeof t.second=="number"&&(r.second=t.second),typeof t.millisecond=="number"&&(r.millisecond=t.millisecond),typeof t.dayOfWeek=="number"&&(r.dayOfWeek=t.dayOfWeek),typeof t.calendarId=="string"&&(r.calendarId=t.calendarId),r.year===void 0||r.month===void 0||r.day===void 0)throw new Error("temporal-fmt: value is missing year/month/day fields \u2014 pass a Temporal.PlainDate / PlainDateTime / ZonedDateTime.");return r}export{m as a,c as b,h as c,p as d,b as e,D as f,k as g,O as h,F as i,V as j,w as k,x as l,g as m,y as n};
5
+ //# sourceMappingURL=chunk-EHLRZULM.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/calendarUtils.ts"],"sourcesContent":["// Calendar utility helpers. These are pure functions\n// over the TemporalLike shape — no Temporal namespace needed, same\n// approach as isoWeek.ts and the field-reading helpers in format.ts.\n// Letting callers compute dayOfYear/weekOfYear/etc. without going\n// through format() means they can build their own derived values\n// without committing to a string format.\n//\n// Calendar-sensitivity: the helpers in this module assume the\n// iso8601 (Gregorian) calendar — that's what TemporalLike fields\n// carry for the overwhelming majority of callers. Non-Gregorian\n// calendars (hebrew, islamic, etc.) need their own helpers; this\n// module doesn't try to be calendar-polymorphic the way Temporal\n// itself is. Documented limitation, not a design choice — see\n// VERIFICATION.md for the rationale.\n\nimport { isGregorianLeapYear, dayOfYear, isoWeekYearAndWeek } from './isoWeek.js';\n\n// A subset of TemporalLike that has the date fields these helpers need,\n// plus optional time fields. PlainTime isn't a DateFieldView (no\n// year/month/day), but PlainDateTime / ZonedDateTime / PlainDate all\n// match. Time fields are optional so callers can pass a PlainDate\n// to startOf(value, 'month') without having to populate hour/minute/etc.\n// Exported so the comparison/arithmetic modules can use the same\n// narrowing.\nexport interface DateFieldView {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n dayOfWeek?: number;\n calendarId?: string;\n}\n\nfunction requireFields(view: DateFieldView, fields: Array<keyof DateFieldView>): void {\n for (const f of fields) {\n if (typeof view[f] !== 'number') {\n throw new Error(\n `temporal-fmt: calendar helper requires \"${String(f)}\", which this value doesn't have. ` +\n `Pass a Temporal.PlainDate / PlainDateTime / ZonedDateTime.`\n );\n }\n }\n}\n\nexport function daysInMonth(view: DateFieldView): number {\n requireFields(view, ['year', 'month']);\n const { year, month } = view;\n // Standard Gregorian month lengths. February's length depends on\n // whether `year` is a leap year — the same isGregorianLeapYear check\n // isoWeek.ts uses for dayOfYear arithmetic.\n const LENGTHS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n if (month === 2 && isGregorianLeapYear(year!)) return 29;\n return LENGTHS[(month! - 1)!]!;\n}\n\nexport function daysInYear(view: DateFieldView): 365 | 366 {\n requireFields(view, ['year']);\n return isGregorianLeapYear(view.year!) ? 366 : 365;\n}\n\nexport function monthsInYear(_view: DateFieldView): 12 {\n // Gregorian always has 12 months. Other calendars (Hebrew leap years\n // have 13) need calendar-aware logic this module doesn't carry — see\n // the file-level comment. The `_view` parameter is kept so the\n // signature mirrors the other helpers and a future calendar-aware\n // implementation can use it without changing call sites.\n return 12;\n}\n\nexport function isLeapYear(view: DateFieldView): boolean {\n requireFields(view, ['year']);\n return isGregorianLeapYear(view.year!);\n}\n\n// `isLeapMonth` would require knowing which month of a leap-year-aware\n// calendar is the leap month — Gregorian doesn't have one, so this\n// returns false unconditionally. Kept here so the public surface\n// matches the module's listing; non-Gregorian calendars need\n// a different implementation.\nexport function isLeapMonth(_view: DateFieldView): boolean {\n return false;\n}\n\nexport function dayOfYearHelper(view: DateFieldView): number {\n requireFields(view, ['year', 'month', 'day']);\n return dayOfYear(view.year!, view.month!, view.day!);\n}\n\n// ISO 8601 week and week-year. Delegates to isoWeek.ts's\n// isoWeekYearAndWeek, which does the full Thursday-of-week\n// computation to handle the year-boundary cases (Dec 29-31 belonging\n// to week 1 of next year, Jan 1-3 belonging to week 52/53 of the\n// previous year).\nexport function weekOfYear(view: DateFieldView): number {\n requireFields(view, ['year', 'month', 'day', 'dayOfWeek']);\n return isoWeekYearAndWeek(view.year!, view.month!, view.day!, view.dayOfWeek!).week;\n}\n\nexport function weekYear(view: DateFieldView): number {\n requireFields(view, ['year', 'month', 'day', 'dayOfWeek']);\n return isoWeekYearAndWeek(view.year!, view.month!, view.day!, view.dayOfWeek!).isoYear;\n}\n\n/**\n * Fiscal-quarter options. `startMonth` is the calendar month (1-12) the\n * fiscal year begins on — e.g. `7` for a fiscal year starting in July.\n * Omitted or `1` gives the calendar-quarter behavior getQuarter() has\n * always had (Jan-Mar = Q1, etc.), so existing callers passing nothing\n * see no change.\n */\nexport interface QuarterOptions {\n startMonth?: number;\n}\n\nfunction validateStartMonth(startMonth: number): void {\n if (!Number.isInteger(startMonth) || startMonth < 1 || startMonth > 12) {\n throw new Error(\n `temporal-fmt: getQuarter's startMonth must be an integer from 1 to 12 (got ${startMonth}).`\n );\n }\n}\n\nexport function getQuarter(view: DateFieldView, options: QuarterOptions = {}): number {\n requireFields(view, ['month']);\n const startMonth = options.startMonth ?? 1;\n validateStartMonth(startMonth);\n if (startMonth === 1) {\n // Mirrors the Q token: months 1-3 → Q1, 4-6 → Q2, 7-9 → Q3, 10-12 → Q4.\n return Math.ceil(view.month! / 3);\n }\n // Fiscal case: shift the month so startMonth becomes month 1 of the\n // fiscal year (mod 12, 1-indexed), then apply the same ceil(/3) rule.\n // E.g. startMonth=7 (fiscal year starts July): July→1, Aug→2, ...,\n // Dec→6, Jan→7, ..., June→12. Then Q1 = fiscal months 1-3 (Jul-Sep),\n // matching the common \"FY starts in July\" convention where Q1 is the\n // first quarter of the fiscal year, not a quarter numbered by which\n // calendar quarter it falls in.\n const shifted = ((view.month! - startMonth + 12) % 12) + 1;\n return Math.ceil(shifted / 3);\n}\n\n// `getMonth` / `getWeekday` look trivial (just read the field) but\n// they're kept as real functions for API surface consistency with the\n// rest of this module. They also normalize: getWeekday returns 1-7\n// (Mon-Sun, matching Temporal's spec) regardless of what numbering the\n// caller's underlying value uses.\nexport function getMonth(view: DateFieldView): number {\n requireFields(view, ['month']);\n return view.month!;\n}\n\nexport function getWeekday(view: DateFieldView): number {\n requireFields(view, ['dayOfWeek']);\n return view.dayOfWeek!;\n}\n\n// startOf / endOf return new field bags (not Temporal objects — this\n// module is polyfill-free) with the relevant fields zeroed/extended.\n// Callers can pass the result to a Temporal constructor if they want\n// a typed value.\nexport type StartOfUnit = 'day' | 'month' | 'year' | 'hour' | 'minute' | 'second';\n\n// Returns true if the given unit (when used with startOf/endOf) should\n// also touch the time fields. 'day', 'month', 'year' all imply a\n// resolution coarser than an hour, so startOf zeroes the time fields\n// and endOf maxes them. Sub-hour units (hour/minute/second) only touch\n// the fields finer than themselves.\nfunction touchesTime(unit: StartOfUnit): boolean {\n return unit === 'day' || unit === 'month' || unit === 'year';\n}\n\n// startOf/endOf reassign year/month/day, which invalidates any\n// dayOfWeek carried over from the input — a plain { ...view } spread\n// leaves the old value sitting there unchanged. Same failure mode\n// businessCalendar.ts's isBusinessDay() works around for add(); we\n// recompute here rather than trust the copied field.\nfunction recomputeDayOfWeek(view: DateFieldView): void {\n if (typeof view.dayOfWeek !== 'number') return;\n /* c8 ignore start @preserve -- unreachable: startOf()/endOf() both call\n * asDateFieldView() before this, which already throws if year/month/day\n * aren't all numbers — so by the time a value with a numeric dayOfWeek\n * reaches here, year/month/day are guaranteed present too. */\n if (typeof view.year !== 'number' || typeof view.month !== 'number' || typeof view.day !== 'number') return;\n /* c8 ignore stop @preserve */\n const jsDow = new Date(Date.UTC(view.year, view.month - 1, view.day)).getUTCDay(); // 0=Sun..6=Sat\n view.dayOfWeek = jsDow === 0 ? 7 : jsDow; // 1=Mon..7=Sun\n}\n\nexport function startOf(value: unknown, unit: StartOfUnit): DateFieldView {\n const view = asDateFieldView(value);\n const result: DateFieldView = { ...view };\n if (unit === 'year') {\n result.month = 1;\n result.day = 1;\n } else if (unit === 'month') {\n result.day = 1;\n }\n recomputeDayOfWeek(result);\n if (touchesTime(unit)) {\n result.hour = 0;\n result.minute = 0;\n result.second = 0;\n result.millisecond = 0;\n } else if (unit === 'hour') {\n result.minute = 0;\n result.second = 0;\n result.millisecond = 0;\n } else if (unit === 'minute') {\n result.second = 0;\n result.millisecond = 0;\n } else if (unit === 'second') {\n result.millisecond = 0;\n }\n return result;\n}\n\nexport function endOf(value: unknown, unit: StartOfUnit): DateFieldView {\n const view = asDateFieldView(value);\n const result: DateFieldView = { ...view };\n if (unit === 'year') {\n result.month = 12;\n result.day = daysInMonth({ year: result.year!, month: 12 });\n } else if (unit === 'month') {\n result.day = daysInMonth({ year: result.year!, month: result.month! });\n }\n recomputeDayOfWeek(result);\n if (touchesTime(unit)) {\n result.hour = 23;\n result.minute = 59;\n result.second = 59;\n result.millisecond = 999;\n } else if (unit === 'hour') {\n result.minute = 59;\n result.second = 59;\n result.millisecond = 999;\n } else if (unit === 'minute') {\n result.second = 59;\n result.millisecond = 999;\n } else if (unit === 'second') {\n result.millisecond = 999;\n }\n return result;\n}\n\n// Type-narrowing helpers used by the comparison/arithmetic modules.\n// Lets them accept any of the four date-carrying Temporal types without\n// importing Temporal itself.\nexport function asDateFieldView(value: unknown): DateFieldView {\n if (typeof value !== 'object' || value === null) {\n throw new Error(`temporal-fmt: expected a date-carrying Temporal value, got ${String(value)}.`);\n }\n // Temporal instances expose year/month/day/etc. as prototype getters,\n // not own enumerable properties — so `{ ...value }` would lose them.\n // Read them explicitly. Only the fields actually present on this\n // value type end up in the returned view.\n const v = value as Record<string, unknown>;\n const out: DateFieldView = {};\n if (typeof v.year === 'number') out.year = v.year;\n if (typeof v.month === 'number') out.month = v.month;\n if (typeof v.day === 'number') out.day = v.day;\n if (typeof v.hour === 'number') out.hour = v.hour;\n if (typeof v.minute === 'number') out.minute = v.minute;\n if (typeof v.second === 'number') out.second = v.second;\n if (typeof v.millisecond === 'number') out.millisecond = v.millisecond;\n if (typeof v.dayOfWeek === 'number') out.dayOfWeek = v.dayOfWeek;\n if (typeof v.calendarId === 'string') out.calendarId = v.calendarId;\n if (out.year === undefined || out.month === undefined || out.day === undefined) {\n throw new Error(\n `temporal-fmt: value is missing year/month/day fields — pass a Temporal.PlainDate / PlainDateTime / ZonedDateTime.`\n );\n }\n return out;\n}\n\n// Re-export the TemporalType alias so callers can import everything\n// from one place.\nexport type { TemporalType } from './tokenMetadata.js';\n// Re-export TemporalLike for the same reason.\nexport type { TemporalLike } from './tokens.js';"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/calendarUtils.ts"],"sourcesContent":["// Calendar utility helpers. These are pure functions\n// over the TemporalLike shape — no Temporal namespace needed, same\n// approach as isoWeek.ts and the field-reading helpers in format.ts.\n// Letting callers compute dayOfYear/weekOfYear/etc. without going\n// through format() means they can build their own derived values\n// without committing to a string format.\n//\n// Calendar-sensitivity: the helpers in this module assume the\n// iso8601 (Gregorian) calendar — that's what TemporalLike fields\n// carry for the overwhelming majority of callers. Non-Gregorian\n// calendars (hebrew, islamic, etc.) need their own helpers; this\n// module doesn't try to be calendar-polymorphic the way Temporal\n// itself is. Documented limitation, not a design choice — see\n// VERIFICATION.md for the rationale.\n\nimport { isGregorianLeapYear, dayOfYear, isoWeekYearAndWeek } from './isoWeek.js';\n\n// A subset of TemporalLike that has the date fields these helpers need,\n// plus optional time fields. PlainTime isn't a DateFieldView (no\n// year/month/day), but PlainDateTime / ZonedDateTime / PlainDate all\n// match. Time fields are optional so callers can pass a PlainDate\n// to startOf(value, 'month') without having to populate hour/minute/etc.\n// Exported so the comparison/arithmetic modules can use the same\n// narrowing.\nexport interface DateFieldView {\n year?: number;\n month?: number;\n day?: number;\n hour?: number;\n minute?: number;\n second?: number;\n millisecond?: number;\n dayOfWeek?: number;\n calendarId?: string;\n}\n\nfunction requireFields(view: DateFieldView, fields: Array<keyof DateFieldView>): void {\n for (const f of fields) {\n if (typeof view[f] !== 'number') {\n throw new Error(\n `temporal-fmt: calendar helper requires \"${String(f)}\", which this value doesn't have. ` +\n `Pass a Temporal.PlainDate / PlainDateTime / ZonedDateTime.`\n );\n }\n }\n}\n\nexport function daysInMonth(view: DateFieldView): number {\n requireFields(view, ['year', 'month']);\n const { year, month } = view;\n // Standard Gregorian month lengths. February's length depends on\n // whether `year` is a leap year — the same isGregorianLeapYear check\n // isoWeek.ts uses for dayOfYear arithmetic.\n const LENGTHS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n if (month === 2 && isGregorianLeapYear(year!)) return 29;\n return LENGTHS[(month! - 1)!]!;\n}\n\nexport function daysInYear(view: DateFieldView): 365 | 366 {\n requireFields(view, ['year']);\n return isGregorianLeapYear(view.year!) ? 366 : 365;\n}\n\nexport function monthsInYear(_view: DateFieldView): 12 {\n // Gregorian always has 12 months. Other calendars (Hebrew leap years\n // have 13) need calendar-aware logic this module doesn't carry — see\n // the file-level comment. The `_view` parameter is kept so the\n // signature mirrors the other helpers and a future calendar-aware\n // implementation can use it without changing call sites.\n return 12;\n}\n\nexport function isLeapYear(view: DateFieldView): boolean {\n requireFields(view, ['year']);\n return isGregorianLeapYear(view.year!);\n}\n\n// `isLeapMonth` would require knowing which month of a leap-year-aware\n// calendar is the leap month — Gregorian doesn't have one, so this\n// returns false unconditionally. Kept here so the public surface\n// matches the module's listing; non-Gregorian calendars need\n// a different implementation.\nexport function isLeapMonth(_view: DateFieldView): boolean {\n return false;\n}\n\nexport function dayOfYearHelper(view: DateFieldView): number {\n requireFields(view, ['year', 'month', 'day']);\n return dayOfYear(view.year!, view.month!, view.day!);\n}\n\n// ISO 8601 week and week-year. Delegates to isoWeek.ts's\n// isoWeekYearAndWeek, which does the full Thursday-of-week\n// computation to handle the year-boundary cases (Dec 29-31 belonging\n// to week 1 of next year, Jan 1-3 belonging to week 52/53 of the\n// previous year).\nexport function weekOfYear(view: DateFieldView): number {\n requireFields(view, ['year', 'month', 'day', 'dayOfWeek']);\n return isoWeekYearAndWeek(view.year!, view.month!, view.day!, view.dayOfWeek!).week;\n}\n\nexport function weekYear(view: DateFieldView): number {\n requireFields(view, ['year', 'month', 'day', 'dayOfWeek']);\n return isoWeekYearAndWeek(view.year!, view.month!, view.day!, view.dayOfWeek!).isoYear;\n}\n\n/**\n * Fiscal-quarter options. `startMonth` is the calendar month (1-12) the\n * fiscal year begins on — e.g. `7` for a fiscal year starting in July.\n * Omitted or `1` gives the calendar-quarter behavior getQuarter() has\n * always had (Jan-Mar = Q1, etc.), so existing callers passing nothing\n * see no change.\n */\nexport interface QuarterOptions {\n startMonth?: number;\n}\n\nfunction validateStartMonth(startMonth: number): void {\n if (!Number.isInteger(startMonth) || startMonth < 1 || startMonth > 12) {\n throw new Error(\n `temporal-fmt: getQuarter's startMonth must be an integer from 1 to 12 (got ${startMonth}).`\n );\n }\n}\n\nexport function getQuarter(view: DateFieldView, options: QuarterOptions = {}): number {\n requireFields(view, ['month']);\n const startMonth = options.startMonth ?? 1;\n validateStartMonth(startMonth);\n if (startMonth === 1) {\n // Mirrors the Q token: months 1-3 → Q1, 4-6 → Q2, 7-9 → Q3, 10-12 → Q4.\n return Math.ceil(view.month! / 3);\n }\n // Fiscal case: shift the month so startMonth becomes month 1 of the\n // fiscal year (mod 12, 1-indexed), then apply the same ceil(/3) rule.\n // E.g. startMonth=7 (fiscal year starts July): July→1, Aug→2, ...,\n // Dec→6, Jan→7, ..., June→12. Then Q1 = fiscal months 1-3 (Jul-Sep),\n // matching the common \"FY starts in July\" convention where Q1 is the\n // first quarter of the fiscal year, not a quarter numbered by which\n // calendar quarter it falls in.\n const shifted = ((view.month! - startMonth + 12) % 12) + 1;\n return Math.ceil(shifted / 3);\n}\n\n// `getMonth` / `getWeekday` look trivial (just read the field) but\n// they're kept as real functions for API surface consistency with the\n// rest of this module. They also normalize: getWeekday returns 1-7\n// (Mon-Sun, matching Temporal's spec) regardless of what numbering the\n// caller's underlying value uses.\nexport function getMonth(view: DateFieldView): number {\n requireFields(view, ['month']);\n return view.month!;\n}\n\nexport function getWeekday(view: DateFieldView): number {\n requireFields(view, ['dayOfWeek']);\n return view.dayOfWeek!;\n}\n\n// startOf / endOf return new field bags (not Temporal objects — this\n// module is polyfill-free) with the relevant fields zeroed/extended.\n// Callers can pass the result to a Temporal constructor if they want\n// a typed value.\nexport type StartOfUnit = 'day' | 'month' | 'year' | 'hour' | 'minute' | 'second';\n\n// Returns true if the given unit (when used with startOf/endOf) should\n// also touch the time fields. 'day', 'month', 'year' all imply a\n// resolution coarser than an hour, so startOf zeroes the time fields\n// and endOf maxes them. Sub-hour units (hour/minute/second) only touch\n// the fields finer than themselves.\nfunction touchesTime(unit: StartOfUnit): boolean {\n return unit === 'day' || unit === 'month' || unit === 'year';\n}\n\n// startOf/endOf reassign year/month/day, which invalidates any\n// dayOfWeek carried over from the input — a plain { ...view } spread\n// leaves the old value sitting there unchanged. Same failure mode\n// businessCalendar.ts's isBusinessDay() works around for add(); we\n// recompute here rather than trust the copied field.\nfunction recomputeDayOfWeek(view: DateFieldView): void {\n if (typeof view.dayOfWeek !== 'number') return;\n /* c8 ignore start @preserve -- unreachable: startOf()/endOf() both call\n * asDateFieldView() before this, which already throws if year/month/day\n * aren't all numbers — so by the time a value with a numeric dayOfWeek\n * reaches here, year/month/day are guaranteed present too. */\n if (typeof view.year !== 'number' || typeof view.month !== 'number' || typeof view.day !== 'number') return;\n /* c8 ignore stop @preserve */\n const jsDow = new Date(Date.UTC(view.year, view.month - 1, view.day)).getUTCDay(); // 0=Sun..6=Sat\n view.dayOfWeek = jsDow === 0 ? 7 : jsDow; // 1=Mon..7=Sun\n}\n\nexport function startOf(value: unknown, unit: StartOfUnit): DateFieldView {\n const view = asDateFieldView(value);\n const result: DateFieldView = { ...view };\n if (unit === 'year') {\n result.month = 1;\n result.day = 1;\n } else if (unit === 'month') {\n result.day = 1;\n }\n recomputeDayOfWeek(result);\n if (touchesTime(unit)) {\n result.hour = 0;\n result.minute = 0;\n result.second = 0;\n result.millisecond = 0;\n } else if (unit === 'hour') {\n result.minute = 0;\n result.second = 0;\n result.millisecond = 0;\n } else if (unit === 'minute') {\n result.second = 0;\n result.millisecond = 0;\n } else if (unit === 'second') {\n result.millisecond = 0;\n }\n return result;\n}\n\nexport function endOf(value: unknown, unit: StartOfUnit): DateFieldView {\n const view = asDateFieldView(value);\n const result: DateFieldView = { ...view };\n if (unit === 'year') {\n result.month = 12;\n result.day = daysInMonth({ year: result.year!, month: 12 });\n } else if (unit === 'month') {\n result.day = daysInMonth({ year: result.year!, month: result.month! });\n }\n recomputeDayOfWeek(result);\n if (touchesTime(unit)) {\n result.hour = 23;\n result.minute = 59;\n result.second = 59;\n result.millisecond = 999;\n } else if (unit === 'hour') {\n result.minute = 59;\n result.second = 59;\n result.millisecond = 999;\n } else if (unit === 'minute') {\n result.second = 59;\n result.millisecond = 999;\n } else if (unit === 'second') {\n result.millisecond = 999;\n }\n return result;\n}\n\n// Type-narrowing helpers used by the comparison/arithmetic modules.\n// Lets them accept any of the four date-carrying Temporal types without\n// importing Temporal itself.\nexport function asDateFieldView(value: unknown): DateFieldView {\n if (typeof value !== 'object' || value === null) {\n throw new Error(`temporal-fmt: expected a date-carrying Temporal value, got ${String(value)}.`);\n }\n // Temporal instances expose year/month/day/etc. as prototype getters,\n // not own enumerable properties — so `{ ...value }` would lose them.\n // Read them explicitly. Only the fields actually present on this\n // value type end up in the returned view.\n const v = value as Record<string, unknown>;\n const out: DateFieldView = {};\n if (typeof v.year === 'number') out.year = v.year;\n if (typeof v.month === 'number') out.month = v.month;\n if (typeof v.day === 'number') out.day = v.day;\n if (typeof v.hour === 'number') out.hour = v.hour;\n if (typeof v.minute === 'number') out.minute = v.minute;\n if (typeof v.second === 'number') out.second = v.second;\n if (typeof v.millisecond === 'number') out.millisecond = v.millisecond;\n if (typeof v.dayOfWeek === 'number') out.dayOfWeek = v.dayOfWeek;\n if (typeof v.calendarId === 'string') out.calendarId = v.calendarId;\n if (out.year === undefined || out.month === undefined || out.day === undefined) {\n throw new Error(\n `temporal-fmt: value is missing year/month/day fields — pass a Temporal.PlainDate / PlainDateTime / ZonedDateTime.`\n );\n }\n return out;\n}\n\n// Re-export the TemporalType alias so callers can import everything\n// from one place.\nexport type { TemporalType } from './tokenMetadata.js';\n// Re-export TemporalLike for the same reason.\nexport type { TemporalLike } from './tokens.js';"],"mappings":"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","names":["requireFields","view","fields","f","daysInMonth","year","month","LENGTHS","isGregorianLeapYear","daysInYear","monthsInYear","_view","isLeapYear","isLeapMonth","dayOfYearHelper","dayOfYear","weekOfYear","isoWeekYearAndWeek","weekYear","validateStartMonth","startMonth","getQuarter","options","shifted","getMonth","getWeekday","touchesTime","unit","recomputeDayOfWeek","jsDow","startOf","value","result","asDateFieldView","endOf","v","out"]}
@@ -0,0 +1,2 @@
1
+ import{a as p,b as h}from"./chunk-4JWGUR4O.js";import{p as b}from"./chunk-5U5WJ465.js";import{a}from"./chunk-UJR6DHXY.js";import{n as f}from"./chunk-EHLRZULM.js";function x(t,n,o="closed"){if(a(t,n)>0)throw new Error("temporal-fmt: interval start must be \u2264 end (got start > end). Pass them in chronological order.");return{start:t,end:n,bounds:o}}function F(t,n){let o=a(n,t.start),r=a(n,t.end),e=t.bounds==="open"||t.bounds==="half-open-end"?o>0:o>=0,s=t.bounds==="open"||t.bounds==="half-open-start"?r<0:r<=0;return e&&s}function E(t,n){return m(t,n)}function m(t,n){return!(a(t.end,n.start)<0||a(t.start,n.end)>0)}function S(t,n){return a(t.end,n.start)<0}function T(t,n){return a(t.start,n.end)>0}function B(t,n){if(!m(t,n))return null;let o=a(t.start,n.start)>=0?t.start:n.start,r=a(t.end,n.end)<=0?t.end:n.end,e=t.bounds==="open"||t.bounds==="half-open-end"||n.bounds==="open"||n.bounds==="half-open-end",s=t.bounds==="open"||t.bounds==="half-open-start"||n.bounds==="open"||n.bounds==="half-open-start";return{start:o,end:r,bounds:e&&s?"open":e?"half-open-end":s?"half-open-start":"closed"}}function R(t,n){if(!m(t,n))return null;let o=a(t.start,n.start)<=0?t.start:n.start,r=a(t.end,n.end)>=0?t.end:n.end,e=(t.bounds==="open"||t.bounds==="half-open-end")&&(n.bounds==="open"||n.bounds==="half-open-end"),s=(t.bounds==="open"||t.bounds==="half-open-start")&&(n.bounds==="open"||n.bounds==="half-open-start");return{start:o,end:r,bounds:e&&s?"open":e?"half-open-end":s?"half-open-start":"closed"}}function v(t,n){if(!m(t,n))return[t];let o=[],r=t.bounds==="closed"||t.bounds==="half-open-end",e=t.bounds==="closed"||t.bounds==="half-open-start";return a(t.start,n.start)<0&&o.push({start:t.start,end:n.start,bounds:r?"half-open-end":"open"}),a(t.end,n.end)>0&&o.push({start:n.end,end:t.end,bounds:e?"half-open-start":"open"}),o}var A=v;function O(t){if(t.length===0)return[];let n=[...t].sort((r,e)=>a(r.start,e.start)),o=[{...n[0]}];for(let r=1;r<n.length;r++){let e=n[r],s=o[o.length-1];m(s,e)||a(s.end,e.start)===0?a(e.end,s.end)>0&&(s.end=e.end):o.push(e)}return o}var I=864e13;function k(t,n){if(n<=0)throw new Error(`temporal-fmt: splitInterval requires n > 0 (got ${n}).`);if(n===1)return[t];let o=f(t.start),r=f(t.end),e=y(o),s=y(r);if(Math.abs(e)>I||Math.abs(s)>I)throw new RangeError("temporal-fmt: splitInterval() endpoints are outside the representable Date range (approximately \xB1275,760 years). Split the interval into smaller ranges first.");let l=(s-e)/n,d=[];for(let u=0;u<n;u++){let c=e+u*l,i=u===n-1?s:c+l;d.push({start:w(c,o),end:w(i,r),bounds:u===0?t.bounds:"half-open-start"})}return d}function y(t){let n=t.year,o=t.month,r=t.day,e=o<=2?n-1:n,s=Math.floor((e>=0?e:e-399)/400),l=e-s*400,d=o>2?o-3:o+9,u=Math.floor((153*d+2)/5)+r-1,c=l*365+Math.floor(l/4)-Math.floor(l/100)+u;return(s*146097+c-719468)*864e5+(t.hour??0)*36e5+(t.minute??0)*6e4+(t.second??0)*1e3+(t.millisecond??0)}function w(t,n){let r=Math.floor(t/864e5),e=t%864e5;e<0&&(e+=864e5);let s=Math.floor(e/36e5),l=Math.floor(e%36e5/6e4),d=Math.floor(e%6e4/1e3),u=e%1e3,c=r*864e5,i=new Date(c);return{...n,year:i.getUTCFullYear(),month:i.getUTCMonth()+1,day:i.getUTCDate(),hour:s,minute:l,second:d,millisecond:u}}function V(t,n,o={}){try{let r=p(t.start,n,o),e=p(t.end,n,o);return`${r} \u2013 ${e}`}catch(r){try{let e=new Intl.DateTimeFormat(b(o.locale??"en-US"),{}),s=_(t.start),l=_(t.end);return e.formatRange(s,l)}catch{throw r}}}function C(t,n,o={}){let r=h(t.start,n,o),e=h(t.end,n,o),s=[...r];return s.push({type:"literal",value:" \u2013 "}),s.push(...e),s}function _(t){let n=t;if(typeof n?.toInstant=="function")return new Date(n.toInstant().epochMilliseconds);if(typeof n?.year=="number"&&typeof n?.month=="number"&&typeof n?.day=="number")return new Date(Date.UTC(n.year,n.month-1,n.day,n.hour??0,n.minute??0,n.second??0,n.millisecond??0));throw new Error(`temporal-fmt: formatRange() expected Temporal values with year/month/day, got ${typeof t}.`)}export{x as a,F as b,E as c,m as d,S as e,T as f,B as g,R as h,v as i,A as j,O as k,k as l,V as m,C as n};
2
+ //# sourceMappingURL=chunk-F4RGUDA3.js.map