@pixerate/editor 0.22.0 → 0.23.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/README.md +80 -2
- package/THIRD_PARTY_NOTICES.md +88 -0
- package/dist/agent/index.cjs +83 -108
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +69 -211
- package/dist/agent/index.d.ts +69 -211
- package/dist/agent/index.js +76 -101
- package/dist/agent/index.js.map +1 -1
- package/dist/arrangeShortcuts-B8O3f8-P.d.cts +184 -0
- package/dist/arrangeShortcuts-sLlD2rSX.d.ts +184 -0
- package/dist/canvas/index.cjs +879 -83
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +291 -186
- package/dist/canvas/index.d.ts +291 -186
- package/dist/canvas/index.js +865 -69
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-26BVFKHU.cjs +453 -0
- package/dist/chunk-26BVFKHU.cjs.map +1 -0
- package/dist/chunk-2H7ZHPEJ.js +762 -0
- package/dist/chunk-2H7ZHPEJ.js.map +1 -0
- package/dist/chunk-7DWMJCAT.js +453 -0
- package/dist/chunk-7DWMJCAT.js.map +1 -0
- package/dist/chunk-ARRTP33I.js +101 -0
- package/dist/chunk-ARRTP33I.js.map +1 -0
- package/dist/chunk-CPOKFNBG.cjs +101 -0
- package/dist/chunk-CPOKFNBG.cjs.map +1 -0
- package/dist/chunk-G2I4QJOT.cjs +762 -0
- package/dist/chunk-G2I4QJOT.cjs.map +1 -0
- package/dist/{chunk-RU52I7QO.js → chunk-K3R5NG2D.js} +147 -42
- package/dist/chunk-K3R5NG2D.js.map +1 -0
- package/dist/{chunk-DENSCKFC.js → chunk-QBJ22YZR.js} +423 -30
- package/dist/chunk-QBJ22YZR.js.map +1 -0
- package/dist/{chunk-SAZRENEZ.cjs → chunk-RIKBJLS2.cjs} +424 -31
- package/dist/chunk-RIKBJLS2.cjs.map +1 -0
- package/dist/{chunk-6M3BCTBD.cjs → chunk-XDMXXC4Z.cjs} +230 -125
- package/dist/chunk-XDMXXC4Z.cjs.map +1 -0
- package/dist/commands/index.cjs +860 -0
- package/dist/commands/index.cjs.map +1 -0
- package/dist/commands/index.d.cts +592 -0
- package/dist/commands/index.d.ts +592 -0
- package/dist/commands/index.js +860 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/{controller-B7GIybc4.d.cts → controller-pePCJLT1.d.cts} +78 -5
- package/dist/{controller-B7GIybc4.d.ts → controller-pePCJLT1.d.ts} +78 -5
- package/dist/history/index.cjs +12 -2
- package/dist/history/index.cjs.map +1 -1
- package/dist/history/index.d.cts +211 -7
- package/dist/history/index.d.ts +211 -7
- package/dist/history/index.js +13 -3
- package/dist/image-editor/index.cjs +418 -13
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +154 -3
- package/dist/image-editor/index.d.ts +154 -3
- package/dist/image-editor/index.js +417 -12
- package/dist/image-editor/index.js.map +1 -1
- package/dist/index.cjs +34 -76
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -42
- package/dist/index.d.ts +5 -42
- package/dist/index.js +27 -69
- package/dist/index.js.map +1 -1
- package/dist/registry-D5-R90p0.d.cts +209 -0
- package/dist/registry-D5-R90p0.d.ts +209 -0
- package/dist/spreadsheet/index.cjs +19 -3
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +67 -9
- package/dist/spreadsheet/index.d.ts +67 -9
- package/dist/spreadsheet/index.js +18 -2
- package/dist/{types-CJ4U-HHI.d.cts → types-DX4Mh4SL.d.cts} +1 -1
- package/dist/{types-CJ4U-HHI.d.ts → types-DX4Mh4SL.d.ts} +1 -1
- package/dist/types-GT5a5YAX.d.cts +86 -0
- package/dist/types-GT5a5YAX.d.ts +86 -0
- package/package.json +8 -2
- package/dist/chunk-2TWGLC5K.cjs +0 -262
- package/dist/chunk-2TWGLC5K.cjs.map +0 -1
- package/dist/chunk-6M3BCTBD.cjs.map +0 -1
- package/dist/chunk-DENSCKFC.js.map +0 -1
- package/dist/chunk-KAADNAPF.js +0 -262
- package/dist/chunk-KAADNAPF.js.map +0 -1
- package/dist/chunk-RU52I7QO.js.map +0 -1
- package/dist/chunk-SAZRENEZ.cjs.map +0 -1
- package/dist/types-BZgcDsC5.d.cts +0 -42
- package/dist/types-BZgcDsC5.d.ts +0 -42
|
@@ -414,9 +414,7 @@ function toNumber(value) {
|
|
|
414
414
|
if (isBlank(value)) return 0;
|
|
415
415
|
if (typeof value === "boolean") return value ? 1 : 0;
|
|
416
416
|
if (typeof value === "number") return value;
|
|
417
|
-
|
|
418
|
-
const num = trimmed === "" ? NaN : Number(trimmed);
|
|
419
|
-
return isNaN(num) ? "#VALUE!" : num;
|
|
417
|
+
return parseNumberText(String(value)) ?? "#VALUE!";
|
|
420
418
|
}
|
|
421
419
|
function toBoolean(value) {
|
|
422
420
|
if (isFormulaError(value)) return value;
|
|
@@ -428,7 +426,26 @@ function toBoolean(value) {
|
|
|
428
426
|
if (upper === "FALSE") return false;
|
|
429
427
|
return "#VALUE!";
|
|
430
428
|
}
|
|
431
|
-
var toText = (value) => isBlank(value) ? "" : typeof value === "boolean" ? value ? "TRUE" : "FALSE" : String(value);
|
|
429
|
+
var toText = (value) => isBlank(value) ? "" : typeof value === "boolean" ? value ? "TRUE" : "FALSE" : typeof value === "number" ? numberToText(value) : String(value);
|
|
430
|
+
function numberToText(n) {
|
|
431
|
+
if (n === 0 || !Number.isFinite(n)) return "0";
|
|
432
|
+
const a = Math.abs(n);
|
|
433
|
+
if ((a < 1e-9 || a >= 1e15) && Math.round(a) !== a || a >= 1e15) return sciText(n, 15);
|
|
434
|
+
let mag = Math.floor(Math.log10(a));
|
|
435
|
+
if (a >= Math.pow(10, mag + 1)) mag++;
|
|
436
|
+
const decimals = Math.min(Math.max(14 - mag, 0), 30);
|
|
437
|
+
return trimDecimal(n.toFixed(decimals));
|
|
438
|
+
}
|
|
439
|
+
function trimDecimal(s) {
|
|
440
|
+
if (!s.includes(".")) return s;
|
|
441
|
+
const t = s.replace(/0+$/, "").replace(/\.$/, "");
|
|
442
|
+
return t === "-0" ? "0" : t;
|
|
443
|
+
}
|
|
444
|
+
function sciText(n, sig) {
|
|
445
|
+
const [mantissa, exp] = n.toExponential(Math.max(sig - 1, 0)).split("e");
|
|
446
|
+
const e = Number(exp);
|
|
447
|
+
return `${trimDecimal(mantissa)}E${e < 0 ? "-" : "+"}${String(Math.abs(e)).padStart(2, "0")}`;
|
|
448
|
+
}
|
|
432
449
|
function numericValue(value) {
|
|
433
450
|
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
434
451
|
if (typeof value !== "string" || FORMULA_ERRORS.has(value)) return null;
|
|
@@ -441,22 +458,68 @@ function normalizeValue(value) {
|
|
|
441
458
|
const num = typeof value === "string" ? numericValue(value) : null;
|
|
442
459
|
return num === null ? value : num;
|
|
443
460
|
}
|
|
461
|
+
var ERROR_ORDER = ["#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A", "#SPILL!", "#CALC!", "#CYCLE!", "#ERROR!"];
|
|
462
|
+
function valueRank(value) {
|
|
463
|
+
if (isBlank(value)) return 4;
|
|
464
|
+
if (typeof value === "number") return 0;
|
|
465
|
+
if (typeof value === "boolean") return 2;
|
|
466
|
+
if (typeof value === "string" && FORMULA_ERRORS.has(value)) return 3;
|
|
467
|
+
return 1;
|
|
468
|
+
}
|
|
469
|
+
function compareNumbers(a, b) {
|
|
470
|
+
if (a === b) return 0;
|
|
471
|
+
if (Math.abs(a - b) > Math.max(Math.abs(a), Math.abs(b)) * 1e-13) return a < b ? -1 : 1;
|
|
472
|
+
const round15 = (x2) => !Number.isFinite(x2) || x2 === 0 ? x2 : Number(x2.toExponential(14));
|
|
473
|
+
const x = round15(a);
|
|
474
|
+
const y = round15(b);
|
|
475
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
476
|
+
}
|
|
477
|
+
function compareText(a, b) {
|
|
478
|
+
const x = a.toLowerCase();
|
|
479
|
+
const y = b.toLowerCase();
|
|
480
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
481
|
+
}
|
|
444
482
|
function compareValues(left, right) {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
if (
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
return
|
|
458
|
-
}
|
|
459
|
-
|
|
483
|
+
const lRank = valueRank(left);
|
|
484
|
+
const rRank = valueRank(right);
|
|
485
|
+
if (lRank === 4 || rRank === 4) {
|
|
486
|
+
if (lRank === rRank) return 0;
|
|
487
|
+
const blankFirst = lRank === 4;
|
|
488
|
+
const other = blankFirst ? right : left;
|
|
489
|
+
const otherRank = blankFirst ? rRank : lRank;
|
|
490
|
+
let cmp;
|
|
491
|
+
if (otherRank === 0) cmp = compareNumbers(0, other);
|
|
492
|
+
else if (otherRank === 1) cmp = String(other) === "" ? 0 : -1;
|
|
493
|
+
else if (otherRank === 2) cmp = other ? -1 : 0;
|
|
494
|
+
else return lRank - rRank;
|
|
495
|
+
return blankFirst ? cmp : -cmp;
|
|
496
|
+
}
|
|
497
|
+
if (lRank === 1 && rRank === 1) {
|
|
498
|
+
const a = String(left);
|
|
499
|
+
const b = String(right);
|
|
500
|
+
const ta = isoDateTime(a);
|
|
501
|
+
const tb = ta === null ? null : isoDateTime(b);
|
|
502
|
+
if (ta !== null && tb !== null) return Math.sign(ta - tb);
|
|
503
|
+
return compareText(a, b);
|
|
504
|
+
}
|
|
505
|
+
if (lRank === 0 && rRank === 1 || lRank === 1 && rRank === 0) {
|
|
506
|
+
const date = parseIsoDate(lRank === 1 ? left : right);
|
|
507
|
+
if (date) {
|
|
508
|
+
const serial = dateToSerial(date);
|
|
509
|
+
return lRank === 0 ? compareNumbers(left, serial) : compareNumbers(serial, right);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (lRank !== rRank) return lRank - rRank;
|
|
513
|
+
if (lRank === 0) return compareNumbers(left, right);
|
|
514
|
+
if (lRank === 2) return Number(left) - Number(right);
|
|
515
|
+
return Math.sign(ERROR_ORDER.indexOf(left) - ERROR_ORDER.indexOf(right));
|
|
516
|
+
}
|
|
517
|
+
function sortCompareValues(left, right) {
|
|
518
|
+
const lBlank = isBlank(left);
|
|
519
|
+
const rBlank = isBlank(right);
|
|
520
|
+
if (lBlank || rBlank) return lBlank === rBlank ? 0 : lBlank ? 1 : -1;
|
|
521
|
+
if (isFormulaError(left) && isFormulaError(right)) return 0;
|
|
522
|
+
return compareValues(left, right);
|
|
460
523
|
}
|
|
461
524
|
function roundHalfAwayFromZero(value, decimals) {
|
|
462
525
|
const factor = Math.pow(10, decimals);
|
|
@@ -565,6 +628,282 @@ var daysBetween = (start, end) => Math.round(
|
|
|
565
628
|
(Date.UTC(end.getFullYear(), end.getMonth(), end.getDate()) - Date.UTC(start.getFullYear(), start.getMonth(), start.getDate())) / MS_PER_DAY
|
|
566
629
|
);
|
|
567
630
|
|
|
631
|
+
// src/spreadsheet/formula/parse-input.ts
|
|
632
|
+
var MONTH_NAMES = [
|
|
633
|
+
"January",
|
|
634
|
+
"February",
|
|
635
|
+
"March",
|
|
636
|
+
"April",
|
|
637
|
+
"May",
|
|
638
|
+
"June",
|
|
639
|
+
"July",
|
|
640
|
+
"August",
|
|
641
|
+
"September",
|
|
642
|
+
"October",
|
|
643
|
+
"November",
|
|
644
|
+
"December"
|
|
645
|
+
];
|
|
646
|
+
function daysFromCivil(year, month, day) {
|
|
647
|
+
const y = month <= 2 ? year - 1 : year;
|
|
648
|
+
const era = Math.floor((y >= 0 ? y : y - 399) / 400);
|
|
649
|
+
const yoe = y - era * 400;
|
|
650
|
+
const doy = Math.floor((153 * (month > 2 ? month - 3 : month + 9) + 2) / 5) + day - 1;
|
|
651
|
+
const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;
|
|
652
|
+
return era * 146097 + doe - 719468;
|
|
653
|
+
}
|
|
654
|
+
var isLeapYear = (y) => y % 4 === 0 && y % 100 !== 0 || y % 400 === 0;
|
|
655
|
+
function daysInMonth(year, month) {
|
|
656
|
+
if (month === 2) return isLeapYear(year) ? 29 : 28;
|
|
657
|
+
if ([4, 6, 9, 11].includes(month)) return 30;
|
|
658
|
+
return month >= 1 && month <= 12 ? 31 : 0;
|
|
659
|
+
}
|
|
660
|
+
var daysInMonth1900 = (year, month) => year === 1900 && month === 2 ? 29 : daysInMonth(year, month);
|
|
661
|
+
var UNIX_1899_12_30 = -25569;
|
|
662
|
+
var MAX_SERIAL_1900 = 2958465;
|
|
663
|
+
function serialFromYmd(year, month, day) {
|
|
664
|
+
if (![year, month, day].every(Number.isSafeInteger)) return null;
|
|
665
|
+
let y = year >= 0 && year < 1900 ? year + 1900 : year;
|
|
666
|
+
const m0 = month - 1;
|
|
667
|
+
y += Math.floor(m0 / 12);
|
|
668
|
+
const m = (m0 % 12 + 12) % 12 + 1;
|
|
669
|
+
if (y < 1900 || y > 9999) return null;
|
|
670
|
+
const first = daysFromCivil(y, m, 1) - UNIX_1899_12_30 - (y === 1900 && m <= 2 ? 1 : 0);
|
|
671
|
+
const serial = first + day - 1;
|
|
672
|
+
return serial >= 0 && serial <= MAX_SERIAL_1900 ? serial : null;
|
|
673
|
+
}
|
|
674
|
+
var timeFraction = (h, m, s) => (h * 3600 + m * 60 + s) / 86400;
|
|
675
|
+
var currentYear = () => (/* @__PURE__ */ new Date()).getFullYear();
|
|
676
|
+
function parseCellInput(input) {
|
|
677
|
+
if (input === "") return { value: "", type: "empty" };
|
|
678
|
+
if (input.startsWith("'")) return { value: input.slice(1), type: "text" };
|
|
679
|
+
const t = input.trim();
|
|
680
|
+
const upper = t.toUpperCase();
|
|
681
|
+
if (upper === "TRUE") return { value: true, type: "boolean" };
|
|
682
|
+
if (upper === "FALSE") return { value: false, type: "boolean" };
|
|
683
|
+
if (FORMULA_ERRORS.has(upper)) return { value: upper, type: "error" };
|
|
684
|
+
const numeric = parseNumeric(t);
|
|
685
|
+
if (numeric) {
|
|
686
|
+
if (numeric.kind === "date") {
|
|
687
|
+
const iso = isoText(numeric.date);
|
|
688
|
+
if (iso !== null) {
|
|
689
|
+
return { value: iso, type: "date", numberFormat: numeric.format, formatKind: "date", cellFormat: "date" };
|
|
690
|
+
}
|
|
691
|
+
} else {
|
|
692
|
+
const formatKind = numeric.kind === "time" ? "time" : formatKindOf(numeric.format);
|
|
693
|
+
return {
|
|
694
|
+
value: normalizeZero(numeric.value),
|
|
695
|
+
type: "number",
|
|
696
|
+
...numeric.format ? { numberFormat: numeric.format } : {},
|
|
697
|
+
...formatKind ? { formatKind } : {},
|
|
698
|
+
...formatKind && formatKind !== "time" ? { cellFormat: formatKind } : {}
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
return { value: input, type: "text" };
|
|
703
|
+
}
|
|
704
|
+
function parseNumberText(text) {
|
|
705
|
+
const numeric = parseNumeric(text.trim());
|
|
706
|
+
if (!numeric) return null;
|
|
707
|
+
if (numeric.kind !== "date") return normalizeZero(numeric.value);
|
|
708
|
+
const { year, month, day, time = 0 } = numeric.date;
|
|
709
|
+
const serial = serialFromYmd(year, month, day);
|
|
710
|
+
return serial === null ? null : serial + time;
|
|
711
|
+
}
|
|
712
|
+
var normalizeZero = (n) => n === 0 ? 0 : n;
|
|
713
|
+
function formatKindOf(format) {
|
|
714
|
+
if (!format) return void 0;
|
|
715
|
+
if (format.includes("$")) return "currency";
|
|
716
|
+
if (format.includes("%")) return "percentage";
|
|
717
|
+
return "number";
|
|
718
|
+
}
|
|
719
|
+
var pad2 = (n, width = 2) => String(n).padStart(width, "0");
|
|
720
|
+
function isoText({ year, month, day, time }) {
|
|
721
|
+
if (day > daysInMonth(year, month)) return null;
|
|
722
|
+
const date = `${pad2(year, 4)}-${pad2(month)}-${pad2(day)}`;
|
|
723
|
+
if (time === void 0) return date;
|
|
724
|
+
let seconds = Math.round(time * 86400);
|
|
725
|
+
if (seconds >= 86400) seconds = 86399;
|
|
726
|
+
return `${date} ${pad2(Math.floor(seconds / 3600))}:${pad2(Math.floor(seconds / 60) % 60)}:${pad2(seconds % 60)}`;
|
|
727
|
+
}
|
|
728
|
+
function parseNumeric(t) {
|
|
729
|
+
if (t === "") return null;
|
|
730
|
+
if (t.startsWith("(") && t.endsWith(")") && t.length >= 2) {
|
|
731
|
+
const inner = parseNumeric(t.slice(1, -1).trim());
|
|
732
|
+
if (!inner || inner.kind === "date") return null;
|
|
733
|
+
return { ...inner, value: -inner.value };
|
|
734
|
+
}
|
|
735
|
+
const plain = parsePlain(t);
|
|
736
|
+
if (plain) return plain;
|
|
737
|
+
const fraction = parseFraction(t);
|
|
738
|
+
if (fraction !== null) return { kind: "number", value: fraction, format: "# ?/?" };
|
|
739
|
+
return parseDateTime(t);
|
|
740
|
+
}
|
|
741
|
+
var startsWithDigitOrDot = (s) => /^[0-9.]/.test(s);
|
|
742
|
+
function parsePlain(t) {
|
|
743
|
+
let s = t;
|
|
744
|
+
let neg = false;
|
|
745
|
+
let currency = false;
|
|
746
|
+
let percent = false;
|
|
747
|
+
if (s.startsWith("-")) {
|
|
748
|
+
neg = true;
|
|
749
|
+
s = s.slice(1).trimStart();
|
|
750
|
+
} else if (s.startsWith("+")) {
|
|
751
|
+
s = s.slice(1).trimStart();
|
|
752
|
+
}
|
|
753
|
+
if (s.startsWith("$")) {
|
|
754
|
+
currency = true;
|
|
755
|
+
s = s.slice(1).trimStart();
|
|
756
|
+
if (!neg && s.startsWith("-")) {
|
|
757
|
+
neg = true;
|
|
758
|
+
s = s.slice(1);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
if (s.endsWith("%")) {
|
|
762
|
+
percent = true;
|
|
763
|
+
s = s.slice(0, -1).trimEnd();
|
|
764
|
+
}
|
|
765
|
+
if (s === "") return null;
|
|
766
|
+
const hasSep = s.includes(",");
|
|
767
|
+
let digits;
|
|
768
|
+
if (hasSep) {
|
|
769
|
+
const dot = s.indexOf(".");
|
|
770
|
+
const int = dot === -1 ? s : s.slice(0, dot);
|
|
771
|
+
const frac = dot === -1 ? null : s.slice(dot + 1);
|
|
772
|
+
const groups = int.split(",");
|
|
773
|
+
const first = groups[0];
|
|
774
|
+
if (first === "" || first.length > 3 || groups.slice(1).some((g) => g.length !== 3)) return null;
|
|
775
|
+
digits = groups.join("") + (frac !== null ? `.${frac}` : "");
|
|
776
|
+
} else {
|
|
777
|
+
digits = s;
|
|
778
|
+
}
|
|
779
|
+
if (!/^[0-9.eE+-]+$/.test(digits) || !startsWithDigitOrDot(digits)) return null;
|
|
780
|
+
if (!/^(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/.test(digits)) return null;
|
|
781
|
+
let n = Number(digits);
|
|
782
|
+
if (!Number.isFinite(n)) return null;
|
|
783
|
+
const sci = /[eE]/.test(digits);
|
|
784
|
+
if (percent) n /= 100;
|
|
785
|
+
if (neg) n = -n;
|
|
786
|
+
const hasDot = digits.includes(".");
|
|
787
|
+
const format = currency ? hasDot ? '"$"#,##0.00' : '"$"#,##0' : percent ? hasDot ? "0.00%" : "0%" : sci ? "0.00E+00" : hasSep ? hasDot ? "#,##0.00" : "#,##0" : void 0;
|
|
788
|
+
return { kind: "number", value: n, ...format ? { format } : {} };
|
|
789
|
+
}
|
|
790
|
+
var parseDecimal = (s) => /^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/.test(s) ? Number(s) : null;
|
|
791
|
+
function parseFraction(t) {
|
|
792
|
+
const space = t.indexOf(" ");
|
|
793
|
+
if (space === -1) return null;
|
|
794
|
+
const whole = t.slice(0, space);
|
|
795
|
+
const frac = t.slice(space + 1).trim();
|
|
796
|
+
const neg = whole.startsWith("-");
|
|
797
|
+
const w = parseDecimal(whole.replace(/^-+/, ""));
|
|
798
|
+
const slash = frac.indexOf("/");
|
|
799
|
+
if (w === null || slash === -1) return null;
|
|
800
|
+
const a = parseDecimal(frac.slice(0, slash));
|
|
801
|
+
const b = parseDecimal(frac.slice(slash + 1));
|
|
802
|
+
if (a === null || b === null || b === 0 || !Number.isFinite(w)) return null;
|
|
803
|
+
const v = w + a / b;
|
|
804
|
+
return neg ? -v : v;
|
|
805
|
+
}
|
|
806
|
+
function monthFromName(s) {
|
|
807
|
+
const l = s.toLowerCase();
|
|
808
|
+
if (l.length < 3) return null;
|
|
809
|
+
const index = MONTH_NAMES.findIndex((m) => m.toLowerCase().startsWith(l));
|
|
810
|
+
return index === -1 ? null : index + 1;
|
|
811
|
+
}
|
|
812
|
+
function parseTime(input) {
|
|
813
|
+
const lower = input.trim().toLowerCase();
|
|
814
|
+
let body = lower;
|
|
815
|
+
let pm = null;
|
|
816
|
+
for (const [suffix, isPm] of [["am", false], ["a", false], ["pm", true], ["p", true]]) {
|
|
817
|
+
if (lower.endsWith(suffix)) {
|
|
818
|
+
body = lower.slice(0, -suffix.length).trim();
|
|
819
|
+
pm = isPm;
|
|
820
|
+
break;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
const parts = body.split(":");
|
|
824
|
+
if (parts.length === 1 && pm === null) return null;
|
|
825
|
+
if (parts.length > 3 || parts.some((p) => p === "")) return null;
|
|
826
|
+
const num = (p) => p === void 0 ? 0 : parseDecimal(p);
|
|
827
|
+
let h = num(parts[0]);
|
|
828
|
+
const m = num(parts[1]);
|
|
829
|
+
const s = num(parts[2]);
|
|
830
|
+
if (h === null || m === null || s === null) return null;
|
|
831
|
+
if (m >= 60 || s >= 60 || h < 0 || m < 0 || s < 0) return null;
|
|
832
|
+
if (pm !== null) {
|
|
833
|
+
if (h > 12) return null;
|
|
834
|
+
if (h === 12) h = 0;
|
|
835
|
+
if (pm) h += 12;
|
|
836
|
+
} else if (h >= 1e4) {
|
|
837
|
+
return null;
|
|
838
|
+
}
|
|
839
|
+
return { fraction: timeFraction(h, m, s), seconds: parts.length === 3, ampm: pm !== null };
|
|
840
|
+
}
|
|
841
|
+
var expandYear = (text, y) => text.length <= 2 ? y < 30 ? 2e3 + y : 1900 + y : y;
|
|
842
|
+
function validYmd(year, month, day) {
|
|
843
|
+
if (month < 1 || month > 12 || day < 1 || year < 1900 || year > 9999) return null;
|
|
844
|
+
if (day > daysInMonth1900(year, month)) return null;
|
|
845
|
+
return { year, month, day };
|
|
846
|
+
}
|
|
847
|
+
function parseDate(input) {
|
|
848
|
+
const t = input.trim().replace(/,+$/, "");
|
|
849
|
+
const num = (s) => /^[+-]?\d+$/.test(s.trim()) ? Number(s.trim()) : null;
|
|
850
|
+
const withFormat = (date, format) => date ? { date, format } : null;
|
|
851
|
+
const parts = t.split(/[/.-]/);
|
|
852
|
+
if (parts.length === 3) {
|
|
853
|
+
const [a, b, c] = parts.map((p) => p.trim());
|
|
854
|
+
if (a.length === 4) {
|
|
855
|
+
const [y2, m2, d2] = [num(a), num(b), num(c)];
|
|
856
|
+
if (y2 !== null && m2 !== null && d2 !== null) return withFormat(validYmd(y2, m2, d2), "yyyy-mm-dd");
|
|
857
|
+
}
|
|
858
|
+
{
|
|
859
|
+
const [m2, d2, y2] = [num(a), num(b), num(c)];
|
|
860
|
+
if (m2 !== null && d2 !== null && y2 !== null) return withFormat(validYmd(expandYear(c, y2), m2, d2), "m/d/yyyy");
|
|
861
|
+
}
|
|
862
|
+
const [d, m, y] = [num(a), monthFromName(b), num(c)];
|
|
863
|
+
if (d !== null && m !== null && y !== null) return withFormat(validYmd(expandYear(c, y), m, d), "d-mmm-yy");
|
|
864
|
+
}
|
|
865
|
+
if (parts.length === 2) {
|
|
866
|
+
const [a, b] = parts.map((p) => p.trim());
|
|
867
|
+
const [x, y] = [num(a), num(b)];
|
|
868
|
+
if (x !== null && y !== null) {
|
|
869
|
+
if (x >= 1 && x <= 12 && y >= 1 && y <= 31) return withFormat(validYmd(currentYear(), x, y), "d-mmm");
|
|
870
|
+
if (x >= 1 && x <= 12 && b.length === 4) return withFormat(validYmd(y, x, 1), "mmm-yy");
|
|
871
|
+
}
|
|
872
|
+
const dayA = num(a);
|
|
873
|
+
const monthB = monthFromName(b);
|
|
874
|
+
if (dayA !== null && monthB !== null) return withFormat(validYmd(currentYear(), monthB, dayA), "d-mmm");
|
|
875
|
+
const monthA = monthFromName(a);
|
|
876
|
+
const yearB = num(b);
|
|
877
|
+
if (monthA !== null && yearB !== null) return withFormat(validYmd(expandYear(b, yearB), monthA, 1), "mmm-yy");
|
|
878
|
+
}
|
|
879
|
+
const words = t.split(/[ ,]/).filter((w) => w !== "");
|
|
880
|
+
if (words.length === 3) {
|
|
881
|
+
const [w0, w1, w2] = words;
|
|
882
|
+
let [m, d, y] = [monthFromName(w0), num(w1), num(w2)];
|
|
883
|
+
if (m !== null && d !== null && y !== null) return withFormat(validYmd(expandYear(w2, y), m, d), "d-mmm-yy");
|
|
884
|
+
[d, m, y] = [num(w0), monthFromName(w1), num(w2)];
|
|
885
|
+
if (d !== null && m !== null && y !== null) return withFormat(validYmd(expandYear(w2, y), m, d), "d-mmm-yy");
|
|
886
|
+
}
|
|
887
|
+
return null;
|
|
888
|
+
}
|
|
889
|
+
function parseDateTime(t) {
|
|
890
|
+
const time = parseTime(t);
|
|
891
|
+
if (time) {
|
|
892
|
+
const format = time.fraction >= 1 ? "[h]:mm:ss" : time.seconds ? time.ampm ? "h:mm:ss AM/PM" : "h:mm:ss" : time.ampm ? "h:mm AM/PM" : "h:mm";
|
|
893
|
+
return { kind: "time", value: time.fraction, format };
|
|
894
|
+
}
|
|
895
|
+
const date = parseDate(t);
|
|
896
|
+
if (date) return { kind: "date", date: date.date, format: date.format };
|
|
897
|
+
for (let i = t.indexOf(" "); i !== -1; i = t.indexOf(" ", i + 1)) {
|
|
898
|
+
const d = parseDate(t.slice(0, i));
|
|
899
|
+
const tm = d ? parseTime(t.slice(i + 1)) : null;
|
|
900
|
+
if (d && tm && tm.fraction < 1) {
|
|
901
|
+
return { kind: "date", date: { ...d.date, time: tm.fraction }, format: "m/d/yyyy h:mm" };
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
return null;
|
|
905
|
+
}
|
|
906
|
+
|
|
568
907
|
// src/spreadsheet/formula/criteria.ts
|
|
569
908
|
function wildcardToRegExp(pattern) {
|
|
570
909
|
let source = "";
|
|
@@ -601,12 +940,17 @@ function parseCriteria(criterion) {
|
|
|
601
940
|
if (op === "<>") return (value) => !isBlank(value);
|
|
602
941
|
return () => false;
|
|
603
942
|
}
|
|
604
|
-
const
|
|
943
|
+
const parsed = parseCellInput(operand.trim());
|
|
944
|
+
const operandNumber = numericValue(operand) ?? (parsed.type === "number" ? parsed.value : null);
|
|
945
|
+
const operandDate = parsed.type === "date" ? parsed.value : null;
|
|
946
|
+
const isDateValue = (value) => typeof value === "number" || parseIsoDate(value) !== null;
|
|
605
947
|
const operandUpper = operand.trim().toUpperCase();
|
|
606
948
|
const operandBoolean = operandUpper === "TRUE" ? true : operandUpper === "FALSE" ? false : null;
|
|
607
949
|
if (op === "=" || op === "<>") {
|
|
608
950
|
let equals;
|
|
609
|
-
if (
|
|
951
|
+
if (operandDate !== null) {
|
|
952
|
+
equals = (value) => isDateValue(value) && compareValues(value, operandDate) === 0;
|
|
953
|
+
} else if (operandNumber !== null) {
|
|
610
954
|
equals = (value) => numericValue(value) === operandNumber;
|
|
611
955
|
} else if (operandBoolean !== null) {
|
|
612
956
|
equals = (value) => value === operandBoolean || typeof value === "string" && value.trim().toUpperCase() === operandUpper;
|
|
@@ -619,6 +963,9 @@ function parseCriteria(criterion) {
|
|
|
619
963
|
return op === "=" ? (value) => !isFormulaError(value) && equals(value) : (value) => !isFormulaError(value) && !equals(value);
|
|
620
964
|
}
|
|
621
965
|
const test = (cmp) => op === "<" ? cmp < 0 : op === "<=" ? cmp <= 0 : op === ">" ? cmp > 0 : cmp >= 0;
|
|
966
|
+
if (operandDate !== null) {
|
|
967
|
+
return (value) => isDateValue(value) && test(compareValues(value, operandDate));
|
|
968
|
+
}
|
|
622
969
|
if (operandNumber !== null) {
|
|
623
970
|
return (value) => {
|
|
624
971
|
const num = numericValue(value);
|
|
@@ -636,6 +983,42 @@ function parseCriteria(criterion) {
|
|
|
636
983
|
}
|
|
637
984
|
|
|
638
985
|
// src/spreadsheet/formula/format.ts
|
|
986
|
+
function formatCellDisplay(cell) {
|
|
987
|
+
if (!cell) return "";
|
|
988
|
+
if (cell.error) return cell.error;
|
|
989
|
+
const { value, numberFormat } = cell;
|
|
990
|
+
if (numberFormat && value !== "" && value !== null && value !== void 0 && typeof value !== "boolean") {
|
|
991
|
+
if (/^\[h\]/i.test(numberFormat) && typeof value === "number") return formatElapsedHours(value);
|
|
992
|
+
if (numberFormat === "# ?/?" && typeof value === "number") return formatFraction(value);
|
|
993
|
+
const formatted = formatValueWithCode(value, numberFormat);
|
|
994
|
+
if (formatted !== null) return formatted;
|
|
995
|
+
}
|
|
996
|
+
return toText(value);
|
|
997
|
+
}
|
|
998
|
+
function formatFraction(value) {
|
|
999
|
+
const sign = value < 0 ? "-" : "";
|
|
1000
|
+
const abs = Math.abs(value);
|
|
1001
|
+
let whole = Math.floor(abs);
|
|
1002
|
+
const frac = abs - whole;
|
|
1003
|
+
let best = { num: 0, den: 1, err: frac };
|
|
1004
|
+
for (let den = 2; den <= 9; den++) {
|
|
1005
|
+
const num = Math.round(frac * den);
|
|
1006
|
+
const err = Math.abs(frac - num / den);
|
|
1007
|
+
if (err < best.err - 1e-12) best = { num, den, err };
|
|
1008
|
+
}
|
|
1009
|
+
if (best.num === best.den) {
|
|
1010
|
+
whole += 1;
|
|
1011
|
+
best = { num: 0, den: 1, err: 0 };
|
|
1012
|
+
}
|
|
1013
|
+
if (best.num === 0) return `${sign}${whole}`;
|
|
1014
|
+
return `${sign}${whole === 0 ? "" : `${whole} `}${best.num}/${best.den}`;
|
|
1015
|
+
}
|
|
1016
|
+
function formatElapsedHours(days) {
|
|
1017
|
+
const total = Math.round(Math.abs(days) * 86400);
|
|
1018
|
+
const p = (n) => String(n).padStart(2, "0");
|
|
1019
|
+
const text = `${Math.floor(total / 3600)}:${p(Math.floor(total / 60) % 60)}:${p(total % 60)}`;
|
|
1020
|
+
return days < 0 ? `-${text}` : text;
|
|
1021
|
+
}
|
|
639
1022
|
function formatValueWithCode(value, format) {
|
|
640
1023
|
if (isDateFormat(format)) {
|
|
641
1024
|
const date = toDate(value);
|
|
@@ -750,7 +1133,7 @@ function splitSections(format) {
|
|
|
750
1133
|
}
|
|
751
1134
|
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
752
1135
|
var DAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
753
|
-
var
|
|
1136
|
+
var pad3 = (n) => String(n).padStart(2, "0");
|
|
754
1137
|
function formatDate(date, format) {
|
|
755
1138
|
const parts = [];
|
|
756
1139
|
for (const token of tokenize(format)) {
|
|
@@ -777,30 +1160,30 @@ function formatDate(date, format) {
|
|
|
777
1160
|
return code[0] === code[0].toLowerCase() ? text.toLowerCase() : text;
|
|
778
1161
|
}
|
|
779
1162
|
if (lower.startsWith("y")) {
|
|
780
|
-
return lower.length <= 2 ?
|
|
1163
|
+
return lower.length <= 2 ? pad3(date.getFullYear() % 100) : String(date.getFullYear());
|
|
781
1164
|
}
|
|
782
1165
|
if (lower.startsWith("d")) {
|
|
783
1166
|
if (lower.length >= 4) return DAYS[date.getDay()];
|
|
784
1167
|
if (lower.length === 3) return DAYS[date.getDay()].slice(0, 3);
|
|
785
|
-
return lower.length === 2 ?
|
|
1168
|
+
return lower.length === 2 ? pad3(date.getDate()) : String(date.getDate());
|
|
786
1169
|
}
|
|
787
1170
|
if (lower.startsWith("h")) {
|
|
788
1171
|
let hours = date.getHours();
|
|
789
1172
|
if (twelveHour) hours = hours % 12 || 12;
|
|
790
|
-
return lower.length >= 2 ?
|
|
1173
|
+
return lower.length >= 2 ? pad3(hours) : String(hours);
|
|
791
1174
|
}
|
|
792
1175
|
if (lower.startsWith("s")) {
|
|
793
|
-
return lower.length >= 2 ?
|
|
1176
|
+
return lower.length >= 2 ? pad3(date.getSeconds()) : String(date.getSeconds());
|
|
794
1177
|
}
|
|
795
1178
|
const position = codes.findIndex((c) => c.i === index);
|
|
796
1179
|
const prev = codes[position - 1]?.text.toLowerCase() ?? "";
|
|
797
1180
|
const next = codes[position + 1]?.text.toLowerCase() ?? "";
|
|
798
1181
|
if (lower.length <= 2 && (prev.startsWith("h") || next.startsWith("s"))) {
|
|
799
|
-
return lower.length === 2 ?
|
|
1182
|
+
return lower.length === 2 ? pad3(date.getMinutes()) : String(date.getMinutes());
|
|
800
1183
|
}
|
|
801
1184
|
if (lower.length >= 4) return MONTHS[date.getMonth()];
|
|
802
1185
|
if (lower.length === 3) return MONTHS[date.getMonth()].slice(0, 3);
|
|
803
|
-
return lower.length === 2 ?
|
|
1186
|
+
return lower.length === 2 ? pad3(date.getMonth() + 1) : String(date.getMonth() + 1);
|
|
804
1187
|
}).join("");
|
|
805
1188
|
}
|
|
806
1189
|
|
|
@@ -1806,7 +2189,7 @@ var TEXT_FUNCTIONS = [
|
|
|
1806
2189
|
if (isFormulaError(value)) return value;
|
|
1807
2190
|
if (typeof value === "number") return value;
|
|
1808
2191
|
if (isBlank(value)) return 0;
|
|
1809
|
-
const num = parseNumericText(toText(value));
|
|
2192
|
+
const num = parseNumericText(toText(value)) ?? parseNumberText(toText(value));
|
|
1810
2193
|
if (num === null) return ctx.argError(0, "#VALUE!", `("${toText(value)}") can't be converted to a number.`);
|
|
1811
2194
|
return num;
|
|
1812
2195
|
}
|
|
@@ -3207,12 +3590,22 @@ export {
|
|
|
3207
3590
|
parseRange,
|
|
3208
3591
|
FormulaParser,
|
|
3209
3592
|
parseFormula,
|
|
3593
|
+
serialFromYmd,
|
|
3594
|
+
parseCellInput,
|
|
3595
|
+
parseNumberText,
|
|
3210
3596
|
FORMULA_ERRORS,
|
|
3211
3597
|
isFormulaError,
|
|
3598
|
+
numberToText,
|
|
3599
|
+
numericValue,
|
|
3600
|
+
compareNumbers,
|
|
3601
|
+
compareValues,
|
|
3602
|
+
sortCompareValues,
|
|
3212
3603
|
colNameToIndex,
|
|
3213
3604
|
indexToColName,
|
|
3605
|
+
parseIsoDate,
|
|
3214
3606
|
wildcardToRegExp,
|
|
3215
3607
|
parseCriteria,
|
|
3608
|
+
formatCellDisplay,
|
|
3216
3609
|
formatValueWithCode,
|
|
3217
3610
|
registerFormulaFunction,
|
|
3218
3611
|
unregisterFormulaFunction,
|
|
@@ -3227,4 +3620,4 @@ export {
|
|
|
3227
3620
|
MAX_FORMULA_ARRAY_SIZE,
|
|
3228
3621
|
FormulaEvaluator
|
|
3229
3622
|
};
|
|
3230
|
-
//# sourceMappingURL=chunk-
|
|
3623
|
+
//# sourceMappingURL=chunk-QBJ22YZR.js.map
|