@rowsncolumns/utils 9.2.39 → 9.2.41
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/cjs/cell-data-helpers.d.ts +13 -0
- package/dist/cjs/cell-data-helpers.d.ts.map +1 -1
- package/dist/cjs/cell-data-helpers.js +19 -1
- package/dist/cjs/excel-number-format.d.ts +128 -0
- package/dist/cjs/excel-number-format.d.ts.map +1 -0
- package/dist/cjs/excel-number-format.js +659 -0
- package/dist/cjs/formatter.d.ts +20 -0
- package/dist/cjs/formatter.d.ts.map +1 -1
- package/dist/cjs/formatter.js +300 -2
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/locale.d.ts +15 -0
- package/dist/cjs/locale.d.ts.map +1 -1
- package/dist/cjs/locale.js +58 -6
- package/dist/cjs/sheet-span.d.ts +13 -0
- package/dist/cjs/sheet-span.d.ts.map +1 -0
- package/dist/cjs/sheet-span.js +24 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/cell-data-helpers.d.ts +13 -0
- package/dist/esm/cell-data-helpers.d.ts.map +1 -1
- package/dist/esm/cell-data-helpers.js +14 -0
- package/dist/esm/excel-number-format.d.ts +128 -0
- package/dist/esm/excel-number-format.d.ts.map +1 -0
- package/dist/esm/excel-number-format.js +640 -0
- package/dist/esm/formatter.d.ts +20 -0
- package/dist/esm/formatter.d.ts.map +1 -1
- package/dist/esm/formatter.js +277 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/locale.d.ts +15 -0
- package/dist/esm/locale.d.ts.map +1 -1
- package/dist/esm/locale.js +42 -5
- package/dist/esm/sheet-span.d.ts +13 -0
- package/dist/esm/sheet-span.d.ts.map +1 -0
- package/dist/esm/sheet-span.js +20 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +2 -2
package/dist/esm/formatter.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { addLocale, format, formatColor, getFormatDateInfo, getLocale, isDateFormat, isTextFormat, } from "numfmt";
|
|
2
2
|
import { IndexedColors } from "./colors";
|
|
3
|
+
import { excelNumberPrePass, splitFormatSections, } from "./excel-number-format";
|
|
3
4
|
/**
|
|
4
5
|
* Pattern-based type inference (Excel parity). xlsx files routinely carry
|
|
5
6
|
* a `numberFormat.pattern` without an accompanying `type` field — these
|
|
@@ -177,12 +178,287 @@ const localeForPattern = (pattern, locale) => {
|
|
|
177
178
|
}
|
|
178
179
|
return standalone ? (getStandaloneMonthLocale(locale) ?? locale) : locale;
|
|
179
180
|
};
|
|
181
|
+
const shortAmPmLocales = new Map();
|
|
182
|
+
/**
|
|
183
|
+
* Excel's `A/P` renders one letter (`6:00 P`) in every locale, but numfmt
|
|
184
|
+
* honours the short form only when no locale is passed — under a locale it
|
|
185
|
+
* emits that locale's full designator (`6:00 PM`). Patterns with `A/P` render
|
|
186
|
+
* under a companion locale whose AM/PM designators are `A`/`P`. `locale` is a
|
|
187
|
+
* BCP 47 tag or an Excel LCID (`409`), as numfmt accepts both.
|
|
188
|
+
*/
|
|
189
|
+
const getShortAmPmLocale = (locale) => {
|
|
190
|
+
const cached = shortAmPmLocales.get(locale);
|
|
191
|
+
if (cached !== undefined)
|
|
192
|
+
return cached;
|
|
193
|
+
let overlay = locale;
|
|
194
|
+
try {
|
|
195
|
+
overlay = `ampm_${locale.replace(/[^a-z\d]/gi, "")}`;
|
|
196
|
+
addLocale({ ...(getLocale(locale) ?? {}), ampm: ["A", "P"] }, overlay);
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
overlay = locale;
|
|
200
|
+
}
|
|
201
|
+
shortAmPmLocales.set(locale, overlay);
|
|
202
|
+
return overlay;
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* An Excel `[$-LCID]` / `[$symbol-LCID]` token pins the section's locale, and
|
|
206
|
+
* numfmt resolves it to that LCID's own table — ahead of the companion locale
|
|
207
|
+
* `ssfFormat` passes, so `[$-409]h:mm A/P` would still render `6:00 PM`.
|
|
208
|
+
* Re-point a known LCID or tag at its companion (`$-409` → `$-ampm_409`); an
|
|
209
|
+
* LCID numfmt does not know (`F400`) or one carrying calendar bits stays as
|
|
210
|
+
* written.
|
|
211
|
+
*/
|
|
212
|
+
const shortAmPmLocaleToken = (token) => {
|
|
213
|
+
const dash = token.indexOf("-");
|
|
214
|
+
if (dash < 0)
|
|
215
|
+
return token;
|
|
216
|
+
const code = token.slice(dash + 1);
|
|
217
|
+
const wincode = Number.parseInt(code, 16);
|
|
218
|
+
if (Number.isFinite(wincode) && wincode & 0xff0000)
|
|
219
|
+
return token;
|
|
220
|
+
if (!getLocale(code))
|
|
221
|
+
return token;
|
|
222
|
+
return `${token.slice(0, dash + 1)}${getShortAmPmLocale(code)}`;
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* Does the pattern carry Excel's short `A/P` marker outside quoted literals,
|
|
226
|
+
* bracket directives and escapes? Returns the pattern with the marker
|
|
227
|
+
* upper-cased (Excel accepts `a/p` and renders it `A`/`P`; numfmt only
|
|
228
|
+
* tokenizes `A/P`) and its `[$-LCID]` tokens re-pointed at the companion
|
|
229
|
+
* `A`/`P` locale, or `undefined` when there is none.
|
|
230
|
+
*/
|
|
231
|
+
export const withShortAmPmMarker = (pattern) => {
|
|
232
|
+
const chunks = [];
|
|
233
|
+
const localeChunks = [];
|
|
234
|
+
let found = false;
|
|
235
|
+
let inQuotes = false;
|
|
236
|
+
let inBrackets = false;
|
|
237
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
238
|
+
const char = pattern[i];
|
|
239
|
+
if (inQuotes) {
|
|
240
|
+
inQuotes = char !== '"';
|
|
241
|
+
}
|
|
242
|
+
else if (inBrackets) {
|
|
243
|
+
inBrackets = char !== "]";
|
|
244
|
+
}
|
|
245
|
+
else if (char === '"') {
|
|
246
|
+
inQuotes = true;
|
|
247
|
+
}
|
|
248
|
+
else if (char === "[") {
|
|
249
|
+
const end = pattern[i + 1] === "$" ? pattern.indexOf("]", i) : -1;
|
|
250
|
+
if (end > 0) {
|
|
251
|
+
localeChunks.push(chunks.length);
|
|
252
|
+
chunks.push(pattern.slice(i + 1, end));
|
|
253
|
+
i = end;
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
inBrackets = true;
|
|
257
|
+
}
|
|
258
|
+
else if (char === "\\" || char === "_" || char === "*") {
|
|
259
|
+
chunks.push(char + (pattern[i + 1] ?? ""));
|
|
260
|
+
i++;
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
else if ((char === "A" || char === "a") &&
|
|
264
|
+
pattern[i + 1] === "/" &&
|
|
265
|
+
(pattern[i + 2] === "P" || pattern[i + 2] === "p")) {
|
|
266
|
+
chunks.push("A/P");
|
|
267
|
+
found = true;
|
|
268
|
+
i += 2;
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
chunks.push(char);
|
|
272
|
+
}
|
|
273
|
+
if (!found)
|
|
274
|
+
return undefined;
|
|
275
|
+
for (const index of localeChunks) {
|
|
276
|
+
chunks[index] = `[${shortAmPmLocaleToken(chunks[index])}]`;
|
|
277
|
+
}
|
|
278
|
+
return chunks.join("");
|
|
279
|
+
};
|
|
280
|
+
const shortAmPmPatternCache = new Map();
|
|
281
|
+
const DEFAULT_SEPARATORS = { decimal: ".", group: "," };
|
|
282
|
+
const separatorsFor = (locale) => {
|
|
283
|
+
if (!locale)
|
|
284
|
+
return DEFAULT_SEPARATORS;
|
|
285
|
+
const l10n = getLocale(locale);
|
|
286
|
+
if (!l10n)
|
|
287
|
+
return DEFAULT_SEPARATORS;
|
|
288
|
+
return {
|
|
289
|
+
decimal: l10n.decimal ?? ".",
|
|
290
|
+
group: l10n.group ?? ",",
|
|
291
|
+
};
|
|
292
|
+
};
|
|
293
|
+
/**
|
|
294
|
+
* Rewrite the `[$symbol-LCID]` tokens of one section through `rewrite`,
|
|
295
|
+
* which receives the bracket content (`€-407`) and returns the new content,
|
|
296
|
+
* or an empty string to drop the token. Quoted literals, escapes and other
|
|
297
|
+
* bracket directives are left as written.
|
|
298
|
+
*/
|
|
299
|
+
const rewriteSectionLocaleTokens = (section, rewrite) => {
|
|
300
|
+
let out = "";
|
|
301
|
+
let inQuotes = false;
|
|
302
|
+
let inBrackets = false;
|
|
303
|
+
for (let i = 0; i < section.length; i++) {
|
|
304
|
+
const char = section[i];
|
|
305
|
+
if (inQuotes) {
|
|
306
|
+
inQuotes = char !== '"';
|
|
307
|
+
}
|
|
308
|
+
else if (inBrackets) {
|
|
309
|
+
inBrackets = char !== "]";
|
|
310
|
+
}
|
|
311
|
+
else if (char === '"') {
|
|
312
|
+
inQuotes = true;
|
|
313
|
+
}
|
|
314
|
+
else if (char === "[") {
|
|
315
|
+
const end = section[i + 1] === "$" ? section.indexOf("]", i) : -1;
|
|
316
|
+
if (end > 0) {
|
|
317
|
+
const token = rewrite(section.slice(i + 1, end));
|
|
318
|
+
if (token)
|
|
319
|
+
out += `[${token}]`;
|
|
320
|
+
i = end;
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
inBrackets = true;
|
|
324
|
+
}
|
|
325
|
+
else if (char === "\\" || char === "_" || char === "*") {
|
|
326
|
+
out += char + (section[i + 1] ?? "");
|
|
327
|
+
i++;
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
out += char;
|
|
331
|
+
}
|
|
332
|
+
return out;
|
|
333
|
+
};
|
|
334
|
+
/** `[$€-407]` → `[$€]`; a bare `[$-407]` goes away. */
|
|
335
|
+
const currencySymbolOnly = (token) => {
|
|
336
|
+
const dash = token.indexOf("-");
|
|
337
|
+
const symbol = dash < 0 ? token : token.slice(0, dash);
|
|
338
|
+
return symbol.length > 1 ? symbol : "";
|
|
339
|
+
};
|
|
340
|
+
const separatorLocales = new Map();
|
|
341
|
+
/**
|
|
342
|
+
* Companion numfmt locale carrying `locale`'s calendar names and AM/PM with
|
|
343
|
+
* the workbook's decimal / group separators, so a date section pinned to
|
|
344
|
+
* `[$-407]` renders German names but a workbook decimal mark in `ss.00`.
|
|
345
|
+
* Returns `locale` itself when its separators already match.
|
|
346
|
+
*/
|
|
347
|
+
const getWorkbookSeparatorLocale = (locale, separators) => {
|
|
348
|
+
const key = `${locale}\u0000${separators.decimal}\u0000${separators.group}`;
|
|
349
|
+
const cached = separatorLocales.get(key);
|
|
350
|
+
if (cached !== undefined)
|
|
351
|
+
return cached;
|
|
352
|
+
let overlay = locale;
|
|
353
|
+
try {
|
|
354
|
+
const base = getLocale(locale);
|
|
355
|
+
if (base &&
|
|
356
|
+
(base.decimal !== separators.decimal || base.group !== separators.group)) {
|
|
357
|
+
// numfmt locale ids are `[a-z\d]+` with one optional `_` part.
|
|
358
|
+
const hex = (text) => [...text].map((c) => c.codePointAt(0).toString(16)).join("x");
|
|
359
|
+
overlay = `sep${hex(separators.decimal)}x${hex(separators.group)}_${locale.replace(/[^a-z\d]/gi, "")}`;
|
|
360
|
+
addLocale({ ...base, decimal: separators.decimal, group: separators.group }, overlay);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
overlay = locale;
|
|
365
|
+
}
|
|
366
|
+
separatorLocales.set(key, overlay);
|
|
367
|
+
return overlay;
|
|
368
|
+
};
|
|
369
|
+
/**
|
|
370
|
+
* Re-point a date section's `[$symbol-LCID]` token at the companion locale
|
|
371
|
+
* with the workbook's separators (`$-407` → `$-sep2ex2c_407`). An LCID numfmt
|
|
372
|
+
* does not know or one carrying calendar bits stays as written.
|
|
373
|
+
*/
|
|
374
|
+
const workbookSeparatorLocaleToken = (separators) => (token) => {
|
|
375
|
+
const dash = token.indexOf("-");
|
|
376
|
+
if (dash < 0)
|
|
377
|
+
return token;
|
|
378
|
+
const code = token.slice(dash + 1);
|
|
379
|
+
const wincode = Number.parseInt(code, 16);
|
|
380
|
+
if (Number.isFinite(wincode) && wincode & 0xff0000)
|
|
381
|
+
return token;
|
|
382
|
+
if (!getLocale(code))
|
|
383
|
+
return token;
|
|
384
|
+
return `${token.slice(0, dash + 1)}${getWorkbookSeparatorLocale(code, separators)}`;
|
|
385
|
+
};
|
|
386
|
+
const isDateSection = (section) => {
|
|
387
|
+
try {
|
|
388
|
+
return isDateFormat(section);
|
|
389
|
+
}
|
|
390
|
+
catch {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
/**
|
|
395
|
+
* Excel's `[$symbol-LCID]` token selects the currency symbol and the
|
|
396
|
+
* language of day/month names and AM/PM; digit grouping and the decimal
|
|
397
|
+
* separator follow the workbook locale (`[$€-407] #,##0.00` is
|
|
398
|
+
* `€ 1,234.50` on a US host). numfmt applies the token's locale to the whole
|
|
399
|
+
* section, separators included, so the locale part is dropped from every
|
|
400
|
+
* section that is not a date (number, scientific, fraction, text, …); a
|
|
401
|
+
* date section keeps the token for its names, re-pointed at a companion
|
|
402
|
+
* locale that carries the workbook's separators for fractional seconds.
|
|
403
|
+
* Returns `undefined` when nothing had to change.
|
|
404
|
+
*/
|
|
405
|
+
export const withWorkbookSeparators = (pattern, locale) => {
|
|
406
|
+
if (!pattern.includes("[$"))
|
|
407
|
+
return undefined;
|
|
408
|
+
const sections = splitFormatSections(pattern);
|
|
409
|
+
let changed = false;
|
|
410
|
+
let dateTokens;
|
|
411
|
+
const rewritten = sections.map((section) => {
|
|
412
|
+
if (!section.includes("[$"))
|
|
413
|
+
return section;
|
|
414
|
+
let rewrite = currencySymbolOnly;
|
|
415
|
+
if (isDateSection(section)) {
|
|
416
|
+
dateTokens ??= workbookSeparatorLocaleToken(separatorsFor(locale));
|
|
417
|
+
rewrite = dateTokens;
|
|
418
|
+
}
|
|
419
|
+
const stripped = rewriteSectionLocaleTokens(section, rewrite);
|
|
420
|
+
changed ||= stripped !== section;
|
|
421
|
+
return stripped;
|
|
422
|
+
});
|
|
423
|
+
return changed ? rewritten.join(";") : undefined;
|
|
424
|
+
};
|
|
425
|
+
const workbookSeparatorPatternCache = new Map();
|
|
426
|
+
const withWorkbookSeparatorsCached = (code, locale) => {
|
|
427
|
+
const key = `${locale ?? ""}\u0000${code}`;
|
|
428
|
+
let rewritten = workbookSeparatorPatternCache.get(key);
|
|
429
|
+
if (rewritten === undefined) {
|
|
430
|
+
rewritten = withWorkbookSeparators(code, locale) ?? code;
|
|
431
|
+
workbookSeparatorPatternCache.set(key, rewritten);
|
|
432
|
+
}
|
|
433
|
+
return rewritten;
|
|
434
|
+
};
|
|
180
435
|
export const ssfFormat = (pattern, value, locale) => {
|
|
181
436
|
try {
|
|
437
|
+
let shortAmPm = shortAmPmPatternCache.get(pattern);
|
|
438
|
+
if (shortAmPm === undefined && !shortAmPmPatternCache.has(pattern)) {
|
|
439
|
+
shortAmPm = withShortAmPmMarker(pattern);
|
|
440
|
+
shortAmPmPatternCache.set(pattern, shortAmPm);
|
|
441
|
+
}
|
|
442
|
+
const code = withWorkbookSeparatorsCached(shortAmPm ?? pattern, locale);
|
|
443
|
+
let patternLocale = localeForPattern(pattern, locale);
|
|
444
|
+
if (shortAmPm !== undefined && patternLocale) {
|
|
445
|
+
patternLocale = getShortAmPmLocale(patternLocale);
|
|
446
|
+
}
|
|
447
|
+
const options = { locale: patternLocale };
|
|
448
|
+
if (typeof value === "number") {
|
|
449
|
+
// Excel decides rounding, `General`, huge magnitudes and conditional
|
|
450
|
+
// sections from the 15-significant-digit decimal, not the binary
|
|
451
|
+
// double (#546 U8 / U21).
|
|
452
|
+
const pre = excelNumberPrePass(code, value, separatorsFor(locale), (section, sectionValue) => format(section, sectionValue, options));
|
|
453
|
+
if (pre.text !== undefined) {
|
|
454
|
+
return pre.text;
|
|
455
|
+
}
|
|
456
|
+
value = pre.value;
|
|
457
|
+
}
|
|
182
458
|
const isNegativeElapsedTime = typeof value === "number" &&
|
|
183
459
|
value < 0 &&
|
|
184
460
|
isSingleSectionElapsedTimePattern(pattern);
|
|
185
|
-
const formatted = format(
|
|
461
|
+
const formatted = format(code, isNegativeElapsedTime ? Math.abs(value) : value, options);
|
|
186
462
|
return isNegativeElapsedTime ? `-${formatted}` : formatted;
|
|
187
463
|
}
|
|
188
464
|
catch (err) {
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from "./locale";
|
|
|
9
9
|
export * from "./date";
|
|
10
10
|
export * from "./log";
|
|
11
11
|
export * from "./array";
|
|
12
|
+
export * from "./excel-number-format";
|
|
12
13
|
export * from "./formatter";
|
|
13
14
|
export * from "./memoize";
|
|
14
15
|
export * from "./cell-data-helpers";
|
|
@@ -22,4 +23,5 @@ export * from "./data-validation";
|
|
|
22
23
|
export * from "./content-hash";
|
|
23
24
|
export * from "./shared-string-canonical";
|
|
24
25
|
export * from "./keyboard";
|
|
26
|
+
export * from "./sheet-span";
|
|
25
27
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,OAAO,CAAC;AACtB,cAAc,SAAS,CAAC;AACxB,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC"}
|
package/dist/esm/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export * from "./locale";
|
|
|
9
9
|
export * from "./date";
|
|
10
10
|
export * from "./log";
|
|
11
11
|
export * from "./array";
|
|
12
|
+
export * from "./excel-number-format";
|
|
12
13
|
export * from "./formatter";
|
|
13
14
|
export * from "./memoize";
|
|
14
15
|
export * from "./cell-data-helpers";
|
|
@@ -22,3 +23,4 @@ export * from "./data-validation";
|
|
|
22
23
|
export * from "./content-hash";
|
|
23
24
|
export * from "./shared-string-canonical";
|
|
24
25
|
export * from "./keyboard";
|
|
26
|
+
export * from "./sheet-span";
|
package/dist/esm/locale.d.ts
CHANGED
|
@@ -16,6 +16,21 @@ export declare const getLocaleDateParts: (locale: string) => [DatePartType, stri
|
|
|
16
16
|
* de-DE → `d.m.yyyy`, hu-HU → `yyyy. mm. dd.`, en-CA → `yyyy-mm-dd`.
|
|
17
17
|
*/
|
|
18
18
|
export declare const getDefaultDateFormat: (locale?: string) => string;
|
|
19
|
+
export interface DateFieldTokens {
|
|
20
|
+
day: "d" | "dd";
|
|
21
|
+
month: "m" | "mm";
|
|
22
|
+
year: "yy" | "yyyy";
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The day / month / year tokens of {@link getDefaultDateFormat} for a
|
|
26
|
+
* locale, i.e. whether the locale zero-pads each numeric field — ru-RU
|
|
27
|
+
* (`dd.mm.yyyy`) → `{ day: "dd", month: "mm", year: "yyyy" }`, en-US
|
|
28
|
+
* (`m/d/yyyy`) → `{ day: "d", month: "m", year: "yyyy" }`. A date typed
|
|
29
|
+
* as digits is displayed with the locale's own padding (Excel re-renders
|
|
30
|
+
* `30.9.2025` as `30.09.2025` under ru-RU), so the date parser assigns
|
|
31
|
+
* these tokens rather than echoing the padding the user happened to type.
|
|
32
|
+
*/
|
|
33
|
+
export declare const getDefaultDateFieldTokens: (locale?: string) => DateFieldTokens;
|
|
19
34
|
/**
|
|
20
35
|
* Default time pattern for a locale, honoring its 12/24-hour convention,
|
|
21
36
|
* separators and hour padding — e.g. en-US → `h:mm:ss AM/PM`,
|
package/dist/esm/locale.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../../locale.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,cAU5B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,GAAI,QAAQ,MAAM,qCAkC3D,CAAC;AAEF,eAAO,MAAM,kBAAkB,sDAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../../locale.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,cAU5B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,GAAI,QAAQ,MAAM,qCAkC3D,CAAC;AAEF,eAAO,MAAM,kBAAkB,sDAAyC,CAAC;AAiGzE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAQ,MAA2B,WAClC,CAAC;AAEvC,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC;IAChB,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;IAClB,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;CACrB;AAwBD;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,GACpC,SAAQ,MAA2B,KAClC,eAA4D,CAAC;AAuChE;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,SAAQ,MAA2B,EACnC,YAAW,QAAQ,GAAG,QAAmB,WACS,CAAC;AAErD,eAAO,MAAM,wBAAwB,GAAI,SAAS,MAAM,WAEvD,CAAC;AA2CF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAQ,MAA2B,WAClC,CAAC"}
|
package/dist/esm/locale.js
CHANGED
|
@@ -105,9 +105,15 @@ const buildPatternFromParts = (parts, toToken) => {
|
|
|
105
105
|
// trailing fields we skipped (e.g. an era) — trim stray whitespace.
|
|
106
106
|
return pattern.trim();
|
|
107
107
|
};
|
|
108
|
-
|
|
108
|
+
/**
|
|
109
|
+
* `formatToParts` of the locale's numeric short date for the sample
|
|
110
|
+
* instant — the single source both the default pattern and its per-field
|
|
111
|
+
* tokens are read from, so they can never disagree. Empty when Intl has
|
|
112
|
+
* no data for the locale.
|
|
113
|
+
*/
|
|
114
|
+
const getDefaultDateParts = memoize((locale) => {
|
|
109
115
|
try {
|
|
110
|
-
|
|
116
|
+
return new Intl.DateTimeFormat(locale, {
|
|
111
117
|
calendar: "gregory",
|
|
112
118
|
numberingSystem: "latn",
|
|
113
119
|
year: "numeric",
|
|
@@ -115,13 +121,15 @@ const getDefaultDateFormatMemoized = memoize((locale) => {
|
|
|
115
121
|
day: "numeric",
|
|
116
122
|
timeZone: "UTC",
|
|
117
123
|
}).formatToParts(FORMAT_SAMPLE_DATE);
|
|
118
|
-
const pattern = buildPatternFromParts(parts, dateFieldToken);
|
|
119
|
-
return pattern || "m/d/yyyy";
|
|
120
124
|
}
|
|
121
125
|
catch (err) {
|
|
122
|
-
return
|
|
126
|
+
return [];
|
|
123
127
|
}
|
|
124
128
|
});
|
|
129
|
+
const getDefaultDateFormatMemoized = memoize((locale) => {
|
|
130
|
+
const pattern = buildPatternFromParts(getDefaultDateParts(locale), dateFieldToken);
|
|
131
|
+
return pattern || "m/d/yyyy";
|
|
132
|
+
});
|
|
125
133
|
/**
|
|
126
134
|
* Default numeric (short) date pattern for a locale, preserving the
|
|
127
135
|
* locale's field order, separators, literal text and zero-padding as
|
|
@@ -129,6 +137,35 @@ const getDefaultDateFormatMemoized = memoize((locale) => {
|
|
|
129
137
|
* de-DE → `d.m.yyyy`, hu-HU → `yyyy. mm. dd.`, en-CA → `yyyy-mm-dd`.
|
|
130
138
|
*/
|
|
131
139
|
export const getDefaultDateFormat = (locale = getCurrentLocale()) => getDefaultDateFormatMemoized(locale);
|
|
140
|
+
const getDefaultDateFieldTokensMemoized = memoize((locale) => {
|
|
141
|
+
const tokens = { day: "d", month: "m", year: "yyyy" };
|
|
142
|
+
for (const part of getDefaultDateParts(locale)) {
|
|
143
|
+
switch (part.type) {
|
|
144
|
+
case "day":
|
|
145
|
+
tokens.day = part.value.length === 2 ? "dd" : "d";
|
|
146
|
+
break;
|
|
147
|
+
case "month":
|
|
148
|
+
tokens.month = part.value.length === 2 ? "mm" : "m";
|
|
149
|
+
break;
|
|
150
|
+
case "year":
|
|
151
|
+
tokens.year = part.value.length === 2 ? "yy" : "yyyy";
|
|
152
|
+
break;
|
|
153
|
+
default:
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return tokens;
|
|
158
|
+
});
|
|
159
|
+
/**
|
|
160
|
+
* The day / month / year tokens of {@link getDefaultDateFormat} for a
|
|
161
|
+
* locale, i.e. whether the locale zero-pads each numeric field — ru-RU
|
|
162
|
+
* (`dd.mm.yyyy`) → `{ day: "dd", month: "mm", year: "yyyy" }`, en-US
|
|
163
|
+
* (`m/d/yyyy`) → `{ day: "d", month: "m", year: "yyyy" }`. A date typed
|
|
164
|
+
* as digits is displayed with the locale's own padding (Excel re-renders
|
|
165
|
+
* `30.9.2025` as `30.09.2025` under ru-RU), so the date parser assigns
|
|
166
|
+
* these tokens rather than echoing the padding the user happened to type.
|
|
167
|
+
*/
|
|
168
|
+
export const getDefaultDateFieldTokens = (locale = getCurrentLocale()) => getDefaultDateFieldTokensMemoized(locale);
|
|
132
169
|
const getDefaultTimeFormatMemoized = memoize((locale, precision) => {
|
|
133
170
|
try {
|
|
134
171
|
const parts = new Intl.DateTimeFormat(locale, {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sheets covered by a 3-D reference span `first:last` (`Sheet1:Sheet3!A1`):
|
|
3
|
+
* every name between the two endpoints in tab order, inclusive. Excel spans
|
|
4
|
+
* the tabs between the endpoints whichever one is written first and matches
|
|
5
|
+
* sheet names case-insensitively. Returns undefined when an endpoint is not a
|
|
6
|
+
* sheet (the caller reports #REF!).
|
|
7
|
+
* @param sheetNames sheet names in tab order
|
|
8
|
+
* @param first
|
|
9
|
+
* @param last
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
export declare const resolveSheetSpan: (sheetNames: readonly string[], first: string, last: string) => string[] | undefined;
|
|
13
|
+
//# sourceMappingURL=sheet-span.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheet-span.d.ts","sourceRoot":"","sources":["../../sheet-span.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,GAC3B,YAAY,SAAS,MAAM,EAAE,EAC7B,OAAO,MAAM,EACb,MAAM,MAAM,KACX,MAAM,EAAE,GAAG,SAQb,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sheets covered by a 3-D reference span `first:last` (`Sheet1:Sheet3!A1`):
|
|
3
|
+
* every name between the two endpoints in tab order, inclusive. Excel spans
|
|
4
|
+
* the tabs between the endpoints whichever one is written first and matches
|
|
5
|
+
* sheet names case-insensitively. Returns undefined when an endpoint is not a
|
|
6
|
+
* sheet (the caller reports #REF!).
|
|
7
|
+
* @param sheetNames sheet names in tab order
|
|
8
|
+
* @param first
|
|
9
|
+
* @param last
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
export const resolveSheetSpan = (sheetNames, first, last) => {
|
|
13
|
+
const lower = sheetNames.map((name) => name.toLowerCase());
|
|
14
|
+
const start = lower.indexOf(first.toLowerCase());
|
|
15
|
+
const end = lower.indexOf(last.toLowerCase());
|
|
16
|
+
if (start === -1 || end === -1) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
return sheetNames.slice(Math.min(start, end), Math.max(start, end) + 1);
|
|
20
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../../array.ts","../../cell-data-helpers.ts","../../color.ts","../../colors.ts","../../conditional-format.ts","../../content-hash.ts","../../data-validation.ts","../../date.ts","../../dom.ts","../../formatter.ts","../../formula-refs.ts","../../formula.ts","../../index.ts","../../keyboard.ts","../../locale.ts","../../log.ts","../../memoize.ts","../../numbers.ts","../../selection.ts","../../shared-string-canonical.ts","../../sort.ts","../../string.ts","../../table-styles.ts","../../typeguards.ts","../../uuid.ts","../../vitest.config.ts"],"version":"5.8.3"}
|
|
1
|
+
{"root":["../../array.ts","../../cell-data-helpers.ts","../../color.ts","../../colors.ts","../../conditional-format.ts","../../content-hash.ts","../../data-validation.ts","../../date.ts","../../dom.ts","../../excel-number-format.ts","../../formatter.ts","../../formula-refs.ts","../../formula.ts","../../index.ts","../../keyboard.ts","../../locale.ts","../../log.ts","../../memoize.ts","../../numbers.ts","../../selection.ts","../../shared-string-canonical.ts","../../sheet-span.ts","../../sort.ts","../../string.ts","../../table-styles.ts","../../typeguards.ts","../../uuid.ts","../../vitest.config.ts"],"version":"5.8.3"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rowsncolumns/utils",
|
|
3
|
-
"version": "9.2.
|
|
3
|
+
"version": "9.2.41",
|
|
4
4
|
"author": "Vinay M",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"numfmt": "^3.2.2",
|
|
45
|
-
"@rowsncolumns/common-types": ">=5.2.
|
|
45
|
+
"@rowsncolumns/common-types": ">=5.2.32"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {},
|
|
48
48
|
"peerDependencies": {}
|