temporal-fmt 0.8.982 → 0.9.0
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/dist/{chunk-FRS42YLM.js → chunk-AXQLUIDY.js} +43 -28
- package/dist/chunk-AXQLUIDY.js.map +1 -0
- package/dist/{chunk-KCSGCK7L.js → chunk-CKVHXFX7.js} +162 -87
- package/dist/chunk-CKVHXFX7.js.map +1 -0
- package/dist/{chunk-B3BFPB3T.js → chunk-FQA4XJME.js} +2 -2
- package/dist/{chunk-BNIIELG5.js → chunk-FTMLZ4EN.js} +2 -2
- package/dist/{chunk-YNXTPXB5.js → chunk-JCIMP43G.js} +3 -5
- package/dist/{chunk-YNXTPXB5.js.map → chunk-JCIMP43G.js.map} +1 -1
- package/dist/{chunk-RTPA5A5T.js → chunk-KDYK72Z2.js} +3 -5
- package/dist/{chunk-RTPA5A5T.js.map → chunk-KDYK72Z2.js.map} +1 -1
- package/dist/{chunk-6MIVOWWX.js → chunk-M33NSC4E.js} +15 -8
- package/dist/chunk-M33NSC4E.js.map +1 -0
- package/dist/{chunk-USONQ7MV.js → chunk-O6GVMBLW.js} +182 -12
- package/dist/chunk-O6GVMBLW.js.map +1 -0
- package/dist/{chunk-XIKLQMF7.js → chunk-VSUCBUTC.js} +2 -2
- package/dist/duration.cjs +93 -90
- package/dist/duration.cjs.map +1 -1
- package/dist/duration.js +2 -3
- package/dist/format.cjs +148 -109
- package/dist/format.cjs.map +1 -1
- package/dist/format.js +4 -5
- package/dist/index.cjs +548 -466
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +10 -12
- package/dist/index.js.map +1 -1
- package/dist/interval.cjs +132 -98
- package/dist/interval.cjs.map +1 -1
- package/dist/interval.js +5 -6
- package/dist/localeRegistry.cjs +86 -81
- package/dist/localeRegistry.cjs.map +1 -1
- package/dist/localeRegistry.js +2 -3
- package/dist/parse.cjs +342 -271
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.js +4 -5
- package/dist/relativeTime.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-3RLYULUQ.js +0 -178
- package/dist/chunk-3RLYULUQ.js.map +0 -1
- package/dist/chunk-6MIVOWWX.js.map +0 -1
- package/dist/chunk-FRS42YLM.js.map +0 -1
- package/dist/chunk-KCSGCK7L.js.map +0 -1
- package/dist/chunk-USONQ7MV.js.map +0 -1
- /package/dist/{chunk-B3BFPB3T.js.map → chunk-FQA4XJME.js.map} +0 -0
- /package/dist/{chunk-BNIIELG5.js.map → chunk-FTMLZ4EN.js.map} +0 -0
- /package/dist/{chunk-XIKLQMF7.js.map → chunk-VSUCBUTC.js.map} +0 -0
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
applyNumbering,
|
|
3
3
|
tokenize
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-M33NSC4E.js";
|
|
5
5
|
import {
|
|
6
6
|
DEFAULT_LOCALE,
|
|
7
7
|
TOKENS
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-VSUCBUTC.js";
|
|
9
9
|
import {
|
|
10
10
|
MAX_FORMAT_LENGTH
|
|
11
11
|
} from "./chunk-EDUFSRWJ.js";
|
|
12
|
+
import {
|
|
13
|
+
FormatSyntaxError,
|
|
14
|
+
UnknownTokenError
|
|
15
|
+
} from "./chunk-O6GVMBLW.js";
|
|
12
16
|
|
|
13
17
|
// src/format.ts
|
|
14
18
|
var HANDLER_BY_TOKEN = new Map(TOKENS.map(([tok, fn, field]) => [tok, { fn, field }]));
|
|
@@ -27,9 +31,10 @@ function getPieces(formatStr) {
|
|
|
27
31
|
}
|
|
28
32
|
function format(temporal, formatStr, options = {}) {
|
|
29
33
|
if (formatStr.length > MAX_FORMAT_LENGTH) {
|
|
30
|
-
throw new
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
throw new FormatSyntaxError({
|
|
35
|
+
format: formatStr,
|
|
36
|
+
message: `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters (got ${formatStr.length}).`
|
|
37
|
+
});
|
|
33
38
|
}
|
|
34
39
|
const locale = options.locale ?? DEFAULT_LOCALE;
|
|
35
40
|
const pieces = getPieces(formatStr);
|
|
@@ -46,13 +51,15 @@ function format(temporal, formatStr, options = {}) {
|
|
|
46
51
|
here. Same defensive-guard category as the twin checks in
|
|
47
52
|
analyze.ts/formatDuration.ts. */
|
|
48
53
|
if (!handler) {
|
|
49
|
-
throw new
|
|
54
|
+
throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token "${piece.value}"` });
|
|
50
55
|
}
|
|
51
56
|
/* c8 ignore stop @preserve */
|
|
52
57
|
if (temporal[handler.field] === void 0) {
|
|
53
|
-
throw new
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
throw new FormatSyntaxError({
|
|
59
|
+
format: formatStr,
|
|
60
|
+
token: piece.value,
|
|
61
|
+
message: `temporal-fmt: token "${piece.value}" requires "${handler.field}", which this Temporal object doesn't have. (e.g. PlainDate has no time fields, PlainTime has no date fields)`
|
|
62
|
+
});
|
|
56
63
|
}
|
|
57
64
|
result += handler.fn(temporal, locale);
|
|
58
65
|
}
|
|
@@ -60,9 +67,10 @@ function format(temporal, formatStr, options = {}) {
|
|
|
60
67
|
}
|
|
61
68
|
function formatToParts(temporal, formatStr, options = {}) {
|
|
62
69
|
if (formatStr.length > MAX_FORMAT_LENGTH) {
|
|
63
|
-
throw new
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
throw new FormatSyntaxError({
|
|
71
|
+
format: formatStr,
|
|
72
|
+
message: `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters (got ${formatStr.length}).`
|
|
73
|
+
});
|
|
66
74
|
}
|
|
67
75
|
const locale = options.locale ?? DEFAULT_LOCALE;
|
|
68
76
|
const pieces = getPieces(formatStr);
|
|
@@ -87,13 +95,15 @@ function formatToParts(temporal, formatStr, options = {}) {
|
|
|
87
95
|
const handler = HANDLER_BY_TOKEN.get(piece.value);
|
|
88
96
|
/* c8 ignore start @preserve -- unreachable, see the note in format() above */
|
|
89
97
|
if (!handler) {
|
|
90
|
-
throw new
|
|
98
|
+
throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token "${piece.value}"` });
|
|
91
99
|
}
|
|
92
100
|
/* c8 ignore stop @preserve */
|
|
93
101
|
if (temporal[handler.field] === void 0) {
|
|
94
|
-
throw new
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
throw new FormatSyntaxError({
|
|
103
|
+
format: formatStr,
|
|
104
|
+
token: piece.value,
|
|
105
|
+
message: `temporal-fmt: token "${piece.value}" requires "${handler.field}", which this Temporal object doesn't have. (e.g. PlainDate has no time fields, PlainTime has no date fields)`
|
|
106
|
+
});
|
|
97
107
|
}
|
|
98
108
|
result.push({ type: "token", value: applyNumbering(handler.fn(temporal, locale), options), token: piece.value });
|
|
99
109
|
}
|
|
@@ -101,9 +111,10 @@ function formatToParts(temporal, formatStr, options = {}) {
|
|
|
101
111
|
}
|
|
102
112
|
function compileFormat(formatStr) {
|
|
103
113
|
if (formatStr.length > MAX_FORMAT_LENGTH) {
|
|
104
|
-
throw new
|
|
105
|
-
|
|
106
|
-
|
|
114
|
+
throw new FormatSyntaxError({
|
|
115
|
+
format: formatStr,
|
|
116
|
+
message: `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters (got ${formatStr.length}).`
|
|
117
|
+
});
|
|
107
118
|
}
|
|
108
119
|
const pieces = getPieces(formatStr);
|
|
109
120
|
return {
|
|
@@ -118,11 +129,13 @@ function compileFormat(formatStr) {
|
|
|
118
129
|
continue;
|
|
119
130
|
}
|
|
120
131
|
const handler = HANDLER_BY_TOKEN.get(piece.value);
|
|
121
|
-
if (!handler) throw new
|
|
132
|
+
if (!handler) throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token "${piece.value}"` });
|
|
122
133
|
if (temporal[handler.field] === void 0) {
|
|
123
|
-
throw new
|
|
124
|
-
|
|
125
|
-
|
|
134
|
+
throw new FormatSyntaxError({
|
|
135
|
+
format: formatStr,
|
|
136
|
+
token: piece.value,
|
|
137
|
+
message: `temporal-fmt: token "${piece.value}" requires "${handler.field}", which this Temporal object doesn't have. (e.g. PlainDate has no time fields, PlainTime has no date fields)`
|
|
138
|
+
});
|
|
126
139
|
}
|
|
127
140
|
result += handler.fn(temporal, locale);
|
|
128
141
|
}
|
|
@@ -139,11 +152,13 @@ function compileFormat(formatStr) {
|
|
|
139
152
|
continue;
|
|
140
153
|
}
|
|
141
154
|
const handler = HANDLER_BY_TOKEN.get(piece.value);
|
|
142
|
-
if (!handler) throw new
|
|
155
|
+
if (!handler) throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token "${piece.value}"` });
|
|
143
156
|
if (temporal[handler.field] === void 0) {
|
|
144
|
-
throw new
|
|
145
|
-
|
|
146
|
-
|
|
157
|
+
throw new FormatSyntaxError({
|
|
158
|
+
format: formatStr,
|
|
159
|
+
token: piece.value,
|
|
160
|
+
message: `temporal-fmt: token "${piece.value}" requires "${handler.field}", which this Temporal object doesn't have. (e.g. PlainDate has no time fields, PlainTime has no date fields)`
|
|
161
|
+
});
|
|
147
162
|
}
|
|
148
163
|
out.push({ type: "token", value: applyNumbering(handler.fn(temporal, locale), options), token: piece.value });
|
|
149
164
|
}
|
|
@@ -165,4 +180,4 @@ export {
|
|
|
165
180
|
_getPieces,
|
|
166
181
|
_handlerFor
|
|
167
182
|
};
|
|
168
|
-
//# sourceMappingURL=chunk-
|
|
183
|
+
//# sourceMappingURL=chunk-AXQLUIDY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/format.ts"],"sourcesContent":["import { TOKENS, DEFAULT_LOCALE, type TemporalLike, type FormatOptions } from './tokens.js';\nimport { tokenize, type Piece } from './tokenize.js';\nimport { MAX_FORMAT_LENGTH } from './constants.js';\nimport { applyNumbering, type NumberingFormatOptions } from './numbering.js';\nimport { FormatSyntaxError, UnknownTokenError } from './errors.js';\n\nconst HANDLER_BY_TOKEN = new Map(TOKENS.map(([tok, fn, field]) => [tok, { fn, field }]));\n\n// Pre-tokenized format strings, keyed by (formatStr) — locale doesn't\n// change the tokenization step, only the per-token rendering, so the\n// piece list is shared across locales. Same eviction shape as the\n// other caches in this library.\nconst tokenizeCache = new Map<string, Piece[]>();\nconst MAX_TOKENIZE_CACHE_SIZE = 500;\n\nfunction getPieces(formatStr: string): Piece[] {\n let pieces = tokenizeCache.get(formatStr);\n if (pieces) return pieces;\n if (tokenizeCache.size >= MAX_TOKENIZE_CACHE_SIZE) {\n const oldestKey = tokenizeCache.keys().next().value;\n if (oldestKey !== undefined) tokenizeCache.delete(oldestKey);\n }\n pieces = tokenize(formatStr);\n tokenizeCache.set(formatStr, pieces);\n return pieces;\n}\n\n/**\n * Format a Temporal.PlainDate, PlainTime, PlainDateTime, or ZonedDateTime\n * using a date-fns-style token string.\n *\n * @example\n * format(Temporal.Now.plainDateISO(), 'yyyy-MM-dd') // \"2026-08-04\"\n * format(zdt, \"MMM d, yyyy 'at' h:mm a\") // \"Aug 4, 2026 at 3:45 PM\"\n * format(zdt, 'MMMM d, yyyy', { locale: 'fr-FR' }) // \"août 4, 2026\"\n *\n * Throws on a token the input type doesn't support (e.g. 'HH' on a PlainDate).\n */\nexport function format(temporal: TemporalLike, formatStr: string, options: NumberingFormatOptions = {}): string {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new FormatSyntaxError({\n format: formatStr,\n message:\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`,\n });\n }\n\n const locale = options.locale ?? DEFAULT_LOCALE;\n const pieces = getPieces(formatStr);\n let result = '';\n\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n result += piece.value;\n continue;\n }\n\n const handler = HANDLER_BY_TOKEN.get(piece.value);\n /* c8 ignore start @preserve -- unreachable: tokenize() only ever emits\n tokens present in TOKENS, and HANDLER_BY_TOKEN is built from that\n same list, so every token piece.value can hold already has an entry\n here. Same defensive-guard category as the twin checks in\n analyze.ts/formatDuration.ts. */\n if (!handler) {\n throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n }\n /* c8 ignore stop @preserve */\n\n if (temporal[handler.field] === undefined) {\n throw new FormatSyntaxError({\n format: formatStr,\n token: piece.value,\n message:\n `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n `which this Temporal object doesn't have. ` +\n `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n });\n }\n\n result += handler.fn(temporal, locale);\n }\n\n // Numeral transliteration happens last and only on request — every\n // upstream token handler still emits plain ASCII digits, so this is\n // the single place output digits can diverge from that default.\n return applyNumbering(result, options);\n}\n\n// Shape mirrors Intl.DateTimeFormat.formatToParts: each entry is either\n// a literal (carrying no token info) or a token piece (carrying the\n// token string and the formatted value). Letting callers iterate parts\n// means they can build custom output — strip a token, swap a separator,\n// render each token to its own DOM node — without re-implementing the\n// tokenizer or the field-check logic.\nexport interface FormattedPart {\n type: 'literal' | 'token';\n value: string;\n // Present when `type === 'token'`. Carries the token string (e.g. \"yyyy\")\n // so a caller can look up its metadata via tokenInfo() from analyze.ts.\n token?: string;\n}\n\nexport function formatToParts(temporal: TemporalLike, formatStr: string, options: NumberingFormatOptions = {}): FormattedPart[] {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new FormatSyntaxError({\n format: formatStr,\n message:\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`,\n });\n }\n const locale = options.locale ?? DEFAULT_LOCALE;\n const pieces = getPieces(formatStr);\n const result: FormattedPart[] = [];\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n // Collapse adjacent literals so formatToParts stays consistent with\n // how format() walks pieces — a multi-char literal \"at \" is one\n // entry, not one per character. Same merge logic as appendLiteral\n // in tokenize.ts.\n const last = result[result.length - 1];\n /* c8 ignore start @preserve -- unreachable through tokenize()'s own\n output: appendLiteral() in tokenize.ts already merges every\n adjacent literal character before pieces ever reaches here, so\n two 'literal' pieces never sit back-to-back in the array this\n loop walks. Kept as defense-in-depth in case that invariant ever\n changes upstream. */\n if (last && last.type === 'literal') {\n last.value += piece.value;\n } else {\n /* c8 ignore stop @preserve */\n result.push({ type: 'literal', value: piece.value });\n }\n continue;\n }\n const handler = HANDLER_BY_TOKEN.get(piece.value);\n /* c8 ignore start @preserve -- unreachable, see the note in format() above */\n if (!handler) {\n throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n }\n /* c8 ignore stop @preserve */\n if (temporal[handler.field] === undefined) {\n throw new FormatSyntaxError({\n format: formatStr,\n token: piece.value,\n message:\n `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n `which this Temporal object doesn't have. ` +\n `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n });\n }\n // Numeral transliteration applies per-token-part here, rather than\n // once at the end like format() does, so a caller styling individual\n // parts (e.g. one <span> per token) still gets correctly-transliterated\n // digits in each part instead of plain ASCII.\n result.push({ type: 'token', value: applyNumbering(handler.fn(temporal, locale), options), token: piece.value });\n }\n return result;\n}\n\n// Pre-compiles a format string into an object whose format()/formatToParts()\n// methods skip the tokenization step on every call. The tokenizeCache in\n// this module means a plain format(temporal, fmt) call already pays only\n// a Map lookup for tokenization after the first call, so compileFormat()\n// is mostly a typing/ergonomics affordance — useful for callers who want\n// to hold onto a compiled form explicitly (e.g. to inspect the pieces\n// via the .pieces property, or to pass the compiled object around\n// instead of the string).\nexport interface CompiledFormat {\n format(temporal: TemporalLike, options?: NumberingFormatOptions): string;\n formatToParts(temporal: TemporalLike, options?: NumberingFormatOptions): FormattedPart[];\n readonly pieces: ReadonlyArray<Piece>;\n readonly formatStr: string;\n}\n\nexport function compileFormat(formatStr: string): CompiledFormat {\n if (formatStr.length > MAX_FORMAT_LENGTH) {\n throw new FormatSyntaxError({\n format: formatStr,\n message:\n `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters ` +\n `(got ${formatStr.length}).`,\n });\n }\n // Pre-tokenize once. Validation (unknown tokens, unterminated quotes)\n // happens here, not lazily on first format() call — surfaces a bad\n // format string at compile time rather than at first use, which is\n // the point of compiling up front.\n const pieces = getPieces(formatStr);\n return {\n formatStr,\n pieces,\n format(temporal: TemporalLike, options: NumberingFormatOptions = {}) {\n const locale = options.locale ?? DEFAULT_LOCALE;\n let result = '';\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n result += piece.value;\n continue;\n }\n const handler = HANDLER_BY_TOKEN.get(piece.value);\n /* c8 ignore next -- unreachable, see the note in format() above */\n if (!handler) throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n if (temporal[handler.field] === undefined) {\n throw new FormatSyntaxError({\n format: formatStr,\n token: piece.value,\n message:\n `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n `which this Temporal object doesn't have. ` +\n `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n });\n }\n result += handler.fn(temporal, locale);\n }\n return applyNumbering(result, options);\n },\n formatToParts(temporal: TemporalLike, options: NumberingFormatOptions = {}) {\n const locale = options.locale ?? DEFAULT_LOCALE;\n const out: FormattedPart[] = [];\n for (const piece of pieces) {\n if (piece.kind === 'literal') {\n const last = out[out.length - 1];\n /* c8 ignore next -- unreachable, see the note in formatToParts() above */\n if (last && last.type === 'literal') last.value += piece.value;\n else out.push({ type: 'literal', value: piece.value });\n continue;\n }\n const handler = HANDLER_BY_TOKEN.get(piece.value);\n /* c8 ignore next -- unreachable, see the note in format() above */\n if (!handler) throw new UnknownTokenError({ token: piece.value, format: formatStr, message: `temporal-fmt: unknown token \"${piece.value}\"` });\n if (temporal[handler.field] === undefined) {\n throw new FormatSyntaxError({\n format: formatStr,\n token: piece.value,\n message:\n `temporal-fmt: token \"${piece.value}\" requires \"${handler.field}\", ` +\n `which this Temporal object doesn't have. ` +\n `(e.g. PlainDate has no time fields, PlainTime has no date fields)`,\n });\n }\n out.push({ type: 'token', value: applyNumbering(handler.fn(temporal, locale), options), token: piece.value });\n }\n return out;\n },\n };\n}\n\n// Exported so analyze.ts can reuse the same tokenization cache rather\n// than re-tokenizing when a caller asks for both a format() and an\n// analyzeFormat() on the same string.\nexport function _getPieces(formatStr: string): Piece[] {\n return getPieces(formatStr);\n}\n\n// Exported for analyze.ts — same reason as above. The handler map is\n// the source of truth for \"what field does this token need\" — analyze\n// consumes it to compute requiredFields and compatibleTypes.\nexport function _handlerFor(token: string): { fn: (t: TemporalLike, locale: string) => string; field: keyof TemporalLike } | undefined {\n return HANDLER_BY_TOKEN.get(token);\n}"],"mappings":"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","names":[]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
applyParseNumbering,
|
|
3
3
|
tokenize
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-M33NSC4E.js";
|
|
5
5
|
import {
|
|
6
6
|
DEFAULT_LOCALE
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-VSUCBUTC.js";
|
|
8
8
|
import {
|
|
9
9
|
MAX_FORMAT_LENGTH,
|
|
10
10
|
MAX_INPUT_LENGTH
|
|
@@ -13,14 +13,18 @@ import {
|
|
|
13
13
|
getTemporal
|
|
14
14
|
} from "./chunk-MXXYIMFJ.js";
|
|
15
15
|
import {
|
|
16
|
+
AmbiguousInputError,
|
|
17
|
+
FormatSyntaxError,
|
|
18
|
+
InvalidDateError,
|
|
19
|
+
InvalidOffsetError,
|
|
16
20
|
InvalidTimeZoneError,
|
|
21
|
+
ParseMismatchError,
|
|
17
22
|
TemporalFmtError,
|
|
18
|
-
|
|
19
|
-
} from "./chunk-USONQ7MV.js";
|
|
20
|
-
import {
|
|
23
|
+
UnknownTokenError,
|
|
21
24
|
canonicalCacheKey,
|
|
22
|
-
getLocaleVocab
|
|
23
|
-
|
|
25
|
+
getLocaleVocab,
|
|
26
|
+
wrapUntypedError
|
|
27
|
+
} from "./chunk-O6GVMBLW.js";
|
|
24
28
|
|
|
25
29
|
// src/pattern.ts
|
|
26
30
|
function escapeRegExp(literal) {
|
|
@@ -126,9 +130,10 @@ function tokenFragment(token, locale, nextToken) {
|
|
|
126
130
|
return QQQ_FRAGMENT;
|
|
127
131
|
}
|
|
128
132
|
if (FORMAT_ONLY_TOKENS.has(token)) {
|
|
129
|
-
throw new
|
|
130
|
-
|
|
131
|
-
|
|
133
|
+
throw new UnknownTokenError({
|
|
134
|
+
token,
|
|
135
|
+
message: `temporal-fmt: token "${token}" is format-only \u2014 it can't be parsed back into a value. Use a different token in the parse format string (e.g. "d" for "do", "MM" for "ww").`
|
|
136
|
+
});
|
|
132
137
|
}
|
|
133
138
|
const vocab = getLocaleVocab(locale);
|
|
134
139
|
switch (token) {
|
|
@@ -168,7 +173,7 @@ function tokenFragment(token, locale, nextToken) {
|
|
|
168
173
|
registering something new or tokenize.ts being bypassed, neither of
|
|
169
174
|
which happens on the parse() path. */
|
|
170
175
|
default:
|
|
171
|
-
throw new
|
|
176
|
+
throw new UnknownTokenError({ token, message: `temporal-fmt: unknown token "${token}"` });
|
|
172
177
|
}
|
|
173
178
|
}
|
|
174
179
|
var UNPADDED_NUMERIC_TOKENS = /* @__PURE__ */ new Set(["M", "d", "H", "h", "m", "s"]);
|
|
@@ -382,22 +387,28 @@ function parseOffsetString(raw, token) {
|
|
|
382
387
|
const hours = Number(hoursStr);
|
|
383
388
|
const minutes = Number(minutesStr);
|
|
384
389
|
if (hours > 14) {
|
|
385
|
-
throw new
|
|
386
|
-
|
|
387
|
-
|
|
390
|
+
throw new InvalidOffsetError({
|
|
391
|
+
actual: raw,
|
|
392
|
+
message: `temporal-fmt: offset hours ${hours} in "${raw}" out of range (max 14 \u2014 Kiritimati, Line Islands is +14:00).`
|
|
393
|
+
});
|
|
388
394
|
}
|
|
389
395
|
if (minutes > 59) {
|
|
390
|
-
throw new
|
|
396
|
+
throw new InvalidOffsetError({
|
|
397
|
+
actual: raw,
|
|
398
|
+
message: `temporal-fmt: offset minutes ${minutes} in "${raw}" out of range (max 59).`
|
|
399
|
+
});
|
|
391
400
|
}
|
|
392
401
|
if (sign === "+" && hours === 14 && minutes !== 0) {
|
|
393
|
-
throw new
|
|
394
|
-
|
|
395
|
-
|
|
402
|
+
throw new InvalidOffsetError({
|
|
403
|
+
actual: raw,
|
|
404
|
+
message: `temporal-fmt: offset "${raw}" exceeds the maximum supported UTC offset of +14:00.`
|
|
405
|
+
});
|
|
396
406
|
}
|
|
397
407
|
if (sign === "-" && hours === 12 && minutes !== 0) {
|
|
398
|
-
throw new
|
|
399
|
-
|
|
400
|
-
|
|
408
|
+
throw new InvalidOffsetError({
|
|
409
|
+
actual: raw,
|
|
410
|
+
message: `temporal-fmt: offset "${raw}" exceeds the maximum supported negative UTC offset of -12:00.`
|
|
411
|
+
});
|
|
401
412
|
}
|
|
402
413
|
return `${sign}${hoursStr}:${minutesStr}`;
|
|
403
414
|
}
|
|
@@ -511,9 +522,9 @@ function pickLenientSplit(splits, tokens) {
|
|
|
511
522
|
}
|
|
512
523
|
function resolveYear(fields) {
|
|
513
524
|
if (fields.year !== void 0 && fields.twoDigitYear !== void 0) {
|
|
514
|
-
throw new
|
|
515
|
-
'temporal-fmt: format string mixes "yyyy" and "yy" year representations.'
|
|
516
|
-
);
|
|
525
|
+
throw new FormatSyntaxError({
|
|
526
|
+
message: 'temporal-fmt: format string mixes "yyyy" and "yy" year representations.'
|
|
527
|
+
});
|
|
517
528
|
}
|
|
518
529
|
if (fields.year !== void 0) return fields.year;
|
|
519
530
|
if (fields.twoDigitYear !== void 0) {
|
|
@@ -523,27 +534,30 @@ function resolveYear(fields) {
|
|
|
523
534
|
}
|
|
524
535
|
function resolveHour(fields, formatStr, locale) {
|
|
525
536
|
if (fields.hour !== void 0 && fields.hour12 !== void 0) {
|
|
526
|
-
throw new
|
|
527
|
-
|
|
528
|
-
|
|
537
|
+
throw new FormatSyntaxError({
|
|
538
|
+
format: formatStr,
|
|
539
|
+
message: `temporal-fmt: format string "${formatStr}" mixes a 24-hour token ("HH"/"H") with a 12-hour token ("hh"/"h").`
|
|
540
|
+
});
|
|
529
541
|
}
|
|
530
542
|
if (fields.hour !== void 0) {
|
|
531
543
|
if (fields.dayPeriodRaw !== void 0) {
|
|
532
544
|
const vocab = getLocaleVocab(locale);
|
|
533
545
|
const expected = fields.hour < 12 ? vocab.dayPeriod[0] : vocab.dayPeriod[1];
|
|
534
546
|
if (fields.dayPeriodRaw.toLowerCase() !== expected?.toLowerCase()) {
|
|
535
|
-
throw new
|
|
536
|
-
|
|
537
|
-
|
|
547
|
+
throw new FormatSyntaxError({
|
|
548
|
+
format: formatStr,
|
|
549
|
+
message: `temporal-fmt: format string "${formatStr}" contains a day period that contradicts the 24-hour value.`
|
|
550
|
+
});
|
|
538
551
|
}
|
|
539
552
|
}
|
|
540
553
|
return fields.hour;
|
|
541
554
|
}
|
|
542
555
|
if (fields.hour12 !== void 0) {
|
|
543
556
|
if (fields.isPM === void 0) {
|
|
544
|
-
throw new
|
|
545
|
-
|
|
546
|
-
|
|
557
|
+
throw new FormatSyntaxError({
|
|
558
|
+
format: formatStr,
|
|
559
|
+
message: `temporal-fmt: format string "${formatStr}" uses a 12-hour token ("hh"/"h") without an "a" token, so parse() can't tell AM from PM.`
|
|
560
|
+
});
|
|
547
561
|
}
|
|
548
562
|
return fields.hour12 % 12 + (fields.isPM ? 12 : 0);
|
|
549
563
|
}
|
|
@@ -551,14 +565,16 @@ function resolveHour(fields, formatStr, locale) {
|
|
|
551
565
|
}
|
|
552
566
|
function parse(formatStr, input, options = {}) {
|
|
553
567
|
if (formatStr.length > MAX_FORMAT_LENGTH) {
|
|
554
|
-
throw new
|
|
555
|
-
|
|
556
|
-
|
|
568
|
+
throw new FormatSyntaxError({
|
|
569
|
+
format: formatStr,
|
|
570
|
+
message: `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters (got ${formatStr.length}).`
|
|
571
|
+
});
|
|
557
572
|
}
|
|
558
573
|
if (input.length > MAX_INPUT_LENGTH) {
|
|
559
|
-
throw new
|
|
560
|
-
|
|
561
|
-
|
|
574
|
+
throw new FormatSyntaxError({
|
|
575
|
+
input,
|
|
576
|
+
message: `temporal-fmt: input exceeds maximum length of ${MAX_INPUT_LENGTH} characters (got ${input.length}).`
|
|
577
|
+
});
|
|
562
578
|
}
|
|
563
579
|
if (options.parseNumberingSystem) {
|
|
564
580
|
input = applyParseNumbering(input, options);
|
|
@@ -568,10 +584,27 @@ function parse(formatStr, input, options = {}) {
|
|
|
568
584
|
const pattern = getPattern(formatStr, locale);
|
|
569
585
|
const match = pattern.regex.exec(input);
|
|
570
586
|
if (!match) {
|
|
571
|
-
throw new
|
|
587
|
+
throw new ParseMismatchError({
|
|
588
|
+
input,
|
|
589
|
+
format: formatStr,
|
|
590
|
+
// reason set explicitly (not just message): parse.test.js's
|
|
591
|
+
// "safeParse: failure returns { ok: false, error } with a
|
|
592
|
+
// TemporalFmtError" asserts result.error.reason carries the
|
|
593
|
+
// underlying detail text, matching what wrapUntypedError used to
|
|
594
|
+
// populate when this message reached it as a caught plain Error.
|
|
595
|
+
reason: "no valid pattern matches the format string and input shape",
|
|
596
|
+
message: `temporal-fmt: no valid pattern matches the format string and input shape`
|
|
597
|
+
});
|
|
572
598
|
}
|
|
573
599
|
if (pattern.groups.length === 0) {
|
|
574
|
-
throw new
|
|
600
|
+
throw new ParseMismatchError({
|
|
601
|
+
format: formatStr,
|
|
602
|
+
// reason set explicitly: errors.test.js's "format string with no
|
|
603
|
+
// tokens at all falls through to ParseMismatchError" asserts
|
|
604
|
+
// error.reason matches /has no tokens/.
|
|
605
|
+
reason: `format string "${formatStr}" has no tokens \u2014 nothing to parse into a value.`,
|
|
606
|
+
message: `temporal-fmt: format string "${formatStr}" has no tokens \u2014 nothing to parse into a value.`
|
|
607
|
+
});
|
|
575
608
|
}
|
|
576
609
|
for (const { name, token } of pattern.groups) {
|
|
577
610
|
if (token === "zzz" && !isValidTimeZone(match.groups[name])) {
|
|
@@ -589,9 +622,11 @@ function parse(formatStr, input, options = {}) {
|
|
|
589
622
|
const splits = enumerateValidSplits(runDigits, run.tokens);
|
|
590
623
|
if (splits.length > 1) {
|
|
591
624
|
if (!options.lenient) {
|
|
592
|
-
throw new
|
|
593
|
-
|
|
594
|
-
|
|
625
|
+
throw new AmbiguousInputError({
|
|
626
|
+
input,
|
|
627
|
+
format: formatStr,
|
|
628
|
+
message: `temporal-fmt: "${runDigits}" in format string "${formatStr}" is ambiguous \u2014 ${splits.length} different ways to read tokens "${run.tokens.join("")}" (with no separator between them) are all individually valid (e.g. ${JSON.stringify(splits[0])} vs ${JSON.stringify(splits[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. Pass { lenient: true } to opt into a documented heuristic that picks one.`
|
|
629
|
+
});
|
|
595
630
|
}
|
|
596
631
|
runPicks.push({ groupNames: run.groupNames, values: pickLenientSplit(splits, run.tokens) });
|
|
597
632
|
}
|
|
@@ -611,28 +646,35 @@ function parse(formatStr, input, options = {}) {
|
|
|
611
646
|
const hasAnyDatePart = year !== void 0 || month !== void 0 || day !== void 0;
|
|
612
647
|
const hasFullDate = year !== void 0 && month !== void 0 && day !== void 0;
|
|
613
648
|
if (hasAnyDatePart && !hasFullDate) {
|
|
614
|
-
throw new
|
|
615
|
-
|
|
616
|
-
|
|
649
|
+
throw new InvalidDateError({
|
|
650
|
+
format: formatStr,
|
|
651
|
+
message: `temporal-fmt: format string "${formatStr}" has an incomplete date \u2014 year, month, and day tokens must all be present together.`
|
|
652
|
+
});
|
|
617
653
|
}
|
|
618
654
|
const hasTime = hour !== void 0 || minute !== void 0 || second !== void 0 || millisecond !== void 0;
|
|
619
655
|
if (timeZoneId !== void 0 && !(hasFullDate && hasTime)) {
|
|
620
|
-
throw new
|
|
621
|
-
|
|
622
|
-
|
|
656
|
+
throw new FormatSyntaxError({
|
|
657
|
+
format: formatStr,
|
|
658
|
+
message: `temporal-fmt: format string "${formatStr}" has a "zzz" token but needs a full date and time to build a ZonedDateTime.`
|
|
659
|
+
});
|
|
623
660
|
}
|
|
624
661
|
if (offsetString !== void 0 && !(hasFullDate && hasTime)) {
|
|
625
|
-
throw new
|
|
626
|
-
|
|
627
|
-
|
|
662
|
+
throw new FormatSyntaxError({
|
|
663
|
+
format: formatStr,
|
|
664
|
+
message: `temporal-fmt: format string "${formatStr}" has an offset token (X/XX/XXX/x/xx/xxx) but needs a full date and time to build a ZonedDateTime.`
|
|
665
|
+
});
|
|
628
666
|
}
|
|
629
667
|
if (weekdayExpected !== void 0 && !hasFullDate) {
|
|
630
|
-
throw new
|
|
631
|
-
|
|
632
|
-
|
|
668
|
+
throw new FormatSyntaxError({
|
|
669
|
+
format: formatStr,
|
|
670
|
+
message: `temporal-fmt: format string "${formatStr}" has a weekday token ("EEEE"/"EEE") but needs a full date to validate it against.`
|
|
671
|
+
});
|
|
633
672
|
}
|
|
634
673
|
if (!hasFullDate && !hasTime) {
|
|
635
|
-
throw new
|
|
674
|
+
throw new FormatSyntaxError({
|
|
675
|
+
format: formatStr,
|
|
676
|
+
message: `temporal-fmt: format string "${formatStr}" has no date or time tokens to parse.`
|
|
677
|
+
});
|
|
636
678
|
}
|
|
637
679
|
const temporal = getTemporal();
|
|
638
680
|
const timeFields = {
|
|
@@ -665,15 +707,19 @@ function parse(formatStr, input, options = {}) {
|
|
|
665
707
|
const zdt = result;
|
|
666
708
|
const wallClockShifted = zdt.hour !== timeFields.hour || zdt.minute !== timeFields.minute || zdt.second !== timeFields.second;
|
|
667
709
|
if (wallClockShifted) {
|
|
668
|
-
throw new
|
|
669
|
-
|
|
670
|
-
|
|
710
|
+
throw new InvalidDateError({
|
|
711
|
+
input,
|
|
712
|
+
format: formatStr,
|
|
713
|
+
message: `"${timeZoneId}" has no such wall-clock time on this date \u2014 it falls in a DST gap, not an ambiguous or valid instant.`
|
|
714
|
+
});
|
|
671
715
|
}
|
|
672
716
|
const actualOffset = zdt.offset;
|
|
673
717
|
if (actualOffset !== offsetString) {
|
|
674
|
-
throw new
|
|
675
|
-
|
|
676
|
-
|
|
718
|
+
throw new ParseMismatchError({
|
|
719
|
+
input,
|
|
720
|
+
format: formatStr,
|
|
721
|
+
message: `has both a "zzz" zone (${timeZoneId}) and an offset token (${offsetString}), but the zone's actual offset at this date/time is ${actualOffset}, not ${offsetString}.`
|
|
722
|
+
});
|
|
677
723
|
}
|
|
678
724
|
}
|
|
679
725
|
} else if (offsetString !== void 0) {
|
|
@@ -686,25 +732,30 @@ function parse(formatStr, input, options = {}) {
|
|
|
686
732
|
result = temporal.PlainTime.from(timeFields, reject);
|
|
687
733
|
}
|
|
688
734
|
} catch (err) {
|
|
689
|
-
throw new
|
|
690
|
-
|
|
691
|
-
|
|
735
|
+
throw new InvalidDateError({
|
|
736
|
+
input,
|
|
737
|
+
format: formatStr,
|
|
738
|
+
message: `temporal-fmt: "${input}" doesn't describe a valid date/time for format "${formatStr}": ${err.message}`
|
|
739
|
+
});
|
|
692
740
|
}
|
|
693
741
|
if (weekdayExpected !== void 0) {
|
|
694
742
|
const actual = result.dayOfWeek;
|
|
695
743
|
if (actual !== weekdayExpected) {
|
|
696
744
|
const vocab = getLocaleVocab(locale);
|
|
697
|
-
throw new
|
|
698
|
-
|
|
699
|
-
|
|
745
|
+
throw new InvalidDateError({
|
|
746
|
+
input,
|
|
747
|
+
format: formatStr,
|
|
748
|
+
message: `temporal-fmt: "${weekdayRaw}" doesn't match the actual weekday (${vocab.weekdayLong[actual - 1]}) for the parsed date.`
|
|
749
|
+
});
|
|
700
750
|
}
|
|
701
751
|
}
|
|
702
752
|
if (quarter !== void 0 && month !== void 0) {
|
|
703
753
|
const expectedQuarter = Math.ceil(month / 3);
|
|
704
754
|
if (quarter !== expectedQuarter) {
|
|
705
|
-
throw new
|
|
706
|
-
|
|
707
|
-
|
|
755
|
+
throw new InvalidDateError({
|
|
756
|
+
format: formatStr,
|
|
757
|
+
message: `temporal-fmt: format string "${formatStr}" contains a quarter token (Q/QQQ) whose value (Q${quarter}) disagrees with the parsed month's actual quarter \u2014 month ${month} is in Q${expectedQuarter}.`
|
|
758
|
+
});
|
|
708
759
|
}
|
|
709
760
|
}
|
|
710
761
|
return result;
|
|
@@ -713,11 +764,13 @@ function safeParse(formatStr, input, options = {}) {
|
|
|
713
764
|
try {
|
|
714
765
|
return { ok: true, value: parse(formatStr, input, options) };
|
|
715
766
|
} catch (err) {
|
|
767
|
+
/* c8 ignore start @preserve */
|
|
716
768
|
if (err instanceof TemporalFmtError) {
|
|
717
769
|
return { ok: false, error: err };
|
|
718
770
|
}
|
|
719
771
|
return { ok: false, error: wrapUntypedError(err, { input, format: formatStr }) };
|
|
720
772
|
}
|
|
773
|
+
/* c8 ignore stop @preserve */
|
|
721
774
|
}
|
|
722
775
|
function tryParse(formatStr, input, options = {}) {
|
|
723
776
|
try {
|
|
@@ -728,14 +781,16 @@ function tryParse(formatStr, input, options = {}) {
|
|
|
728
781
|
}
|
|
729
782
|
function parseToParts(formatStr, input, options = {}) {
|
|
730
783
|
if (formatStr.length > MAX_FORMAT_LENGTH) {
|
|
731
|
-
throw new
|
|
732
|
-
|
|
733
|
-
|
|
784
|
+
throw new FormatSyntaxError({
|
|
785
|
+
format: formatStr,
|
|
786
|
+
message: `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters (got ${formatStr.length}).`
|
|
787
|
+
});
|
|
734
788
|
}
|
|
735
789
|
if (input.length > MAX_INPUT_LENGTH) {
|
|
736
|
-
throw new
|
|
737
|
-
|
|
738
|
-
|
|
790
|
+
throw new FormatSyntaxError({
|
|
791
|
+
input,
|
|
792
|
+
message: `temporal-fmt: input exceeds maximum length of ${MAX_INPUT_LENGTH} characters (got ${input.length}).`
|
|
793
|
+
});
|
|
739
794
|
}
|
|
740
795
|
if (options.parseNumberingSystem) {
|
|
741
796
|
input = applyParseNumbering(input, options);
|
|
@@ -744,10 +799,27 @@ function parseToParts(formatStr, input, options = {}) {
|
|
|
744
799
|
const pattern = getPattern(formatStr, locale);
|
|
745
800
|
const match = pattern.regex.exec(input);
|
|
746
801
|
if (!match) {
|
|
747
|
-
throw new
|
|
802
|
+
throw new ParseMismatchError({
|
|
803
|
+
input,
|
|
804
|
+
format: formatStr,
|
|
805
|
+
// reason set explicitly (not just message): parse.test.js's
|
|
806
|
+
// "safeParse: failure returns { ok: false, error } with a
|
|
807
|
+
// TemporalFmtError" asserts result.error.reason carries the
|
|
808
|
+
// underlying detail text, matching what wrapUntypedError used to
|
|
809
|
+
// populate when this message reached it as a caught plain Error.
|
|
810
|
+
reason: "no valid pattern matches the format string and input shape",
|
|
811
|
+
message: `temporal-fmt: no valid pattern matches the format string and input shape`
|
|
812
|
+
});
|
|
748
813
|
}
|
|
749
814
|
if (pattern.groups.length === 0) {
|
|
750
|
-
throw new
|
|
815
|
+
throw new ParseMismatchError({
|
|
816
|
+
format: formatStr,
|
|
817
|
+
// reason set explicitly: errors.test.js's "format string with no
|
|
818
|
+
// tokens at all falls through to ParseMismatchError" asserts
|
|
819
|
+
// error.reason matches /has no tokens/.
|
|
820
|
+
reason: `format string "${formatStr}" has no tokens \u2014 nothing to parse into a value.`,
|
|
821
|
+
message: `temporal-fmt: format string "${formatStr}" has no tokens \u2014 nothing to parse into a value.`
|
|
822
|
+
});
|
|
751
823
|
}
|
|
752
824
|
for (const { name, token } of pattern.groups) {
|
|
753
825
|
if (token === "zzz" && !isValidTimeZone(match.groups[name])) {
|
|
@@ -765,9 +837,11 @@ function parseToParts(formatStr, input, options = {}) {
|
|
|
765
837
|
const splits = enumerateValidSplits(runDigits, run.tokens);
|
|
766
838
|
if (splits.length > 1) {
|
|
767
839
|
if (!options.lenient) {
|
|
768
|
-
throw new
|
|
769
|
-
|
|
770
|
-
|
|
840
|
+
throw new AmbiguousInputError({
|
|
841
|
+
input,
|
|
842
|
+
format: formatStr,
|
|
843
|
+
message: `temporal-fmt: "${runDigits}" in format string "${formatStr}" is ambiguous \u2014 ${splits.length} different ways to read tokens "${run.tokens.join("")}" (with no separator between them) are all individually valid (e.g. ${JSON.stringify(splits[0])} vs ${JSON.stringify(splits[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. Pass { lenient: true } to opt into a documented heuristic that picks one.`
|
|
844
|
+
});
|
|
771
845
|
}
|
|
772
846
|
runPicks.push({ groupNames: run.groupNames, values: pickLenientSplit(splits, run.tokens) });
|
|
773
847
|
}
|
|
@@ -791,9 +865,10 @@ function parseToParts(formatStr, input, options = {}) {
|
|
|
791
865
|
}
|
|
792
866
|
function compileParser(formatStr, options = {}) {
|
|
793
867
|
if (formatStr.length > MAX_FORMAT_LENGTH) {
|
|
794
|
-
throw new
|
|
795
|
-
|
|
796
|
-
|
|
868
|
+
throw new FormatSyntaxError({
|
|
869
|
+
format: formatStr,
|
|
870
|
+
message: `temporal-fmt: format string exceeds maximum length of ${MAX_FORMAT_LENGTH} characters (got ${formatStr.length}).`
|
|
871
|
+
});
|
|
797
872
|
}
|
|
798
873
|
const locale = options.locale ?? DEFAULT_LOCALE;
|
|
799
874
|
const pattern = getPattern(formatStr, locale);
|
|
@@ -824,4 +899,4 @@ export {
|
|
|
824
899
|
parseToParts,
|
|
825
900
|
compileParser
|
|
826
901
|
};
|
|
827
|
-
//# sourceMappingURL=chunk-
|
|
902
|
+
//# sourceMappingURL=chunk-CKVHXFX7.js.map
|