@eternl/formats 0.9.14 → 0.9.16
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/LICENSE +177 -0
- package/README.md +3 -3
- package/dist/index.cjs +810 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +112 -0
- package/dist/index.d.mts +112 -0
- package/dist/index.mjs +759 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +23 -35
- package/dist/cjs/constants.js +0 -22
- package/dist/cjs/csv.js +0 -98
- package/dist/cjs/date.js +0 -70
- package/dist/cjs/display.js +0 -556
- package/dist/cjs/errors.js +0 -48
- package/dist/cjs/index.js +0 -31
- package/dist/cjs/internal/intl-cache.js +0 -92
- package/dist/cjs/internal/locale.js +0 -9
- package/dist/cjs/internal/numeric.js +0 -167
- package/dist/cjs/package.json +0 -3
- package/dist/cjs/types.js +0 -16
- package/dist/esm/constants.js +0 -20
- package/dist/esm/constants.js.map +0 -1
- package/dist/esm/csv.js +0 -92
- package/dist/esm/csv.js.map +0 -1
- package/dist/esm/date.js +0 -66
- package/dist/esm/date.js.map +0 -1
- package/dist/esm/display.js +0 -545
- package/dist/esm/display.js.map +0 -1
- package/dist/esm/errors.js +0 -42
- package/dist/esm/errors.js.map +0 -1
- package/dist/esm/index.js +0 -6
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/internal/intl-cache.js +0 -87
- package/dist/esm/internal/intl-cache.js.map +0 -1
- package/dist/esm/internal/locale.js +0 -6
- package/dist/esm/internal/locale.js.map +0 -1
- package/dist/esm/internal/numeric.js +0 -157
- package/dist/esm/internal/numeric.js.map +0 -1
- package/dist/esm/package.json +0 -3
- package/dist/esm/types.js +0 -14
- package/dist/esm/types.js.map +0 -1
- package/dist/types/constants.d.ts +0 -20
- package/dist/types/csv.d.ts +0 -5
- package/dist/types/date.d.ts +0 -3
- package/dist/types/display.d.ts +0 -7
- package/dist/types/errors.d.ts +0 -21
- package/dist/types/index.d.ts +0 -6
- package/dist/types/internal/intl-cache.d.ts +0 -17
- package/dist/types/internal/locale.d.ts +0 -1
- package/dist/types/internal/numeric.d.ts +0 -19
- package/dist/types/types.d.ts +0 -59
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,810 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
|
+
key = keys[i];
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
14
|
+
__defProp(to, key, {
|
|
15
|
+
get: ((k) => from[k]).bind(null, key),
|
|
16
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
24
|
+
value: mod,
|
|
25
|
+
enumerable: true
|
|
26
|
+
}) : target, mod));
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
let big_js = require("big.js");
|
|
30
|
+
big_js = __toESM(big_js);
|
|
31
|
+
|
|
32
|
+
//#region src/types.ts
|
|
33
|
+
const NUMBER_STYLES = {
|
|
34
|
+
decimal: "decimal",
|
|
35
|
+
currency: "currency",
|
|
36
|
+
percent: "percent"
|
|
37
|
+
};
|
|
38
|
+
const SIGN_DISPLAYS = {
|
|
39
|
+
auto: "auto",
|
|
40
|
+
always: "always",
|
|
41
|
+
exceptZero: "exceptZero",
|
|
42
|
+
never: "never",
|
|
43
|
+
negative: "negative"
|
|
44
|
+
};
|
|
45
|
+
const COMPACT_UNITS = [
|
|
46
|
+
"K",
|
|
47
|
+
"M",
|
|
48
|
+
"B",
|
|
49
|
+
"T"
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/constants.ts
|
|
54
|
+
const STYLE_DECIMAL = NUMBER_STYLES.decimal;
|
|
55
|
+
const STYLE_CURRENCY = NUMBER_STYLES.currency;
|
|
56
|
+
const STYLE_PERCENT = NUMBER_STYLES.percent;
|
|
57
|
+
const DEFAULT_LOCALE = "en-US";
|
|
58
|
+
const DISPLAY_SIGNS = {
|
|
59
|
+
minus: "minus",
|
|
60
|
+
plus: "plus",
|
|
61
|
+
none: "none"
|
|
62
|
+
};
|
|
63
|
+
const DISPLAY_SIGN_MINUS = DISPLAY_SIGNS.minus;
|
|
64
|
+
const DISPLAY_SIGN_PLUS = DISPLAY_SIGNS.plus;
|
|
65
|
+
const DISPLAY_SIGN_NONE = DISPLAY_SIGNS.none;
|
|
66
|
+
const COMPACT_ORDER = [...COMPACT_UNITS].reverse();
|
|
67
|
+
const DEFAULT_SIGN_MINUS = "-";
|
|
68
|
+
const DEFAULT_SIGN_PLUS = "+";
|
|
69
|
+
const DECIMAL_ZERO = "0";
|
|
70
|
+
const DECIMAL_EMPTY = "";
|
|
71
|
+
const DECIMAL_DOT = ".";
|
|
72
|
+
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/errors.ts
|
|
75
|
+
let FormatError = /* @__PURE__ */ function(FormatError) {
|
|
76
|
+
FormatError["NonNegativeIntegerRequired"] = "nonNegativeIntegerRequired";
|
|
77
|
+
FormatError["PositiveIntegerRequired"] = "positiveIntegerRequired";
|
|
78
|
+
FormatError["NumericValueNonFinite"] = "numericValueNonFinite";
|
|
79
|
+
FormatError["NumericStringEmpty"] = "numericStringEmpty";
|
|
80
|
+
FormatError["UnsupportedNumericInput"] = "unsupportedNumericInput";
|
|
81
|
+
FormatError["MaxDecimalsLessThanMinimum"] = "maxDecimalsLessThanMinimum";
|
|
82
|
+
FormatError["MissingLocale"] = "missingLocale";
|
|
83
|
+
FormatError["MissingCurrencyCode"] = "missingCurrencyCode";
|
|
84
|
+
FormatError["DateValueInvalid"] = "dateValueInvalid";
|
|
85
|
+
FormatError["DateStringEmpty"] = "dateStringEmpty";
|
|
86
|
+
FormatError["DateNumberNonFinite"] = "dateNumberNonFinite";
|
|
87
|
+
FormatError["InvalidDateString"] = "invalidDateString";
|
|
88
|
+
FormatError["UnsupportedDateInput"] = "unsupportedDateInput";
|
|
89
|
+
return FormatError;
|
|
90
|
+
}({});
|
|
91
|
+
const FORMAT_ERROR_MESSAGES = {
|
|
92
|
+
[FormatError.NonNegativeIntegerRequired]: "%label% must be a non-negative integer",
|
|
93
|
+
[FormatError.PositiveIntegerRequired]: "%label% must be a positive integer",
|
|
94
|
+
[FormatError.NumericValueNonFinite]: "Numeric value must be a finite number",
|
|
95
|
+
[FormatError.NumericStringEmpty]: "Numeric string cannot be empty",
|
|
96
|
+
[FormatError.UnsupportedNumericInput]: "Unsupported numeric input type",
|
|
97
|
+
[FormatError.MaxDecimalsLessThanMinimum]: "maxDecimals cannot be less than minDecimals",
|
|
98
|
+
[FormatError.MissingLocale]: "Display formatting requires a locale",
|
|
99
|
+
[FormatError.MissingCurrencyCode]: "Currency formatting requires a currencyCode",
|
|
100
|
+
[FormatError.DateValueInvalid]: "Invalid date value",
|
|
101
|
+
[FormatError.DateStringEmpty]: "Date string cannot be empty",
|
|
102
|
+
[FormatError.DateNumberNonFinite]: "Date number must be finite",
|
|
103
|
+
[FormatError.InvalidDateString]: "Invalid date string",
|
|
104
|
+
[FormatError.UnsupportedDateInput]: "Unsupported date input type"
|
|
105
|
+
};
|
|
106
|
+
const applyDetails = (template, details) => {
|
|
107
|
+
if (!details) return template;
|
|
108
|
+
return Object.keys(details).reduce((message, key) => message.replace(new RegExp(`%${key}%`, "g"), details[key]), template);
|
|
109
|
+
};
|
|
110
|
+
const getFormatErrorMessage = (code, details) => applyDetails(FORMAT_ERROR_MESSAGES[code], details);
|
|
111
|
+
const toRangeError = (code, details) => new RangeError(getFormatErrorMessage(code, details));
|
|
112
|
+
const toTypeError = (code, details) => new TypeError(getFormatErrorMessage(code, details));
|
|
113
|
+
const toError = (code, details) => new Error(getFormatErrorMessage(code, details));
|
|
114
|
+
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/internal/numeric.ts
|
|
117
|
+
const BIG_ZERO = new big_js.default(0);
|
|
118
|
+
const ROUNDING_MODE_MAP = {
|
|
119
|
+
roundDown: big_js.default.roundDown,
|
|
120
|
+
roundHalfUp: big_js.default.roundHalfUp,
|
|
121
|
+
roundHalfEven: big_js.default.roundHalfEven,
|
|
122
|
+
roundUp: big_js.default.roundUp
|
|
123
|
+
};
|
|
124
|
+
const assertNonNegativeInteger = (value, label) => {
|
|
125
|
+
if (value === void 0) return;
|
|
126
|
+
if (!Number.isInteger(value) || value < 0) throw toRangeError(FormatError.NonNegativeIntegerRequired, { label });
|
|
127
|
+
return value;
|
|
128
|
+
};
|
|
129
|
+
const assertPositiveInteger = (value, label) => {
|
|
130
|
+
if (value === void 0) return;
|
|
131
|
+
if (!Number.isInteger(value) || value <= 0) throw toRangeError(FormatError.PositiveIntegerRequired, { label });
|
|
132
|
+
return value;
|
|
133
|
+
};
|
|
134
|
+
const isZeroString = (input) => {
|
|
135
|
+
return /^[-+]?0+(?:\.0+)?$/.test(input);
|
|
136
|
+
};
|
|
137
|
+
const normalizeNumeric = (value, clone = false) => {
|
|
138
|
+
if (value instanceof big_js.default) return clone ? new big_js.default(value) : value;
|
|
139
|
+
if (typeof value === "number") {
|
|
140
|
+
if (!Number.isFinite(value)) throw toRangeError(FormatError.NumericValueNonFinite);
|
|
141
|
+
return value === 0 ? BIG_ZERO : new big_js.default(value);
|
|
142
|
+
}
|
|
143
|
+
if (typeof value === "string") {
|
|
144
|
+
const trimmed = value.trim();
|
|
145
|
+
if (!trimmed) throw toRangeError(FormatError.NumericStringEmpty);
|
|
146
|
+
if (isZeroString(trimmed)) return BIG_ZERO;
|
|
147
|
+
return new big_js.default(trimmed);
|
|
148
|
+
}
|
|
149
|
+
throw toTypeError(FormatError.UnsupportedNumericInput);
|
|
150
|
+
};
|
|
151
|
+
const mapRoundingMode = (mode) => {
|
|
152
|
+
if (!mode) return big_js.default.roundHalfUp;
|
|
153
|
+
return ROUNDING_MODE_MAP[mode];
|
|
154
|
+
};
|
|
155
|
+
const computeNumericParts = (value, options = {}) => {
|
|
156
|
+
const minDecimals = assertNonNegativeInteger(options.minDecimals, "minDecimals") ?? 0;
|
|
157
|
+
const maxDecimals = assertNonNegativeInteger(options.maxDecimals, "maxDecimals");
|
|
158
|
+
const precision = assertPositiveInteger(options.precision, "precision");
|
|
159
|
+
const roundingMode = mapRoundingMode(options.roundingMode);
|
|
160
|
+
if (maxDecimals !== void 0 && maxDecimals < minDecimals) throw toRangeError(FormatError.MaxDecimalsLessThanMinimum);
|
|
161
|
+
let bigValue = normalizeNumeric(value);
|
|
162
|
+
if (precision !== void 0) bigValue = bigValue.prec(precision, roundingMode);
|
|
163
|
+
if (maxDecimals !== void 0) bigValue = bigValue.round(maxDecimals, roundingMode);
|
|
164
|
+
const isZero = bigValue.eq(0);
|
|
165
|
+
const isNegative = !isZero && bigValue.s < 0;
|
|
166
|
+
let [integerPart, fractionPart = DECIMAL_EMPTY] = bigToDecimalString(bigValue.abs()).split(DECIMAL_DOT);
|
|
167
|
+
integerPart = integerPart.replace(/^(0+)(\d)/, "$2");
|
|
168
|
+
if (!integerPart) integerPart = DECIMAL_ZERO;
|
|
169
|
+
if (!options.trimTrailingZeros && fractionPart.length < minDecimals) fractionPart = fractionPart.padEnd(minDecimals, DECIMAL_ZERO);
|
|
170
|
+
if (maxDecimals !== void 0 && fractionPart.length > maxDecimals) fractionPart = fractionPart.slice(0, maxDecimals);
|
|
171
|
+
if (options.trimTrailingZeros) {
|
|
172
|
+
const minKeep = minDecimals;
|
|
173
|
+
while (fractionPart.length > minKeep && fractionPart.endsWith(DECIMAL_ZERO)) fractionPart = fractionPart.slice(0, -1);
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
big: bigValue,
|
|
177
|
+
integer: integerPart,
|
|
178
|
+
fraction: fractionPart,
|
|
179
|
+
isNegative,
|
|
180
|
+
isZero
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
const bigToDecimalString = (value) => {
|
|
184
|
+
const coefficient = value.c ?? [0];
|
|
185
|
+
const exponent = value.e ?? 0;
|
|
186
|
+
const sign = value.s < 0 ? DEFAULT_SIGN_MINUS : DECIMAL_EMPTY;
|
|
187
|
+
if (coefficient.every((digit) => digit === 0)) return DECIMAL_ZERO;
|
|
188
|
+
const digits = coefficient.join("");
|
|
189
|
+
const decimalIndex = exponent + 1;
|
|
190
|
+
if (decimalIndex <= 0) return `${sign}${DECIMAL_ZERO}${DECIMAL_DOT}${DECIMAL_ZERO.repeat(Math.abs(decimalIndex))}${digits}`.replace(/\.$/, DECIMAL_EMPTY);
|
|
191
|
+
if (decimalIndex >= digits.length) return `${sign}${digits}${DECIMAL_ZERO.repeat(decimalIndex - digits.length)}`;
|
|
192
|
+
return `${sign}${digits.slice(0, decimalIndex)}${DECIMAL_DOT}${digits.slice(decimalIndex)}`;
|
|
193
|
+
};
|
|
194
|
+
const applyGrouping = (integer, grouping, enableGrouping) => {
|
|
195
|
+
if (!enableGrouping || grouping.primary === 0 || integer.length <= grouping.primary) return integer;
|
|
196
|
+
const groups = [];
|
|
197
|
+
const primary = grouping.primary;
|
|
198
|
+
const secondary = grouping.secondary ?? primary;
|
|
199
|
+
let index = integer.length;
|
|
200
|
+
let usePrimary = true;
|
|
201
|
+
while (index > 0) {
|
|
202
|
+
const size = usePrimary ? primary : secondary;
|
|
203
|
+
if (size <= 0) {
|
|
204
|
+
groups.unshift(integer.slice(0, index));
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
const start = Math.max(index - size, 0);
|
|
208
|
+
groups.unshift(integer.slice(start, index));
|
|
209
|
+
index = start;
|
|
210
|
+
if (index <= 0) break;
|
|
211
|
+
usePrimary = false;
|
|
212
|
+
}
|
|
213
|
+
return groups.join(grouping.separator);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
//#endregion
|
|
217
|
+
//#region src/internal/locale.ts
|
|
218
|
+
const resolveLocale = (value) => {
|
|
219
|
+
const candidate = value?.trim();
|
|
220
|
+
return candidate && candidate.length > 0 ? candidate : DEFAULT_LOCALE;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
//#endregion
|
|
224
|
+
//#region src/internal/intl-cache.ts
|
|
225
|
+
const numberFormatCache = /* @__PURE__ */ new Map();
|
|
226
|
+
const numberFormatMetaCache = /* @__PURE__ */ new Map();
|
|
227
|
+
const dateFormatCache = /* @__PURE__ */ new Map();
|
|
228
|
+
const serializeOptions = (options) => {
|
|
229
|
+
return Object.entries(options).filter(([, value]) => value !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, value]) => {
|
|
230
|
+
if (value && typeof value === "object" && !Array.isArray(value)) return `${key}:{${serializeOptions(value)}}`;
|
|
231
|
+
if (Array.isArray(value)) return `${key}:[${value.join("|")}]`;
|
|
232
|
+
return `${key}:${String(value)}`;
|
|
233
|
+
}).join(",");
|
|
234
|
+
};
|
|
235
|
+
const buildNumberFormatKey = (locale, options) => `${locale}|${serializeOptions(options)}`;
|
|
236
|
+
const buildDateFormatKey = (locale, options) => `${locale}|${options ? serializeOptions(options) : ""}`;
|
|
237
|
+
const getNumberFormat = (locale, options) => {
|
|
238
|
+
const key = buildNumberFormatKey(locale, options);
|
|
239
|
+
const cached = numberFormatCache.get(key);
|
|
240
|
+
if (cached) return cached;
|
|
241
|
+
const nf = new Intl.NumberFormat(locale, options);
|
|
242
|
+
numberFormatCache.set(key, nf);
|
|
243
|
+
return nf;
|
|
244
|
+
};
|
|
245
|
+
const deriveGrouping = (parts) => {
|
|
246
|
+
const integerParts = parts.filter((part) => part.type === "integer");
|
|
247
|
+
if (integerParts.length <= 1) return { primary: 0 };
|
|
248
|
+
const lengths = integerParts.map((part) => part.value.length);
|
|
249
|
+
const primary = lengths[lengths.length - 1];
|
|
250
|
+
const secondary = lengths.length > 1 ? lengths[lengths.length - 2] : void 0;
|
|
251
|
+
if (secondary === primary) return { primary };
|
|
252
|
+
return {
|
|
253
|
+
primary,
|
|
254
|
+
secondary
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
const analyzePattern = (nf) => {
|
|
258
|
+
const sampleValue = 1234567.89123456;
|
|
259
|
+
const positiveParts = nf.formatToParts(sampleValue);
|
|
260
|
+
const negativeParts = nf.formatToParts(-sampleValue);
|
|
261
|
+
const plusProbe = nf.formatToParts(1);
|
|
262
|
+
return {
|
|
263
|
+
positive: positiveParts,
|
|
264
|
+
negative: negativeParts,
|
|
265
|
+
groupSeparator: positiveParts.find((part) => part.type === "group")?.value ?? "",
|
|
266
|
+
decimalSeparator: positiveParts.find((part) => part.type === "decimal")?.value ?? ".",
|
|
267
|
+
grouping: deriveGrouping(positiveParts),
|
|
268
|
+
minusSign: negativeParts.find((part) => part.type === "minusSign")?.value,
|
|
269
|
+
plusSign: plusProbe.find((part) => part.type === "plusSign")?.value
|
|
270
|
+
};
|
|
271
|
+
};
|
|
272
|
+
const getNumberFormatPattern = (locale, options) => {
|
|
273
|
+
const key = buildNumberFormatKey(locale, options);
|
|
274
|
+
const cached = numberFormatMetaCache.get(key);
|
|
275
|
+
if (cached) return cached;
|
|
276
|
+
const pattern = analyzePattern(getNumberFormat(locale, options));
|
|
277
|
+
numberFormatMetaCache.set(key, pattern);
|
|
278
|
+
return pattern;
|
|
279
|
+
};
|
|
280
|
+
const getDateFormat = (locale, options) => {
|
|
281
|
+
const key = buildDateFormatKey(locale, options);
|
|
282
|
+
const cached = dateFormatCache.get(key);
|
|
283
|
+
if (cached) return cached;
|
|
284
|
+
const df = new Intl.DateTimeFormat(locale, options);
|
|
285
|
+
dateFormatCache.set(key, df);
|
|
286
|
+
return df;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
//#endregion
|
|
290
|
+
//#region src/display.ts
|
|
291
|
+
const defaultCompactThresholds = {
|
|
292
|
+
K: new big_js.default(1e3),
|
|
293
|
+
M: new big_js.default(1e6),
|
|
294
|
+
B: new big_js.default(1e9),
|
|
295
|
+
T: new big_js.default(0xe8d4a51000)
|
|
296
|
+
};
|
|
297
|
+
const defaultCompactSuffixes = {
|
|
298
|
+
K: "K",
|
|
299
|
+
M: "M",
|
|
300
|
+
B: "B",
|
|
301
|
+
T: "T"
|
|
302
|
+
};
|
|
303
|
+
const compactThresholdCache = /* @__PURE__ */ new WeakMap();
|
|
304
|
+
const COMPACT_DECIMAL_BUFFER = 12;
|
|
305
|
+
const SUBSCRIPT_DIGITS = [
|
|
306
|
+
"₀",
|
|
307
|
+
"₁",
|
|
308
|
+
"₂",
|
|
309
|
+
"₃",
|
|
310
|
+
"₄",
|
|
311
|
+
"₅",
|
|
312
|
+
"₆",
|
|
313
|
+
"₇",
|
|
314
|
+
"₈",
|
|
315
|
+
"₉"
|
|
316
|
+
];
|
|
317
|
+
const SUBSCRIPT_TO_DIGIT = SUBSCRIPT_DIGITS.reduce((acc, digit, index) => {
|
|
318
|
+
acc[digit] = index.toString();
|
|
319
|
+
return acc;
|
|
320
|
+
}, {});
|
|
321
|
+
const toSubscriptNumber = (value) => value.toString().split("").map((digit) => SUBSCRIPT_DIGITS[digit.charCodeAt(0) - 48]).join("");
|
|
322
|
+
const expandSubscriptDigits = (value) => {
|
|
323
|
+
let result = "";
|
|
324
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
325
|
+
const char = value[index];
|
|
326
|
+
const mapped = SUBSCRIPT_TO_DIGIT[char];
|
|
327
|
+
if (mapped === void 0) {
|
|
328
|
+
result += char;
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
let subscriptBuffer = mapped;
|
|
332
|
+
while (index + 1 < value.length) {
|
|
333
|
+
const nextMapped = SUBSCRIPT_TO_DIGIT[value[index + 1]];
|
|
334
|
+
if (nextMapped === void 0) break;
|
|
335
|
+
subscriptBuffer += nextMapped;
|
|
336
|
+
index += 1;
|
|
337
|
+
}
|
|
338
|
+
const zeroCount = Number(subscriptBuffer);
|
|
339
|
+
if (Number.isNaN(zeroCount) || zeroCount <= 0) continue;
|
|
340
|
+
result += "0".repeat(zeroCount);
|
|
341
|
+
}
|
|
342
|
+
return result;
|
|
343
|
+
};
|
|
344
|
+
const compactFractionLeadingZeros = (fraction) => {
|
|
345
|
+
const match = /^(0{2,})(.+)$/.exec(fraction);
|
|
346
|
+
if (!match) return fraction;
|
|
347
|
+
const [, zeros, remainder] = match;
|
|
348
|
+
if (!remainder || /^0+$/.test(remainder)) return fraction;
|
|
349
|
+
const annotation = toSubscriptNumber(zeros.length - 1);
|
|
350
|
+
return `${zeros[0]}${annotation}${remainder}`;
|
|
351
|
+
};
|
|
352
|
+
const resolveSignKind = (isNegative, isZero, signDisplay, forceSign) => {
|
|
353
|
+
switch (signDisplay ?? (forceSign ? SIGN_DISPLAYS.always : SIGN_DISPLAYS.auto)) {
|
|
354
|
+
case SIGN_DISPLAYS.always: return isNegative ? DISPLAY_SIGN_MINUS : DISPLAY_SIGN_PLUS;
|
|
355
|
+
case SIGN_DISPLAYS.exceptZero: return isNegative ? DISPLAY_SIGN_MINUS : isZero ? DISPLAY_SIGN_NONE : DISPLAY_SIGN_PLUS;
|
|
356
|
+
case SIGN_DISPLAYS.never: return DISPLAY_SIGN_NONE;
|
|
357
|
+
case SIGN_DISPLAYS.negative: return isNegative ? DISPLAY_SIGN_MINUS : DISPLAY_SIGN_NONE;
|
|
358
|
+
case SIGN_DISPLAYS.auto:
|
|
359
|
+
default: return isNegative ? DISPLAY_SIGN_MINUS : DISPLAY_SIGN_NONE;
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
const resolveCurrencyToken = (template, options) => {
|
|
363
|
+
const code = options.currencyCode?.toUpperCase() ?? "";
|
|
364
|
+
if (options.useSymbol === false) return {
|
|
365
|
+
value: code,
|
|
366
|
+
fromCustom: false
|
|
367
|
+
};
|
|
368
|
+
const custom = code ? options.customSymbols?.[code] : void 0;
|
|
369
|
+
if (custom) return {
|
|
370
|
+
value: custom,
|
|
371
|
+
fromCustom: true
|
|
372
|
+
};
|
|
373
|
+
if (template && template !== code) return {
|
|
374
|
+
value: template,
|
|
375
|
+
fromCustom: false
|
|
376
|
+
};
|
|
377
|
+
return {
|
|
378
|
+
value: code,
|
|
379
|
+
fromCustom: false
|
|
380
|
+
};
|
|
381
|
+
};
|
|
382
|
+
const getNormalizedThreshold = (options, unit) => {
|
|
383
|
+
const overrides = options.compactThresholds;
|
|
384
|
+
if (!overrides || overrides[unit] === void 0) return;
|
|
385
|
+
let cache = compactThresholdCache.get(options);
|
|
386
|
+
if (!cache) {
|
|
387
|
+
cache = /* @__PURE__ */ new Map();
|
|
388
|
+
compactThresholdCache.set(options, cache);
|
|
389
|
+
}
|
|
390
|
+
let normalized = cache.get(unit);
|
|
391
|
+
if (!normalized) {
|
|
392
|
+
normalized = normalizeNumeric(overrides[unit], true);
|
|
393
|
+
cache.set(unit, normalized);
|
|
394
|
+
}
|
|
395
|
+
return normalized;
|
|
396
|
+
};
|
|
397
|
+
const resolveCompact = (value, options, enabled) => {
|
|
398
|
+
if (!enabled) return { value };
|
|
399
|
+
const abs = value.abs();
|
|
400
|
+
for (const unit of COMPACT_ORDER) {
|
|
401
|
+
const threshold = getNormalizedThreshold(options, unit) ?? getDefaultCompactThreshold(unit);
|
|
402
|
+
if (abs.gte(threshold)) {
|
|
403
|
+
const suffix = options.compactSuffixes?.[unit] ?? getDefaultCompactSuffix(unit);
|
|
404
|
+
return {
|
|
405
|
+
value: threshold.eq(0) ? value : value.div(threshold),
|
|
406
|
+
suffix
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return { value };
|
|
411
|
+
};
|
|
412
|
+
const getDefaultCompactThreshold = (unit) => {
|
|
413
|
+
return defaultCompactThresholds[unit];
|
|
414
|
+
};
|
|
415
|
+
const getDefaultCompactSuffix = (unit) => {
|
|
416
|
+
return defaultCompactSuffixes[unit];
|
|
417
|
+
};
|
|
418
|
+
const buildNumberFormatOptions = (options, style) => {
|
|
419
|
+
const nfOptions = {
|
|
420
|
+
style,
|
|
421
|
+
useGrouping: options.useGrouping !== false
|
|
422
|
+
};
|
|
423
|
+
if (options.signDisplay && options.signDisplay !== SIGN_DISPLAYS.negative) nfOptions.signDisplay = options.signDisplay;
|
|
424
|
+
else if (!options.signDisplay && options.forceSign) nfOptions.signDisplay = SIGN_DISPLAYS.always;
|
|
425
|
+
if (options.minDecimals !== void 0) nfOptions.minimumFractionDigits = options.minDecimals;
|
|
426
|
+
if (options.maxDecimals !== void 0) nfOptions.maximumFractionDigits = options.maxDecimals;
|
|
427
|
+
if (style === STYLE_CURRENCY && options.currencyCode) {
|
|
428
|
+
nfOptions.currency = options.currencyCode;
|
|
429
|
+
nfOptions.currencyDisplay = options.useSymbol === false ? "code" : "symbol";
|
|
430
|
+
}
|
|
431
|
+
return nfOptions;
|
|
432
|
+
};
|
|
433
|
+
const formatFromPattern = (options, style, integerPart, fractionPart, sign, pattern, suffix, currencyOverride, currencyOverrideIsCustom) => {
|
|
434
|
+
const parts = sign === DISPLAY_SIGN_MINUS ? pattern.negative : pattern.positive;
|
|
435
|
+
const useGrouping = options.useGrouping !== false;
|
|
436
|
+
const groupedInteger = applyGrouping(integerPart, {
|
|
437
|
+
separator: pattern.groupSeparator,
|
|
438
|
+
primary: pattern.grouping.primary,
|
|
439
|
+
secondary: pattern.grouping.secondary
|
|
440
|
+
}, useGrouping);
|
|
441
|
+
const hasFraction = fractionPart.length > 0;
|
|
442
|
+
let result = "";
|
|
443
|
+
let integerInjected = false;
|
|
444
|
+
let currencyMeta;
|
|
445
|
+
let previousType;
|
|
446
|
+
let suffixInjected = false;
|
|
447
|
+
const appendSuffix = () => {
|
|
448
|
+
if (!suffix || suffixInjected) return;
|
|
449
|
+
result += suffix;
|
|
450
|
+
suffixInjected = true;
|
|
451
|
+
};
|
|
452
|
+
const stripTrailingWhitespace = () => {
|
|
453
|
+
if (!result) return;
|
|
454
|
+
const trimmed = result.replace(/\s+$/gu, "");
|
|
455
|
+
if (trimmed !== result) result = trimmed;
|
|
456
|
+
};
|
|
457
|
+
for (const part of parts) {
|
|
458
|
+
switch (part.type) {
|
|
459
|
+
case "integer":
|
|
460
|
+
if (!integerInjected) {
|
|
461
|
+
result += groupedInteger;
|
|
462
|
+
integerInjected = true;
|
|
463
|
+
if (!hasFraction) appendSuffix();
|
|
464
|
+
}
|
|
465
|
+
break;
|
|
466
|
+
case "group": break;
|
|
467
|
+
case "decimal":
|
|
468
|
+
if (hasFraction) result += pattern.decimalSeparator;
|
|
469
|
+
break;
|
|
470
|
+
case "fraction":
|
|
471
|
+
if (hasFraction) {
|
|
472
|
+
result += fractionPart;
|
|
473
|
+
appendSuffix();
|
|
474
|
+
}
|
|
475
|
+
break;
|
|
476
|
+
case "minusSign":
|
|
477
|
+
if (sign === DISPLAY_SIGN_MINUS) result += pattern.minusSign ?? part.value ?? DEFAULT_SIGN_MINUS;
|
|
478
|
+
break;
|
|
479
|
+
case "plusSign":
|
|
480
|
+
if (sign === DISPLAY_SIGN_PLUS) result += pattern.plusSign ?? part.value ?? DEFAULT_SIGN_PLUS;
|
|
481
|
+
break;
|
|
482
|
+
case "currency":
|
|
483
|
+
if (integerInjected) appendSuffix();
|
|
484
|
+
if (currencyOverride !== void 0) currencyMeta = {
|
|
485
|
+
value: currencyOverride,
|
|
486
|
+
fromCustom: currencyOverrideIsCustom ?? false
|
|
487
|
+
};
|
|
488
|
+
else currencyMeta = currencyMeta ?? resolveCurrencyToken(part.value, options);
|
|
489
|
+
result += currencyMeta.value;
|
|
490
|
+
break;
|
|
491
|
+
case "percentSign":
|
|
492
|
+
stripTrailingWhitespace();
|
|
493
|
+
result += part.value;
|
|
494
|
+
break;
|
|
495
|
+
case "literal":
|
|
496
|
+
if (previousType === "currency" && currencyMeta?.fromCustom && /^\s+$/.test(part.value)) break;
|
|
497
|
+
result += part.value;
|
|
498
|
+
break;
|
|
499
|
+
default:
|
|
500
|
+
result += part.value;
|
|
501
|
+
break;
|
|
502
|
+
}
|
|
503
|
+
previousType = part.type;
|
|
504
|
+
}
|
|
505
|
+
appendSuffix();
|
|
506
|
+
return result;
|
|
507
|
+
};
|
|
508
|
+
const resolveDisplayStyle = (options, overrideStyle) => {
|
|
509
|
+
const style = overrideStyle ?? options.style ?? STYLE_DECIMAL;
|
|
510
|
+
if (style === STYLE_CURRENCY && !options.currencyCode) throw toError(FormatError.MissingCurrencyCode);
|
|
511
|
+
return style;
|
|
512
|
+
};
|
|
513
|
+
const formatDisplayInternal = (value, options, styleOverride, forceCompact) => {
|
|
514
|
+
const style = resolveDisplayStyle(options, styleOverride);
|
|
515
|
+
const base = normalizeNumeric(value);
|
|
516
|
+
const { value: scaled, suffix } = resolveCompact(style === STYLE_PERCENT ? base.times(100) : base, options, forceCompact ?? options.compact === true);
|
|
517
|
+
const numericParts = computeNumericParts(scaled, options);
|
|
518
|
+
const sign = resolveSignKind(numericParts.isNegative, numericParts.isZero, options.signDisplay, options.forceSign);
|
|
519
|
+
let integerPart = numericParts.integer;
|
|
520
|
+
let fractionPart = numericParts.fraction;
|
|
521
|
+
const locale = resolveLocale(options.locale);
|
|
522
|
+
let pattern;
|
|
523
|
+
let currencyOverride;
|
|
524
|
+
let currencyOverrideIsCustom = false;
|
|
525
|
+
if (options.compactDecimalZeros && !options.isHidden) {
|
|
526
|
+
const baseMatch = /^(0{2,})(.+)$/.exec(fractionPart);
|
|
527
|
+
const baseRemainder = baseMatch?.[2];
|
|
528
|
+
if (baseMatch && baseRemainder && !/^0+$/.test(baseRemainder)) fractionPart = compactFractionLeadingZeros(fractionPart);
|
|
529
|
+
else {
|
|
530
|
+
const extendedMax = options.maxDecimals !== void 0 ? options.maxDecimals + COMPACT_DECIMAL_BUFFER : void 0;
|
|
531
|
+
const extendedParts = computeNumericParts(scaled, {
|
|
532
|
+
...options,
|
|
533
|
+
maxDecimals: extendedMax,
|
|
534
|
+
trimTrailingZeros: false
|
|
535
|
+
});
|
|
536
|
+
const extendedFraction = extendedParts.fraction;
|
|
537
|
+
const match = /^(0{2,})(.+)$/.exec(extendedFraction);
|
|
538
|
+
if (match) {
|
|
539
|
+
const zerosPortion = match[1];
|
|
540
|
+
let remainder = match[2];
|
|
541
|
+
if (!/^0+$/.test(remainder)) {
|
|
542
|
+
const targetMax = options.maxDecimals;
|
|
543
|
+
const targetMin = options.minDecimals ?? 0;
|
|
544
|
+
if (targetMax === 0) fractionPart = "";
|
|
545
|
+
else {
|
|
546
|
+
let digits = zerosPortion;
|
|
547
|
+
const remainderNeeded = targetMax !== void 0 ? Math.max(targetMax - 1, 0) : remainder.length;
|
|
548
|
+
if (remainderNeeded > 0) {
|
|
549
|
+
if (remainder.length < remainderNeeded) remainder = remainder.padEnd(remainderNeeded, "0");
|
|
550
|
+
digits += remainder.slice(0, remainderNeeded);
|
|
551
|
+
}
|
|
552
|
+
if (targetMax === void 0 && digits.length < targetMin) {
|
|
553
|
+
const extraNeeded = targetMin - digits.length;
|
|
554
|
+
let extraSource = remainder.slice(remainderNeeded);
|
|
555
|
+
if (extraSource.length < extraNeeded) extraSource = extraSource.padEnd(extraNeeded, "0");
|
|
556
|
+
digits += extraSource.slice(0, extraNeeded);
|
|
557
|
+
}
|
|
558
|
+
if (targetMax !== void 0 && digits.length < targetMin) digits = digits.padEnd(targetMin, "0");
|
|
559
|
+
if (options.trimTrailingZeros) {
|
|
560
|
+
const minKeep = Math.max(targetMin, zerosPortion ? 1 : 0);
|
|
561
|
+
while (digits.length > Math.max(minKeep, zerosPortion.length) && digits.endsWith("0")) digits = digits.slice(0, -1);
|
|
562
|
+
}
|
|
563
|
+
fractionPart = compactFractionLeadingZeros(digits);
|
|
564
|
+
integerPart = extendedParts.integer;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
if (options.isHidden) {
|
|
571
|
+
const maskChar = options.hiddenCharacter && options.hiddenCharacter.length > 0 ? options.hiddenCharacter[0] : "*";
|
|
572
|
+
integerPart = maskChar;
|
|
573
|
+
fractionPart = fractionPart.length > 0 ? maskChar.repeat(fractionPart.length) : fractionPart;
|
|
574
|
+
}
|
|
575
|
+
try {
|
|
576
|
+
pattern = getNumberFormatPattern(locale, buildNumberFormatOptions(options, style));
|
|
577
|
+
} catch (error) {
|
|
578
|
+
if (!(error instanceof RangeError) || style !== STYLE_CURRENCY || !options.currencyCode) throw error;
|
|
579
|
+
pattern = getNumberFormatPattern(locale, buildNumberFormatOptions({
|
|
580
|
+
...options,
|
|
581
|
+
currencyCode: "USD"
|
|
582
|
+
}, STYLE_CURRENCY));
|
|
583
|
+
const rawCode = options.currencyCode;
|
|
584
|
+
const code = rawCode.toUpperCase();
|
|
585
|
+
if (options.useSymbol === false) currencyOverride = rawCode;
|
|
586
|
+
else {
|
|
587
|
+
const customSymbol = options.customSymbols?.[code] ?? options.customSymbols?.[rawCode];
|
|
588
|
+
if (customSymbol) {
|
|
589
|
+
currencyOverride = customSymbol;
|
|
590
|
+
currencyOverrideIsCustom = true;
|
|
591
|
+
} else currencyOverride = rawCode;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return formatFromPattern(options, style, integerPart, fractionPart, sign, pattern, suffix, currencyOverride, currencyOverrideIsCustom);
|
|
595
|
+
};
|
|
596
|
+
const formatDisplayNumber = (value, options) => formatDisplayInternal(value, options);
|
|
597
|
+
const formatDisplayCurrency = (value, options) => formatDisplayInternal(value, options, STYLE_CURRENCY);
|
|
598
|
+
const formatDisplayPercent = (value, options) => formatDisplayInternal(value, options, STYLE_PERCENT);
|
|
599
|
+
const formatDisplayCompact = (value, options) => formatDisplayInternal(value, options, void 0, true);
|
|
600
|
+
const stripGroupSeparators = (value, separator) => {
|
|
601
|
+
if (!separator) return value;
|
|
602
|
+
return value.split(separator).join("");
|
|
603
|
+
};
|
|
604
|
+
const normalizeNumericCore = (core, pattern) => {
|
|
605
|
+
let normalized = expandSubscriptDigits(core);
|
|
606
|
+
if (pattern.groupSeparator) normalized = stripGroupSeparators(normalized, pattern.groupSeparator);
|
|
607
|
+
normalized = normalized.replace(/\s+/gu, "");
|
|
608
|
+
if (pattern.decimalSeparator && pattern.decimalSeparator !== ".") normalized = normalized.replace(pattern.decimalSeparator, ".");
|
|
609
|
+
if (pattern.minusSign && pattern.minusSign !== DEFAULT_SIGN_MINUS) normalized = normalized.split(pattern.minusSign).join(DEFAULT_SIGN_MINUS);
|
|
610
|
+
if (pattern.plusSign && pattern.plusSign !== DEFAULT_SIGN_PLUS) normalized = normalized.split(pattern.plusSign).join(DEFAULT_SIGN_PLUS);
|
|
611
|
+
return normalized;
|
|
612
|
+
};
|
|
613
|
+
const parseDisplayInternal = (formatted, options) => {
|
|
614
|
+
const numericCore = extractNumberCore(formatted);
|
|
615
|
+
if (!numericCore) return NaN;
|
|
616
|
+
const locale = options?.locale;
|
|
617
|
+
if (locale) {
|
|
618
|
+
const normalizedCore = normalizeNumericCore(numericCore, getNumberFormatPattern(resolveLocale(locale), buildNumberFormatOptions(options ?? {}, STYLE_DECIMAL)));
|
|
619
|
+
if (!normalizedCore || normalizedCore === DEFAULT_SIGN_MINUS || normalizedCore === DEFAULT_SIGN_PLUS) return NaN;
|
|
620
|
+
try {
|
|
621
|
+
return (0, big_js.default)(normalizedCore).toNumber();
|
|
622
|
+
} catch (error) {}
|
|
623
|
+
}
|
|
624
|
+
let normalized = expandSubscriptDigits(numericCore);
|
|
625
|
+
normalized = normalized.replace(/['’`_\s\u00A0]/gu, "");
|
|
626
|
+
const lastDot = normalized.lastIndexOf(".");
|
|
627
|
+
const lastComma = normalized.lastIndexOf(",");
|
|
628
|
+
if (lastDot !== -1 || lastComma !== -1) {
|
|
629
|
+
let decimalIndex = Math.max(lastDot, lastComma);
|
|
630
|
+
let decimalChar = decimalIndex === lastDot ? "." : ",";
|
|
631
|
+
if (lastDot !== -1 && lastComma !== -1) {
|
|
632
|
+
decimalChar = decimalIndex === lastDot ? "." : ",";
|
|
633
|
+
const thousandsChar = decimalChar === "." ? "," : ".";
|
|
634
|
+
normalized = normalized.split(thousandsChar).join("");
|
|
635
|
+
} else if (lastComma !== -1) if (normalized.slice(lastComma + 1).length === 3 && normalized.slice(0, lastComma).replace(/[^0-9]/g, "").length > 3) {
|
|
636
|
+
normalized = normalized.replace(/,/g, "");
|
|
637
|
+
decimalChar = ".";
|
|
638
|
+
} else decimalChar = ",";
|
|
639
|
+
else if (lastDot !== -1) if (normalized.slice(lastDot + 1).length === 3 && normalized.slice(0, lastDot).replace(/[^0-9]/g, "").length > 3) {
|
|
640
|
+
decimalChar = ",";
|
|
641
|
+
normalized = normalized.replace(/\./g, "");
|
|
642
|
+
} else decimalChar = ".";
|
|
643
|
+
if (decimalChar !== ".") normalized = normalized.split(decimalChar).join(".");
|
|
644
|
+
}
|
|
645
|
+
normalized = normalized.replace(/,/g, "");
|
|
646
|
+
if (!normalized || normalized === DEFAULT_SIGN_MINUS || normalized === DEFAULT_SIGN_PLUS) return NaN;
|
|
647
|
+
try {
|
|
648
|
+
return (0, big_js.default)(normalized).toNumber();
|
|
649
|
+
} catch (error) {
|
|
650
|
+
return NaN;
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
const parseDisplayValue = (formatted, options) => parseDisplayInternal(formatted, options);
|
|
654
|
+
const NUMERIC_OR_SUBSCRIPT = /[0-9₀-₉]/;
|
|
655
|
+
const MINUS_SIGNS = new Set([
|
|
656
|
+
"-",
|
|
657
|
+
"−",
|
|
658
|
+
"﹣",
|
|
659
|
+
"-"
|
|
660
|
+
]);
|
|
661
|
+
const isWhitespace = (char) => /\s/.test(char);
|
|
662
|
+
const extractNumberCore = (formatted) => {
|
|
663
|
+
let startIndex = -1;
|
|
664
|
+
let endIndex = -1;
|
|
665
|
+
for (let i = 0; i < formatted.length; i += 1) if (NUMERIC_OR_SUBSCRIPT.test(formatted[i])) {
|
|
666
|
+
startIndex = i;
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
if (startIndex === -1) return "";
|
|
670
|
+
for (let i = formatted.length - 1; i >= startIndex; i -= 1) if (NUMERIC_OR_SUBSCRIPT.test(formatted[i])) {
|
|
671
|
+
endIndex = i;
|
|
672
|
+
break;
|
|
673
|
+
}
|
|
674
|
+
if (endIndex === -1) return "";
|
|
675
|
+
let signPrefix = "";
|
|
676
|
+
for (let idx = startIndex - 1; idx >= 0; idx -= 1) {
|
|
677
|
+
const candidate = formatted[idx];
|
|
678
|
+
if (isWhitespace(candidate)) continue;
|
|
679
|
+
if (MINUS_SIGNS.has(candidate)) {
|
|
680
|
+
signPrefix = candidate;
|
|
681
|
+
break;
|
|
682
|
+
}
|
|
683
|
+
if (NUMERIC_OR_SUBSCRIPT.test(candidate)) break;
|
|
684
|
+
}
|
|
685
|
+
if (!signPrefix) for (let idx = endIndex + 1; idx < formatted.length; idx += 1) {
|
|
686
|
+
const candidate = formatted[idx];
|
|
687
|
+
if (isWhitespace(candidate)) continue;
|
|
688
|
+
if (MINUS_SIGNS.has(candidate)) {
|
|
689
|
+
signPrefix = candidate;
|
|
690
|
+
break;
|
|
691
|
+
}
|
|
692
|
+
if (NUMERIC_OR_SUBSCRIPT.test(candidate)) break;
|
|
693
|
+
}
|
|
694
|
+
return `${signPrefix}${formatted.slice(startIndex, endIndex + 1)}`;
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
//#endregion
|
|
698
|
+
//#region src/date.ts
|
|
699
|
+
const toDate = (value) => {
|
|
700
|
+
if (value instanceof Date) {
|
|
701
|
+
const timestamp = value.getTime();
|
|
702
|
+
if (Number.isNaN(timestamp)) throw toRangeError(FormatError.DateValueInvalid);
|
|
703
|
+
return new Date(timestamp);
|
|
704
|
+
}
|
|
705
|
+
if (typeof value === "number") {
|
|
706
|
+
if (!Number.isFinite(value)) throw toRangeError(FormatError.DateNumberNonFinite);
|
|
707
|
+
const date = new Date(value);
|
|
708
|
+
if (Number.isNaN(date.getTime())) throw toRangeError(FormatError.DateValueInvalid);
|
|
709
|
+
return date;
|
|
710
|
+
}
|
|
711
|
+
if (typeof value === "string") {
|
|
712
|
+
const trimmed = value.trim();
|
|
713
|
+
if (!trimmed) throw toRangeError(FormatError.DateStringEmpty);
|
|
714
|
+
const date = new Date(trimmed);
|
|
715
|
+
if (Number.isNaN(date.getTime())) throw toRangeError(FormatError.InvalidDateString);
|
|
716
|
+
return date;
|
|
717
|
+
}
|
|
718
|
+
throw toTypeError(FormatError.UnsupportedDateInput);
|
|
719
|
+
};
|
|
720
|
+
const formatDisplayDate = (date, locale, options) => {
|
|
721
|
+
const resolvedLocale = resolveLocale(locale);
|
|
722
|
+
const parsed = toDate(date);
|
|
723
|
+
return getDateFormat(resolvedLocale, options).format(parsed);
|
|
724
|
+
};
|
|
725
|
+
const formatCsvDate = (date, options) => {
|
|
726
|
+
const parsed = toDate(date);
|
|
727
|
+
if ((options?.format ?? "iso") === "utc-datetime") return `${parsed.getUTCFullYear()}-${String(parsed.getUTCMonth() + 1).padStart(2, "0")}-${String(parsed.getUTCDate()).padStart(2, "0")} ${String(parsed.getUTCHours()).padStart(2, "0")}:${String(parsed.getUTCMinutes()).padStart(2, "0")}:${String(parsed.getUTCSeconds()).padStart(2, "0")}`;
|
|
728
|
+
const iso = parsed.toISOString();
|
|
729
|
+
const datePart = iso.slice(0, 10);
|
|
730
|
+
if (!(parsed.getUTCHours() !== 0 || parsed.getUTCMinutes() !== 0 || parsed.getUTCSeconds() !== 0 || parsed.getUTCMilliseconds() !== 0)) return datePart;
|
|
731
|
+
return `${datePart}T${iso.slice(11).replace(/\.\d+Z$/, "Z")}`;
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
//#endregion
|
|
735
|
+
//#region src/csv.ts
|
|
736
|
+
const resolveDecimalDelimiter = (options) => {
|
|
737
|
+
if (options.decimalDelimiter !== void 0) return options.decimalDelimiter;
|
|
738
|
+
if (options.locale) return getNumberFormatPattern(resolveLocale(options.locale), { style: STYLE_DECIMAL }).decimalSeparator;
|
|
739
|
+
return DECIMAL_DOT;
|
|
740
|
+
};
|
|
741
|
+
const stringifyNumericParts = (parts, decimalDelimiter = DECIMAL_DOT) => {
|
|
742
|
+
const fraction = parts.fraction.length > 0 ? `${decimalDelimiter}${parts.fraction}` : DECIMAL_EMPTY;
|
|
743
|
+
const integer = parts.integer || DECIMAL_ZERO;
|
|
744
|
+
return `${parts.isNegative ? DEFAULT_SIGN_MINUS : DECIMAL_EMPTY}${integer}${fraction}`;
|
|
745
|
+
};
|
|
746
|
+
const formatCsvNumber = (value, options = {}) => {
|
|
747
|
+
return stringifyNumericParts(computeNumericParts(value, options), resolveDecimalDelimiter(options));
|
|
748
|
+
};
|
|
749
|
+
const formatCsvPercent = (value, options = {}) => {
|
|
750
|
+
return stringifyNumericParts(computeNumericParts(normalizeNumeric(value).times(100), options), resolveDecimalDelimiter(options));
|
|
751
|
+
};
|
|
752
|
+
const csvCurrencyCode = (code, customSymbols, useSymbol) => {
|
|
753
|
+
const trimmed = code.trim();
|
|
754
|
+
if (!trimmed) return DECIMAL_EMPTY;
|
|
755
|
+
const normalized = trimmed.toUpperCase();
|
|
756
|
+
if (useSymbol) {
|
|
757
|
+
const symbol = customSymbols?.[normalized];
|
|
758
|
+
if (symbol) return symbol;
|
|
759
|
+
}
|
|
760
|
+
return normalized;
|
|
761
|
+
};
|
|
762
|
+
const escapeCsvField = (value, delimiter) => {
|
|
763
|
+
if (!(value.includes(delimiter) || value.includes("\n") || value.includes("\r") || value.includes("\""))) return value;
|
|
764
|
+
return `"${value.replace(/"/g, "\"\"")}"`;
|
|
765
|
+
};
|
|
766
|
+
const defaultFormatter = (value) => {
|
|
767
|
+
if (value === null || value === void 0) return DECIMAL_EMPTY;
|
|
768
|
+
if (value instanceof Date) return formatCsvDate(value);
|
|
769
|
+
if (typeof value === "number") return formatCsvNumber(value);
|
|
770
|
+
if (typeof value === "string") return value;
|
|
771
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
772
|
+
return String(value);
|
|
773
|
+
};
|
|
774
|
+
const buildCsv = (rows, columns, delimiter = ",", lineEnding = "\n") => {
|
|
775
|
+
const lines = [columns.map((col) => escapeCsvField(col.header, delimiter)).join(delimiter)];
|
|
776
|
+
for (const row of rows) {
|
|
777
|
+
const fields = columns.map((col) => {
|
|
778
|
+
const raw = col.accessor(row);
|
|
779
|
+
return escapeCsvField((col.formatter ? col.formatter(raw) : defaultFormatter(raw)) ?? DECIMAL_EMPTY, delimiter);
|
|
780
|
+
});
|
|
781
|
+
lines.push(fields.join(delimiter));
|
|
782
|
+
}
|
|
783
|
+
return `${lines.join(lineEnding)}${lineEnding}`;
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
//#endregion
|
|
787
|
+
exports.DECIMAL_DOT = DECIMAL_DOT;
|
|
788
|
+
exports.DECIMAL_EMPTY = DECIMAL_EMPTY;
|
|
789
|
+
exports.DECIMAL_ZERO = DECIMAL_ZERO;
|
|
790
|
+
exports.DEFAULT_SIGN_MINUS = DEFAULT_SIGN_MINUS;
|
|
791
|
+
exports.DEFAULT_SIGN_PLUS = DEFAULT_SIGN_PLUS;
|
|
792
|
+
exports.DISPLAY_SIGNS = DISPLAY_SIGNS;
|
|
793
|
+
exports.FormatError = FormatError;
|
|
794
|
+
exports.buildCsv = buildCsv;
|
|
795
|
+
exports.csvCurrencyCode = csvCurrencyCode;
|
|
796
|
+
exports.extractNumberCore = extractNumberCore;
|
|
797
|
+
exports.formatCsvDate = formatCsvDate;
|
|
798
|
+
exports.formatCsvNumber = formatCsvNumber;
|
|
799
|
+
exports.formatCsvPercent = formatCsvPercent;
|
|
800
|
+
exports.formatDisplayCompact = formatDisplayCompact;
|
|
801
|
+
exports.formatDisplayCurrency = formatDisplayCurrency;
|
|
802
|
+
exports.formatDisplayDate = formatDisplayDate;
|
|
803
|
+
exports.formatDisplayNumber = formatDisplayNumber;
|
|
804
|
+
exports.formatDisplayPercent = formatDisplayPercent;
|
|
805
|
+
exports.getFormatErrorMessage = getFormatErrorMessage;
|
|
806
|
+
exports.parseDisplayValue = parseDisplayValue;
|
|
807
|
+
exports.toError = toError;
|
|
808
|
+
exports.toRangeError = toRangeError;
|
|
809
|
+
exports.toTypeError = toTypeError;
|
|
810
|
+
//# sourceMappingURL=index.cjs.map
|