temporal-fmt 0.7.7 β†’ 0.7.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # temporal-fmt
1
+ # temporal-fmt πŸ₯ΆπŸ”₯
2
2
 
3
3
  Format `Temporal.PlainDate` / `PlainTime` / `PlainDateTime` / `ZonedDateTime` objects
4
4
  using date-fns-style token strings.
@@ -200,6 +200,19 @@ sitting in your output waiting to confuse someone in three weeks.
200
200
  Gregorian calendar throughout β€” see
201
201
  [tc39/ecma402#1003](https://github.com/tc39/ecma402/issues/1003). Numeric
202
202
  tokens (`yyyy`/`MM`/`dd`) never go through `Intl` and aren't affected.
203
+ - Gluing two unpadded numeric tokens with no separator between them (e.g.
204
+ `Md`, `dM`, `Hm`) is ambiguous for some inputs, and `parse()` throws rather
205
+ than guessing. `"121"` against `yyyy-Md` could mean month 1/day 21 or month
206
+ 12/day 1 β€” both are valid, so there's no single correct reading to fall
207
+ back to. Unambiguous inputs against the same format string still parse
208
+ normally (`"85"` against `yyyy-Md` only has one valid split). If you need
209
+ glued numeric fields, either zero-pad them (`MM`/`dd`) or put a separator
210
+ between them; that removes the ambiguity entirely.
211
+
212
+ Note: `Md` (or `dM`/`Hm`) alone, with no `yyyy`, always throws β€”
213
+ `parse()` requires year, month, and day together to build a date, so a
214
+ bare `Md` format string is incomplete regardless of ambiguity. The
215
+ examples above use `yyyy-Md` for exactly this reason.
203
216
 
204
217
  ## Dev notes
205
218
 
@@ -219,4 +232,4 @@ through `Intl.DateTimeFormat` directly; on the polyfill, it falls back to
219
232
 
220
233
  ## License
221
234
 
222
- MIT
235
+ MIT
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var V=Object.defineProperty;var ee=Object.getOwnPropertyDescriptor;var te=Object.getOwnPropertyNames;var ne=Object.prototype.hasOwnProperty;var re=(e,t)=>{for(var n in t)V(e,n,{get:t[n],enumerable:!0})},oe=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of te(t))!ne.call(e,o)&&o!==n&&V(e,o,{get:()=>t[o],enumerable:!(r=ee(t,o))||r.enumerable});return e};var ae=e=>oe(V({},"__esModule",{value:!0}),e);var Me={};re(Me,{format:()=>G,parse:()=>J,setTemporal:()=>W});module.exports=ae(Me);var Y;function W(e){Y=e}function ie(){return Y??globalThis.Temporal}function L(){let e=ie();if(!e)throw new Error("temporal-fmt: parse() needs a Temporal implementation to construct its result. Call setTemporal(Temporal) once at startup, or assign one to globalThis.Temporal (native on Node 26+, or a polyfill like temporal-polyfill).");return e}function h(e,t){let n=e<0,r=String(Math.abs(e)).padStart(t,"0");return n?"-"+r:r}var S="en-US",x=new Map,se=500;function X(e,t){let n=e+JSON.stringify(t),r=x.get(n);if(r)return r;if(x.size>=se){let o=x.keys().next().value;o!==void 0&&x.delete(o)}return r=new Intl.DateTimeFormat(e,t),x.set(n,r),r}var $;function me(){if($===void 0){$=!1;try{let e=L();new Intl.DateTimeFormat("en-US",{day:"numeric"}).formatToParts(e.PlainDate.from({year:1970,month:1,day:1})),$=!0}catch{}}return $}function O(e,t,n,r){let o=e?.calendarId,a={...n,...o&&o!=="iso8601"?{calendar:o}:{}};if(!me())return e.toLocaleString(t,a);let{toInstant:i,timeZoneId:s}=e,d=typeof i=="function"&&typeof s=="string",y=d?e.toInstant():e,l={...a,...d?{timeZone:s}:{}},p=X(t,l).formatToParts(y),f=p.findIndex(N=>N.type===r);if(f===-1)throw new Error(`temporal-fmt: locale "${t}" produced no "${r}" part for this token. This usually means the Temporal object is missing the field the token needs.`);let c=p[f].value,m=p[f-1],u=p[f+1];return m?.type==="literal"&&!/\s/.test(m.value)&&(c=m.value+c),u?.type==="literal"&&!/\s/.test(u.value)&&(c=c+u.value),c}function de(e,t){let n=new Date(Date.UTC(1970,0,1,e)),o=X(t,{hour:"numeric",hour12:!0,timeZone:"UTC"}).formatToParts(n).find(a=>a.type==="dayPeriod");if(!o)throw new Error(`temporal-fmt: locale "${t}" produced no "dayPeriod" part for token "a".`);return o.value}var A=[["yyyy",e=>h(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 h(e.year%100,2)},"year"],["MMMM",(e,t)=>O(e,t,{month:"long"},"month"),"month"],["MMM",(e,t)=>O(e,t,{month:"short"},"month"),"month"],["MM",e=>h(e.month,2),"month"],["M",e=>String(e.month),"month"],["dd",e=>h(e.day,2),"day"],["d",e=>String(e.day),"day"],["EEEE",(e,t)=>O(e,t,{weekday:"long"},"weekday"),"dayOfWeek"],["EEE",(e,t)=>O(e,t,{weekday:"short"},"weekday"),"dayOfWeek"],["HH",e=>h(e.hour,2),"hour"],["H",e=>String(e.hour),"hour"],["hh",e=>h(e.hour%12||12,2),"hour"],["h",e=>String(e.hour%12||12),"hour"],["mm",e=>h(e.minute,2),"minute"],["m",e=>String(e.minute),"minute"],["ss",e=>h(e.second,2),"second"],["s",e=>String(e.second),"second"],["SSS",e=>h(e.millisecond,3),"millisecond"],["a",(e,t)=>de(e.hour,t),"hour"],["zzz",e=>e.timeZoneId,"timeZoneId"]];var ue=A.map(([e])=>e).sort((e,t)=>t.length-e.length);function Z(e){let t=[],n=0;for(;n<e.length;){let r=e[n];if(r==="'"){if(e[n+1]==="'"){j(t,"'"),n+=2;continue}let a=n+1,i="",s=!1;for(;a<e.length;){if(e[a]==="'"){if(e[a+1]==="'"){i+="'",a+=2;continue}s=!0,a+=1;break}i+=e[a],a+=1}if(!s)throw new Error(`temporal-fmt: unterminated quote in format string "${e}"`);j(t,i),n=a;continue}let o=ue.find(a=>e.startsWith(a,n));if(o){t.push({kind:"token",value:o}),n+=o.length;continue}j(t,r),n+=1}return t}function j(e,t){let n=e[e.length-1];n&&n.kind==="literal"?n.value+=t:e.push({kind:"literal",value:t})}var ce=new Map(A.map(([e,t,n])=>[e,{fn:t,field:n}]));function G(e,t,n={}){if(t.length>1e3)throw new Error(`temporal-fmt: format string exceeds maximum length of ${1e3} characters (got ${t.length}).`);let r=n.locale??S,o=Z(t),a="";for(let i of o){if(i.kind==="literal"){a+=i.value;continue}let s=ce.get(i.value);if(!s)throw new Error(`temporal-fmt: unknown token "${i.value}"`);if(e[s.field]===void 0)throw new Error(`temporal-fmt: token "${i.value}" requires "${s.field}", which this Temporal object doesn't have. (e.g. PlainDate has no time fields, PlainTime has no date fields)`);a+=s.fn(e,r)}return a}var D=new Map,le=500;function b(e,t,n){let r=e.formatToParts(t),o=r.findIndex(d=>d.type===n);if(o===-1)throw new Error(`temporal-fmt: locale produced no "${n}" part while building match vocabulary.`);let a=r[o].value,i=r[o-1],s=r[o+1];return i?.type==="literal"&&!/\s/.test(i.value)&&(a=i.value+a),s?.type==="literal"&&!/\s/.test(s.value)&&(a=a+s.value),a}function _(e,t,n){let r=new Map;for(let o=0;o<e.length;o++){let a=r.get(e[o]);if(a!==void 0)throw new Error(`temporal-fmt: locale "${n}" renders ${t} index ${a} and ${o} identically ("${e[o]}"). parse() can't reliably tell these apart for this locale/token, so this combination isn't supported.`);r.set(e[o],o)}}function g(e){let t=D.get(e);if(t)return t;let n=new Intl.DateTimeFormat(e,{month:"long",timeZone:"UTC"}),r=new Intl.DateTimeFormat(e,{month:"short",timeZone:"UTC"}),o=[],a=[];for(let m=0;m<12;m++){let u=new Date(Date.UTC(2020,m,1));o.push(b(n,u,"month")),a.push(b(r,u,"month"))}_(o,"MMMM month",e),_(a,"MMM month",e);let i=new Intl.DateTimeFormat(e,{weekday:"long",timeZone:"UTC"}),s=new Intl.DateTimeFormat(e,{weekday:"short",timeZone:"UTC"}),d=[],y=[];for(let m=0;m<7;m++){let u=new Date(Date.UTC(2024,0,1+m));d.push(b(i,u,"weekday")),y.push(b(s,u,"weekday"))}_(d,"EEEE weekday",e),_(y,"EEE weekday",e);let l=new Intl.DateTimeFormat(e,{hour:"numeric",hour12:!0,timeZone:"UTC"}),k=b(l,new Date(Date.UTC(2020,0,1,1)),"dayPeriod"),p=b(l,new Date(Date.UTC(2020,0,1,13)),"dayPeriod"),f=[...new Set([k,p])],c={monthLong:o,monthShort:a,weekdayLong:d,weekdayShort:y,dayPeriod:f};if(D.size>=le){let m=D.keys().next().value;m!==void 0&&D.delete(m)}return D.set(e,c),c}function pe(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function v(e){return`(?:${e.map(pe).join("|")})`}var F;function fe(){if(F)return F;let e=Intl.supportedValuesOf;return typeof e=="function"?F=v([...e("timeZone"),"UTC"]):F="[A-Za-z_]+(?:\\/[A-Za-z_+\\-0-9]+)+|UTC",F}var he={yyyy:"\\d{4}",yy:"\\d{2}",MM:"(?:0[1-9]|1[0-2])",M:"(?:[1-9]|1[0-2])",dd:"(?:0[1-9]|[12]\\d|3[01])",d:"(?:[1-9]|[12]\\d|3[01])",HH:"(?:[01]\\d|2[0-3])",H:"(?:[0-9]|1\\d|2[0-3])",hh:"(?:0[1-9]|1[0-2])",h:"(?:[1-9]|1[0-2])",mm:"(?:[0-5]\\d)",m:"(?:[0-9]|[1-5]\\d)",ss:"(?:[0-5]\\d)",s:"(?:[0-9]|[1-5]\\d)",SSS:"\\d{3}"};function q(e,t){let n=he[e];if(n)return n;let r=g(t);switch(e){case"MMMM":return v(r.monthLong);case"MMM":return v(r.monthShort);case"EEEE":return v(r.weekdayLong);case"EEE":return v(r.weekdayShort);case"a":return v(r.dayPeriod);case"zzz":return fe();default:throw new Error(`temporal-fmt: unknown token "${e}"`)}}function ge(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function B(e,t){let n=[],r="",o=0;for(let a of e){if(a.kind==="literal"){r+=ge(a.value);continue}let i=`g${o++}`;n.push({name:i,token:a.value}),r+=`(?<${i}>${q(a.value,t)})`}return{regex:new RegExp(`^(?:${r})$`,"u"),groups:n}}var P=new Map,ye=500;function ke(e,t){let n=t+" "+e,r=P.get(n);if(r)return r;if(P.size>=ye){let o=P.keys().next().value;o!==void 0&&P.delete(o)}return r=B(Z(e),t),P.set(n,r),r}var M=new Map,we=500;function Te(e){if(M.has(e))return M.get(e);if(M.size>=we){let n=M.keys().next().value;n!==void 0&&M.delete(n)}let t;if(e.includes("-u-ca-")){let n=new Intl.DateTimeFormat(e).resolvedOptions().calendar;t=n==="gregory"?void 0:n}return M.set(e,t),t}function Ee(e,t,n,r){switch(t){case"yyyy":e.year=parseInt(n,10);break;case"yy":e.twoDigitYear=parseInt(n,10);break;case"MM":case"M":e.month=parseInt(n,10);break;case"MMMM":e.month=g(r).monthLong.indexOf(n)+1;break;case"MMM":e.month=g(r).monthShort.indexOf(n)+1;break;case"dd":case"d":e.day=parseInt(n,10);break;case"EEEE":e.weekdayRaw=n,e.weekdayExpected=g(r).weekdayLong.indexOf(n)+1;break;case"EEE":e.weekdayRaw=n,e.weekdayExpected=g(r).weekdayShort.indexOf(n)+1;break;case"HH":case"H":e.hour=parseInt(n,10);break;case"hh":case"h":e.hour12=parseInt(n,10);break;case"mm":case"m":e.minute=parseInt(n,10);break;case"ss":case"s":e.second=parseInt(n,10);break;case"SSS":e.millisecond=parseInt(n,10);break;case"a":e.isPM=n===g(r).dayPeriod[1];break;case"zzz":e.timeZoneId=n;break}}function be(e){if(e.year!==void 0)return e.year;if(e.twoDigitYear!==void 0)return e.twoDigitYear<=68?2e3+e.twoDigitYear:1900+e.twoDigitYear}function ve(e,t){if(e.hour!==void 0&&e.hour12!==void 0)throw new Error(`temporal-fmt: format string "${t}" mixes a 24-hour token ("HH"/"H") with a 12-hour token ("hh"/"h"). Pick one or the other \u2014 parse() won't guess which is authoritative.`);if(e.hour!==void 0)return e.hour;if(e.hour12!==void 0){if(e.isPM===void 0)throw new Error(`temporal-fmt: format string "${t}" uses a 12-hour token ("hh"/"h") without an "a" token, so parse() can't tell AM from PM.`);return e.hour12%12+(e.isPM?12:0)}}function J(e,t,n={}){if(e.length>1e3)throw new Error(`temporal-fmt: format string exceeds maximum length of ${1e3} characters (got ${e.length}).`);let r=n.locale??S,o=Te(r),a=ke(e,r),i=a.regex.exec(t);if(!i)throw new Error("temporal-fmt: no valid pattern matches the format string and input shape");if(a.groups.length===0)throw new Error(`temporal-fmt: format string "${e}" has no tokens \u2014 nothing to parse into a value.`);let s={};for(let{name:E,token:R}of a.groups)Ee(s,R,i.groups[E],r);let d=be(s),y=ve(s,e),{month:l,day:k,minute:p,second:f,millisecond:c,timeZoneId:m,weekdayExpected:u,weekdayRaw:N}=s,Q=d!==void 0||l!==void 0||k!==void 0,w=d!==void 0&&l!==void 0&&k!==void 0;if(Q&&!w)throw new Error(`temporal-fmt: format string "${e}" has an incomplete date \u2014 year, month, and day tokens must all be present together.`);let z=y!==void 0||p!==void 0||f!==void 0||c!==void 0;if(m!==void 0&&!(w&&z))throw new Error(`temporal-fmt: format string "${e}" has a "zzz" token but needs a full date and time to build a ZonedDateTime.`);if(u!==void 0&&!w)throw new Error(`temporal-fmt: format string "${e}" has a weekday token ("EEEE"/"EEE") but needs a full date to validate it against.`);if(!w&&!z)throw new Error(`temporal-fmt: format string "${e}" has no date or time tokens to parse.`);let I=L(),H={hour:y??0,minute:p??0,second:f??0,millisecond:c??0},U=o?{calendar:o}:{},C={overflow:"reject"},T;try{m!==void 0?T=I.ZonedDateTime.from({year:d,month:l,day:k,...H,...U,timeZone:m},C):w&&z?T=I.PlainDateTime.from({year:d,month:l,day:k,...H,...U},C):w?T=I.PlainDate.from({year:d,month:l,day:k,...U},C):T=I.PlainTime.from(H,C)}catch(E){throw new Error(`temporal-fmt: "${t}" doesn't describe a valid date/time for format "${e}": ${E.message}`)}if(u!==void 0){let E=T.dayOfWeek;if(E!==u){let R=g(r);throw new Error(`temporal-fmt: "${N}" doesn't match the actual weekday (${R.weekdayLong[E-1]}) for the parsed date.`)}}return T}0&&(module.exports={format,parse,setTemporal});
1
+ "use strict";var j=Object.defineProperty;var oe=Object.getOwnPropertyDescriptor;var ae=Object.getOwnPropertyNames;var ie=Object.prototype.hasOwnProperty;var se=(e,t)=>{for(var n in t)j(e,n,{get:t[n],enumerable:!0})},me=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ae(t))!ie.call(e,o)&&o!==n&&j(e,o,{get:()=>t[o],enumerable:!(r=oe(t,o))||r.enumerable});return e};var ue=e=>me(j({},"__esModule",{value:!0}),e);var Pe={};se(Pe,{format:()=>q,parse:()=>te,setTemporal:()=>X});module.exports=ue(Pe);var W;function X(e){W=e}function de(){return W??globalThis.Temporal}function S(){let e=de();if(!e)throw new Error("temporal-fmt: parse() needs a Temporal implementation to construct its result. Call setTemporal(Temporal) once at startup, or assign one to globalThis.Temporal (native on Node 26+, or a polyfill like temporal-polyfill).");return e}function k(e,t){let n=e<0,r=String(Math.abs(e)).padStart(t,"0");return n?"-"+r:r}var A="en-US",D=new Map,ce=500;function J(e,t){let n=e+JSON.stringify(t),r=D.get(n);if(r)return r;if(D.size>=ce){let o=D.keys().next().value;o!==void 0&&D.delete(o)}return r=new Intl.DateTimeFormat(e,t),D.set(n,r),r}var L;function le(){if(L===void 0){L=!1;try{let e=S();new Intl.DateTimeFormat("en-US",{day:"numeric"}).formatToParts(e.PlainDate.from({year:1970,month:1,day:1})),L=!0}catch{}}return L}function N(e,t,n,r){let o=e?.calendarId,a={...n,...o&&o!=="iso8601"?{calendar:o}:{}};if(!le())return e.toLocaleString(t,a);let{toInstant:i,timeZoneId:s}=e,m=typeof i=="function"&&typeof s=="string",d=m?e.toInstant():e,c={...a,...m?{timeZone:s}:{}},p=J(t,c).formatToParts(d),y=p.findIndex(U=>U.type===r);if(y===-1)throw new Error(`temporal-fmt: locale "${t}" produced no "${r}" part for this token. This usually means the Temporal object is missing the field the token needs.`);let f=p[y].value,u=p[y-1],l=p[y+1];return u?.type==="literal"&&!/\s/.test(u.value)&&(f=u.value+f),l?.type==="literal"&&!/\s/.test(l.value)&&(f=f+l.value),f}function pe(e,t){let n=new Date(Date.UTC(1970,0,1,e)),o=J(t,{hour:"numeric",hour12:!0,timeZone:"UTC"}).formatToParts(n).find(a=>a.type==="dayPeriod");if(!o)throw new Error(`temporal-fmt: locale "${t}" produced no "dayPeriod" part for token "a".`);return o.value}var _=[["yyyy",e=>k(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 k(e.year%100,2)},"year"],["MMMM",(e,t)=>N(e,t,{month:"long"},"month"),"month"],["MMM",(e,t)=>N(e,t,{month:"short"},"month"),"month"],["MM",e=>k(e.month,2),"month"],["M",e=>String(e.month),"month"],["dd",e=>k(e.day,2),"day"],["d",e=>String(e.day),"day"],["EEEE",(e,t)=>N(e,t,{weekday:"long"},"weekday"),"dayOfWeek"],["EEE",(e,t)=>N(e,t,{weekday:"short"},"weekday"),"dayOfWeek"],["HH",e=>k(e.hour,2),"hour"],["H",e=>String(e.hour),"hour"],["hh",e=>k(e.hour%12||12,2),"hour"],["h",e=>String(e.hour%12||12),"hour"],["mm",e=>k(e.minute,2),"minute"],["m",e=>String(e.minute),"minute"],["ss",e=>k(e.second,2),"second"],["s",e=>String(e.second),"second"],["SSS",e=>k(e.millisecond,3),"millisecond"],["a",(e,t)=>pe(e.hour,t),"hour"],["zzz",e=>e.timeZoneId,"timeZoneId"]];var fe=_.map(([e])=>e).sort((e,t)=>t.length-e.length);function R(e){let t=[],n=0;for(;n<e.length;){let r=e[n];if(r==="'"){if(e[n+1]==="'"){K(t,"'"),n+=2;continue}let a=n+1,i="",s=!1;for(;a<e.length;){if(e[a]==="'"){if(e[a+1]==="'"){i+="'",a+=2;continue}s=!0,a+=1;break}i+=e[a],a+=1}if(!s)throw new Error(`temporal-fmt: unterminated quote in format string "${e}"`);K(t,i),n=a;continue}let o=fe.find(a=>e.startsWith(a,n));if(o){t.push({kind:"token",value:o}),n+=o.length;continue}K(t,r),n+=1}return t}function K(e,t){let n=e[e.length-1];n&&n.kind==="literal"?n.value+=t:e.push({kind:"literal",value:t})}var ge=new Map(_.map(([e,t,n])=>[e,{fn:t,field:n}]));function q(e,t,n={}){if(t.length>1e3)throw new Error(`temporal-fmt: format string exceeds maximum length of ${1e3} characters (got ${t.length}).`);let r=n.locale??A,o=R(t),a="";for(let i of o){if(i.kind==="literal"){a+=i.value;continue}let s=ge.get(i.value);if(!s)throw new Error(`temporal-fmt: unknown token "${i.value}"`);if(e[s.field]===void 0)throw new Error(`temporal-fmt: token "${i.value}" requires "${s.field}", which this Temporal object doesn't have. (e.g. PlainDate has no time fields, PlainTime has no date fields)`);a+=s.fn(e,r)}return a}var F=new Map,he=500;function x(e,t,n){let r=e.formatToParts(t),o=r.findIndex(m=>m.type===n);if(o===-1)throw new Error(`temporal-fmt: locale produced no "${n}" part while building match vocabulary.`);let a=r[o].value,i=r[o-1],s=r[o+1];return i?.type==="literal"&&!/\s/.test(i.value)&&(a=i.value+a),s?.type==="literal"&&!/\s/.test(s.value)&&(a=a+s.value),a}function Z(e,t,n){let r=new Map;for(let o=0;o<e.length;o++){let a=r.get(e[o]);if(a!==void 0)throw new Error(`temporal-fmt: locale "${n}" renders ${t} index ${a} and ${o} identically ("${e[o]}"). parse() can't reliably tell these apart for this locale/token, so this combination isn't supported.`);r.set(e[o],o)}}function w(e){let t=F.get(e);if(t)return t;let n=new Intl.DateTimeFormat(e,{month:"long",timeZone:"UTC"}),r=new Intl.DateTimeFormat(e,{month:"short",timeZone:"UTC"}),o=[],a=[];for(let u=0;u<12;u++){let l=new Date(Date.UTC(2020,u,1));o.push(x(n,l,"month")),a.push(x(r,l,"month"))}Z(o,"MMMM month",e),Z(a,"MMM month",e);let i=new Intl.DateTimeFormat(e,{weekday:"long",timeZone:"UTC"}),s=new Intl.DateTimeFormat(e,{weekday:"short",timeZone:"UTC"}),m=[],d=[];for(let u=0;u<7;u++){let l=new Date(Date.UTC(2024,0,1+u));m.push(x(i,l,"weekday")),d.push(x(s,l,"weekday"))}Z(m,"EEEE weekday",e),Z(d,"EEE weekday",e);let c=new Intl.DateTimeFormat(e,{hour:"numeric",hour12:!0,timeZone:"UTC"}),g=x(c,new Date(Date.UTC(2020,0,1,1)),"dayPeriod"),p=x(c,new Date(Date.UTC(2020,0,1,13)),"dayPeriod"),y=[...new Set([g,p])],f={monthLong:o,monthShort:a,weekdayLong:m,weekdayShort:d,dayPeriod:y};if(F.size>=he){let u=F.keys().next().value;u!==void 0&&F.delete(u)}return F.set(e,f),f}function ye(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function M(e){return`(?:${e.map(ye).join("|")})`}var I;function ke(){if(I)return I;let e=Intl.supportedValuesOf;return typeof e=="function"?I=M([...e("timeZone"),"UTC"]):I="[A-Za-z_]+(?:\\/[A-Za-z_+\\-0-9]+)+|UTC",I}var we={yyyy:"\\d{4}",yy:"\\d{2}",MM:"(?:0[1-9]|1[0-2])",M:"(?:1[0-2]|[1-9])",dd:"(?:0[1-9]|[12]\\d|3[01])",d:"(?:[12]\\d|3[01]|[1-9])",HH:"(?:[01]\\d|2[0-3])",H:"(?:1\\d|2[0-3]|[0-9])",hh:"(?:0[1-9]|1[0-2])",h:"(?:1[0-2]|[1-9])",mm:"(?:[0-5]\\d)",m:"(?:[1-5]\\d|[0-9])",ss:"(?:[0-5]\\d)",s:"(?:[1-5]\\d|[0-9])",SSS:"\\d{3}"};function B(e,t){let n=we[e];if(n)return n;let r=w(t);switch(e){case"MMMM":return M(r.monthLong);case"MMM":return M(r.monthShort);case"EEEE":return M(r.weekdayLong);case"EEE":return M(r.weekdayShort);case"a":return M(r.dayPeriod);case"zzz":return ke();default:throw new Error(`temporal-fmt: unknown token "${e}"`)}}var Q=new Set(["M","d","H","h","m","s"]),Te={M:[{digits:1,min:1,max:9},{digits:2,min:10,max:12}],d:[{digits:1,min:1,max:9},{digits:2,min:10,max:31}],H:[{digits:1,min:0,max:9},{digits:2,min:10,max:23}],h:[{digits:1,min:1,max:9},{digits:2,min:10,max:12}],m:[{digits:1,min:0,max:9},{digits:2,min:10,max:59}],s:[{digits:1,min:0,max:9},{digits:2,min:10,max:59}]};function G(e,t){if(t.length===0)return e.length===0?[[]]:[];let[n,...r]=t,o=Te[n];if(!o)throw new Error(`temporal-fmt: internal error \u2014 "${n}" is not an unpadded numeric token`);let a=[];for(let{digits:i,min:s,max:m}of o){if(e.length<i)continue;let d=e.slice(0,i);if(i===2&&d[0]==="0")continue;let c=parseInt(d,10);if(c<s||c>m)continue;let g=G(e.slice(i),r);for(let p of g)a.push([c,...p])}return a}function Ee(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function ee(e,t){let n=[],r=[],o="",a=0,i={groupNames:[],tokens:[]},s=()=>{i.tokens.length>=2&&r.push(i),i={groupNames:[],tokens:[]}};for(let m of e){if(m.kind==="literal"){o+=Ee(m.value),s();continue}let d=`g${a++}`;n.push({name:d,token:m.value}),o+=`(?<${d}>${B(m.value,t)})`,Q.has(m.value)?(i.groupNames.push(d),i.tokens.push(m.value)):s()}return s(),{regex:new RegExp(`^(?:${o})$`,"u"),groups:n,ambiguousRuns:r}}var P=new Map,be=500;function xe(e,t){let n=t+" "+e,r=P.get(n);if(r)return r;if(P.size>=be){let o=P.keys().next().value;o!==void 0&&P.delete(o)}return r=ee(R(e),t),P.set(n,r),r}var v=new Map,Me=500;function ve(e){if(v.has(e))return v.get(e);if(v.size>=Me){let n=v.keys().next().value;n!==void 0&&v.delete(n)}let t;if(e.includes("-u-ca-")){let n=new Intl.DateTimeFormat(e).resolvedOptions().calendar;t=n==="gregory"?void 0:n}return v.set(e,t),t}function De(e,t,n,r){switch(t){case"yyyy":e.year=parseInt(n,10);break;case"yy":e.twoDigitYear=parseInt(n,10);break;case"MM":case"M":e.month=parseInt(n,10);break;case"MMMM":e.month=w(r).monthLong.indexOf(n)+1;break;case"MMM":e.month=w(r).monthShort.indexOf(n)+1;break;case"dd":case"d":e.day=parseInt(n,10);break;case"EEEE":e.weekdayRaw=n,e.weekdayExpected=w(r).weekdayLong.indexOf(n)+1;break;case"EEE":e.weekdayRaw=n,e.weekdayExpected=w(r).weekdayShort.indexOf(n)+1;break;case"HH":case"H":e.hour=parseInt(n,10);break;case"hh":case"h":e.hour12=parseInt(n,10);break;case"mm":case"m":e.minute=parseInt(n,10);break;case"ss":case"s":e.second=parseInt(n,10);break;case"SSS":e.millisecond=parseInt(n,10);break;case"a":e.isPM=n===w(r).dayPeriod[1];break;case"zzz":e.timeZoneId=n;break}}function Fe(e){if(e.year!==void 0)return e.year;if(e.twoDigitYear!==void 0)return e.twoDigitYear<=68?2e3+e.twoDigitYear:1900+e.twoDigitYear}function Ie(e,t){if(e.hour!==void 0&&e.hour12!==void 0)throw new Error(`temporal-fmt: format string "${t}" mixes a 24-hour token ("HH"/"H") with a 12-hour token ("hh"/"h"). Pick one or the other \u2014 parse() won't guess which is authoritative.`);if(e.hour!==void 0)return e.hour;if(e.hour12!==void 0){if(e.isPM===void 0)throw new Error(`temporal-fmt: format string "${t}" uses a 12-hour token ("hh"/"h") without an "a" token, so parse() can't tell AM from PM.`);return e.hour12%12+(e.isPM?12:0)}}function te(e,t,n={}){if(e.length>1e3)throw new Error(`temporal-fmt: format string exceeds maximum length of ${1e3} characters (got ${e.length}).`);let r=n.locale??A,o=ve(r),a=xe(e,r),i=a.regex.exec(t);if(!i)throw new Error("temporal-fmt: no valid pattern matches the format string and input shape");if(a.groups.length===0)throw new Error(`temporal-fmt: format string "${e}" has no tokens \u2014 nothing to parse into a value.`);for(let h of a.ambiguousRuns){let b=h.groupNames.map(re=>i.groups[re]).join(""),O=G(b,h.tokens);if(O.length>1)throw new Error(`temporal-fmt: "${b}" in format string "${e}" is ambiguous \u2014 ${O.length} different ways to read tokens "${h.tokens.join("")}" (with no separator between them) are all individually valid (e.g. ${JSON.stringify(O[0])} vs ${JSON.stringify(O[1])}). parse() won't guess; add a separator between these tokens, or use their padded form (e.g. "MM" instead of "M") so each one has a fixed width.`)}let s={};for(let{name:h,token:b}of a.groups)De(s,b,i.groups[h],r);let m=Fe(s),d=Ie(s,e),{month:c,day:g,minute:p,second:y,millisecond:f,timeZoneId:u,weekdayExpected:l,weekdayRaw:U}=s,ne=m!==void 0||c!==void 0||g!==void 0,T=m!==void 0&&c!==void 0&&g!==void 0;if(ne&&!T)throw new Error(`temporal-fmt: format string "${e}" has an incomplete date \u2014 year, month, and day tokens must all be present together.`);let H=d!==void 0||p!==void 0||y!==void 0||f!==void 0;if(u!==void 0&&!(T&&H))throw new Error(`temporal-fmt: format string "${e}" has a "zzz" token but needs a full date and time to build a ZonedDateTime.`);if(l!==void 0&&!T)throw new Error(`temporal-fmt: format string "${e}" has a weekday token ("EEEE"/"EEE") but needs a full date to validate it against.`);if(!T&&!H)throw new Error(`temporal-fmt: format string "${e}" has no date or time tokens to parse.`);let $=S(),z={hour:d??0,minute:p??0,second:y??0,millisecond:f??0},V=o?{calendar:o}:{},C={overflow:"reject"},E;try{u!==void 0?E=$.ZonedDateTime.from({year:m,month:c,day:g,...z,...V,timeZone:u},C):T&&H?E=$.PlainDateTime.from({year:m,month:c,day:g,...z,...V},C):T?E=$.PlainDate.from({year:m,month:c,day:g,...V},C):E=$.PlainTime.from(z,C)}catch(h){throw new Error(`temporal-fmt: "${t}" doesn't describe a valid date/time for format "${e}": ${h.message}`)}if(l!==void 0){let h=E.dayOfWeek;if(h!==l){let b=w(r);throw new Error(`temporal-fmt: "${U}" doesn't match the actual weekday (${b.weekdayLong[h-1]}) for the parsed date.`)}}return E}0&&(module.exports={format,parse,setTemporal});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/temporalProvider.ts","../src/tokens.ts","../src/tokenize.ts","../src/format.ts","../src/localeVocab.ts","../src/pattern.ts","../src/parsePattern.ts","../src/parse.ts"],"sourcesContent":["export { format } from './format.js';\nexport { parse } from './parse.js';\nexport { setTemporal } from './temporalProvider.js';\nexport type { TemporalLike, FormatOptions } from './tokens.js';\nexport type { TemporalNamespace } from './temporalProvider.js';","// 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' }): unknown;\n}\n\nexport interface TemporalNamespace {\n PlainDate: TemporalFactory;\n PlainTime: TemporalFactory;\n PlainDateTime: TemporalFactory;\n ZonedDateTime: TemporalFactory;\n}\n\nlet injectedTemporal: TemporalNamespace | undefined;\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()`\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}\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","import { getTemporal } from './temporalProvider.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// 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 timeZoneId?: 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\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 = locale + JSON.stringify(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 formatter = new Intl.DateTimeFormat(locale, options);\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;\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 nativeSupport = true;\n } catch {\n // native Temporal absent, or present but not recognized by Intl β€” fall back\n }\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 // skip this for iso8601 specifically β€” passing `calendar: 'iso8601'`\n // explicitly alongside a single-field options object makes formatToParts()\n // come back empty for some reason.\n const calendar = temporal?.calendarId;\n const formatterOptions: Intl.DateTimeFormatOptions = {\n ...options,\n ...(calendar && calendar !== 'iso8601' ? { calendar } : {}),\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 if (!intlSupportsNativeTemporal()) {\n return temporal.toLocaleString!(locale, formatterOptions);\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\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 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 if (!part) {\n throw new Error(`temporal-fmt: locale \"${locale}\" produced no \"dayPeriod\" part for token \"a\".`);\n }\n return part.value;\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) => intlPart(t, locale, { month: 'long' }, 'month'), 'month'],\n ['MMM', (t, locale) => intlPart(t, locale, { month: 'short' }, 'month'), '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) => intlPart(t, locale, { weekday: 'long' }, 'weekday'), 'dayOfWeek'],\n ['EEE', (t, locale) => intlPart(t, locale, { weekday: 'short' }, 'weekday'), '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 ['SSS', (t) => pad(t.millisecond!, 3), '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];","import { TOKENS } from './tokens.js';\n\nexport type Piece =\n | { kind: 'token'; value: string }\n | { kind: 'literal'; value: string };\n\n// longest-first so the greedy scan never matches \"M\" when \"MMMM\" was there\nconst SORTED_TOKEN_STRINGS = TOKENS.map(([tok]) => tok).sort((a, b) => b.length - a.length);\n\n/**\n * Splits a format string like `\"yyyy-MM-dd 'at' HH:mm\"` into token/literal\n * pieces. Text in single quotes is always literal (e.g. write 'rd' in\n * \"3rd\" so it's not read as the day token). A doubled quote ('') means a\n * literal quote character, both inside a quoted span and standalone.\n */\nexport function tokenize(format: string): Piece[] {\n const pieces: Piece[] = [];\n let i = 0;\n\n while (i < format.length) {\n const ch = format[i];\n\n if (ch === \"'\") {\n // check doubled-quote first or \"''best''\" parses wrong\n if (format[i + 1] === \"'\") {\n appendLiteral(pieces, \"'\");\n i += 2;\n continue;\n }\n\n let j = i + 1;\n let literal = '';\n let closed = false;\n while (j < format.length) {\n if (format[j] === \"'\") {\n if (format[j + 1] === \"'\") {\n literal += \"'\";\n j += 2;\n continue;\n }\n closed = true;\n j += 1;\n break;\n }\n literal += format[j];\n j += 1;\n }\n\n if (!closed) {\n throw new Error(`temporal-fmt: unterminated quote in format string \"${format}\"`);\n }\n\n appendLiteral(pieces, literal);\n i = j;\n continue;\n }\n\n const match = SORTED_TOKEN_STRINGS.find((tok) => format.startsWith(tok, i));\n if (match) {\n pieces.push({ kind: 'token', value: match });\n i += match.length;\n continue;\n }\n\n // not a token or quote β€” pass through as-is\n appendLiteral(pieces, ch);\n i += 1;\n }\n\n return pieces;\n}\n\n// merges into the previous piece if it's also a literal, so \"---\" is one\n// piece instead of three\nfunction appendLiteral(pieces: Piece[], value: string): void {\n const last = pieces[pieces.length - 1];\n if (last && last.kind === 'literal') {\n last.value += value;\n } else {\n pieces.push({ kind: 'literal', value });\n }\n}\n","import { TOKENS, DEFAULT_LOCALE, type TemporalLike, type FormatOptions } from './tokens.js';\nimport { tokenize } from './tokenize.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\n\nconst HANDLER_BY_TOKEN = new Map(TOKENS.map(([tok, fn, field]) => [tok, { fn, field }]));\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: FormatOptions = {}): string {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`\n );\n }\n\n const locale = options.locale ?? DEFAULT_LOCALE;\n const pieces = tokenize(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 if (!handler) {\n // shouldn't happen β€” tokenize() only emits tokens from TOKENS\n throw new Error(`temporal-fmt: unknown token \"${piece.value}\"`);\n }\n\n if (temporal[handler.field] === undefined) {\n throw new Error(\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 return result;\n}\n","// 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\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\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 if (index === -1) {\n throw new Error(`temporal-fmt: locale produced no \"${type}\" part while building match vocabulary.`);\n }\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 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\nexport function getLocaleVocab(locale: string): LocaleVocab {\n const cached = vocabCache.get(locale);\n if (cached) {\n return cached;\n }\n\n const monthLongFmt = new Intl.DateTimeFormat(locale, { month: 'long', timeZone: 'UTC' });\n const monthShortFmt = new Intl.DateTimeFormat(locale, { 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(locale, { weekday: 'long', timeZone: 'UTC' });\n const weekdayShortFmt = new Intl.DateTimeFormat(locale, { 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(locale, { 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(locale, vocab);\n return vocab;\n}","import { getLocaleVocab } from './localeVocab.js';\n\nfunction escapeRegExp(literal: string): string {\n return literal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction alternation(values: string[]): string {\n return `(?:${values.map(escapeRegExp).join('|')})`;\n}\n\nlet timeZoneFragment: string | undefined;\n\nfunction getTimeZoneFragment(): string {\n if (timeZoneFragment) {\n return timeZoneFragment;\n }\n const supportedValuesOf = (Intl as unknown as { supportedValuesOf?: (key: string) => string[] }).supportedValuesOf;\n if (typeof supportedValuesOf === 'function') {\n // supportedValuesOf('timeZone') leaves out 'UTC', but format() can\n // produce it from a real ZonedDateTime β€” without this, parse() couldn't\n // parse our own library's own output back.\n timeZoneFragment = alternation([...supportedValuesOf('timeZone'), 'UTC']);\n } else {\n // no Intl.supportedValuesOf β€” match on shape only\n timeZoneFragment = '[A-Za-z_]+(?:\\\\/[A-Za-z_+\\\\-0-9]+)+|UTC';\n }\n return timeZoneFragment;\n}\n\n// mirrors the ranges pad() in tokens.ts actually produces β€” keep in sync\n// if those ever change\nconst NUMERIC_FRAGMENTS: Record<string, string> = {\n yyyy: '\\\\d{4}',\n yy: '\\\\d{2}',\n MM: '(?:0[1-9]|1[0-2])',\n M: '(?:[1-9]|1[0-2])',\n dd: '(?:0[1-9]|[12]\\\\d|3[01])',\n d: '(?:[1-9]|[12]\\\\d|3[01])',\n HH: '(?:[01]\\\\d|2[0-3])',\n H: '(?:[0-9]|1\\\\d|2[0-3])',\n hh: '(?:0[1-9]|1[0-2])',\n h: '(?:[1-9]|1[0-2])',\n mm: '(?:[0-5]\\\\d)',\n m: '(?:[0-9]|[1-5]\\\\d)',\n ss: '(?:[0-5]\\\\d)',\n s: '(?:[0-9]|[1-5]\\\\d)',\n SSS: '\\\\d{3}',\n};\n\nexport function tokenFragment(token: string, locale: string): string {\n const numeric = NUMERIC_FRAGMENTS[token];\n if (numeric) {\n return numeric;\n }\n\n const vocab = getLocaleVocab(locale);\n switch (token) {\n case 'MMMM': return alternation(vocab.monthLong);\n case 'MMM': return alternation(vocab.monthShort);\n case 'EEEE': return alternation(vocab.weekdayLong);\n case 'EEE': return alternation(vocab.weekdayShort);\n case 'a': return alternation(vocab.dayPeriod);\n case 'zzz': return getTimeZoneFragment();\n default:\n throw new Error(`temporal-fmt: unknown token \"${token}\"`);\n }\n}\n","import type { Piece } from './tokenize.js';\nimport { tokenFragment } from './pattern.js';\n\nfunction escapeRegExp(literal: string): string {\n return literal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport interface CapturingPattern {\n regex: RegExp;\n groups: Array<{ name: string; token: string }>; // token pieces, in order\n}\n\n/**\n * Same walk as buildPatternSource() in pattern.ts, but each token piece\n * gets its own named capture group (positionally named so the same token,\n * e.g. \"yyyy\", could in theory appear twice) so a caller can pull the\n * matched substring for each token back out after a successful match.\n */\nexport function buildCapturingPattern(pieces: Piece[], locale: string): CapturingPattern {\n const groups: Array<{ name: string; token: string }> = [];\n let source = '';\n let i = 0;\n\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n source += escapeRegExp(piece.value);\n continue;\n }\n const name = `g${i++}`;\n groups.push({ name, token: piece.value });\n source += `(?<${name}>${tokenFragment(piece.value, locale)})`;\n }\n\n return { regex: new RegExp(`^(?:${source})$`, 'u'), groups };\n}\n","import { DEFAULT_LOCALE, type FormatOptions } from './tokens.js';\nimport { tokenize } from './tokenize.js';\nimport { buildCapturingPattern, type CapturingPattern } from './parsePattern.js';\nimport { getLocaleVocab } from './localeVocab.js';\nimport { getTemporal } from './temporalProvider.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\n\n// format strings are short hand-written literals reused across many calls β€”\n// cache the compiled capturing pattern per (formatStr, locale) pair instead\n// of rebuilding it every call.\nconst patternCache = new Map<string, CapturingPattern>();\nconst MAX_CACHE_SIZE = 500;\n\nfunction getPattern(formatStr: string, locale: string): CapturingPattern {\n const key = locale + ' ' + formatStr;\n let pattern = patternCache.get(key);\n if (pattern) {\n return pattern;\n }\n if (patternCache.size >= MAX_CACHE_SIZE) {\n const oldestKey = patternCache.keys().next().value;\n if (oldestKey !== undefined) patternCache.delete(oldestKey);\n }\n pattern = buildCapturingPattern(tokenize(formatStr), locale);\n patternCache.set(key, pattern);\n return pattern;\n}\n\n// Requires an explicit `-u-ca-` extension (e.g. 'en-u-ca-hebrew') to apply\n// a non-Gregorian calendar, per parse()'s own docstring. 'gregory' counts\n// as \"no calendar\" so the default locale keeps constructing plain ISO 8601.\n//\n// Used to key off resolvedOptions().calendar instead β€” a locale's\n// *default* calendar, whether the caller asked for one or not. That broke\n// th-TH silently: its default is 'buddhist', so plain Gregorian-looking\n// digits parsed 543 years off, while format() has no matching calendar\n// step and just prints the object's own ISO fields either way.\nconst calendarCache = new Map<string, string | undefined>();\nconst MAX_CALENDAR_CACHE_SIZE = 500;\n\nfunction resolveCalendar(locale: string): string | undefined {\n if (calendarCache.has(locale)) {\n return calendarCache.get(locale);\n }\n if (calendarCache.size >= MAX_CALENDAR_CACHE_SIZE) {\n const oldestKey = calendarCache.keys().next().value;\n if (oldestKey !== undefined) calendarCache.delete(oldestKey);\n }\n let calendar: string | undefined;\n if (locale.includes('-u-ca-')) {\n const resolved = new Intl.DateTimeFormat(locale).resolvedOptions().calendar;\n calendar = resolved === 'gregory' ? undefined : resolved;\n }\n calendarCache.set(locale, calendar);\n return calendar;\n}\n\ninterface Fields {\n year?: number;\n twoDigitYear?: number;\n month?: number;\n day?: number;\n hour?: number;\n hour12?: number;\n isPM?: boolean;\n minute?: number;\n second?: number;\n millisecond?: number;\n timeZoneId?: string;\n weekdayExpected?: number; // ISO dayOfWeek, 1=Mon, 7=Sun\n weekdayRaw?: string;\n}\n\nfunction applyGroup(fields: Fields, token: string, raw: string, locale: string): void {\n switch (token) {\n case 'yyyy': fields.year = parseInt(raw, 10); break;\n case 'yy': fields.twoDigitYear = parseInt(raw, 10); break;\n case 'MM': case 'M': fields.month = parseInt(raw, 10); break;\n case 'MMMM': fields.month = getLocaleVocab(locale).monthLong.indexOf(raw) + 1; break;\n case 'MMM': fields.month = getLocaleVocab(locale).monthShort.indexOf(raw) + 1; break;\n case 'dd': case 'd': fields.day = parseInt(raw, 10); break;\n case 'EEEE':\n fields.weekdayRaw = raw;\n fields.weekdayExpected = getLocaleVocab(locale).weekdayLong.indexOf(raw) + 1;\n break;\n case 'EEE':\n fields.weekdayRaw = raw;\n fields.weekdayExpected = getLocaleVocab(locale).weekdayShort.indexOf(raw) + 1;\n break;\n case 'HH': case 'H': fields.hour = parseInt(raw, 10); break;\n case 'hh': case 'h': fields.hour12 = parseInt(raw, 10); break;\n case 'mm': case 'm': fields.minute = parseInt(raw, 10); break;\n case 'ss': case 's': fields.second = parseInt(raw, 10); break;\n case 'SSS': fields.millisecond = parseInt(raw, 10); break;\n case 'a': fields.isPM = raw === getLocaleVocab(locale).dayPeriod[1]; break;\n case 'zzz': fields.timeZoneId = raw; break;\n }\n}\n\n// emulates strptime (POSIX) for 2-digit years so the result doesn't depend\n// on the current clock: 00-68 -> 2000-2068, 69-99 -> 1900-1999\n// https://www.man7.org/linux//man-pages/man3/strptime.3p.html\nfunction resolveYear(fields: Fields): number | undefined {\n if (fields.year !== undefined) return fields.year;\n if (fields.twoDigitYear !== undefined) {\n return fields.twoDigitYear <= 68 ? 2000 + fields.twoDigitYear : 1900 + fields.twoDigitYear;\n }\n return undefined;\n}\n\nfunction resolveHour(fields: Fields, formatStr: string): number | undefined {\n if (fields.hour !== undefined && fields.hour12 !== undefined) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" mixes a 24-hour token (\"HH\"/\"H\") with a ` +\n `12-hour token (\"hh\"/\"h\"). Pick one or the other β€” parse() won't guess which is authoritative.`\n );\n }\n if (fields.hour !== undefined) return fields.hour;\n if (fields.hour12 !== undefined) {\n if (fields.isPM === undefined) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" uses a 12-hour token (\"hh\"/\"h\") without an \"a\" token, ` +\n `so parse() can't tell AM from PM.`\n );\n }\n return (fields.hour12 % 12) + (fields.isPM ? 12 : 0);\n }\n return undefined;\n}\n\n/**\n * Parses `input` against `formatStr` and builds the real Temporal value it\n * describes: a `Temporal.PlainDate`, `PlainTime`, `PlainDateTime`, or\n * `ZonedDateTime` depending on which tokens are present.\n *\n * Returns `unknown` β€” this package has no ambient `Temporal` types to return\n * a real one against.\n *\n * `options.locale` picks the calendar the result is built in. Pass a locale\n * tag with a `-u-ca-` extension (e.g. `'en-u-ca-hebrew'`) to parse into a\n * non-Gregorian calendar.\n *\n * @throws if `input` doesn't match `formatStr`'s shape at all\n * @throws if it matches the shape but describes an impossible date (e.g. Feb\n * 30) or self-contradictory data (e.g. a weekday name that doesn't match the\n * actual date)\n *\n * @example\n * parse('yyyy-MM-dd HH:mm', '2026-08-04 15:45') // Temporal.PlainDateTime\n * parse('yyyy-MM', '2026-08-04T15:45:30') // throws β€” shape doesn't match\n * parse('yyyy-MM-dd', '2026-02-30') // throws β€” not a real date\n */\nexport function parse(formatStr: string, input: string, options: FormatOptions = {}): unknown | undefined {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`\n );\n }\n\n const locale = options.locale ?? DEFAULT_LOCALE;\n const calendar = resolveCalendar(locale);\n const pattern = getPattern(formatStr, locale);\n const match = pattern.regex.exec(input);\n if (!match) {\n throw new Error(`temporal-fmt: no valid pattern matches the format string and input shape`);\n }\n\n if (pattern.groups.length === 0) {\n throw new Error(`temporal-fmt: format string \"${formatStr}\" has no tokens β€” nothing to parse into a value.`);\n }\n\n const fields: Fields = {};\n for (const { name, token } of pattern.groups) {\n applyGroup(fields, token, match.groups![name]!, locale);\n }\n\n const year = resolveYear(fields);\n const hour = resolveHour(fields, formatStr);\n const { month, day, minute, second, millisecond, timeZoneId, weekdayExpected, weekdayRaw } = fields;\n\n const hasAnyDatePart = year !== undefined || month !== undefined || day !== undefined;\n const hasFullDate = year !== undefined && month !== undefined && day !== undefined;\n if (hasAnyDatePart && !hasFullDate) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" has an incomplete date β€” ` +\n `year, month, and day tokens must all be present together.`\n );\n }\n\n const hasTime = hour !== undefined || minute !== undefined || second !== undefined || millisecond !== undefined;\n\n if (timeZoneId !== undefined && !(hasFullDate && hasTime)) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" has a \"zzz\" token but needs a full date and time ` +\n `to build a ZonedDateTime.`\n );\n }\n\n if (weekdayExpected !== undefined && !hasFullDate) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" has a weekday token (\"EEEE\"/\"EEE\") but needs ` +\n `a full date to validate it against.`\n );\n }\n\n if (!hasFullDate && !hasTime) {\n // shouldn't happen β€” every token maps to a date, time, zone, or\n // weekday field, and weekday-without-date already threw above\n throw new Error(`temporal-fmt: format string \"${formatStr}\" has no date or time tokens to parse.`);\n }\n\n const temporal = getTemporal();\n const timeFields = { hour: hour ?? 0, minute: minute ?? 0, second: second ?? 0, millisecond: millisecond ?? 0 };\n // omitted entirely for the default calendar (see resolveCalendar) so\n // construction stays plain ISO 8601 unless a caller's locale asks for\n // something else β€” Temporal calendars don't apply to time-only values.\n const calendarField = calendar ? { calendar } : {};\n\n // overflow: 'reject' β€” without it Temporal *clamps* out-of-range fields\n // (Feb 30 silently becomes Feb 28) instead of throwing, which would\n // contradict the \"throws on genuinely invalid data\" behavior parse() promises.\n const reject = { overflow: 'reject' as const };\n\n let result: unknown;\n try {\n if (timeZoneId !== undefined) {\n result = temporal.ZonedDateTime.from({ year: year!, month: month!, day: day!, ...timeFields, ...calendarField, timeZone: timeZoneId }, reject);\n } else if (hasFullDate && hasTime) {\n result = temporal.PlainDateTime.from({ year: year!, month: month!, day: day!, ...timeFields, ...calendarField }, reject);\n } else if (hasFullDate) {\n result = temporal.PlainDate.from({ year: year!, month: month!, day: day!, ...calendarField }, reject);\n } else {\n result = temporal.PlainTime.from(timeFields, reject);\n }\n } catch (err) {\n throw new Error(\n `temporal-fmt: \"${input}\" doesn't describe a valid date/time for format \"${formatStr}\": ` +\n `${(err as Error).message}`\n );\n }\n\n if (weekdayExpected !== undefined) {\n const actual = (result as { dayOfWeek: number }).dayOfWeek;\n if (actual !== weekdayExpected) {\n const vocab = getLocaleVocab(locale);\n throw new Error(\n `temporal-fmt: \"${weekdayRaw}\" doesn't match the actual weekday (${vocab.weekdayLong[actual - 1]}) ` +\n `for the parsed date.`\n );\n }\n }\n\n return result;\n}\n"],"mappings":"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","names":["index_exports","__export","format","parse","setTemporal","__toCommonJS","injectedTemporal","setTemporal","temporal","resolveTemporal","getTemporal","pad","n","len","negative","digits","DEFAULT_LOCALE","formatterCache","MAX_CACHE_SIZE","getFormatter","locale","options","key","formatter","oldestKey","nativeSupport","intlSupportsNativeTemporal","temporal","getTemporal","intlPart","partType","calendar","formatterOptions","toInstant","timeZoneId","isZoned","intlSafeTemporal","nativeOptions","parts","index","p","value","prev","next","dayPeriodPart","hour","date","part","TOKENS","t","SORTED_TOKEN_STRINGS","TOKENS","tok","a","b","tokenize","format","pieces","i","ch","appendLiteral","j","literal","closed","match","value","last","HANDLER_BY_TOKEN","TOKENS","tok","fn","field","format","temporal","formatStr","options","locale","DEFAULT_LOCALE","pieces","tokenize","result","piece","handler","vocabCache","MAX_VOCAB_CACHE_SIZE","partValue","formatter","date","type","parts","index","p","value","prev","next","assertNoCollision","names","label","locale","seen","i","prior","getLocaleVocab","cached","monthLongFmt","monthShortFmt","monthLong","monthShort","weekdayLongFmt","weekdayShortFmt","weekdayLong","weekdayShort","d","dayPeriodFmt","am","pm","dayPeriod","vocab","oldestKey","escapeRegExp","literal","alternation","values","timeZoneFragment","getTimeZoneFragment","supportedValuesOf","NUMERIC_FRAGMENTS","tokenFragment","token","locale","numeric","vocab","getLocaleVocab","escapeRegExp","literal","buildCapturingPattern","pieces","locale","groups","source","i","piece","name","tokenFragment","patternCache","MAX_CACHE_SIZE","getPattern","formatStr","locale","key","pattern","oldestKey","buildCapturingPattern","tokenize","calendarCache","MAX_CALENDAR_CACHE_SIZE","resolveCalendar","calendar","resolved","applyGroup","fields","token","raw","getLocaleVocab","resolveYear","resolveHour","parse","input","options","DEFAULT_LOCALE","match","name","year","hour","month","day","minute","second","millisecond","timeZoneId","weekdayExpected","weekdayRaw","hasAnyDatePart","hasFullDate","hasTime","temporal","getTemporal","timeFields","calendarField","reject","result","err","actual","vocab"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/temporalProvider.ts","../src/tokens.ts","../src/tokenize.ts","../src/format.ts","../src/localeVocab.ts","../src/pattern.ts","../src/parsePattern.ts","../src/parse.ts"],"sourcesContent":["export { format } from './format.js';\nexport { parse } from './parse.js';\nexport { setTemporal } from './temporalProvider.js';\nexport type { TemporalLike, FormatOptions } from './tokens.js';\nexport type { TemporalNamespace } from './temporalProvider.js';","// 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' }): unknown;\n}\n\nexport interface TemporalNamespace {\n PlainDate: TemporalFactory;\n PlainTime: TemporalFactory;\n PlainDateTime: TemporalFactory;\n ZonedDateTime: TemporalFactory;\n}\n\nlet injectedTemporal: TemporalNamespace | undefined;\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()`\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}\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","import { getTemporal } from './temporalProvider.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// 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 timeZoneId?: 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\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 = locale + JSON.stringify(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 formatter = new Intl.DateTimeFormat(locale, options);\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;\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 nativeSupport = true;\n } catch {\n // native Temporal absent, or present but not recognized by Intl β€” fall back\n }\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 // skip this for iso8601 specifically β€” passing `calendar: 'iso8601'`\n // explicitly alongside a single-field options object makes formatToParts()\n // come back empty for some reason.\n const calendar = temporal?.calendarId;\n const formatterOptions: Intl.DateTimeFormatOptions = {\n ...options,\n ...(calendar && calendar !== 'iso8601' ? { calendar } : {}),\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 if (!intlSupportsNativeTemporal()) {\n return temporal.toLocaleString!(locale, formatterOptions);\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\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 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 if (!part) {\n throw new Error(`temporal-fmt: locale \"${locale}\" produced no \"dayPeriod\" part for token \"a\".`);\n }\n return part.value;\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) => intlPart(t, locale, { month: 'long' }, 'month'), 'month'],\n ['MMM', (t, locale) => intlPart(t, locale, { month: 'short' }, 'month'), '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) => intlPart(t, locale, { weekday: 'long' }, 'weekday'), 'dayOfWeek'],\n ['EEE', (t, locale) => intlPart(t, locale, { weekday: 'short' }, 'weekday'), '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 ['SSS', (t) => pad(t.millisecond!, 3), '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];","import { TOKENS } from './tokens.js';\n\nexport type Piece =\n | { kind: 'token'; value: string }\n | { kind: 'literal'; value: string };\n\n// longest-first so the greedy scan never matches \"M\" when \"MMMM\" was there\nconst SORTED_TOKEN_STRINGS = TOKENS.map(([tok]) => tok).sort((a, b) => b.length - a.length);\n\n/**\n * Splits a format string like `\"yyyy-MM-dd 'at' HH:mm\"` into token/literal\n * pieces. Text in single quotes is always literal (e.g. write 'rd' in\n * \"3rd\" so it's not read as the day token). A doubled quote ('') means a\n * literal quote character, both inside a quoted span and standalone.\n */\nexport function tokenize(format: string): Piece[] {\n const pieces: Piece[] = [];\n let i = 0;\n\n while (i < format.length) {\n const ch = format[i];\n\n if (ch === \"'\") {\n // check doubled-quote first or \"''best''\" parses wrong\n if (format[i + 1] === \"'\") {\n appendLiteral(pieces, \"'\");\n i += 2;\n continue;\n }\n\n let j = i + 1;\n let literal = '';\n let closed = false;\n while (j < format.length) {\n if (format[j] === \"'\") {\n if (format[j + 1] === \"'\") {\n literal += \"'\";\n j += 2;\n continue;\n }\n closed = true;\n j += 1;\n break;\n }\n literal += format[j];\n j += 1;\n }\n\n if (!closed) {\n throw new Error(`temporal-fmt: unterminated quote in format string \"${format}\"`);\n }\n\n appendLiteral(pieces, literal);\n i = j;\n continue;\n }\n\n const match = SORTED_TOKEN_STRINGS.find((tok) => format.startsWith(tok, i));\n if (match) {\n pieces.push({ kind: 'token', value: match });\n i += match.length;\n continue;\n }\n\n // not a token or quote β€” pass through as-is\n appendLiteral(pieces, ch);\n i += 1;\n }\n\n return pieces;\n}\n\n// merges into the previous piece if it's also a literal, so \"---\" is one\n// piece instead of three\nfunction appendLiteral(pieces: Piece[], value: string): void {\n const last = pieces[pieces.length - 1];\n if (last && last.kind === 'literal') {\n last.value += value;\n } else {\n pieces.push({ kind: 'literal', value });\n }\n}\n","import { TOKENS, DEFAULT_LOCALE, type TemporalLike, type FormatOptions } from './tokens.js';\nimport { tokenize } from './tokenize.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\n\nconst HANDLER_BY_TOKEN = new Map(TOKENS.map(([tok, fn, field]) => [tok, { fn, field }]));\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: FormatOptions = {}): string {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`\n );\n }\n\n const locale = options.locale ?? DEFAULT_LOCALE;\n const pieces = tokenize(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 if (!handler) {\n // shouldn't happen β€” tokenize() only emits tokens from TOKENS\n throw new Error(`temporal-fmt: unknown token \"${piece.value}\"`);\n }\n\n if (temporal[handler.field] === undefined) {\n throw new Error(\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 return result;\n}\n","// 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\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\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 if (index === -1) {\n throw new Error(`temporal-fmt: locale produced no \"${type}\" part while building match vocabulary.`);\n }\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 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\nexport function getLocaleVocab(locale: string): LocaleVocab {\n const cached = vocabCache.get(locale);\n if (cached) {\n return cached;\n }\n\n const monthLongFmt = new Intl.DateTimeFormat(locale, { month: 'long', timeZone: 'UTC' });\n const monthShortFmt = new Intl.DateTimeFormat(locale, { 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(locale, { weekday: 'long', timeZone: 'UTC' });\n const weekdayShortFmt = new Intl.DateTimeFormat(locale, { 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(locale, { 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(locale, vocab);\n return vocab;\n}","import { getLocaleVocab } from './localeVocab.js';\n\nfunction escapeRegExp(literal: string): string {\n return literal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction alternation(values: string[]): string {\n return `(?:${values.map(escapeRegExp).join('|')})`;\n}\n\nlet timeZoneFragment: string | undefined;\n\nfunction getTimeZoneFragment(): string {\n if (timeZoneFragment) {\n return timeZoneFragment;\n }\n const supportedValuesOf = (Intl as unknown as { supportedValuesOf?: (key: string) => string[] }).supportedValuesOf;\n if (typeof supportedValuesOf === 'function') {\n // supportedValuesOf('timeZone') leaves out 'UTC', but format() can\n // produce it from a real ZonedDateTime β€” without this, parse() couldn't\n // parse our own library's own output back.\n timeZoneFragment = alternation([...supportedValuesOf('timeZone'), 'UTC']);\n } else {\n // no Intl.supportedValuesOf β€” match on shape only\n timeZoneFragment = '[A-Za-z_]+(?:\\\\/[A-Za-z_+\\\\-0-9]+)+|UTC';\n }\n return timeZoneFragment;\n}\n\n// mirrors the ranges pad() in tokens.ts actually produces β€” keep in sync\n// if those ever change\n//\n// Unpadded alternatives (M, H, h, m, s) list the longer branch first\n// (e.g. '1[0-2]|[1-9]', not '[1-9]|1[0-2]'). This matters only when two\n// unpadded tokens are glued with no separator: with short-first ordering,\n// a regex engine takes the first successful overall match, and won't\n// backtrack into a token's second alternative unless its first choice\n// makes the *rest* of the pattern fail outright. If the short reading also\n// happens to leave a valid match for the next token, the engine stops\n// there β€” silently, deterministically, and with no relation to which\n// reading a human intended. E.g. \"Md\" against \"121\": short-first order\n// resolves it as month=1/day=21 (M grabs '1', d gets '21', which is a\n// valid day) instead of month=12/day=1. Longer-first ordering fixes this\n// by making the greedy match try to consume as many digits as possible\n// before ever handing digits to the next token, which is the reading\n// that matches how format() itself produces glued output in the first\n// place (format() always emits the token's natural width, so decoding\n// should prefer the same). Found via the tokenΓ—token combinatorial glue\n// matrix in combinatorial.test.js β€” see that file for the full case list.\nconst NUMERIC_FRAGMENTS: Record<string, string> = {\n yyyy: '\\\\d{4}',\n yy: '\\\\d{2}',\n MM: '(?:0[1-9]|1[0-2])',\n M: '(?:1[0-2]|[1-9])',\n dd: '(?:0[1-9]|[12]\\\\d|3[01])',\n d: '(?:[12]\\\\d|3[01]|[1-9])',\n HH: '(?:[01]\\\\d|2[0-3])',\n H: '(?:1\\\\d|2[0-3]|[0-9])',\n hh: '(?:0[1-9]|1[0-2])',\n h: '(?:1[0-2]|[1-9])',\n mm: '(?:[0-5]\\\\d)',\n m: '(?:[1-5]\\\\d|[0-9])',\n ss: '(?:[0-5]\\\\d)',\n s: '(?:[1-5]\\\\d|[0-9])',\n SSS: '\\\\d{3}',\n};\n\nexport function tokenFragment(token: string, locale: string): string {\n const numeric = NUMERIC_FRAGMENTS[token];\n if (numeric) {\n return numeric;\n }\n\n const vocab = getLocaleVocab(locale);\n switch (token) {\n case 'MMMM': return alternation(vocab.monthLong);\n case 'MMM': return alternation(vocab.monthShort);\n case 'EEEE': return alternation(vocab.weekdayLong);\n case 'EEE': return alternation(vocab.weekdayShort);\n case 'a': return alternation(vocab.dayPeriod);\n case 'zzz': return getTimeZoneFragment();\n default:\n throw new Error(`temporal-fmt: unknown token \"${token}\"`);\n }\n}\n\n// Tokens whose fragment is variable-width (1-2 digits, no leading zero).\n// Two or more of these glued with no literal separator between them can\n// have more than one digit-split that's independently valid against every\n// fragment in the run β€” see the big comment on NUMERIC_FRAGMENTS above.\n// Reordering alternation branches picks a winner for *some* of these\n// cases, but can't make both directions of a pair (e.g. \"Md\" and \"dM\")\n// agree, because the ambiguity is in the input string itself, not in how\n// any one fragment is written. exported so parsePattern.ts can find runs\n// of these that need split-counting at match time instead of a single\n// fixed regex.\nexport const UNPADDED_NUMERIC_TOKENS = new Set(['M', 'd', 'H', 'h', 'm', 's']);\n\n// Every accept width for a given unpadded numeric token, as plain min/max\n// value + digit-length pairs β€” used to enumerate candidate splits of a\n// digit run at match time. Mirrors NUMERIC_FRAGMENTS's semantics exactly\n// (same accepted values), just as data instead of regex source, since\n// enumerating splits against a compiled regex per-candidate would be\n// slower and harder to reason about than checking numeric ranges directly.\nexport const UNPADDED_NUMERIC_RANGES: Record<string, Array<{ digits: 1 | 2; min: number; max: number }>> = {\n M: [{ digits: 1, min: 1, max: 9 }, { digits: 2, min: 10, max: 12 }],\n d: [{ digits: 1, min: 1, max: 9 }, { digits: 2, min: 10, max: 31 }],\n H: [{ digits: 1, min: 0, max: 9 }, { digits: 2, min: 10, max: 23 }],\n h: [{ digits: 1, min: 1, max: 9 }, { digits: 2, min: 10, max: 12 }],\n m: [{ digits: 1, min: 0, max: 9 }, { digits: 2, min: 10, max: 59 }],\n s: [{ digits: 1, min: 0, max: 9 }, { digits: 2, min: 10, max: 59 }],\n};\n\n/**\n * Given the literal digit string a run of N adjacent unpadded-numeric\n * tokens matched as a whole (e.g. \"112\" for a 2-token run), enumerates\n * every way to split it into N pieces (one per token, each piece 1-2\n * digits per that token's own width rule) and returns every split where\n * every piece is independently valid for its token. Length 0 means the\n * run's regex match shouldn't have been possible in the first place\n * (shouldn't happen β€” the caller only invokes this after the whole\n * pattern already matched, meaning at least one split exists: the one the\n * regex actually took). Length 1 means the reading is unambiguous.\n * Length 2+ means true ambiguity β€” the caller should throw rather than\n * pick one.\n *\n * Recursive over token count rather than hardcoded to 2, so a 3+ token\n * unseparated run (e.g. \"Hms\") is covered by the same logic without a\n * special case β€” those are rarer in practice but not impossible, and a\n * partial fix that only covered pairs would leave the identical bug for\n * anyone writing a 3-token glued run.\n */\nexport function enumerateValidSplits(digits: string, tokens: string[]): number[][] {\n if (tokens.length === 0) {\n return digits.length === 0 ? [[]] : [];\n }\n const [token, ...rest] = tokens;\n const ranges = UNPADDED_NUMERIC_RANGES[token!];\n if (!ranges) {\n throw new Error(`temporal-fmt: internal error β€” \"${token}\" is not an unpadded numeric token`);\n }\n const results: number[][] = [];\n for (const { digits: width, min, max } of ranges) {\n if (digits.length < width) continue;\n const piece = digits.slice(0, width);\n // reject a leading zero on the 2-digit branch's piece β€” matches the\n // regex fragments, which never allow M/d/H/h/m/s to start with '0' in\n // their 2-digit form (that shape belongs to the padded token instead)\n if (width === 2 && piece[0] === '0') continue;\n const value = parseInt(piece, 10);\n if (value < min || value > max) continue;\n const restSplits = enumerateValidSplits(digits.slice(width), rest);\n for (const restSplit of restSplits) {\n results.push([value, ...restSplit]);\n }\n }\n return results;\n}\n","import type { Piece } from './tokenize.js';\nimport { tokenFragment, UNPADDED_NUMERIC_TOKENS } from './pattern.js';\n\nfunction escapeRegExp(literal: string): string {\n return literal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport interface CapturingPattern {\n regex: RegExp;\n groups: Array<{ name: string; token: string }>; // token pieces, in order\n // Runs of 2+ adjacent unpadded-numeric tokens with no literal separator\n // between them (e.g. \"Md\", \"dM\", \"Hm\") β€” these need a split-ambiguity\n // check at match time, since a single fixed regex can't distinguish\n // \"the only valid split\" from \"one of several valid splits taken\n // arbitrarily\". Empty for the overwhelmingly common case (no such runs).\n ambiguousRuns: Array<{ groupNames: string[]; tokens: string[] }>;\n}\n\n/**\n * Same walk as buildPatternSource() in pattern.ts, but each token piece\n * gets its own named capture group (positionally named so the same token,\n * e.g. \"yyyy\", could in theory appear twice) so a caller can pull the\n * matched substring for each token back out after a successful match.\n */\nexport function buildCapturingPattern(pieces: Piece[], locale: string): CapturingPattern {\n const groups: Array<{ name: string; token: string }> = [];\n const ambiguousRuns: Array<{ groupNames: string[]; tokens: string[] }> = [];\n let source = '';\n let i = 0;\n\n // tracks the group names/tokens of the current run of adjacent unpadded\n // numeric token pieces (no literal piece has broken it yet)\n let currentRun: { groupNames: string[]; tokens: string[] } = { groupNames: [], tokens: [] };\n const flushRun = () => {\n if (currentRun.tokens.length >= 2) {\n ambiguousRuns.push(currentRun);\n }\n currentRun = { groupNames: [], tokens: [] };\n };\n\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n source += escapeRegExp(piece.value);\n flushRun(); // a literal (even a single character) breaks adjacency\n continue;\n }\n const name = `g${i++}`;\n groups.push({ name, token: piece.value });\n source += `(?<${name}>${tokenFragment(piece.value, locale)})`;\n\n if (UNPADDED_NUMERIC_TOKENS.has(piece.value)) {\n currentRun.groupNames.push(name);\n currentRun.tokens.push(piece.value);\n } else {\n flushRun(); // a non-unpadded-numeric token (padded, locale-aware, zzz) also breaks adjacency\n }\n }\n flushRun();\n\n return { regex: new RegExp(`^(?:${source})$`, 'u'), groups, ambiguousRuns };\n}\n","import { DEFAULT_LOCALE, type FormatOptions } from './tokens.js';\nimport { tokenize } from './tokenize.js';\nimport { buildCapturingPattern, type CapturingPattern } from './parsePattern.js';\nimport { enumerateValidSplits } from './pattern.js';\nimport { getLocaleVocab } from './localeVocab.js';\nimport { getTemporal } from './temporalProvider.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\n\n// format strings are short hand-written literals reused across many calls β€”\n// cache the compiled capturing pattern per (formatStr, locale) pair instead\n// of rebuilding it every call.\nconst patternCache = new Map<string, CapturingPattern>();\nconst MAX_CACHE_SIZE = 500;\n\nfunction getPattern(formatStr: string, locale: string): CapturingPattern {\n const key = locale + ' ' + formatStr;\n let pattern = patternCache.get(key);\n if (pattern) {\n return pattern;\n }\n if (patternCache.size >= MAX_CACHE_SIZE) {\n const oldestKey = patternCache.keys().next().value;\n if (oldestKey !== undefined) patternCache.delete(oldestKey);\n }\n pattern = buildCapturingPattern(tokenize(formatStr), locale);\n patternCache.set(key, pattern);\n return pattern;\n}\n\n// Requires an explicit `-u-ca-` extension (e.g. 'en-u-ca-hebrew') to apply\n// a non-Gregorian calendar, per parse()'s own docstring. 'gregory' counts\n// as \"no calendar\" so the default locale keeps constructing plain ISO 8601.\n//\n// Used to key off resolvedOptions().calendar instead β€” a locale's\n// *default* calendar, whether the caller asked for one or not. That broke\n// th-TH silently: its default is 'buddhist', so plain Gregorian-looking\n// digits parsed 543 years off, while format() has no matching calendar\n// step and just prints the object's own ISO fields either way.\nconst calendarCache = new Map<string, string | undefined>();\nconst MAX_CALENDAR_CACHE_SIZE = 500;\n\nfunction resolveCalendar(locale: string): string | undefined {\n if (calendarCache.has(locale)) {\n return calendarCache.get(locale);\n }\n if (calendarCache.size >= MAX_CALENDAR_CACHE_SIZE) {\n const oldestKey = calendarCache.keys().next().value;\n if (oldestKey !== undefined) calendarCache.delete(oldestKey);\n }\n let calendar: string | undefined;\n if (locale.includes('-u-ca-')) {\n const resolved = new Intl.DateTimeFormat(locale).resolvedOptions().calendar;\n calendar = resolved === 'gregory' ? undefined : resolved;\n }\n calendarCache.set(locale, calendar);\n return calendar;\n}\n\ninterface Fields {\n year?: number;\n twoDigitYear?: number;\n month?: number;\n day?: number;\n hour?: number;\n hour12?: number;\n isPM?: boolean;\n minute?: number;\n second?: number;\n millisecond?: number;\n timeZoneId?: string;\n weekdayExpected?: number; // ISO dayOfWeek, 1=Mon, 7=Sun\n weekdayRaw?: string;\n}\n\nfunction applyGroup(fields: Fields, token: string, raw: string, locale: string): void {\n switch (token) {\n case 'yyyy': fields.year = parseInt(raw, 10); break;\n case 'yy': fields.twoDigitYear = parseInt(raw, 10); break;\n case 'MM': case 'M': fields.month = parseInt(raw, 10); break;\n case 'MMMM': fields.month = getLocaleVocab(locale).monthLong.indexOf(raw) + 1; break;\n case 'MMM': fields.month = getLocaleVocab(locale).monthShort.indexOf(raw) + 1; break;\n case 'dd': case 'd': fields.day = parseInt(raw, 10); break;\n case 'EEEE':\n fields.weekdayRaw = raw;\n fields.weekdayExpected = getLocaleVocab(locale).weekdayLong.indexOf(raw) + 1;\n break;\n case 'EEE':\n fields.weekdayRaw = raw;\n fields.weekdayExpected = getLocaleVocab(locale).weekdayShort.indexOf(raw) + 1;\n break;\n case 'HH': case 'H': fields.hour = parseInt(raw, 10); break;\n case 'hh': case 'h': fields.hour12 = parseInt(raw, 10); break;\n case 'mm': case 'm': fields.minute = parseInt(raw, 10); break;\n case 'ss': case 's': fields.second = parseInt(raw, 10); break;\n case 'SSS': fields.millisecond = parseInt(raw, 10); break;\n case 'a': fields.isPM = raw === getLocaleVocab(locale).dayPeriod[1]; break;\n case 'zzz': fields.timeZoneId = raw; break;\n }\n}\n\n// emulates strptime (POSIX) for 2-digit years so the result doesn't depend\n// on the current clock: 00-68 -> 2000-2068, 69-99 -> 1900-1999\n// https://www.man7.org/linux//man-pages/man3/strptime.3p.html\nfunction resolveYear(fields: Fields): number | undefined {\n if (fields.year !== undefined) return fields.year;\n if (fields.twoDigitYear !== undefined) {\n return fields.twoDigitYear <= 68 ? 2000 + fields.twoDigitYear : 1900 + fields.twoDigitYear;\n }\n return undefined;\n}\n\nfunction resolveHour(fields: Fields, formatStr: string): number | undefined {\n if (fields.hour !== undefined && fields.hour12 !== undefined) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" mixes a 24-hour token (\"HH\"/\"H\") with a ` +\n `12-hour token (\"hh\"/\"h\"). Pick one or the other β€” parse() won't guess which is authoritative.`\n );\n }\n if (fields.hour !== undefined) return fields.hour;\n if (fields.hour12 !== undefined) {\n if (fields.isPM === undefined) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" uses a 12-hour token (\"hh\"/\"h\") without an \"a\" token, ` +\n `so parse() can't tell AM from PM.`\n );\n }\n return (fields.hour12 % 12) + (fields.isPM ? 12 : 0);\n }\n return undefined;\n}\n\n/**\n * Parses `input` against `formatStr` and builds the real Temporal value it\n * describes: a `Temporal.PlainDate`, `PlainTime`, `PlainDateTime`, or\n * `ZonedDateTime` depending on which tokens are present.\n *\n * Returns `unknown` β€” this package has no ambient `Temporal` types to return\n * a real one against.\n *\n * `options.locale` picks the calendar the result is built in. Pass a locale\n * tag with a `-u-ca-` extension (e.g. `'en-u-ca-hebrew'`) to parse into a\n * non-Gregorian calendar.\n *\n * @throws if `input` doesn't match `formatStr`'s shape at all\n * @throws if it matches the shape but describes an impossible date (e.g. Feb\n * 30) or self-contradictory data (e.g. a weekday name that doesn't match the\n * actual date)\n *\n * @example\n * parse('yyyy-MM-dd HH:mm', '2026-08-04 15:45') // Temporal.PlainDateTime\n * parse('yyyy-MM', '2026-08-04T15:45:30') // throws β€” shape doesn't match\n * parse('yyyy-MM-dd', '2026-02-30') // throws β€” not a real date\n */\nexport function parse(formatStr: string, input: string, options: FormatOptions = {}): unknown | undefined {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`\n );\n }\n\n const locale = options.locale ?? DEFAULT_LOCALE;\n const calendar = resolveCalendar(locale);\n const pattern = getPattern(formatStr, locale);\n const match = pattern.regex.exec(input);\n if (!match) {\n throw new Error(`temporal-fmt: no valid pattern matches the format string and input shape`);\n }\n\n if (pattern.groups.length === 0) {\n throw new Error(`temporal-fmt: format string \"${formatStr}\" has no tokens β€” nothing to parse into a value.`);\n }\n\n // A run of 2+ adjacent unpadded-numeric tokens with no literal separator\n // (e.g. \"Md\", \"dM\", \"Hms\") can have more than one way to split the\n // digits it matched that's independently valid for every token in the\n // run β€” see the comment on NUMERIC_FRAGMENTS in pattern.ts for the\n // mechanism. The regex above only ever finds one such split (whichever\n // its alternation ordering happens to prefer); silently trusting that\n // one would mean parse() sometimes returns a value indistinguishable\n // from a different, equally valid value the same input could describe.\n // Rather than guess, check every ambiguous run explicitly and throw if\n // more than one split is actually valid for the substring this call\n // matched β€” the input itself is what's ambiguous, not a fixable\n // property of the pattern.\n for (const run of pattern.ambiguousRuns) {\n const runDigits = run.groupNames.map((name) => match.groups![name]!).join('');\n const splits = enumerateValidSplits(runDigits, run.tokens);\n if (splits.length > 1) {\n throw new Error(\n `temporal-fmt: \"${runDigits}\" in format string \"${formatStr}\" is ambiguous β€” ` +\n `${splits.length} different ways to read tokens \"${run.tokens.join('')}\" (with no separator ` +\n `between them) are all individually valid (e.g. ${JSON.stringify(splits[0])} vs ${JSON.stringify(splits[1])}). ` +\n `parse() won't guess; add a separator between these tokens, or use their padded form ` +\n `(e.g. \"MM\" instead of \"M\") so each one has a fixed width.`\n );\n }\n }\n\n const fields: Fields = {};\n for (const { name, token } of pattern.groups) {\n applyGroup(fields, token, match.groups![name]!, locale);\n }\n\n const year = resolveYear(fields);\n const hour = resolveHour(fields, formatStr);\n const { month, day, minute, second, millisecond, timeZoneId, weekdayExpected, weekdayRaw } = fields;\n\n const hasAnyDatePart = year !== undefined || month !== undefined || day !== undefined;\n const hasFullDate = year !== undefined && month !== undefined && day !== undefined;\n if (hasAnyDatePart && !hasFullDate) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" has an incomplete date β€” ` +\n `year, month, and day tokens must all be present together.`\n );\n }\n\n const hasTime = hour !== undefined || minute !== undefined || second !== undefined || millisecond !== undefined;\n\n if (timeZoneId !== undefined && !(hasFullDate && hasTime)) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" has a \"zzz\" token but needs a full date and time ` +\n `to build a ZonedDateTime.`\n );\n }\n\n if (weekdayExpected !== undefined && !hasFullDate) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" has a weekday token (\"EEEE\"/\"EEE\") but needs ` +\n `a full date to validate it against.`\n );\n }\n\n if (!hasFullDate && !hasTime) {\n // shouldn't happen β€” every token maps to a date, time, zone, or\n // weekday field, and weekday-without-date already threw above\n throw new Error(`temporal-fmt: format string \"${formatStr}\" has no date or time tokens to parse.`);\n }\n\n const temporal = getTemporal();\n const timeFields = { hour: hour ?? 0, minute: minute ?? 0, second: second ?? 0, millisecond: millisecond ?? 0 };\n // omitted entirely for the default calendar (see resolveCalendar) so\n // construction stays plain ISO 8601 unless a caller's locale asks for\n // something else β€” Temporal calendars don't apply to time-only values.\n const calendarField = calendar ? { calendar } : {};\n\n // overflow: 'reject' β€” without it Temporal *clamps* out-of-range fields\n // (Feb 30 silently becomes Feb 28) instead of throwing, which would\n // contradict the \"throws on genuinely invalid data\" behavior parse() promises.\n const reject = { overflow: 'reject' as const };\n\n let result: unknown;\n try {\n if (timeZoneId !== undefined) {\n result = temporal.ZonedDateTime.from({ year: year!, month: month!, day: day!, ...timeFields, ...calendarField, timeZone: timeZoneId }, reject);\n } else if (hasFullDate && hasTime) {\n result = temporal.PlainDateTime.from({ year: year!, month: month!, day: day!, ...timeFields, ...calendarField }, reject);\n } else if (hasFullDate) {\n result = temporal.PlainDate.from({ year: year!, month: month!, day: day!, ...calendarField }, reject);\n } else {\n result = temporal.PlainTime.from(timeFields, reject);\n }\n } catch (err) {\n throw new Error(\n `temporal-fmt: \"${input}\" doesn't describe a valid date/time for format \"${formatStr}\": ` +\n `${(err as Error).message}`\n );\n }\n\n if (weekdayExpected !== undefined) {\n const actual = (result as { dayOfWeek: number }).dayOfWeek;\n if (actual !== weekdayExpected) {\n const vocab = getLocaleVocab(locale);\n throw new Error(\n `temporal-fmt: \"${weekdayRaw}\" doesn't match the actual weekday (${vocab.weekdayLong[actual - 1]}) ` +\n `for the parsed date.`\n );\n }\n }\n\n return result;\n}\n"],"mappings":"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","names":["index_exports","__export","format","parse","setTemporal","__toCommonJS","injectedTemporal","setTemporal","temporal","resolveTemporal","getTemporal","pad","n","len","negative","digits","DEFAULT_LOCALE","formatterCache","MAX_CACHE_SIZE","getFormatter","locale","options","key","formatter","oldestKey","nativeSupport","intlSupportsNativeTemporal","temporal","getTemporal","intlPart","partType","calendar","formatterOptions","toInstant","timeZoneId","isZoned","intlSafeTemporal","nativeOptions","parts","index","p","value","prev","next","dayPeriodPart","hour","date","part","TOKENS","t","SORTED_TOKEN_STRINGS","TOKENS","tok","a","b","tokenize","format","pieces","i","ch","appendLiteral","j","literal","closed","match","value","last","HANDLER_BY_TOKEN","TOKENS","tok","fn","field","format","temporal","formatStr","options","locale","DEFAULT_LOCALE","pieces","tokenize","result","piece","handler","vocabCache","MAX_VOCAB_CACHE_SIZE","partValue","formatter","date","type","parts","index","p","value","prev","next","assertNoCollision","names","label","locale","seen","i","prior","getLocaleVocab","cached","monthLongFmt","monthShortFmt","monthLong","monthShort","m","weekdayLongFmt","weekdayShortFmt","weekdayLong","weekdayShort","d","dayPeriodFmt","am","pm","dayPeriod","vocab","oldestKey","escapeRegExp","literal","alternation","values","timeZoneFragment","getTimeZoneFragment","supportedValuesOf","NUMERIC_FRAGMENTS","tokenFragment","token","locale","numeric","vocab","getLocaleVocab","UNPADDED_NUMERIC_TOKENS","UNPADDED_NUMERIC_RANGES","enumerateValidSplits","digits","tokens","rest","ranges","results","width","min","max","piece","value","restSplits","restSplit","escapeRegExp","literal","buildCapturingPattern","pieces","locale","groups","ambiguousRuns","source","i","currentRun","flushRun","piece","name","tokenFragment","UNPADDED_NUMERIC_TOKENS","patternCache","MAX_CACHE_SIZE","getPattern","formatStr","locale","key","pattern","oldestKey","buildCapturingPattern","tokenize","calendarCache","MAX_CALENDAR_CACHE_SIZE","resolveCalendar","calendar","resolved","applyGroup","fields","token","raw","getLocaleVocab","resolveYear","resolveHour","parse","input","options","DEFAULT_LOCALE","match","run","runDigits","name","splits","enumerateValidSplits","year","hour","month","day","minute","second","millisecond","timeZoneId","weekdayExpected","weekdayRaw","hasAnyDatePart","hasFullDate","hasTime","temporal","getTemporal","timeFields","calendarField","reject","result","err","actual","vocab"]}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var K;function q(e){K=e}function B(){return K??globalThis.Temporal}function L(){let e=B();if(!e)throw new Error("temporal-fmt: parse() needs a Temporal implementation to construct its result. Call setTemporal(Temporal) once at startup, or assign one to globalThis.Temporal (native on Node 26+, or a polyfill like temporal-polyfill).");return e}function h(e,n){let t=e<0,r=String(Math.abs(e)).padStart(n,"0");return t?"-"+r:r}var S="en-US",x=new Map,J=500;function Y(e,n){let t=e+JSON.stringify(n),r=x.get(t);if(r)return r;if(x.size>=J){let a=x.keys().next().value;a!==void 0&&x.delete(a)}return r=new Intl.DateTimeFormat(e,n),x.set(t,r),r}var $;function Q(){if($===void 0){$=!1;try{let e=L();new Intl.DateTimeFormat("en-US",{day:"numeric"}).formatToParts(e.PlainDate.from({year:1970,month:1,day:1})),$=!0}catch{}}return $}function O(e,n,t,r){let a=e?.calendarId,o={...t,...a&&a!=="iso8601"?{calendar:a}:{}};if(!Q())return e.toLocaleString(n,o);let{toInstant:i,timeZoneId:s}=e,d=typeof i=="function"&&typeof s=="string",y=d?e.toInstant():e,l={...o,...d?{timeZone:s}:{}},p=Y(n,l).formatToParts(y),f=p.findIndex(N=>N.type===r);if(f===-1)throw new Error(`temporal-fmt: locale "${n}" produced no "${r}" part for this token. This usually means the Temporal object is missing the field the token needs.`);let c=p[f].value,m=p[f-1],u=p[f+1];return m?.type==="literal"&&!/\s/.test(m.value)&&(c=m.value+c),u?.type==="literal"&&!/\s/.test(u.value)&&(c=c+u.value),c}function ee(e,n){let t=new Date(Date.UTC(1970,0,1,e)),a=Y(n,{hour:"numeric",hour12:!0,timeZone:"UTC"}).formatToParts(t).find(o=>o.type==="dayPeriod");if(!a)throw new Error(`temporal-fmt: locale "${n}" produced no "dayPeriod" part for token "a".`);return a.value}var A=[["yyyy",e=>h(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 h(e.year%100,2)},"year"],["MMMM",(e,n)=>O(e,n,{month:"long"},"month"),"month"],["MMM",(e,n)=>O(e,n,{month:"short"},"month"),"month"],["MM",e=>h(e.month,2),"month"],["M",e=>String(e.month),"month"],["dd",e=>h(e.day,2),"day"],["d",e=>String(e.day),"day"],["EEEE",(e,n)=>O(e,n,{weekday:"long"},"weekday"),"dayOfWeek"],["EEE",(e,n)=>O(e,n,{weekday:"short"},"weekday"),"dayOfWeek"],["HH",e=>h(e.hour,2),"hour"],["H",e=>String(e.hour),"hour"],["hh",e=>h(e.hour%12||12,2),"hour"],["h",e=>String(e.hour%12||12),"hour"],["mm",e=>h(e.minute,2),"minute"],["m",e=>String(e.minute),"minute"],["ss",e=>h(e.second,2),"second"],["s",e=>String(e.second),"second"],["SSS",e=>h(e.millisecond,3),"millisecond"],["a",(e,n)=>ee(e.hour,n),"hour"],["zzz",e=>e.timeZoneId,"timeZoneId"]];var te=A.map(([e])=>e).sort((e,n)=>n.length-e.length);function Z(e){let n=[],t=0;for(;t<e.length;){let r=e[t];if(r==="'"){if(e[t+1]==="'"){V(n,"'"),t+=2;continue}let o=t+1,i="",s=!1;for(;o<e.length;){if(e[o]==="'"){if(e[o+1]==="'"){i+="'",o+=2;continue}s=!0,o+=1;break}i+=e[o],o+=1}if(!s)throw new Error(`temporal-fmt: unterminated quote in format string "${e}"`);V(n,i),t=o;continue}let a=te.find(o=>e.startsWith(o,t));if(a){n.push({kind:"token",value:a}),t+=a.length;continue}V(n,r),t+=1}return n}function V(e,n){let t=e[e.length-1];t&&t.kind==="literal"?t.value+=n:e.push({kind:"literal",value:n})}var ne=new Map(A.map(([e,n,t])=>[e,{fn:n,field:t}]));function re(e,n,t={}){if(n.length>1e3)throw new Error(`temporal-fmt: format string exceeds maximum length of ${1e3} characters (got ${n.length}).`);let r=t.locale??S,a=Z(n),o="";for(let i of a){if(i.kind==="literal"){o+=i.value;continue}let s=ne.get(i.value);if(!s)throw new Error(`temporal-fmt: unknown token "${i.value}"`);if(e[s.field]===void 0)throw new Error(`temporal-fmt: token "${i.value}" requires "${s.field}", which this Temporal object doesn't have. (e.g. PlainDate has no time fields, PlainTime has no date fields)`);o+=s.fn(e,r)}return o}var D=new Map,oe=500;function b(e,n,t){let r=e.formatToParts(n),a=r.findIndex(d=>d.type===t);if(a===-1)throw new Error(`temporal-fmt: locale produced no "${t}" part while building match vocabulary.`);let o=r[a].value,i=r[a-1],s=r[a+1];return i?.type==="literal"&&!/\s/.test(i.value)&&(o=i.value+o),s?.type==="literal"&&!/\s/.test(s.value)&&(o=o+s.value),o}function _(e,n,t){let r=new Map;for(let a=0;a<e.length;a++){let o=r.get(e[a]);if(o!==void 0)throw new Error(`temporal-fmt: locale "${t}" renders ${n} index ${o} and ${a} identically ("${e[a]}"). parse() can't reliably tell these apart for this locale/token, so this combination isn't supported.`);r.set(e[a],a)}}function g(e){let n=D.get(e);if(n)return n;let t=new Intl.DateTimeFormat(e,{month:"long",timeZone:"UTC"}),r=new Intl.DateTimeFormat(e,{month:"short",timeZone:"UTC"}),a=[],o=[];for(let m=0;m<12;m++){let u=new Date(Date.UTC(2020,m,1));a.push(b(t,u,"month")),o.push(b(r,u,"month"))}_(a,"MMMM month",e),_(o,"MMM month",e);let i=new Intl.DateTimeFormat(e,{weekday:"long",timeZone:"UTC"}),s=new Intl.DateTimeFormat(e,{weekday:"short",timeZone:"UTC"}),d=[],y=[];for(let m=0;m<7;m++){let u=new Date(Date.UTC(2024,0,1+m));d.push(b(i,u,"weekday")),y.push(b(s,u,"weekday"))}_(d,"EEEE weekday",e),_(y,"EEE weekday",e);let l=new Intl.DateTimeFormat(e,{hour:"numeric",hour12:!0,timeZone:"UTC"}),k=b(l,new Date(Date.UTC(2020,0,1,1)),"dayPeriod"),p=b(l,new Date(Date.UTC(2020,0,1,13)),"dayPeriod"),f=[...new Set([k,p])],c={monthLong:a,monthShort:o,weekdayLong:d,weekdayShort:y,dayPeriod:f};if(D.size>=oe){let m=D.keys().next().value;m!==void 0&&D.delete(m)}return D.set(e,c),c}function ae(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function v(e){return`(?:${e.map(ae).join("|")})`}var F;function ie(){if(F)return F;let e=Intl.supportedValuesOf;return typeof e=="function"?F=v([...e("timeZone"),"UTC"]):F="[A-Za-z_]+(?:\\/[A-Za-z_+\\-0-9]+)+|UTC",F}var se={yyyy:"\\d{4}",yy:"\\d{2}",MM:"(?:0[1-9]|1[0-2])",M:"(?:[1-9]|1[0-2])",dd:"(?:0[1-9]|[12]\\d|3[01])",d:"(?:[1-9]|[12]\\d|3[01])",HH:"(?:[01]\\d|2[0-3])",H:"(?:[0-9]|1\\d|2[0-3])",hh:"(?:0[1-9]|1[0-2])",h:"(?:[1-9]|1[0-2])",mm:"(?:[0-5]\\d)",m:"(?:[0-9]|[1-5]\\d)",ss:"(?:[0-5]\\d)",s:"(?:[0-9]|[1-5]\\d)",SSS:"\\d{3}"};function W(e,n){let t=se[e];if(t)return t;let r=g(n);switch(e){case"MMMM":return v(r.monthLong);case"MMM":return v(r.monthShort);case"EEEE":return v(r.weekdayLong);case"EEE":return v(r.weekdayShort);case"a":return v(r.dayPeriod);case"zzz":return ie();default:throw new Error(`temporal-fmt: unknown token "${e}"`)}}function me(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function X(e,n){let t=[],r="",a=0;for(let o of e){if(o.kind==="literal"){r+=me(o.value);continue}let i=`g${a++}`;t.push({name:i,token:o.value}),r+=`(?<${i}>${W(o.value,n)})`}return{regex:new RegExp(`^(?:${r})$`,"u"),groups:t}}var P=new Map,de=500;function ue(e,n){let t=n+" "+e,r=P.get(t);if(r)return r;if(P.size>=de){let a=P.keys().next().value;a!==void 0&&P.delete(a)}return r=X(Z(e),n),P.set(t,r),r}var M=new Map,ce=500;function le(e){if(M.has(e))return M.get(e);if(M.size>=ce){let t=M.keys().next().value;t!==void 0&&M.delete(t)}let n;if(e.includes("-u-ca-")){let t=new Intl.DateTimeFormat(e).resolvedOptions().calendar;n=t==="gregory"?void 0:t}return M.set(e,n),n}function pe(e,n,t,r){switch(n){case"yyyy":e.year=parseInt(t,10);break;case"yy":e.twoDigitYear=parseInt(t,10);break;case"MM":case"M":e.month=parseInt(t,10);break;case"MMMM":e.month=g(r).monthLong.indexOf(t)+1;break;case"MMM":e.month=g(r).monthShort.indexOf(t)+1;break;case"dd":case"d":e.day=parseInt(t,10);break;case"EEEE":e.weekdayRaw=t,e.weekdayExpected=g(r).weekdayLong.indexOf(t)+1;break;case"EEE":e.weekdayRaw=t,e.weekdayExpected=g(r).weekdayShort.indexOf(t)+1;break;case"HH":case"H":e.hour=parseInt(t,10);break;case"hh":case"h":e.hour12=parseInt(t,10);break;case"mm":case"m":e.minute=parseInt(t,10);break;case"ss":case"s":e.second=parseInt(t,10);break;case"SSS":e.millisecond=parseInt(t,10);break;case"a":e.isPM=t===g(r).dayPeriod[1];break;case"zzz":e.timeZoneId=t;break}}function fe(e){if(e.year!==void 0)return e.year;if(e.twoDigitYear!==void 0)return e.twoDigitYear<=68?2e3+e.twoDigitYear:1900+e.twoDigitYear}function he(e,n){if(e.hour!==void 0&&e.hour12!==void 0)throw new Error(`temporal-fmt: format string "${n}" mixes a 24-hour token ("HH"/"H") with a 12-hour token ("hh"/"h"). Pick one or the other \u2014 parse() won't guess which is authoritative.`);if(e.hour!==void 0)return e.hour;if(e.hour12!==void 0){if(e.isPM===void 0)throw new Error(`temporal-fmt: format string "${n}" uses a 12-hour token ("hh"/"h") without an "a" token, so parse() can't tell AM from PM.`);return e.hour12%12+(e.isPM?12:0)}}function ge(e,n,t={}){if(e.length>1e3)throw new Error(`temporal-fmt: format string exceeds maximum length of ${1e3} characters (got ${e.length}).`);let r=t.locale??S,a=le(r),o=ue(e,r),i=o.regex.exec(n);if(!i)throw new Error("temporal-fmt: no valid pattern matches the format string and input shape");if(o.groups.length===0)throw new Error(`temporal-fmt: format string "${e}" has no tokens \u2014 nothing to parse into a value.`);let s={};for(let{name:E,token:R}of o.groups)pe(s,R,i.groups[E],r);let d=fe(s),y=he(s,e),{month:l,day:k,minute:p,second:f,millisecond:c,timeZoneId:m,weekdayExpected:u,weekdayRaw:N}=s,G=d!==void 0||l!==void 0||k!==void 0,w=d!==void 0&&l!==void 0&&k!==void 0;if(G&&!w)throw new Error(`temporal-fmt: format string "${e}" has an incomplete date \u2014 year, month, and day tokens must all be present together.`);let z=y!==void 0||p!==void 0||f!==void 0||c!==void 0;if(m!==void 0&&!(w&&z))throw new Error(`temporal-fmt: format string "${e}" has a "zzz" token but needs a full date and time to build a ZonedDateTime.`);if(u!==void 0&&!w)throw new Error(`temporal-fmt: format string "${e}" has a weekday token ("EEEE"/"EEE") but needs a full date to validate it against.`);if(!w&&!z)throw new Error(`temporal-fmt: format string "${e}" has no date or time tokens to parse.`);let I=L(),H={hour:y??0,minute:p??0,second:f??0,millisecond:c??0},U=a?{calendar:a}:{},C={overflow:"reject"},T;try{m!==void 0?T=I.ZonedDateTime.from({year:d,month:l,day:k,...H,...U,timeZone:m},C):w&&z?T=I.PlainDateTime.from({year:d,month:l,day:k,...H,...U},C):w?T=I.PlainDate.from({year:d,month:l,day:k,...U},C):T=I.PlainTime.from(H,C)}catch(E){throw new Error(`temporal-fmt: "${n}" doesn't describe a valid date/time for format "${e}": ${E.message}`)}if(u!==void 0){let E=T.dayOfWeek;if(E!==u){let R=g(r);throw new Error(`temporal-fmt: "${N}" doesn't match the actual weekday (${R.weekdayLong[E-1]}) for the parsed date.`)}}return T}export{re as format,ge as parse,q as setTemporal};
1
+ var G;function ee(e){G=e}function te(){return G??globalThis.Temporal}function S(){let e=te();if(!e)throw new Error("temporal-fmt: parse() needs a Temporal implementation to construct its result. Call setTemporal(Temporal) once at startup, or assign one to globalThis.Temporal (native on Node 26+, or a polyfill like temporal-polyfill).");return e}function k(e,n){let t=e<0,r=String(Math.abs(e)).padStart(n,"0");return t?"-"+r:r}var A="en-US",D=new Map,ne=500;function W(e,n){let t=e+JSON.stringify(n),r=D.get(t);if(r)return r;if(D.size>=ne){let o=D.keys().next().value;o!==void 0&&D.delete(o)}return r=new Intl.DateTimeFormat(e,n),D.set(t,r),r}var L;function re(){if(L===void 0){L=!1;try{let e=S();new Intl.DateTimeFormat("en-US",{day:"numeric"}).formatToParts(e.PlainDate.from({year:1970,month:1,day:1})),L=!0}catch{}}return L}function N(e,n,t,r){let o=e?.calendarId,a={...t,...o&&o!=="iso8601"?{calendar:o}:{}};if(!re())return e.toLocaleString(n,a);let{toInstant:i,timeZoneId:s}=e,m=typeof i=="function"&&typeof s=="string",d=m?e.toInstant():e,c={...a,...m?{timeZone:s}:{}},p=W(n,c).formatToParts(d),y=p.findIndex(U=>U.type===r);if(y===-1)throw new Error(`temporal-fmt: locale "${n}" produced no "${r}" part for this token. This usually means the Temporal object is missing the field the token needs.`);let f=p[y].value,u=p[y-1],l=p[y+1];return u?.type==="literal"&&!/\s/.test(u.value)&&(f=u.value+f),l?.type==="literal"&&!/\s/.test(l.value)&&(f=f+l.value),f}function oe(e,n){let t=new Date(Date.UTC(1970,0,1,e)),o=W(n,{hour:"numeric",hour12:!0,timeZone:"UTC"}).formatToParts(t).find(a=>a.type==="dayPeriod");if(!o)throw new Error(`temporal-fmt: locale "${n}" produced no "dayPeriod" part for token "a".`);return o.value}var _=[["yyyy",e=>k(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 k(e.year%100,2)},"year"],["MMMM",(e,n)=>N(e,n,{month:"long"},"month"),"month"],["MMM",(e,n)=>N(e,n,{month:"short"},"month"),"month"],["MM",e=>k(e.month,2),"month"],["M",e=>String(e.month),"month"],["dd",e=>k(e.day,2),"day"],["d",e=>String(e.day),"day"],["EEEE",(e,n)=>N(e,n,{weekday:"long"},"weekday"),"dayOfWeek"],["EEE",(e,n)=>N(e,n,{weekday:"short"},"weekday"),"dayOfWeek"],["HH",e=>k(e.hour,2),"hour"],["H",e=>String(e.hour),"hour"],["hh",e=>k(e.hour%12||12,2),"hour"],["h",e=>String(e.hour%12||12),"hour"],["mm",e=>k(e.minute,2),"minute"],["m",e=>String(e.minute),"minute"],["ss",e=>k(e.second,2),"second"],["s",e=>String(e.second),"second"],["SSS",e=>k(e.millisecond,3),"millisecond"],["a",(e,n)=>oe(e.hour,n),"hour"],["zzz",e=>e.timeZoneId,"timeZoneId"]];var ae=_.map(([e])=>e).sort((e,n)=>n.length-e.length);function R(e){let n=[],t=0;for(;t<e.length;){let r=e[t];if(r==="'"){if(e[t+1]==="'"){j(n,"'"),t+=2;continue}let a=t+1,i="",s=!1;for(;a<e.length;){if(e[a]==="'"){if(e[a+1]==="'"){i+="'",a+=2;continue}s=!0,a+=1;break}i+=e[a],a+=1}if(!s)throw new Error(`temporal-fmt: unterminated quote in format string "${e}"`);j(n,i),t=a;continue}let o=ae.find(a=>e.startsWith(a,t));if(o){n.push({kind:"token",value:o}),t+=o.length;continue}j(n,r),t+=1}return n}function j(e,n){let t=e[e.length-1];t&&t.kind==="literal"?t.value+=n:e.push({kind:"literal",value:n})}var ie=new Map(_.map(([e,n,t])=>[e,{fn:n,field:t}]));function se(e,n,t={}){if(n.length>1e3)throw new Error(`temporal-fmt: format string exceeds maximum length of ${1e3} characters (got ${n.length}).`);let r=t.locale??A,o=R(n),a="";for(let i of o){if(i.kind==="literal"){a+=i.value;continue}let s=ie.get(i.value);if(!s)throw new Error(`temporal-fmt: unknown token "${i.value}"`);if(e[s.field]===void 0)throw new Error(`temporal-fmt: token "${i.value}" requires "${s.field}", which this Temporal object doesn't have. (e.g. PlainDate has no time fields, PlainTime has no date fields)`);a+=s.fn(e,r)}return a}var F=new Map,me=500;function x(e,n,t){let r=e.formatToParts(n),o=r.findIndex(m=>m.type===t);if(o===-1)throw new Error(`temporal-fmt: locale produced no "${t}" part while building match vocabulary.`);let a=r[o].value,i=r[o-1],s=r[o+1];return i?.type==="literal"&&!/\s/.test(i.value)&&(a=i.value+a),s?.type==="literal"&&!/\s/.test(s.value)&&(a=a+s.value),a}function Z(e,n,t){let r=new Map;for(let o=0;o<e.length;o++){let a=r.get(e[o]);if(a!==void 0)throw new Error(`temporal-fmt: locale "${t}" renders ${n} index ${a} and ${o} identically ("${e[o]}"). parse() can't reliably tell these apart for this locale/token, so this combination isn't supported.`);r.set(e[o],o)}}function w(e){let n=F.get(e);if(n)return n;let t=new Intl.DateTimeFormat(e,{month:"long",timeZone:"UTC"}),r=new Intl.DateTimeFormat(e,{month:"short",timeZone:"UTC"}),o=[],a=[];for(let u=0;u<12;u++){let l=new Date(Date.UTC(2020,u,1));o.push(x(t,l,"month")),a.push(x(r,l,"month"))}Z(o,"MMMM month",e),Z(a,"MMM month",e);let i=new Intl.DateTimeFormat(e,{weekday:"long",timeZone:"UTC"}),s=new Intl.DateTimeFormat(e,{weekday:"short",timeZone:"UTC"}),m=[],d=[];for(let u=0;u<7;u++){let l=new Date(Date.UTC(2024,0,1+u));m.push(x(i,l,"weekday")),d.push(x(s,l,"weekday"))}Z(m,"EEEE weekday",e),Z(d,"EEE weekday",e);let c=new Intl.DateTimeFormat(e,{hour:"numeric",hour12:!0,timeZone:"UTC"}),g=x(c,new Date(Date.UTC(2020,0,1,1)),"dayPeriod"),p=x(c,new Date(Date.UTC(2020,0,1,13)),"dayPeriod"),y=[...new Set([g,p])],f={monthLong:o,monthShort:a,weekdayLong:m,weekdayShort:d,dayPeriod:y};if(F.size>=me){let u=F.keys().next().value;u!==void 0&&F.delete(u)}return F.set(e,f),f}function ue(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function M(e){return`(?:${e.map(ue).join("|")})`}var I;function de(){if(I)return I;let e=Intl.supportedValuesOf;return typeof e=="function"?I=M([...e("timeZone"),"UTC"]):I="[A-Za-z_]+(?:\\/[A-Za-z_+\\-0-9]+)+|UTC",I}var ce={yyyy:"\\d{4}",yy:"\\d{2}",MM:"(?:0[1-9]|1[0-2])",M:"(?:1[0-2]|[1-9])",dd:"(?:0[1-9]|[12]\\d|3[01])",d:"(?:[12]\\d|3[01]|[1-9])",HH:"(?:[01]\\d|2[0-3])",H:"(?:1\\d|2[0-3]|[0-9])",hh:"(?:0[1-9]|1[0-2])",h:"(?:1[0-2]|[1-9])",mm:"(?:[0-5]\\d)",m:"(?:[1-5]\\d|[0-9])",ss:"(?:[0-5]\\d)",s:"(?:[1-5]\\d|[0-9])",SSS:"\\d{3}"};function X(e,n){let t=ce[e];if(t)return t;let r=w(n);switch(e){case"MMMM":return M(r.monthLong);case"MMM":return M(r.monthShort);case"EEEE":return M(r.weekdayLong);case"EEE":return M(r.weekdayShort);case"a":return M(r.dayPeriod);case"zzz":return de();default:throw new Error(`temporal-fmt: unknown token "${e}"`)}}var J=new Set(["M","d","H","h","m","s"]),le={M:[{digits:1,min:1,max:9},{digits:2,min:10,max:12}],d:[{digits:1,min:1,max:9},{digits:2,min:10,max:31}],H:[{digits:1,min:0,max:9},{digits:2,min:10,max:23}],h:[{digits:1,min:1,max:9},{digits:2,min:10,max:12}],m:[{digits:1,min:0,max:9},{digits:2,min:10,max:59}],s:[{digits:1,min:0,max:9},{digits:2,min:10,max:59}]};function Y(e,n){if(n.length===0)return e.length===0?[[]]:[];let[t,...r]=n,o=le[t];if(!o)throw new Error(`temporal-fmt: internal error \u2014 "${t}" is not an unpadded numeric token`);let a=[];for(let{digits:i,min:s,max:m}of o){if(e.length<i)continue;let d=e.slice(0,i);if(i===2&&d[0]==="0")continue;let c=parseInt(d,10);if(c<s||c>m)continue;let g=Y(e.slice(i),r);for(let p of g)a.push([c,...p])}return a}function pe(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function q(e,n){let t=[],r=[],o="",a=0,i={groupNames:[],tokens:[]},s=()=>{i.tokens.length>=2&&r.push(i),i={groupNames:[],tokens:[]}};for(let m of e){if(m.kind==="literal"){o+=pe(m.value),s();continue}let d=`g${a++}`;t.push({name:d,token:m.value}),o+=`(?<${d}>${X(m.value,n)})`,J.has(m.value)?(i.groupNames.push(d),i.tokens.push(m.value)):s()}return s(),{regex:new RegExp(`^(?:${o})$`,"u"),groups:t,ambiguousRuns:r}}var P=new Map,fe=500;function ge(e,n){let t=n+" "+e,r=P.get(t);if(r)return r;if(P.size>=fe){let o=P.keys().next().value;o!==void 0&&P.delete(o)}return r=q(R(e),n),P.set(t,r),r}var v=new Map,he=500;function ye(e){if(v.has(e))return v.get(e);if(v.size>=he){let t=v.keys().next().value;t!==void 0&&v.delete(t)}let n;if(e.includes("-u-ca-")){let t=new Intl.DateTimeFormat(e).resolvedOptions().calendar;n=t==="gregory"?void 0:t}return v.set(e,n),n}function ke(e,n,t,r){switch(n){case"yyyy":e.year=parseInt(t,10);break;case"yy":e.twoDigitYear=parseInt(t,10);break;case"MM":case"M":e.month=parseInt(t,10);break;case"MMMM":e.month=w(r).monthLong.indexOf(t)+1;break;case"MMM":e.month=w(r).monthShort.indexOf(t)+1;break;case"dd":case"d":e.day=parseInt(t,10);break;case"EEEE":e.weekdayRaw=t,e.weekdayExpected=w(r).weekdayLong.indexOf(t)+1;break;case"EEE":e.weekdayRaw=t,e.weekdayExpected=w(r).weekdayShort.indexOf(t)+1;break;case"HH":case"H":e.hour=parseInt(t,10);break;case"hh":case"h":e.hour12=parseInt(t,10);break;case"mm":case"m":e.minute=parseInt(t,10);break;case"ss":case"s":e.second=parseInt(t,10);break;case"SSS":e.millisecond=parseInt(t,10);break;case"a":e.isPM=t===w(r).dayPeriod[1];break;case"zzz":e.timeZoneId=t;break}}function we(e){if(e.year!==void 0)return e.year;if(e.twoDigitYear!==void 0)return e.twoDigitYear<=68?2e3+e.twoDigitYear:1900+e.twoDigitYear}function Te(e,n){if(e.hour!==void 0&&e.hour12!==void 0)throw new Error(`temporal-fmt: format string "${n}" mixes a 24-hour token ("HH"/"H") with a 12-hour token ("hh"/"h"). Pick one or the other \u2014 parse() won't guess which is authoritative.`);if(e.hour!==void 0)return e.hour;if(e.hour12!==void 0){if(e.isPM===void 0)throw new Error(`temporal-fmt: format string "${n}" uses a 12-hour token ("hh"/"h") without an "a" token, so parse() can't tell AM from PM.`);return e.hour12%12+(e.isPM?12:0)}}function Ee(e,n,t={}){if(e.length>1e3)throw new Error(`temporal-fmt: format string exceeds maximum length of ${1e3} characters (got ${e.length}).`);let r=t.locale??A,o=ye(r),a=ge(e,r),i=a.regex.exec(n);if(!i)throw new Error("temporal-fmt: no valid pattern matches the format string and input shape");if(a.groups.length===0)throw new Error(`temporal-fmt: format string "${e}" has no tokens \u2014 nothing to parse into a value.`);for(let h of a.ambiguousRuns){let b=h.groupNames.map(Q=>i.groups[Q]).join(""),O=Y(b,h.tokens);if(O.length>1)throw new Error(`temporal-fmt: "${b}" in format string "${e}" is ambiguous \u2014 ${O.length} different ways to read tokens "${h.tokens.join("")}" (with no separator between them) are all individually valid (e.g. ${JSON.stringify(O[0])} vs ${JSON.stringify(O[1])}). parse() won't guess; add a separator between these tokens, or use their padded form (e.g. "MM" instead of "M") so each one has a fixed width.`)}let s={};for(let{name:h,token:b}of a.groups)ke(s,b,i.groups[h],r);let m=we(s),d=Te(s,e),{month:c,day:g,minute:p,second:y,millisecond:f,timeZoneId:u,weekdayExpected:l,weekdayRaw:U}=s,B=m!==void 0||c!==void 0||g!==void 0,T=m!==void 0&&c!==void 0&&g!==void 0;if(B&&!T)throw new Error(`temporal-fmt: format string "${e}" has an incomplete date \u2014 year, month, and day tokens must all be present together.`);let H=d!==void 0||p!==void 0||y!==void 0||f!==void 0;if(u!==void 0&&!(T&&H))throw new Error(`temporal-fmt: format string "${e}" has a "zzz" token but needs a full date and time to build a ZonedDateTime.`);if(l!==void 0&&!T)throw new Error(`temporal-fmt: format string "${e}" has a weekday token ("EEEE"/"EEE") but needs a full date to validate it against.`);if(!T&&!H)throw new Error(`temporal-fmt: format string "${e}" has no date or time tokens to parse.`);let $=S(),z={hour:d??0,minute:p??0,second:y??0,millisecond:f??0},V=o?{calendar:o}:{},C={overflow:"reject"},E;try{u!==void 0?E=$.ZonedDateTime.from({year:m,month:c,day:g,...z,...V,timeZone:u},C):T&&H?E=$.PlainDateTime.from({year:m,month:c,day:g,...z,...V},C):T?E=$.PlainDate.from({year:m,month:c,day:g,...V},C):E=$.PlainTime.from(z,C)}catch(h){throw new Error(`temporal-fmt: "${n}" doesn't describe a valid date/time for format "${e}": ${h.message}`)}if(l!==void 0){let h=E.dayOfWeek;if(h!==l){let b=w(r);throw new Error(`temporal-fmt: "${U}" doesn't match the actual weekday (${b.weekdayLong[h-1]}) for the parsed date.`)}}return E}export{se as format,Ee as parse,ee as setTemporal};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/temporalProvider.ts","../src/tokens.ts","../src/tokenize.ts","../src/format.ts","../src/localeVocab.ts","../src/pattern.ts","../src/parsePattern.ts","../src/parse.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' }): unknown;\n}\n\nexport interface TemporalNamespace {\n PlainDate: TemporalFactory;\n PlainTime: TemporalFactory;\n PlainDateTime: TemporalFactory;\n ZonedDateTime: TemporalFactory;\n}\n\nlet injectedTemporal: TemporalNamespace | undefined;\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()`\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}\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","import { getTemporal } from './temporalProvider.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// 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 timeZoneId?: 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\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 = locale + JSON.stringify(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 formatter = new Intl.DateTimeFormat(locale, options);\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;\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 nativeSupport = true;\n } catch {\n // native Temporal absent, or present but not recognized by Intl β€” fall back\n }\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 // skip this for iso8601 specifically β€” passing `calendar: 'iso8601'`\n // explicitly alongside a single-field options object makes formatToParts()\n // come back empty for some reason.\n const calendar = temporal?.calendarId;\n const formatterOptions: Intl.DateTimeFormatOptions = {\n ...options,\n ...(calendar && calendar !== 'iso8601' ? { calendar } : {}),\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 if (!intlSupportsNativeTemporal()) {\n return temporal.toLocaleString!(locale, formatterOptions);\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\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 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 if (!part) {\n throw new Error(`temporal-fmt: locale \"${locale}\" produced no \"dayPeriod\" part for token \"a\".`);\n }\n return part.value;\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) => intlPart(t, locale, { month: 'long' }, 'month'), 'month'],\n ['MMM', (t, locale) => intlPart(t, locale, { month: 'short' }, 'month'), '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) => intlPart(t, locale, { weekday: 'long' }, 'weekday'), 'dayOfWeek'],\n ['EEE', (t, locale) => intlPart(t, locale, { weekday: 'short' }, 'weekday'), '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 ['SSS', (t) => pad(t.millisecond!, 3), '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];","import { TOKENS } from './tokens.js';\n\nexport type Piece =\n | { kind: 'token'; value: string }\n | { kind: 'literal'; value: string };\n\n// longest-first so the greedy scan never matches \"M\" when \"MMMM\" was there\nconst SORTED_TOKEN_STRINGS = TOKENS.map(([tok]) => tok).sort((a, b) => b.length - a.length);\n\n/**\n * Splits a format string like `\"yyyy-MM-dd 'at' HH:mm\"` into token/literal\n * pieces. Text in single quotes is always literal (e.g. write 'rd' in\n * \"3rd\" so it's not read as the day token). A doubled quote ('') means a\n * literal quote character, both inside a quoted span and standalone.\n */\nexport function tokenize(format: string): Piece[] {\n const pieces: Piece[] = [];\n let i = 0;\n\n while (i < format.length) {\n const ch = format[i];\n\n if (ch === \"'\") {\n // check doubled-quote first or \"''best''\" parses wrong\n if (format[i + 1] === \"'\") {\n appendLiteral(pieces, \"'\");\n i += 2;\n continue;\n }\n\n let j = i + 1;\n let literal = '';\n let closed = false;\n while (j < format.length) {\n if (format[j] === \"'\") {\n if (format[j + 1] === \"'\") {\n literal += \"'\";\n j += 2;\n continue;\n }\n closed = true;\n j += 1;\n break;\n }\n literal += format[j];\n j += 1;\n }\n\n if (!closed) {\n throw new Error(`temporal-fmt: unterminated quote in format string \"${format}\"`);\n }\n\n appendLiteral(pieces, literal);\n i = j;\n continue;\n }\n\n const match = SORTED_TOKEN_STRINGS.find((tok) => format.startsWith(tok, i));\n if (match) {\n pieces.push({ kind: 'token', value: match });\n i += match.length;\n continue;\n }\n\n // not a token or quote β€” pass through as-is\n appendLiteral(pieces, ch);\n i += 1;\n }\n\n return pieces;\n}\n\n// merges into the previous piece if it's also a literal, so \"---\" is one\n// piece instead of three\nfunction appendLiteral(pieces: Piece[], value: string): void {\n const last = pieces[pieces.length - 1];\n if (last && last.kind === 'literal') {\n last.value += value;\n } else {\n pieces.push({ kind: 'literal', value });\n }\n}\n","import { TOKENS, DEFAULT_LOCALE, type TemporalLike, type FormatOptions } from './tokens.js';\nimport { tokenize } from './tokenize.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\n\nconst HANDLER_BY_TOKEN = new Map(TOKENS.map(([tok, fn, field]) => [tok, { fn, field }]));\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: FormatOptions = {}): string {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`\n );\n }\n\n const locale = options.locale ?? DEFAULT_LOCALE;\n const pieces = tokenize(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 if (!handler) {\n // shouldn't happen β€” tokenize() only emits tokens from TOKENS\n throw new Error(`temporal-fmt: unknown token \"${piece.value}\"`);\n }\n\n if (temporal[handler.field] === undefined) {\n throw new Error(\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 return result;\n}\n","// 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\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\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 if (index === -1) {\n throw new Error(`temporal-fmt: locale produced no \"${type}\" part while building match vocabulary.`);\n }\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 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\nexport function getLocaleVocab(locale: string): LocaleVocab {\n const cached = vocabCache.get(locale);\n if (cached) {\n return cached;\n }\n\n const monthLongFmt = new Intl.DateTimeFormat(locale, { month: 'long', timeZone: 'UTC' });\n const monthShortFmt = new Intl.DateTimeFormat(locale, { 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(locale, { weekday: 'long', timeZone: 'UTC' });\n const weekdayShortFmt = new Intl.DateTimeFormat(locale, { 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(locale, { 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(locale, vocab);\n return vocab;\n}","import { getLocaleVocab } from './localeVocab.js';\n\nfunction escapeRegExp(literal: string): string {\n return literal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction alternation(values: string[]): string {\n return `(?:${values.map(escapeRegExp).join('|')})`;\n}\n\nlet timeZoneFragment: string | undefined;\n\nfunction getTimeZoneFragment(): string {\n if (timeZoneFragment) {\n return timeZoneFragment;\n }\n const supportedValuesOf = (Intl as unknown as { supportedValuesOf?: (key: string) => string[] }).supportedValuesOf;\n if (typeof supportedValuesOf === 'function') {\n // supportedValuesOf('timeZone') leaves out 'UTC', but format() can\n // produce it from a real ZonedDateTime β€” without this, parse() couldn't\n // parse our own library's own output back.\n timeZoneFragment = alternation([...supportedValuesOf('timeZone'), 'UTC']);\n } else {\n // no Intl.supportedValuesOf β€” match on shape only\n timeZoneFragment = '[A-Za-z_]+(?:\\\\/[A-Za-z_+\\\\-0-9]+)+|UTC';\n }\n return timeZoneFragment;\n}\n\n// mirrors the ranges pad() in tokens.ts actually produces β€” keep in sync\n// if those ever change\nconst NUMERIC_FRAGMENTS: Record<string, string> = {\n yyyy: '\\\\d{4}',\n yy: '\\\\d{2}',\n MM: '(?:0[1-9]|1[0-2])',\n M: '(?:[1-9]|1[0-2])',\n dd: '(?:0[1-9]|[12]\\\\d|3[01])',\n d: '(?:[1-9]|[12]\\\\d|3[01])',\n HH: '(?:[01]\\\\d|2[0-3])',\n H: '(?:[0-9]|1\\\\d|2[0-3])',\n hh: '(?:0[1-9]|1[0-2])',\n h: '(?:[1-9]|1[0-2])',\n mm: '(?:[0-5]\\\\d)',\n m: '(?:[0-9]|[1-5]\\\\d)',\n ss: '(?:[0-5]\\\\d)',\n s: '(?:[0-9]|[1-5]\\\\d)',\n SSS: '\\\\d{3}',\n};\n\nexport function tokenFragment(token: string, locale: string): string {\n const numeric = NUMERIC_FRAGMENTS[token];\n if (numeric) {\n return numeric;\n }\n\n const vocab = getLocaleVocab(locale);\n switch (token) {\n case 'MMMM': return alternation(vocab.monthLong);\n case 'MMM': return alternation(vocab.monthShort);\n case 'EEEE': return alternation(vocab.weekdayLong);\n case 'EEE': return alternation(vocab.weekdayShort);\n case 'a': return alternation(vocab.dayPeriod);\n case 'zzz': return getTimeZoneFragment();\n default:\n throw new Error(`temporal-fmt: unknown token \"${token}\"`);\n }\n}\n","import type { Piece } from './tokenize.js';\nimport { tokenFragment } from './pattern.js';\n\nfunction escapeRegExp(literal: string): string {\n return literal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport interface CapturingPattern {\n regex: RegExp;\n groups: Array<{ name: string; token: string }>; // token pieces, in order\n}\n\n/**\n * Same walk as buildPatternSource() in pattern.ts, but each token piece\n * gets its own named capture group (positionally named so the same token,\n * e.g. \"yyyy\", could in theory appear twice) so a caller can pull the\n * matched substring for each token back out after a successful match.\n */\nexport function buildCapturingPattern(pieces: Piece[], locale: string): CapturingPattern {\n const groups: Array<{ name: string; token: string }> = [];\n let source = '';\n let i = 0;\n\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n source += escapeRegExp(piece.value);\n continue;\n }\n const name = `g${i++}`;\n groups.push({ name, token: piece.value });\n source += `(?<${name}>${tokenFragment(piece.value, locale)})`;\n }\n\n return { regex: new RegExp(`^(?:${source})$`, 'u'), groups };\n}\n","import { DEFAULT_LOCALE, type FormatOptions } from './tokens.js';\nimport { tokenize } from './tokenize.js';\nimport { buildCapturingPattern, type CapturingPattern } from './parsePattern.js';\nimport { getLocaleVocab } from './localeVocab.js';\nimport { getTemporal } from './temporalProvider.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\n\n// format strings are short hand-written literals reused across many calls β€”\n// cache the compiled capturing pattern per (formatStr, locale) pair instead\n// of rebuilding it every call.\nconst patternCache = new Map<string, CapturingPattern>();\nconst MAX_CACHE_SIZE = 500;\n\nfunction getPattern(formatStr: string, locale: string): CapturingPattern {\n const key = locale + ' ' + formatStr;\n let pattern = patternCache.get(key);\n if (pattern) {\n return pattern;\n }\n if (patternCache.size >= MAX_CACHE_SIZE) {\n const oldestKey = patternCache.keys().next().value;\n if (oldestKey !== undefined) patternCache.delete(oldestKey);\n }\n pattern = buildCapturingPattern(tokenize(formatStr), locale);\n patternCache.set(key, pattern);\n return pattern;\n}\n\n// Requires an explicit `-u-ca-` extension (e.g. 'en-u-ca-hebrew') to apply\n// a non-Gregorian calendar, per parse()'s own docstring. 'gregory' counts\n// as \"no calendar\" so the default locale keeps constructing plain ISO 8601.\n//\n// Used to key off resolvedOptions().calendar instead β€” a locale's\n// *default* calendar, whether the caller asked for one or not. That broke\n// th-TH silently: its default is 'buddhist', so plain Gregorian-looking\n// digits parsed 543 years off, while format() has no matching calendar\n// step and just prints the object's own ISO fields either way.\nconst calendarCache = new Map<string, string | undefined>();\nconst MAX_CALENDAR_CACHE_SIZE = 500;\n\nfunction resolveCalendar(locale: string): string | undefined {\n if (calendarCache.has(locale)) {\n return calendarCache.get(locale);\n }\n if (calendarCache.size >= MAX_CALENDAR_CACHE_SIZE) {\n const oldestKey = calendarCache.keys().next().value;\n if (oldestKey !== undefined) calendarCache.delete(oldestKey);\n }\n let calendar: string | undefined;\n if (locale.includes('-u-ca-')) {\n const resolved = new Intl.DateTimeFormat(locale).resolvedOptions().calendar;\n calendar = resolved === 'gregory' ? undefined : resolved;\n }\n calendarCache.set(locale, calendar);\n return calendar;\n}\n\ninterface Fields {\n year?: number;\n twoDigitYear?: number;\n month?: number;\n day?: number;\n hour?: number;\n hour12?: number;\n isPM?: boolean;\n minute?: number;\n second?: number;\n millisecond?: number;\n timeZoneId?: string;\n weekdayExpected?: number; // ISO dayOfWeek, 1=Mon, 7=Sun\n weekdayRaw?: string;\n}\n\nfunction applyGroup(fields: Fields, token: string, raw: string, locale: string): void {\n switch (token) {\n case 'yyyy': fields.year = parseInt(raw, 10); break;\n case 'yy': fields.twoDigitYear = parseInt(raw, 10); break;\n case 'MM': case 'M': fields.month = parseInt(raw, 10); break;\n case 'MMMM': fields.month = getLocaleVocab(locale).monthLong.indexOf(raw) + 1; break;\n case 'MMM': fields.month = getLocaleVocab(locale).monthShort.indexOf(raw) + 1; break;\n case 'dd': case 'd': fields.day = parseInt(raw, 10); break;\n case 'EEEE':\n fields.weekdayRaw = raw;\n fields.weekdayExpected = getLocaleVocab(locale).weekdayLong.indexOf(raw) + 1;\n break;\n case 'EEE':\n fields.weekdayRaw = raw;\n fields.weekdayExpected = getLocaleVocab(locale).weekdayShort.indexOf(raw) + 1;\n break;\n case 'HH': case 'H': fields.hour = parseInt(raw, 10); break;\n case 'hh': case 'h': fields.hour12 = parseInt(raw, 10); break;\n case 'mm': case 'm': fields.minute = parseInt(raw, 10); break;\n case 'ss': case 's': fields.second = parseInt(raw, 10); break;\n case 'SSS': fields.millisecond = parseInt(raw, 10); break;\n case 'a': fields.isPM = raw === getLocaleVocab(locale).dayPeriod[1]; break;\n case 'zzz': fields.timeZoneId = raw; break;\n }\n}\n\n// emulates strptime (POSIX) for 2-digit years so the result doesn't depend\n// on the current clock: 00-68 -> 2000-2068, 69-99 -> 1900-1999\n// https://www.man7.org/linux//man-pages/man3/strptime.3p.html\nfunction resolveYear(fields: Fields): number | undefined {\n if (fields.year !== undefined) return fields.year;\n if (fields.twoDigitYear !== undefined) {\n return fields.twoDigitYear <= 68 ? 2000 + fields.twoDigitYear : 1900 + fields.twoDigitYear;\n }\n return undefined;\n}\n\nfunction resolveHour(fields: Fields, formatStr: string): number | undefined {\n if (fields.hour !== undefined && fields.hour12 !== undefined) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" mixes a 24-hour token (\"HH\"/\"H\") with a ` +\n `12-hour token (\"hh\"/\"h\"). Pick one or the other β€” parse() won't guess which is authoritative.`\n );\n }\n if (fields.hour !== undefined) return fields.hour;\n if (fields.hour12 !== undefined) {\n if (fields.isPM === undefined) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" uses a 12-hour token (\"hh\"/\"h\") without an \"a\" token, ` +\n `so parse() can't tell AM from PM.`\n );\n }\n return (fields.hour12 % 12) + (fields.isPM ? 12 : 0);\n }\n return undefined;\n}\n\n/**\n * Parses `input` against `formatStr` and builds the real Temporal value it\n * describes: a `Temporal.PlainDate`, `PlainTime`, `PlainDateTime`, or\n * `ZonedDateTime` depending on which tokens are present.\n *\n * Returns `unknown` β€” this package has no ambient `Temporal` types to return\n * a real one against.\n *\n * `options.locale` picks the calendar the result is built in. Pass a locale\n * tag with a `-u-ca-` extension (e.g. `'en-u-ca-hebrew'`) to parse into a\n * non-Gregorian calendar.\n *\n * @throws if `input` doesn't match `formatStr`'s shape at all\n * @throws if it matches the shape but describes an impossible date (e.g. Feb\n * 30) or self-contradictory data (e.g. a weekday name that doesn't match the\n * actual date)\n *\n * @example\n * parse('yyyy-MM-dd HH:mm', '2026-08-04 15:45') // Temporal.PlainDateTime\n * parse('yyyy-MM', '2026-08-04T15:45:30') // throws β€” shape doesn't match\n * parse('yyyy-MM-dd', '2026-02-30') // throws β€” not a real date\n */\nexport function parse(formatStr: string, input: string, options: FormatOptions = {}): unknown | undefined {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`\n );\n }\n\n const locale = options.locale ?? DEFAULT_LOCALE;\n const calendar = resolveCalendar(locale);\n const pattern = getPattern(formatStr, locale);\n const match = pattern.regex.exec(input);\n if (!match) {\n throw new Error(`temporal-fmt: no valid pattern matches the format string and input shape`);\n }\n\n if (pattern.groups.length === 0) {\n throw new Error(`temporal-fmt: format string \"${formatStr}\" has no tokens β€” nothing to parse into a value.`);\n }\n\n const fields: Fields = {};\n for (const { name, token } of pattern.groups) {\n applyGroup(fields, token, match.groups![name]!, locale);\n }\n\n const year = resolveYear(fields);\n const hour = resolveHour(fields, formatStr);\n const { month, day, minute, second, millisecond, timeZoneId, weekdayExpected, weekdayRaw } = fields;\n\n const hasAnyDatePart = year !== undefined || month !== undefined || day !== undefined;\n const hasFullDate = year !== undefined && month !== undefined && day !== undefined;\n if (hasAnyDatePart && !hasFullDate) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" has an incomplete date β€” ` +\n `year, month, and day tokens must all be present together.`\n );\n }\n\n const hasTime = hour !== undefined || minute !== undefined || second !== undefined || millisecond !== undefined;\n\n if (timeZoneId !== undefined && !(hasFullDate && hasTime)) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" has a \"zzz\" token but needs a full date and time ` +\n `to build a ZonedDateTime.`\n );\n }\n\n if (weekdayExpected !== undefined && !hasFullDate) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" has a weekday token (\"EEEE\"/\"EEE\") but needs ` +\n `a full date to validate it against.`\n );\n }\n\n if (!hasFullDate && !hasTime) {\n // shouldn't happen β€” every token maps to a date, time, zone, or\n // weekday field, and weekday-without-date already threw above\n throw new Error(`temporal-fmt: format string \"${formatStr}\" has no date or time tokens to parse.`);\n }\n\n const temporal = getTemporal();\n const timeFields = { hour: hour ?? 0, minute: minute ?? 0, second: second ?? 0, millisecond: millisecond ?? 0 };\n // omitted entirely for the default calendar (see resolveCalendar) so\n // construction stays plain ISO 8601 unless a caller's locale asks for\n // something else β€” Temporal calendars don't apply to time-only values.\n const calendarField = calendar ? { calendar } : {};\n\n // overflow: 'reject' β€” without it Temporal *clamps* out-of-range fields\n // (Feb 30 silently becomes Feb 28) instead of throwing, which would\n // contradict the \"throws on genuinely invalid data\" behavior parse() promises.\n const reject = { overflow: 'reject' as const };\n\n let result: unknown;\n try {\n if (timeZoneId !== undefined) {\n result = temporal.ZonedDateTime.from({ year: year!, month: month!, day: day!, ...timeFields, ...calendarField, timeZone: timeZoneId }, reject);\n } else if (hasFullDate && hasTime) {\n result = temporal.PlainDateTime.from({ year: year!, month: month!, day: day!, ...timeFields, ...calendarField }, reject);\n } else if (hasFullDate) {\n result = temporal.PlainDate.from({ year: year!, month: month!, day: day!, ...calendarField }, reject);\n } else {\n result = temporal.PlainTime.from(timeFields, reject);\n }\n } catch (err) {\n throw new Error(\n `temporal-fmt: \"${input}\" doesn't describe a valid date/time for format \"${formatStr}\": ` +\n `${(err as Error).message}`\n );\n }\n\n if (weekdayExpected !== undefined) {\n const actual = (result as { dayOfWeek: number }).dayOfWeek;\n if (actual !== weekdayExpected) {\n const vocab = getLocaleVocab(locale);\n throw new Error(\n `temporal-fmt: \"${weekdayRaw}\" doesn't match the actual weekday (${vocab.weekdayLong[actual - 1]}) ` +\n `for the parsed date.`\n );\n }\n }\n\n return result;\n}\n"],"mappings":"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","names":["injectedTemporal","setTemporal","temporal","resolveTemporal","getTemporal","pad","n","len","negative","digits","DEFAULT_LOCALE","formatterCache","MAX_CACHE_SIZE","getFormatter","locale","options","key","formatter","oldestKey","nativeSupport","intlSupportsNativeTemporal","temporal","getTemporal","intlPart","partType","calendar","formatterOptions","toInstant","timeZoneId","isZoned","intlSafeTemporal","nativeOptions","parts","index","p","value","prev","next","dayPeriodPart","hour","date","part","TOKENS","t","SORTED_TOKEN_STRINGS","TOKENS","tok","a","b","tokenize","format","pieces","i","ch","appendLiteral","j","literal","closed","match","value","last","HANDLER_BY_TOKEN","TOKENS","tok","fn","field","format","temporal","formatStr","options","locale","DEFAULT_LOCALE","pieces","tokenize","result","piece","handler","vocabCache","MAX_VOCAB_CACHE_SIZE","partValue","formatter","date","type","parts","index","p","value","prev","next","assertNoCollision","names","label","locale","seen","i","prior","getLocaleVocab","cached","monthLongFmt","monthShortFmt","monthLong","monthShort","weekdayLongFmt","weekdayShortFmt","weekdayLong","weekdayShort","d","dayPeriodFmt","am","pm","dayPeriod","vocab","oldestKey","escapeRegExp","literal","alternation","values","timeZoneFragment","getTimeZoneFragment","supportedValuesOf","NUMERIC_FRAGMENTS","tokenFragment","token","locale","numeric","vocab","getLocaleVocab","escapeRegExp","literal","buildCapturingPattern","pieces","locale","groups","source","i","piece","name","tokenFragment","patternCache","MAX_CACHE_SIZE","getPattern","formatStr","locale","key","pattern","oldestKey","buildCapturingPattern","tokenize","calendarCache","MAX_CALENDAR_CACHE_SIZE","resolveCalendar","calendar","resolved","applyGroup","fields","token","raw","getLocaleVocab","resolveYear","resolveHour","parse","input","options","DEFAULT_LOCALE","match","name","year","hour","month","day","minute","second","millisecond","timeZoneId","weekdayExpected","weekdayRaw","hasAnyDatePart","hasFullDate","hasTime","temporal","getTemporal","timeFields","calendarField","reject","result","err","actual","vocab"]}
1
+ {"version":3,"sources":["../src/temporalProvider.ts","../src/tokens.ts","../src/tokenize.ts","../src/format.ts","../src/localeVocab.ts","../src/pattern.ts","../src/parsePattern.ts","../src/parse.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' }): unknown;\n}\n\nexport interface TemporalNamespace {\n PlainDate: TemporalFactory;\n PlainTime: TemporalFactory;\n PlainDateTime: TemporalFactory;\n ZonedDateTime: TemporalFactory;\n}\n\nlet injectedTemporal: TemporalNamespace | undefined;\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()`\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}\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","import { getTemporal } from './temporalProvider.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// 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 timeZoneId?: 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\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 = locale + JSON.stringify(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 formatter = new Intl.DateTimeFormat(locale, options);\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;\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 nativeSupport = true;\n } catch {\n // native Temporal absent, or present but not recognized by Intl β€” fall back\n }\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 // skip this for iso8601 specifically β€” passing `calendar: 'iso8601'`\n // explicitly alongside a single-field options object makes formatToParts()\n // come back empty for some reason.\n const calendar = temporal?.calendarId;\n const formatterOptions: Intl.DateTimeFormatOptions = {\n ...options,\n ...(calendar && calendar !== 'iso8601' ? { calendar } : {}),\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 if (!intlSupportsNativeTemporal()) {\n return temporal.toLocaleString!(locale, formatterOptions);\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\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 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 if (!part) {\n throw new Error(`temporal-fmt: locale \"${locale}\" produced no \"dayPeriod\" part for token \"a\".`);\n }\n return part.value;\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) => intlPart(t, locale, { month: 'long' }, 'month'), 'month'],\n ['MMM', (t, locale) => intlPart(t, locale, { month: 'short' }, 'month'), '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) => intlPart(t, locale, { weekday: 'long' }, 'weekday'), 'dayOfWeek'],\n ['EEE', (t, locale) => intlPart(t, locale, { weekday: 'short' }, 'weekday'), '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 ['SSS', (t) => pad(t.millisecond!, 3), '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];","import { TOKENS } from './tokens.js';\n\nexport type Piece =\n | { kind: 'token'; value: string }\n | { kind: 'literal'; value: string };\n\n// longest-first so the greedy scan never matches \"M\" when \"MMMM\" was there\nconst SORTED_TOKEN_STRINGS = TOKENS.map(([tok]) => tok).sort((a, b) => b.length - a.length);\n\n/**\n * Splits a format string like `\"yyyy-MM-dd 'at' HH:mm\"` into token/literal\n * pieces. Text in single quotes is always literal (e.g. write 'rd' in\n * \"3rd\" so it's not read as the day token). A doubled quote ('') means a\n * literal quote character, both inside a quoted span and standalone.\n */\nexport function tokenize(format: string): Piece[] {\n const pieces: Piece[] = [];\n let i = 0;\n\n while (i < format.length) {\n const ch = format[i];\n\n if (ch === \"'\") {\n // check doubled-quote first or \"''best''\" parses wrong\n if (format[i + 1] === \"'\") {\n appendLiteral(pieces, \"'\");\n i += 2;\n continue;\n }\n\n let j = i + 1;\n let literal = '';\n let closed = false;\n while (j < format.length) {\n if (format[j] === \"'\") {\n if (format[j + 1] === \"'\") {\n literal += \"'\";\n j += 2;\n continue;\n }\n closed = true;\n j += 1;\n break;\n }\n literal += format[j];\n j += 1;\n }\n\n if (!closed) {\n throw new Error(`temporal-fmt: unterminated quote in format string \"${format}\"`);\n }\n\n appendLiteral(pieces, literal);\n i = j;\n continue;\n }\n\n const match = SORTED_TOKEN_STRINGS.find((tok) => format.startsWith(tok, i));\n if (match) {\n pieces.push({ kind: 'token', value: match });\n i += match.length;\n continue;\n }\n\n // not a token or quote β€” pass through as-is\n appendLiteral(pieces, ch);\n i += 1;\n }\n\n return pieces;\n}\n\n// merges into the previous piece if it's also a literal, so \"---\" is one\n// piece instead of three\nfunction appendLiteral(pieces: Piece[], value: string): void {\n const last = pieces[pieces.length - 1];\n if (last && last.kind === 'literal') {\n last.value += value;\n } else {\n pieces.push({ kind: 'literal', value });\n }\n}\n","import { TOKENS, DEFAULT_LOCALE, type TemporalLike, type FormatOptions } from './tokens.js';\nimport { tokenize } from './tokenize.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\n\nconst HANDLER_BY_TOKEN = new Map(TOKENS.map(([tok, fn, field]) => [tok, { fn, field }]));\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: FormatOptions = {}): string {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`\n );\n }\n\n const locale = options.locale ?? DEFAULT_LOCALE;\n const pieces = tokenize(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 if (!handler) {\n // shouldn't happen β€” tokenize() only emits tokens from TOKENS\n throw new Error(`temporal-fmt: unknown token \"${piece.value}\"`);\n }\n\n if (temporal[handler.field] === undefined) {\n throw new Error(\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 return result;\n}\n","// 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\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\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 if (index === -1) {\n throw new Error(`temporal-fmt: locale produced no \"${type}\" part while building match vocabulary.`);\n }\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 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\nexport function getLocaleVocab(locale: string): LocaleVocab {\n const cached = vocabCache.get(locale);\n if (cached) {\n return cached;\n }\n\n const monthLongFmt = new Intl.DateTimeFormat(locale, { month: 'long', timeZone: 'UTC' });\n const monthShortFmt = new Intl.DateTimeFormat(locale, { 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(locale, { weekday: 'long', timeZone: 'UTC' });\n const weekdayShortFmt = new Intl.DateTimeFormat(locale, { 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(locale, { 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(locale, vocab);\n return vocab;\n}","import { getLocaleVocab } from './localeVocab.js';\n\nfunction escapeRegExp(literal: string): string {\n return literal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction alternation(values: string[]): string {\n return `(?:${values.map(escapeRegExp).join('|')})`;\n}\n\nlet timeZoneFragment: string | undefined;\n\nfunction getTimeZoneFragment(): string {\n if (timeZoneFragment) {\n return timeZoneFragment;\n }\n const supportedValuesOf = (Intl as unknown as { supportedValuesOf?: (key: string) => string[] }).supportedValuesOf;\n if (typeof supportedValuesOf === 'function') {\n // supportedValuesOf('timeZone') leaves out 'UTC', but format() can\n // produce it from a real ZonedDateTime β€” without this, parse() couldn't\n // parse our own library's own output back.\n timeZoneFragment = alternation([...supportedValuesOf('timeZone'), 'UTC']);\n } else {\n // no Intl.supportedValuesOf β€” match on shape only\n timeZoneFragment = '[A-Za-z_]+(?:\\\\/[A-Za-z_+\\\\-0-9]+)+|UTC';\n }\n return timeZoneFragment;\n}\n\n// mirrors the ranges pad() in tokens.ts actually produces β€” keep in sync\n// if those ever change\n//\n// Unpadded alternatives (M, H, h, m, s) list the longer branch first\n// (e.g. '1[0-2]|[1-9]', not '[1-9]|1[0-2]'). This matters only when two\n// unpadded tokens are glued with no separator: with short-first ordering,\n// a regex engine takes the first successful overall match, and won't\n// backtrack into a token's second alternative unless its first choice\n// makes the *rest* of the pattern fail outright. If the short reading also\n// happens to leave a valid match for the next token, the engine stops\n// there β€” silently, deterministically, and with no relation to which\n// reading a human intended. E.g. \"Md\" against \"121\": short-first order\n// resolves it as month=1/day=21 (M grabs '1', d gets '21', which is a\n// valid day) instead of month=12/day=1. Longer-first ordering fixes this\n// by making the greedy match try to consume as many digits as possible\n// before ever handing digits to the next token, which is the reading\n// that matches how format() itself produces glued output in the first\n// place (format() always emits the token's natural width, so decoding\n// should prefer the same). Found via the tokenΓ—token combinatorial glue\n// matrix in combinatorial.test.js β€” see that file for the full case list.\nconst NUMERIC_FRAGMENTS: Record<string, string> = {\n yyyy: '\\\\d{4}',\n yy: '\\\\d{2}',\n MM: '(?:0[1-9]|1[0-2])',\n M: '(?:1[0-2]|[1-9])',\n dd: '(?:0[1-9]|[12]\\\\d|3[01])',\n d: '(?:[12]\\\\d|3[01]|[1-9])',\n HH: '(?:[01]\\\\d|2[0-3])',\n H: '(?:1\\\\d|2[0-3]|[0-9])',\n hh: '(?:0[1-9]|1[0-2])',\n h: '(?:1[0-2]|[1-9])',\n mm: '(?:[0-5]\\\\d)',\n m: '(?:[1-5]\\\\d|[0-9])',\n ss: '(?:[0-5]\\\\d)',\n s: '(?:[1-5]\\\\d|[0-9])',\n SSS: '\\\\d{3}',\n};\n\nexport function tokenFragment(token: string, locale: string): string {\n const numeric = NUMERIC_FRAGMENTS[token];\n if (numeric) {\n return numeric;\n }\n\n const vocab = getLocaleVocab(locale);\n switch (token) {\n case 'MMMM': return alternation(vocab.monthLong);\n case 'MMM': return alternation(vocab.monthShort);\n case 'EEEE': return alternation(vocab.weekdayLong);\n case 'EEE': return alternation(vocab.weekdayShort);\n case 'a': return alternation(vocab.dayPeriod);\n case 'zzz': return getTimeZoneFragment();\n default:\n throw new Error(`temporal-fmt: unknown token \"${token}\"`);\n }\n}\n\n// Tokens whose fragment is variable-width (1-2 digits, no leading zero).\n// Two or more of these glued with no literal separator between them can\n// have more than one digit-split that's independently valid against every\n// fragment in the run β€” see the big comment on NUMERIC_FRAGMENTS above.\n// Reordering alternation branches picks a winner for *some* of these\n// cases, but can't make both directions of a pair (e.g. \"Md\" and \"dM\")\n// agree, because the ambiguity is in the input string itself, not in how\n// any one fragment is written. exported so parsePattern.ts can find runs\n// of these that need split-counting at match time instead of a single\n// fixed regex.\nexport const UNPADDED_NUMERIC_TOKENS = new Set(['M', 'd', 'H', 'h', 'm', 's']);\n\n// Every accept width for a given unpadded numeric token, as plain min/max\n// value + digit-length pairs β€” used to enumerate candidate splits of a\n// digit run at match time. Mirrors NUMERIC_FRAGMENTS's semantics exactly\n// (same accepted values), just as data instead of regex source, since\n// enumerating splits against a compiled regex per-candidate would be\n// slower and harder to reason about than checking numeric ranges directly.\nexport const UNPADDED_NUMERIC_RANGES: Record<string, Array<{ digits: 1 | 2; min: number; max: number }>> = {\n M: [{ digits: 1, min: 1, max: 9 }, { digits: 2, min: 10, max: 12 }],\n d: [{ digits: 1, min: 1, max: 9 }, { digits: 2, min: 10, max: 31 }],\n H: [{ digits: 1, min: 0, max: 9 }, { digits: 2, min: 10, max: 23 }],\n h: [{ digits: 1, min: 1, max: 9 }, { digits: 2, min: 10, max: 12 }],\n m: [{ digits: 1, min: 0, max: 9 }, { digits: 2, min: 10, max: 59 }],\n s: [{ digits: 1, min: 0, max: 9 }, { digits: 2, min: 10, max: 59 }],\n};\n\n/**\n * Given the literal digit string a run of N adjacent unpadded-numeric\n * tokens matched as a whole (e.g. \"112\" for a 2-token run), enumerates\n * every way to split it into N pieces (one per token, each piece 1-2\n * digits per that token's own width rule) and returns every split where\n * every piece is independently valid for its token. Length 0 means the\n * run's regex match shouldn't have been possible in the first place\n * (shouldn't happen β€” the caller only invokes this after the whole\n * pattern already matched, meaning at least one split exists: the one the\n * regex actually took). Length 1 means the reading is unambiguous.\n * Length 2+ means true ambiguity β€” the caller should throw rather than\n * pick one.\n *\n * Recursive over token count rather than hardcoded to 2, so a 3+ token\n * unseparated run (e.g. \"Hms\") is covered by the same logic without a\n * special case β€” those are rarer in practice but not impossible, and a\n * partial fix that only covered pairs would leave the identical bug for\n * anyone writing a 3-token glued run.\n */\nexport function enumerateValidSplits(digits: string, tokens: string[]): number[][] {\n if (tokens.length === 0) {\n return digits.length === 0 ? [[]] : [];\n }\n const [token, ...rest] = tokens;\n const ranges = UNPADDED_NUMERIC_RANGES[token!];\n if (!ranges) {\n throw new Error(`temporal-fmt: internal error β€” \"${token}\" is not an unpadded numeric token`);\n }\n const results: number[][] = [];\n for (const { digits: width, min, max } of ranges) {\n if (digits.length < width) continue;\n const piece = digits.slice(0, width);\n // reject a leading zero on the 2-digit branch's piece β€” matches the\n // regex fragments, which never allow M/d/H/h/m/s to start with '0' in\n // their 2-digit form (that shape belongs to the padded token instead)\n if (width === 2 && piece[0] === '0') continue;\n const value = parseInt(piece, 10);\n if (value < min || value > max) continue;\n const restSplits = enumerateValidSplits(digits.slice(width), rest);\n for (const restSplit of restSplits) {\n results.push([value, ...restSplit]);\n }\n }\n return results;\n}\n","import type { Piece } from './tokenize.js';\nimport { tokenFragment, UNPADDED_NUMERIC_TOKENS } from './pattern.js';\n\nfunction escapeRegExp(literal: string): string {\n return literal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport interface CapturingPattern {\n regex: RegExp;\n groups: Array<{ name: string; token: string }>; // token pieces, in order\n // Runs of 2+ adjacent unpadded-numeric tokens with no literal separator\n // between them (e.g. \"Md\", \"dM\", \"Hm\") β€” these need a split-ambiguity\n // check at match time, since a single fixed regex can't distinguish\n // \"the only valid split\" from \"one of several valid splits taken\n // arbitrarily\". Empty for the overwhelmingly common case (no such runs).\n ambiguousRuns: Array<{ groupNames: string[]; tokens: string[] }>;\n}\n\n/**\n * Same walk as buildPatternSource() in pattern.ts, but each token piece\n * gets its own named capture group (positionally named so the same token,\n * e.g. \"yyyy\", could in theory appear twice) so a caller can pull the\n * matched substring for each token back out after a successful match.\n */\nexport function buildCapturingPattern(pieces: Piece[], locale: string): CapturingPattern {\n const groups: Array<{ name: string; token: string }> = [];\n const ambiguousRuns: Array<{ groupNames: string[]; tokens: string[] }> = [];\n let source = '';\n let i = 0;\n\n // tracks the group names/tokens of the current run of adjacent unpadded\n // numeric token pieces (no literal piece has broken it yet)\n let currentRun: { groupNames: string[]; tokens: string[] } = { groupNames: [], tokens: [] };\n const flushRun = () => {\n if (currentRun.tokens.length >= 2) {\n ambiguousRuns.push(currentRun);\n }\n currentRun = { groupNames: [], tokens: [] };\n };\n\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n source += escapeRegExp(piece.value);\n flushRun(); // a literal (even a single character) breaks adjacency\n continue;\n }\n const name = `g${i++}`;\n groups.push({ name, token: piece.value });\n source += `(?<${name}>${tokenFragment(piece.value, locale)})`;\n\n if (UNPADDED_NUMERIC_TOKENS.has(piece.value)) {\n currentRun.groupNames.push(name);\n currentRun.tokens.push(piece.value);\n } else {\n flushRun(); // a non-unpadded-numeric token (padded, locale-aware, zzz) also breaks adjacency\n }\n }\n flushRun();\n\n return { regex: new RegExp(`^(?:${source})$`, 'u'), groups, ambiguousRuns };\n}\n","import { DEFAULT_LOCALE, type FormatOptions } from './tokens.js';\nimport { tokenize } from './tokenize.js';\nimport { buildCapturingPattern, type CapturingPattern } from './parsePattern.js';\nimport { enumerateValidSplits } from './pattern.js';\nimport { getLocaleVocab } from './localeVocab.js';\nimport { getTemporal } from './temporalProvider.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\n\n// format strings are short hand-written literals reused across many calls β€”\n// cache the compiled capturing pattern per (formatStr, locale) pair instead\n// of rebuilding it every call.\nconst patternCache = new Map<string, CapturingPattern>();\nconst MAX_CACHE_SIZE = 500;\n\nfunction getPattern(formatStr: string, locale: string): CapturingPattern {\n const key = locale + ' ' + formatStr;\n let pattern = patternCache.get(key);\n if (pattern) {\n return pattern;\n }\n if (patternCache.size >= MAX_CACHE_SIZE) {\n const oldestKey = patternCache.keys().next().value;\n if (oldestKey !== undefined) patternCache.delete(oldestKey);\n }\n pattern = buildCapturingPattern(tokenize(formatStr), locale);\n patternCache.set(key, pattern);\n return pattern;\n}\n\n// Requires an explicit `-u-ca-` extension (e.g. 'en-u-ca-hebrew') to apply\n// a non-Gregorian calendar, per parse()'s own docstring. 'gregory' counts\n// as \"no calendar\" so the default locale keeps constructing plain ISO 8601.\n//\n// Used to key off resolvedOptions().calendar instead β€” a locale's\n// *default* calendar, whether the caller asked for one or not. That broke\n// th-TH silently: its default is 'buddhist', so plain Gregorian-looking\n// digits parsed 543 years off, while format() has no matching calendar\n// step and just prints the object's own ISO fields either way.\nconst calendarCache = new Map<string, string | undefined>();\nconst MAX_CALENDAR_CACHE_SIZE = 500;\n\nfunction resolveCalendar(locale: string): string | undefined {\n if (calendarCache.has(locale)) {\n return calendarCache.get(locale);\n }\n if (calendarCache.size >= MAX_CALENDAR_CACHE_SIZE) {\n const oldestKey = calendarCache.keys().next().value;\n if (oldestKey !== undefined) calendarCache.delete(oldestKey);\n }\n let calendar: string | undefined;\n if (locale.includes('-u-ca-')) {\n const resolved = new Intl.DateTimeFormat(locale).resolvedOptions().calendar;\n calendar = resolved === 'gregory' ? undefined : resolved;\n }\n calendarCache.set(locale, calendar);\n return calendar;\n}\n\ninterface Fields {\n year?: number;\n twoDigitYear?: number;\n month?: number;\n day?: number;\n hour?: number;\n hour12?: number;\n isPM?: boolean;\n minute?: number;\n second?: number;\n millisecond?: number;\n timeZoneId?: string;\n weekdayExpected?: number; // ISO dayOfWeek, 1=Mon, 7=Sun\n weekdayRaw?: string;\n}\n\nfunction applyGroup(fields: Fields, token: string, raw: string, locale: string): void {\n switch (token) {\n case 'yyyy': fields.year = parseInt(raw, 10); break;\n case 'yy': fields.twoDigitYear = parseInt(raw, 10); break;\n case 'MM': case 'M': fields.month = parseInt(raw, 10); break;\n case 'MMMM': fields.month = getLocaleVocab(locale).monthLong.indexOf(raw) + 1; break;\n case 'MMM': fields.month = getLocaleVocab(locale).monthShort.indexOf(raw) + 1; break;\n case 'dd': case 'd': fields.day = parseInt(raw, 10); break;\n case 'EEEE':\n fields.weekdayRaw = raw;\n fields.weekdayExpected = getLocaleVocab(locale).weekdayLong.indexOf(raw) + 1;\n break;\n case 'EEE':\n fields.weekdayRaw = raw;\n fields.weekdayExpected = getLocaleVocab(locale).weekdayShort.indexOf(raw) + 1;\n break;\n case 'HH': case 'H': fields.hour = parseInt(raw, 10); break;\n case 'hh': case 'h': fields.hour12 = parseInt(raw, 10); break;\n case 'mm': case 'm': fields.minute = parseInt(raw, 10); break;\n case 'ss': case 's': fields.second = parseInt(raw, 10); break;\n case 'SSS': fields.millisecond = parseInt(raw, 10); break;\n case 'a': fields.isPM = raw === getLocaleVocab(locale).dayPeriod[1]; break;\n case 'zzz': fields.timeZoneId = raw; break;\n }\n}\n\n// emulates strptime (POSIX) for 2-digit years so the result doesn't depend\n// on the current clock: 00-68 -> 2000-2068, 69-99 -> 1900-1999\n// https://www.man7.org/linux//man-pages/man3/strptime.3p.html\nfunction resolveYear(fields: Fields): number | undefined {\n if (fields.year !== undefined) return fields.year;\n if (fields.twoDigitYear !== undefined) {\n return fields.twoDigitYear <= 68 ? 2000 + fields.twoDigitYear : 1900 + fields.twoDigitYear;\n }\n return undefined;\n}\n\nfunction resolveHour(fields: Fields, formatStr: string): number | undefined {\n if (fields.hour !== undefined && fields.hour12 !== undefined) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" mixes a 24-hour token (\"HH\"/\"H\") with a ` +\n `12-hour token (\"hh\"/\"h\"). Pick one or the other β€” parse() won't guess which is authoritative.`\n );\n }\n if (fields.hour !== undefined) return fields.hour;\n if (fields.hour12 !== undefined) {\n if (fields.isPM === undefined) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" uses a 12-hour token (\"hh\"/\"h\") without an \"a\" token, ` +\n `so parse() can't tell AM from PM.`\n );\n }\n return (fields.hour12 % 12) + (fields.isPM ? 12 : 0);\n }\n return undefined;\n}\n\n/**\n * Parses `input` against `formatStr` and builds the real Temporal value it\n * describes: a `Temporal.PlainDate`, `PlainTime`, `PlainDateTime`, or\n * `ZonedDateTime` depending on which tokens are present.\n *\n * Returns `unknown` β€” this package has no ambient `Temporal` types to return\n * a real one against.\n *\n * `options.locale` picks the calendar the result is built in. Pass a locale\n * tag with a `-u-ca-` extension (e.g. `'en-u-ca-hebrew'`) to parse into a\n * non-Gregorian calendar.\n *\n * @throws if `input` doesn't match `formatStr`'s shape at all\n * @throws if it matches the shape but describes an impossible date (e.g. Feb\n * 30) or self-contradictory data (e.g. a weekday name that doesn't match the\n * actual date)\n *\n * @example\n * parse('yyyy-MM-dd HH:mm', '2026-08-04 15:45') // Temporal.PlainDateTime\n * parse('yyyy-MM', '2026-08-04T15:45:30') // throws β€” shape doesn't match\n * parse('yyyy-MM-dd', '2026-02-30') // throws β€” not a real date\n */\nexport function parse(formatStr: string, input: string, options: FormatOptions = {}): unknown | undefined {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new Error(\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`\n );\n }\n\n const locale = options.locale ?? DEFAULT_LOCALE;\n const calendar = resolveCalendar(locale);\n const pattern = getPattern(formatStr, locale);\n const match = pattern.regex.exec(input);\n if (!match) {\n throw new Error(`temporal-fmt: no valid pattern matches the format string and input shape`);\n }\n\n if (pattern.groups.length === 0) {\n throw new Error(`temporal-fmt: format string \"${formatStr}\" has no tokens β€” nothing to parse into a value.`);\n }\n\n // A run of 2+ adjacent unpadded-numeric tokens with no literal separator\n // (e.g. \"Md\", \"dM\", \"Hms\") can have more than one way to split the\n // digits it matched that's independently valid for every token in the\n // run β€” see the comment on NUMERIC_FRAGMENTS in pattern.ts for the\n // mechanism. The regex above only ever finds one such split (whichever\n // its alternation ordering happens to prefer); silently trusting that\n // one would mean parse() sometimes returns a value indistinguishable\n // from a different, equally valid value the same input could describe.\n // Rather than guess, check every ambiguous run explicitly and throw if\n // more than one split is actually valid for the substring this call\n // matched β€” the input itself is what's ambiguous, not a fixable\n // property of the pattern.\n for (const run of pattern.ambiguousRuns) {\n const runDigits = run.groupNames.map((name) => match.groups![name]!).join('');\n const splits = enumerateValidSplits(runDigits, run.tokens);\n if (splits.length > 1) {\n throw new Error(\n `temporal-fmt: \"${runDigits}\" in format string \"${formatStr}\" is ambiguous β€” ` +\n `${splits.length} different ways to read tokens \"${run.tokens.join('')}\" (with no separator ` +\n `between them) are all individually valid (e.g. ${JSON.stringify(splits[0])} vs ${JSON.stringify(splits[1])}). ` +\n `parse() won't guess; add a separator between these tokens, or use their padded form ` +\n `(e.g. \"MM\" instead of \"M\") so each one has a fixed width.`\n );\n }\n }\n\n const fields: Fields = {};\n for (const { name, token } of pattern.groups) {\n applyGroup(fields, token, match.groups![name]!, locale);\n }\n\n const year = resolveYear(fields);\n const hour = resolveHour(fields, formatStr);\n const { month, day, minute, second, millisecond, timeZoneId, weekdayExpected, weekdayRaw } = fields;\n\n const hasAnyDatePart = year !== undefined || month !== undefined || day !== undefined;\n const hasFullDate = year !== undefined && month !== undefined && day !== undefined;\n if (hasAnyDatePart && !hasFullDate) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" has an incomplete date β€” ` +\n `year, month, and day tokens must all be present together.`\n );\n }\n\n const hasTime = hour !== undefined || minute !== undefined || second !== undefined || millisecond !== undefined;\n\n if (timeZoneId !== undefined && !(hasFullDate && hasTime)) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" has a \"zzz\" token but needs a full date and time ` +\n `to build a ZonedDateTime.`\n );\n }\n\n if (weekdayExpected !== undefined && !hasFullDate) {\n throw new Error(\n `temporal-fmt: format string \"${formatStr}\" has a weekday token (\"EEEE\"/\"EEE\") but needs ` +\n `a full date to validate it against.`\n );\n }\n\n if (!hasFullDate && !hasTime) {\n // shouldn't happen β€” every token maps to a date, time, zone, or\n // weekday field, and weekday-without-date already threw above\n throw new Error(`temporal-fmt: format string \"${formatStr}\" has no date or time tokens to parse.`);\n }\n\n const temporal = getTemporal();\n const timeFields = { hour: hour ?? 0, minute: minute ?? 0, second: second ?? 0, millisecond: millisecond ?? 0 };\n // omitted entirely for the default calendar (see resolveCalendar) so\n // construction stays plain ISO 8601 unless a caller's locale asks for\n // something else β€” Temporal calendars don't apply to time-only values.\n const calendarField = calendar ? { calendar } : {};\n\n // overflow: 'reject' β€” without it Temporal *clamps* out-of-range fields\n // (Feb 30 silently becomes Feb 28) instead of throwing, which would\n // contradict the \"throws on genuinely invalid data\" behavior parse() promises.\n const reject = { overflow: 'reject' as const };\n\n let result: unknown;\n try {\n if (timeZoneId !== undefined) {\n result = temporal.ZonedDateTime.from({ year: year!, month: month!, day: day!, ...timeFields, ...calendarField, timeZone: timeZoneId }, reject);\n } else if (hasFullDate && hasTime) {\n result = temporal.PlainDateTime.from({ year: year!, month: month!, day: day!, ...timeFields, ...calendarField }, reject);\n } else if (hasFullDate) {\n result = temporal.PlainDate.from({ year: year!, month: month!, day: day!, ...calendarField }, reject);\n } else {\n result = temporal.PlainTime.from(timeFields, reject);\n }\n } catch (err) {\n throw new Error(\n `temporal-fmt: \"${input}\" doesn't describe a valid date/time for format \"${formatStr}\": ` +\n `${(err as Error).message}`\n );\n }\n\n if (weekdayExpected !== undefined) {\n const actual = (result as { dayOfWeek: number }).dayOfWeek;\n if (actual !== weekdayExpected) {\n const vocab = getLocaleVocab(locale);\n throw new Error(\n `temporal-fmt: \"${weekdayRaw}\" doesn't match the actual weekday (${vocab.weekdayLong[actual - 1]}) ` +\n `for the parsed date.`\n );\n }\n }\n\n return result;\n}\n"],"mappings":"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","names":["injectedTemporal","setTemporal","temporal","resolveTemporal","getTemporal","pad","n","len","negative","digits","DEFAULT_LOCALE","formatterCache","MAX_CACHE_SIZE","getFormatter","locale","options","key","formatter","oldestKey","nativeSupport","intlSupportsNativeTemporal","temporal","getTemporal","intlPart","partType","calendar","formatterOptions","toInstant","timeZoneId","isZoned","intlSafeTemporal","nativeOptions","parts","index","p","value","prev","next","dayPeriodPart","hour","date","part","TOKENS","t","SORTED_TOKEN_STRINGS","TOKENS","tok","a","b","tokenize","format","pieces","i","ch","appendLiteral","j","literal","closed","match","value","last","HANDLER_BY_TOKEN","TOKENS","tok","fn","field","format","temporal","formatStr","options","locale","DEFAULT_LOCALE","pieces","tokenize","result","piece","handler","vocabCache","MAX_VOCAB_CACHE_SIZE","partValue","formatter","date","type","parts","index","p","value","prev","next","assertNoCollision","names","label","locale","seen","i","prior","getLocaleVocab","cached","monthLongFmt","monthShortFmt","monthLong","monthShort","m","weekdayLongFmt","weekdayShortFmt","weekdayLong","weekdayShort","d","dayPeriodFmt","am","pm","dayPeriod","vocab","oldestKey","escapeRegExp","literal","alternation","values","timeZoneFragment","getTimeZoneFragment","supportedValuesOf","NUMERIC_FRAGMENTS","tokenFragment","token","locale","numeric","vocab","getLocaleVocab","UNPADDED_NUMERIC_TOKENS","UNPADDED_NUMERIC_RANGES","enumerateValidSplits","digits","tokens","rest","ranges","results","width","min","max","piece","value","restSplits","restSplit","escapeRegExp","literal","buildCapturingPattern","pieces","locale","groups","ambiguousRuns","source","i","currentRun","flushRun","piece","name","tokenFragment","UNPADDED_NUMERIC_TOKENS","patternCache","MAX_CACHE_SIZE","getPattern","formatStr","locale","key","pattern","oldestKey","buildCapturingPattern","tokenize","calendarCache","MAX_CALENDAR_CACHE_SIZE","resolveCalendar","calendar","resolved","applyGroup","fields","token","raw","getLocaleVocab","resolveYear","resolveHour","parse","input","options","DEFAULT_LOCALE","match","run","runDigits","name","splits","enumerateValidSplits","year","hour","month","day","minute","second","millisecond","timeZoneId","weekdayExpected","weekdayRaw","hasAnyDatePart","hasFullDate","hasTime","temporal","getTemporal","timeFields","calendarField","reject","result","err","actual","vocab"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "temporal-fmt",
3
- "version": "0.7.7",
3
+ "version": "0.7.9",
4
4
  "description": "Format Temporal.PlainDate/PlainDateTime/PlainTime/ZonedDateTime objects using date-fns-style token strings.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",