temporal-fmt 0.9.2 → 0.9.4
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 +480 -9
- package/dist/calendarUtils.cjs +259 -4
- package/dist/calendarUtils.cjs.map +1 -1
- package/dist/calendarUtils.js +33 -1
- package/dist/chunk-4N3WCGEY.js +183 -0
- package/dist/{chunk-4JWGUR4O.js.map → chunk-4N3WCGEY.js.map} +1 -1
- package/dist/chunk-5UTV5VP6.js +984 -0
- package/dist/chunk-5UTV5VP6.js.map +1 -0
- package/dist/chunk-ACKKWH5Z.js +578 -0
- package/dist/{chunk-2JHEV7ZF.js.map → chunk-ACKKWH5Z.js.map} +1 -1
- package/dist/chunk-EGUUO6LE.js +439 -0
- package/dist/chunk-EGUUO6LE.js.map +1 -0
- package/dist/chunk-FBPHNRVW.js +2939 -0
- package/dist/chunk-FBPHNRVW.js.map +1 -0
- package/dist/chunk-GPB4JHGI.js +65 -0
- package/dist/chunk-GPB4JHGI.js.map +1 -0
- package/dist/chunk-H7YQX25T.js +170 -0
- package/dist/{chunk-J2AQNXF2.js.map → chunk-H7YQX25T.js.map} +1 -1
- package/dist/chunk-HXY2GUUM.js +182 -0
- package/dist/{chunk-EHLRZULM.js.map → chunk-HXY2GUUM.js.map} +1 -1
- package/dist/chunk-L24NPTAJ.js +328 -0
- package/dist/chunk-L24NPTAJ.js.map +1 -0
- package/dist/chunk-M3GDTHMT.js +169 -0
- package/dist/chunk-M3GDTHMT.js.map +1 -0
- package/dist/chunk-MKPDLQKD.js +51 -0
- package/dist/chunk-MKPDLQKD.js.map +1 -0
- package/dist/chunk-TSLPIURC.js +242 -0
- package/dist/{chunk-VQXUMFB2.js.map → chunk-TSLPIURC.js.map} +1 -1
- package/dist/chunk-UOPAV3WX.js +75 -0
- package/dist/chunk-UOPAV3WX.js.map +1 -0
- package/dist/chunk-VNIUIQA4.js +398 -0
- package/dist/chunk-VNIUIQA4.js.map +1 -0
- package/dist/chunk-YEUASGDK.js +9 -0
- package/dist/chunk-YEUASGDK.js.map +1 -0
- package/dist/chunk-ZQZF5EXW.js +29 -0
- package/dist/chunk-ZQZF5EXW.js.map +1 -0
- package/dist/config.d.cts +4 -2
- package/dist/config.d.ts +4 -2
- package/dist/duration.cjs +638 -26
- package/dist/duration.cjs.map +1 -1
- package/dist/duration.js +28 -1
- package/dist/format.cjs +833 -35
- package/dist/format.cjs.map +1 -1
- package/dist/format.js +20 -1
- package/dist/index.cjs +7698 -163
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +108 -24
- package/dist/index.d.ts +108 -24
- package/dist/index.js +1536 -58
- package/dist/index.js.map +1 -1
- package/dist/interval.cjs +5480 -35
- package/dist/interval.cjs.map +1 -1
- package/dist/interval.js +46 -1
- package/dist/localeRegistry.cjs +375 -32
- package/dist/localeRegistry.cjs.map +1 -1
- package/dist/localeRegistry.js +11 -1
- package/dist/modApi.d.cts +131 -0
- package/dist/modApi.d.ts +131 -0
- package/dist/parse.cjs +1797 -70
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.js +20 -1
- package/dist/pattern.d.cts +1 -0
- package/dist/pattern.d.ts +1 -0
- package/dist/recurrence.cjs +452 -20
- package/dist/recurrence.cjs.map +1 -1
- package/dist/recurrence.js +19 -1
- package/dist/relativeTime.cjs +268 -21
- package/dist/relativeTime.cjs.map +1 -1
- package/dist/relativeTime.js +14 -1
- package/dist/runtime.d.cts +201 -0
- package/dist/runtime.d.ts +201 -0
- package/dist/timezone.cjs +387 -20
- package/dist/timezone.cjs.map +1 -1
- package/dist/timezone.js +26 -1
- package/package.json +4 -6
- package/scripts/cli.mjs +27 -5
- package/dist/chunk-2JHEV7ZF.js +0 -7
- package/dist/chunk-3MZLTVP3.js +0 -2
- package/dist/chunk-3MZLTVP3.js.map +0 -1
- package/dist/chunk-4JWGUR4O.js +0 -11
- package/dist/chunk-5U5WJ465.js +0 -36
- package/dist/chunk-5U5WJ465.js.map +0 -1
- package/dist/chunk-C5YESWFT.js +0 -2
- package/dist/chunk-C5YESWFT.js.map +0 -1
- package/dist/chunk-C6ZZ62ET.js +0 -2
- package/dist/chunk-C6ZZ62ET.js.map +0 -1
- package/dist/chunk-EHLRZULM.js +0 -5
- package/dist/chunk-F4RGUDA3.js +0 -2
- package/dist/chunk-F4RGUDA3.js.map +0 -1
- package/dist/chunk-J2AQNXF2.js +0 -2
- package/dist/chunk-NBXF7V5B.js +0 -2
- package/dist/chunk-NBXF7V5B.js.map +0 -1
- package/dist/chunk-R52YOKI3.js +0 -7
- package/dist/chunk-R52YOKI3.js.map +0 -1
- package/dist/chunk-UJR6DHXY.js +0 -2
- package/dist/chunk-UJR6DHXY.js.map +0 -1
- package/dist/chunk-VQXUMFB2.js +0 -21
- package/dist/chunk-XH46JNPK.js +0 -2
- package/dist/chunk-XH46JNPK.js.map +0 -1
- package/dist/chunk-YB6YAG7E.js +0 -35
- package/dist/chunk-YB6YAG7E.js.map +0 -1
- package/dist/chunk-ZGMTY52O.js +0 -2
- package/dist/chunk-ZGMTY52O.js.map +0 -1
package/dist/interval.js
CHANGED
|
@@ -1,2 +1,47 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import {
|
|
2
|
+
contains,
|
|
3
|
+
difference,
|
|
4
|
+
formatRange,
|
|
5
|
+
formatRangeToParts,
|
|
6
|
+
intersection,
|
|
7
|
+
intersects,
|
|
8
|
+
interval,
|
|
9
|
+
isAfter,
|
|
10
|
+
isBefore,
|
|
11
|
+
mergeIntervals,
|
|
12
|
+
overlaps,
|
|
13
|
+
splitInterval,
|
|
14
|
+
subtract,
|
|
15
|
+
union
|
|
16
|
+
} from "./chunk-FBPHNRVW.js";
|
|
17
|
+
import "./chunk-H7YQX25T.js";
|
|
18
|
+
import "./chunk-ACKKWH5Z.js";
|
|
19
|
+
import "./chunk-4N3WCGEY.js";
|
|
20
|
+
import "./chunk-UOPAV3WX.js";
|
|
21
|
+
import "./chunk-5UTV5VP6.js";
|
|
22
|
+
import "./chunk-M3GDTHMT.js";
|
|
23
|
+
import "./chunk-L24NPTAJ.js";
|
|
24
|
+
import "./chunk-ZQZF5EXW.js";
|
|
25
|
+
import "./chunk-YEUASGDK.js";
|
|
26
|
+
import "./chunk-EGUUO6LE.js";
|
|
27
|
+
import "./chunk-VNIUIQA4.js";
|
|
28
|
+
import "./chunk-TSLPIURC.js";
|
|
29
|
+
import "./chunk-HXY2GUUM.js";
|
|
30
|
+
import "./chunk-MKPDLQKD.js";
|
|
31
|
+
export {
|
|
32
|
+
contains,
|
|
33
|
+
difference,
|
|
34
|
+
formatRange,
|
|
35
|
+
formatRangeToParts,
|
|
36
|
+
intersection,
|
|
37
|
+
intersects,
|
|
38
|
+
interval,
|
|
39
|
+
isAfter,
|
|
40
|
+
isBefore,
|
|
41
|
+
mergeIntervals,
|
|
42
|
+
overlaps,
|
|
43
|
+
splitInterval,
|
|
44
|
+
subtract,
|
|
45
|
+
union
|
|
46
|
+
};
|
|
2
47
|
//# sourceMappingURL=interval.js.map
|
package/dist/localeRegistry.cjs
CHANGED
|
@@ -1,36 +1,379 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/localeRegistry.ts
|
|
21
|
+
var localeRegistry_exports = {};
|
|
22
|
+
__export(localeRegistry_exports, {
|
|
23
|
+
getLocale: () => getLocale,
|
|
24
|
+
hasLocale: () => hasLocale,
|
|
25
|
+
registerLocale: () => registerLocale
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(localeRegistry_exports);
|
|
28
|
+
|
|
29
|
+
// src/errors.ts
|
|
30
|
+
var TemporalFmtError = class extends Error {
|
|
31
|
+
code;
|
|
32
|
+
input;
|
|
33
|
+
format;
|
|
34
|
+
token;
|
|
35
|
+
position;
|
|
36
|
+
expected;
|
|
37
|
+
actual;
|
|
38
|
+
reason;
|
|
39
|
+
constructor(message, fields) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = "TemporalFmtError";
|
|
42
|
+
this.code = fields.code;
|
|
43
|
+
this.input = fields.input;
|
|
44
|
+
this.format = fields.format;
|
|
45
|
+
this.token = fields.token;
|
|
46
|
+
this.position = fields.position;
|
|
47
|
+
this.expected = fields.expected;
|
|
48
|
+
this.actual = fields.actual;
|
|
49
|
+
this.reason = fields.reason;
|
|
50
|
+
const capture = Error.captureStackTrace;
|
|
51
|
+
if (typeof capture === "function") {
|
|
52
|
+
capture(this, this.constructor);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// lets callers just call err.toJSON() for logging. plain Error doesn't
|
|
56
|
+
// serialize its non-enumerable fields on its own, so this picks them
|
|
57
|
+
// up explicitly
|
|
58
|
+
toJSON() {
|
|
59
|
+
return {
|
|
60
|
+
name: this.name,
|
|
61
|
+
message: this.message,
|
|
62
|
+
code: this.code,
|
|
63
|
+
input: this.input,
|
|
64
|
+
format: this.format,
|
|
65
|
+
token: this.token,
|
|
66
|
+
position: this.position,
|
|
67
|
+
expected: this.expected,
|
|
68
|
+
actual: this.actual,
|
|
69
|
+
reason: this.reason
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
/* c8 ignore start @preserve -- InvalidTimeError is part of the public
|
|
74
|
+
error-class surface (exported from index.ts, code 'INVALID_TIME') but
|
|
75
|
+
nothing in this package actually constructs one. went and checked
|
|
76
|
+
whether it could get wired in the same way InvalidTimeZoneError just
|
|
77
|
+
was (see parse.ts's zzz-validation loop) — does hour/minute/second have
|
|
78
|
+
a post-match semantic range check the way zone ids do? nope.
|
|
7
79
|
pattern.ts's regex fragments for HH/H/hh/h/mm/m/ss/s already enforce
|
|
8
|
-
their valid ranges at the regex level (e.g. HH is
|
|
9
|
-
which can't match "99"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
redundant check purely to give this class a body.
|
|
13
|
-
until the library actually
|
|
80
|
+
their valid ranges right at the regex level (e.g. HH is
|
|
81
|
+
'(?:[01]\d|2[0-3])', which literally can't match "99"), so an
|
|
82
|
+
out-of-range time just gets rejected as a plain shape mismatch before
|
|
83
|
+
any semantic check would even run. no live gap to hook this into
|
|
84
|
+
without inventing a redundant check purely to give this class a body.
|
|
85
|
+
leaving it unconstructed until the library actually hits a real
|
|
86
|
+
invalid-time case worth reporting */
|
|
87
|
+
/* c8 ignore stop @preserve */
|
|
88
|
+
/* c8 ignore start @preserve -- InvalidCalendarError is part of the
|
|
14
89
|
public error-class surface (exported from index.ts, code
|
|
15
|
-
'INVALID_CALENDAR') but
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
90
|
+
'INVALID_CALENDAR') but same story as InvalidTimeError above — nothing
|
|
91
|
+
in this package constructs one. checked for a wiring opportunity the
|
|
92
|
+
same way: there's no user-supplied calendar identifier anywhere in the
|
|
93
|
+
library that we'd validate against a supported list. resolveCalendar()
|
|
19
94
|
in parse.ts derives the calendar entirely from Intl's own resolution
|
|
20
|
-
of the locale string — it's never handed an arbitrary "calendar"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
parameter that could be invalid
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
95
|
+
of the locale string — it's never handed an arbitrary "calendar" value
|
|
96
|
+
a caller could actually get wrong. no live input to reject here.
|
|
97
|
+
leaving it unconstructed until the library accepts an actual calendar
|
|
98
|
+
parameter that could be invalid */
|
|
99
|
+
/* c8 ignore stop @preserve */
|
|
100
|
+
var InvalidLocaleError = class extends TemporalFmtError {
|
|
101
|
+
constructor(fields) {
|
|
102
|
+
const { message, ...rest } = fields;
|
|
103
|
+
super(
|
|
104
|
+
message ?? `locale "${fields.actual ?? ""}" is not a valid BCP-47 tag${fields.reason ? `: ${fields.reason}` : ""}.`,
|
|
105
|
+
{ code: "INVALID_LOCALE", ...rest }
|
|
106
|
+
);
|
|
107
|
+
this.name = "InvalidLocaleError";
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
/* c8 ignore start @preserve -- unreachable from the current test suite,
|
|
111
|
+
see rationale above */
|
|
112
|
+
/* c8 ignore stop @preserve */
|
|
113
|
+
|
|
114
|
+
// src/localeVocab.ts
|
|
115
|
+
var customVocabs = /* @__PURE__ */ new Map();
|
|
116
|
+
var MAX_CUSTOM_VOCABS = 500;
|
|
117
|
+
var MAX_LOCALE_TAG_LENGTH = 256;
|
|
118
|
+
var MAX_VOCAB_ENTRY_LENGTH = 256;
|
|
119
|
+
function assertValidVocab(vocab, locale) {
|
|
120
|
+
const required = [
|
|
121
|
+
{ key: "monthLong", length: 12, label: "long month names" },
|
|
122
|
+
{ key: "monthShort", length: 12, label: "short month names" },
|
|
123
|
+
{ key: "weekdayLong", length: 7, label: "long weekday names" },
|
|
124
|
+
{ key: "weekdayShort", length: 7, label: "short weekday names" },
|
|
125
|
+
{ key: "dayPeriod", length: 2, label: "day period markers (AM/PM-equivalent)" }
|
|
126
|
+
];
|
|
127
|
+
for (const { key, length, label } of required) {
|
|
128
|
+
const value = vocab[key];
|
|
129
|
+
if (value === void 0) {
|
|
130
|
+
throw new Error(
|
|
131
|
+
`temporal-fmt: registerLocaleVocab for locale "${locale}" is missing required field "${key}" (${label}).`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
if (!Array.isArray(value)) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
`temporal-fmt: registerLocaleVocab for locale "${locale}": "${key}" must be an array, got ${typeof value}.`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
if (value.length !== length) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`temporal-fmt: registerLocaleVocab for locale "${locale}": "${key}" must have exactly ${length} entries (got ${value.length}) \u2014 ${label}.`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
value.forEach((entry, i) => {
|
|
145
|
+
if (typeof entry !== "string" || entry.length === 0) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`temporal-fmt: registerLocaleVocab for locale "${locale}": "${key}[${i}]" must be a non-empty string, got ${String(entry)}.`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
if (entry.length > MAX_VOCAB_ENTRY_LENGTH) {
|
|
151
|
+
throw new RangeError(
|
|
152
|
+
`temporal-fmt: registerLocaleVocab for locale "${locale}": "${key}[${i}]" is too long (maximum ${MAX_VOCAB_ENTRY_LENGTH} characters).`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
assertNoCollision(vocab.monthLong, "MMMM month", locale);
|
|
158
|
+
assertNoCollision(vocab.monthShort, "MMM month", locale);
|
|
159
|
+
assertNoCollision(vocab.weekdayLong, "EEEE weekday", locale);
|
|
160
|
+
assertNoCollision(vocab.weekdayShort, "EEE weekday", locale);
|
|
161
|
+
if (vocab.dayPeriod[0] === vocab.dayPeriod[1]) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`temporal-fmt: registerLocaleVocab for locale "${locale}": dayPeriod entries must differ (both are "${vocab.dayPeriod[0]}"); otherwise parse() can't tell AM from PM.`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
var onVocabChanged = [];
|
|
168
|
+
function registerLocaleVocab(locale, vocab) {
|
|
169
|
+
if (typeof locale !== "string" || locale.length === 0) {
|
|
170
|
+
throw new Error(`temporal-fmt: registerLocaleVocab requires a non-empty locale string, got ${String(locale)}.`);
|
|
171
|
+
}
|
|
172
|
+
if (locale.length > MAX_LOCALE_TAG_LENGTH) {
|
|
173
|
+
throw new RangeError(`temporal-fmt: registerLocaleVocab locale is too long (maximum ${MAX_LOCALE_TAG_LENGTH} characters).`);
|
|
174
|
+
}
|
|
175
|
+
assertValidVocab(vocab, locale);
|
|
176
|
+
const cacheKey = canonicalCacheKey(locale);
|
|
177
|
+
if (!customVocabs.has(cacheKey) && customVocabs.size >= MAX_CUSTOM_VOCABS) {
|
|
178
|
+
throw new RangeError(`temporal-fmt: registerLocaleVocab reached the ${MAX_CUSTOM_VOCABS}-locale limit.`);
|
|
179
|
+
}
|
|
180
|
+
customVocabs.set(cacheKey, {
|
|
181
|
+
monthLong: [...vocab.monthLong],
|
|
182
|
+
monthShort: [...vocab.monthShort],
|
|
183
|
+
weekdayLong: [...vocab.weekdayLong],
|
|
184
|
+
weekdayShort: [...vocab.weekdayShort],
|
|
185
|
+
dayPeriod: [...vocab.dayPeriod]
|
|
186
|
+
});
|
|
187
|
+
vocabCache.delete(cacheKey);
|
|
188
|
+
for (const listener of onVocabChanged) listener();
|
|
189
|
+
}
|
|
190
|
+
function normalizeLocaleTag(locale) {
|
|
191
|
+
return locale.replace(/_/g, "-");
|
|
192
|
+
}
|
|
193
|
+
var canonicalKeyCache = /* @__PURE__ */ new Map();
|
|
194
|
+
var MAX_CANONICAL_KEY_CACHE = 500;
|
|
195
|
+
function canonicalCacheKey(locale) {
|
|
196
|
+
const hit = canonicalKeyCache.get(locale);
|
|
197
|
+
if (hit !== void 0) return hit;
|
|
198
|
+
let key;
|
|
199
|
+
try {
|
|
200
|
+
key = new Intl.Locale(locale.replace(/_/g, "-")).toString().toLowerCase();
|
|
201
|
+
} catch {
|
|
202
|
+
key = locale;
|
|
203
|
+
}
|
|
204
|
+
if (canonicalKeyCache.size >= MAX_CANONICAL_KEY_CACHE) {
|
|
205
|
+
const oldestKey = canonicalKeyCache.keys().next().value;
|
|
206
|
+
if (oldestKey !== void 0) canonicalKeyCache.delete(oldestKey);
|
|
207
|
+
}
|
|
208
|
+
canonicalKeyCache.set(locale, key);
|
|
209
|
+
return key;
|
|
210
|
+
}
|
|
211
|
+
function assertValidLocaleTag(locale) {
|
|
212
|
+
try {
|
|
213
|
+
new Intl.Locale(normalizeLocaleTag(locale));
|
|
214
|
+
} catch {
|
|
215
|
+
throw new InvalidLocaleError({
|
|
216
|
+
actual: locale,
|
|
217
|
+
reason: "not a valid BCP-47 locale tag"
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
var vocabCache = /* @__PURE__ */ new Map();
|
|
222
|
+
var MAX_VOCAB_CACHE_SIZE = 500;
|
|
223
|
+
function partValue(formatter, date, type) {
|
|
224
|
+
const parts = formatter.formatToParts(date);
|
|
225
|
+
const index = parts.findIndex((p) => p.type === type);
|
|
226
|
+
/* c8 ignore start @preserve -- defensive guard against a real but
|
|
227
|
+
unreproducible failure mode: an Intl implementation that omits the
|
|
228
|
+
requested part type entirely for some locale. Checked every locale
|
|
229
|
+
with unusual dayPeriod/weekday/month rendering available in this
|
|
230
|
+
runtime's ICU data (ja-JP, zh-CN, th-TH, he-IL, ar-SA, ko-KR, fa-IR)
|
|
231
|
+
against the exact formatter options getLocaleVocab uses (notably
|
|
232
|
+
hour12: true for the dayPeriod formatter, which is what makes every
|
|
233
|
+
locale here actually emit a dayPeriod part — omitting it is what
|
|
234
|
+
produced a false "gap" during investigation). None omit their part
|
|
235
|
+
on this runtime. A different ICU version or a non-Node Intl
|
|
236
|
+
implementation could plausibly behave differently, so this stays a
|
|
237
|
+
real check rather than an assertion. */
|
|
238
|
+
/* c8 ignore start @preserve */
|
|
239
|
+
if (index === -1) {
|
|
240
|
+
throw new InvalidLocaleError({
|
|
241
|
+
message: `temporal-fmt: locale produced no "${type}" part while building match vocabulary.`
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
/* c8 ignore stop @preserve */
|
|
245
|
+
let value = parts[index].value;
|
|
246
|
+
const prev = parts[index - 1];
|
|
247
|
+
const next = parts[index + 1];
|
|
248
|
+
if (prev?.type === "literal" && !/\s/.test(prev.value)) value = prev.value + value;
|
|
249
|
+
if (next?.type === "literal" && !/\s/.test(next.value)) value = value + next.value;
|
|
250
|
+
return value;
|
|
251
|
+
}
|
|
252
|
+
function assertNoCollision(names, label, locale) {
|
|
253
|
+
const seen = /* @__PURE__ */ new Map();
|
|
254
|
+
for (let i = 0; i < names.length; i++) {
|
|
255
|
+
const prior = seen.get(names[i]);
|
|
256
|
+
if (prior !== void 0) {
|
|
257
|
+
throw new Error(
|
|
258
|
+
`temporal-fmt: locale "${locale}" renders ${label} index ${prior} and ${i} identically ("${names[i]}"). parse() can't reliably tell these apart for this locale/token, so this combination isn't supported.`
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
seen.set(names[i], i);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function getLocaleVocab(locale) {
|
|
265
|
+
assertValidLocaleTag(locale);
|
|
266
|
+
const cacheKey = canonicalCacheKey(locale);
|
|
267
|
+
const custom = customVocabs.get(cacheKey);
|
|
268
|
+
if (custom) {
|
|
269
|
+
return custom;
|
|
270
|
+
}
|
|
271
|
+
const cached = vocabCache.get(cacheKey);
|
|
272
|
+
if (cached) {
|
|
273
|
+
return cached;
|
|
274
|
+
}
|
|
275
|
+
const intlLocale = normalizeLocaleTag(locale);
|
|
276
|
+
const monthLongFmt = new Intl.DateTimeFormat(intlLocale, { month: "long", timeZone: "UTC" });
|
|
277
|
+
const monthShortFmt = new Intl.DateTimeFormat(intlLocale, { month: "short", timeZone: "UTC" });
|
|
278
|
+
const monthLong = [];
|
|
279
|
+
const monthShort = [];
|
|
280
|
+
for (let m = 0; m < 12; m++) {
|
|
281
|
+
const date = new Date(Date.UTC(2020, m, 1));
|
|
282
|
+
monthLong.push(partValue(monthLongFmt, date, "month"));
|
|
283
|
+
monthShort.push(partValue(monthShortFmt, date, "month"));
|
|
284
|
+
}
|
|
285
|
+
assertNoCollision(monthLong, "MMMM month", locale);
|
|
286
|
+
assertNoCollision(monthShort, "MMM month", locale);
|
|
287
|
+
const weekdayLongFmt = new Intl.DateTimeFormat(intlLocale, { weekday: "long", timeZone: "UTC" });
|
|
288
|
+
const weekdayShortFmt = new Intl.DateTimeFormat(intlLocale, { weekday: "short", timeZone: "UTC" });
|
|
289
|
+
const weekdayLong = [];
|
|
290
|
+
const weekdayShort = [];
|
|
291
|
+
for (let d = 0; d < 7; d++) {
|
|
292
|
+
const date = new Date(Date.UTC(2024, 0, 1 + d));
|
|
293
|
+
weekdayLong.push(partValue(weekdayLongFmt, date, "weekday"));
|
|
294
|
+
weekdayShort.push(partValue(weekdayShortFmt, date, "weekday"));
|
|
295
|
+
}
|
|
296
|
+
assertNoCollision(weekdayLong, "EEEE weekday", locale);
|
|
297
|
+
assertNoCollision(weekdayShort, "EEE weekday", locale);
|
|
298
|
+
const dayPeriodFmt = new Intl.DateTimeFormat(intlLocale, { hour: "numeric", hour12: true, timeZone: "UTC" });
|
|
299
|
+
const am = partValue(dayPeriodFmt, new Date(Date.UTC(2020, 0, 1, 1)), "dayPeriod");
|
|
300
|
+
const pm = partValue(dayPeriodFmt, new Date(Date.UTC(2020, 0, 1, 13)), "dayPeriod");
|
|
301
|
+
const dayPeriod = [.../* @__PURE__ */ new Set([am, pm])];
|
|
302
|
+
const vocab = { monthLong, monthShort, weekdayLong, weekdayShort, dayPeriod };
|
|
303
|
+
if (vocabCache.size >= MAX_VOCAB_CACHE_SIZE) {
|
|
304
|
+
const oldestKey = vocabCache.keys().next().value;
|
|
305
|
+
if (oldestKey !== void 0) vocabCache.delete(oldestKey);
|
|
306
|
+
}
|
|
307
|
+
vocabCache.set(cacheKey, vocab);
|
|
308
|
+
return vocab;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/localeRegistry.ts
|
|
312
|
+
var extendedVocabs = /* @__PURE__ */ new Map();
|
|
313
|
+
var MAX_LOCALE_TAG_LENGTH2 = 256;
|
|
314
|
+
var MAX_VOCAB_STRING_LENGTH = 256;
|
|
315
|
+
function canonicalKey(locale) {
|
|
316
|
+
try {
|
|
317
|
+
return new Intl.Locale(locale.replace(/_/g, "-")).toString().toLowerCase();
|
|
318
|
+
} catch {
|
|
319
|
+
return locale;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
function registerLocale(locale, vocab) {
|
|
323
|
+
if (typeof locale !== "string" || locale.length === 0) {
|
|
324
|
+
throw new InvalidLocaleError({ actual: String(locale), reason: "locale string must be non-empty" });
|
|
325
|
+
}
|
|
326
|
+
if (locale.length > MAX_LOCALE_TAG_LENGTH2) {
|
|
327
|
+
throw new InvalidLocaleError({ actual: String(locale.length), reason: `locale tag must be at most ${MAX_LOCALE_TAG_LENGTH2} characters` });
|
|
328
|
+
}
|
|
329
|
+
registerLocaleVocab(locale, vocab);
|
|
330
|
+
validateExtended(vocab, locale);
|
|
331
|
+
const key = canonicalKey(locale);
|
|
332
|
+
extendedVocabs.set(key, { ...vocab });
|
|
333
|
+
}
|
|
334
|
+
function validateExtended(vocab, locale) {
|
|
335
|
+
const checkArray = (val, key, length) => {
|
|
336
|
+
if (val === void 0) return;
|
|
337
|
+
if (!Array.isArray(val)) {
|
|
338
|
+
throw new InvalidLocaleError({ actual: String(val), reason: `locale "${locale}": "${key}" must be an array` });
|
|
339
|
+
}
|
|
340
|
+
if (val.length !== length) {
|
|
341
|
+
throw new InvalidLocaleError({ actual: String(val.length), reason: `locale "${locale}": "${key}" must have ${length} entries (got ${val.length})` });
|
|
342
|
+
}
|
|
343
|
+
for (let i = 0; i < val.length; i++) {
|
|
344
|
+
if (typeof val[i] !== "string" || val[i].length === 0) {
|
|
345
|
+
throw new InvalidLocaleError({ actual: String(val[i]), reason: `locale "${locale}": "${key}[${i}]" must be a non-empty string` });
|
|
346
|
+
}
|
|
347
|
+
if (val[i].length > MAX_VOCAB_STRING_LENGTH) {
|
|
348
|
+
throw new InvalidLocaleError({ actual: String(val[i].length), reason: `locale "${locale}": "${key}[${i}]" must be at most ${MAX_VOCAB_STRING_LENGTH} characters` });
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
checkArray(vocab.quartersLong, "quartersLong", 4);
|
|
353
|
+
checkArray(vocab.quartersShort, "quartersShort", 4);
|
|
354
|
+
checkArray(vocab.erasLong, "erasLong", 2);
|
|
355
|
+
checkArray(vocab.erasShort, "erasShort", 2);
|
|
356
|
+
checkArray(vocab.ordinals, "ordinals", 4);
|
|
357
|
+
}
|
|
358
|
+
function getLocale(locale) {
|
|
359
|
+
const key = canonicalKey(locale);
|
|
360
|
+
const ext = extendedVocabs.get(key);
|
|
361
|
+
if (ext) return ext;
|
|
362
|
+
try {
|
|
363
|
+
const base = getLocaleVocab(locale);
|
|
364
|
+
return { ...base };
|
|
365
|
+
} catch {
|
|
366
|
+
return void 0;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
function hasLocale(locale) {
|
|
370
|
+
const key = canonicalKey(locale);
|
|
371
|
+
return extendedVocabs.has(key);
|
|
372
|
+
}
|
|
373
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
374
|
+
0 && (module.exports = {
|
|
375
|
+
getLocale,
|
|
376
|
+
hasLocale,
|
|
377
|
+
registerLocale
|
|
378
|
+
});
|
|
36
379
|
//# sourceMappingURL=localeRegistry.cjs.map
|