ooxml-core 1.2.0 → 1.2.1
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/{PptxHandler-SJTINPU4.mjs → PptxHandler-VQQS4VS6.mjs} +2 -2
- package/dist/automation/index.cjs +1059 -328
- package/dist/automation/index.mjs +1059 -328
- package/dist/chart/bar-cluster-geometry.d.ts +6 -0
- package/dist/chart/bar-cluster-geometry.d.ts.map +1 -1
- package/dist/chart/index.cjs +5 -2
- package/dist/chart/index.mjs +5 -3
- package/dist/chart/render/chart-spacing.d.ts.map +1 -1
- package/dist/{chunk-TEOAOAIF.mjs → chunk-5U27IVB7.mjs} +3 -3
- package/dist/{chunk-VYTA2OUN.mjs → chunk-5VLNF4OX.mjs} +1 -1
- package/dist/{chunk-CQQAPUAG.mjs → chunk-V2BIGIH4.mjs} +11 -9
- package/dist/{chunk-FI4RSJ24.mjs → chunk-XBNSBDNT.mjs} +1 -1
- package/dist/{chunk-XCZ7U3GZ.mjs → chunk-XSFHGZFH.mjs} +11 -9
- package/dist/docx/index.cjs +4 -2
- package/dist/docx/index.mjs +4 -2
- package/dist/docx/layout/index.cjs +4 -2
- package/dist/docx/layout/index.mjs +4 -2
- package/dist/docx/ui/index.cjs +4 -2
- package/dist/docx/ui/index.mjs +4 -2
- package/dist/index.cjs +5 -2
- package/dist/index.mjs +5 -2
- package/dist/pptx/automation/index.cjs +27 -17
- package/dist/pptx/automation/index.mjs +5 -5
- package/dist/pptx/chunks/index-EZJZ7USt.d.ts.map +1 -1
- package/dist/pptx/cli/index.cjs +27 -17
- package/dist/pptx/cli/index.mjs +4 -4
- package/dist/pptx/converter/index.mjs +2 -2
- package/dist/pptx/index.cjs +27 -17
- package/dist/pptx/index.mjs +5 -5
- package/dist/teams/index.cjs +157 -82
- package/dist/teams/index.mjs +157 -82
- package/dist/xlsx/edit/context.d.ts +3 -1
- package/dist/xlsx/edit/context.d.ts.map +1 -1
- package/dist/xlsx/edit/history.d.ts +18 -0
- package/dist/xlsx/edit/history.d.ts.map +1 -1
- package/dist/xlsx/edit/session-calc.d.ts +30 -8
- package/dist/xlsx/edit/session-calc.d.ts.map +1 -1
- package/dist/xlsx/edit/session.d.ts.map +1 -1
- package/dist/xlsx/edit/sheets.d.ts.map +1 -1
- package/dist/xlsx/edit/types.d.ts +23 -3
- package/dist/xlsx/edit/types.d.ts.map +1 -1
- package/dist/xlsx/formula/engine-core.d.ts.map +1 -1
- package/dist/xlsx/formula/engine-host.d.ts +6 -2
- package/dist/xlsx/formula/engine-host.d.ts.map +1 -1
- package/dist/xlsx/formula/engine-prepare.d.ts +33 -0
- package/dist/xlsx/formula/engine-prepare.d.ts.map +1 -0
- package/dist/xlsx/formula/engine-structure.d.ts +40 -0
- package/dist/xlsx/formula/engine-structure.d.ts.map +1 -0
- package/dist/xlsx/formula/engine-types.d.ts +26 -0
- package/dist/xlsx/formula/engine-types.d.ts.map +1 -1
- package/dist/xlsx/formula/engine.d.ts.map +1 -1
- package/dist/xlsx/formula/formula-shape.d.ts +28 -0
- package/dist/xlsx/formula/formula-shape.d.ts.map +1 -0
- package/dist/xlsx/formula/graph-index.d.ts +3 -1
- package/dist/xlsx/formula/graph-index.d.ts.map +1 -1
- package/dist/xlsx/formula/graph.d.ts +5 -0
- package/dist/xlsx/formula/graph.d.ts.map +1 -1
- package/dist/xlsx/formula/lexemes.d.ts.map +1 -1
- package/dist/xlsx/formula/parse-cache.d.ts +9 -0
- package/dist/xlsx/formula/parse-cache.d.ts.map +1 -0
- package/dist/xlsx/formula/parser.d.ts +3 -0
- package/dist/xlsx/formula/parser.d.ts.map +1 -1
- package/dist/xlsx/formula/ref-text.d.ts +14 -0
- package/dist/xlsx/formula/ref-text.d.ts.map +1 -0
- package/dist/xlsx/formula/references.d.ts.map +1 -1
- package/dist/xlsx/formula/shift-formula.d.ts +19 -0
- package/dist/xlsx/formula/shift-formula.d.ts.map +1 -0
- package/dist/xlsx/formula/shift-graph.d.ts +42 -0
- package/dist/xlsx/formula/shift-graph.d.ts.map +1 -0
- package/dist/xlsx/formula/transform.d.ts +2 -23
- package/dist/xlsx/formula/transform.d.ts.map +1 -1
- package/dist/xlsx/index.cjs +1069 -329
- package/dist/xlsx/index.mjs +1069 -330
- package/dist/xlsx/layout/index.d.ts +1 -1
- package/dist/xlsx/layout/index.d.ts.map +1 -1
- package/dist/xlsx/layout/sheet-queries.d.ts +7 -0
- package/dist/xlsx/layout/sheet-queries.d.ts.map +1 -1
- package/dist/xlsx/load/index.cjs +152 -90
- package/dist/xlsx/load/index.mjs +152 -90
- package/dist/xlsx/ui/index.cjs +1071 -340
- package/dist/xlsx/ui/index.mjs +1071 -340
- package/package.json +1 -1
package/dist/xlsx/ui/index.cjs
CHANGED
|
@@ -2042,7 +2042,7 @@ var NAME_RE = /^[A-Za-z_\\\u00A1-\uFFFF][A-Za-z0-9_.?\\\u00A1-\uFFFF]*/;
|
|
|
2042
2042
|
var CELL_RE = /^(\$?)([A-Za-z]{1,3})(\$?)(\d{1,7})/;
|
|
2043
2043
|
var COLS_RE = /^(\$?)([A-Za-z]{1,3}):(\$?)([A-Za-z]{1,3})/;
|
|
2044
2044
|
var ROWS_RE = /^(\$?)(\d{1,7}):(\$?)(\d{1,7})/;
|
|
2045
|
-
var NUMBER_RE2 = /^(?:\d
|
|
2045
|
+
var NUMBER_RE2 = /^(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?/;
|
|
2046
2046
|
var sticky = (re) => new RegExp(re.source.replace(/^\^/, ""), "y");
|
|
2047
2047
|
var CELL_AT = sticky(CELL_RE);
|
|
2048
2048
|
var COLS_AT = sticky(COLS_RE);
|
|
@@ -2414,7 +2414,9 @@ var PREC_INTERSECT = 9;
|
|
|
2414
2414
|
var PREC_RANGE = 10;
|
|
2415
2415
|
var OPERAND_START = /* @__PURE__ */ new Set(["ref", "name", "func", "open", "structured"]);
|
|
2416
2416
|
function parseFormula(formula) {
|
|
2417
|
-
|
|
2417
|
+
return parseTokens(tokenize(formula));
|
|
2418
|
+
}
|
|
2419
|
+
function parseTokens(all2) {
|
|
2418
2420
|
const tokens = [];
|
|
2419
2421
|
const wsBefore = [];
|
|
2420
2422
|
let sawWs = false;
|
|
@@ -2699,6 +2701,222 @@ function localDateToSerial(date, date1904 = date1904Mode) {
|
|
|
2699
2701
|
return base + (utc - dayStart) / DAY_MS;
|
|
2700
2702
|
}
|
|
2701
2703
|
|
|
2704
|
+
// xlsx/formula/area-index.ts
|
|
2705
|
+
var BUCKET_WIDTH = 64;
|
|
2706
|
+
var CHUNK_SHIFT = 6;
|
|
2707
|
+
var CHUNKS = 64;
|
|
2708
|
+
function push(map, key, value2) {
|
|
2709
|
+
const list = map.get(key);
|
|
2710
|
+
if (list) list.push(value2);
|
|
2711
|
+
else map.set(key, [value2]);
|
|
2712
|
+
}
|
|
2713
|
+
function inner(map, sheet) {
|
|
2714
|
+
let found = map.get(sheet);
|
|
2715
|
+
if (!found) map.set(sheet, found = /* @__PURE__ */ new Map());
|
|
2716
|
+
return found;
|
|
2717
|
+
}
|
|
2718
|
+
var AreaIndex = class {
|
|
2719
|
+
cells = /* @__PURE__ */ new Map();
|
|
2720
|
+
chunked = /* @__PURE__ */ new Map();
|
|
2721
|
+
tall = /* @__PURE__ */ new Map();
|
|
2722
|
+
wide = /* @__PURE__ */ new Map();
|
|
2723
|
+
add(area, node) {
|
|
2724
|
+
const { start, end } = area.range;
|
|
2725
|
+
if (start.row === end.row && end.col - start.col + 1 <= BUCKET_WIDTH) {
|
|
2726
|
+
const cells = inner(this.cells, area.sheet);
|
|
2727
|
+
for (let col = start.col; col <= end.col; col++) push(cells, cellKey(start.row, col), node);
|
|
2728
|
+
return;
|
|
2729
|
+
}
|
|
2730
|
+
const entry = { range: area.range, node };
|
|
2731
|
+
if (end.col - start.col + 1 > BUCKET_WIDTH) {
|
|
2732
|
+
const list = this.wide.get(area.sheet);
|
|
2733
|
+
if (list) list.push(entry);
|
|
2734
|
+
else this.wide.set(area.sheet, [entry]);
|
|
2735
|
+
return;
|
|
2736
|
+
}
|
|
2737
|
+
const first2 = start.row >> CHUNK_SHIFT;
|
|
2738
|
+
const last = end.row >> CHUNK_SHIFT;
|
|
2739
|
+
if (last - first2 + 1 > CHUNKS) {
|
|
2740
|
+
const cols2 = inner(this.tall, area.sheet);
|
|
2741
|
+
for (let c = start.col; c <= end.col; c++) push(cols2, c, entry);
|
|
2742
|
+
return;
|
|
2743
|
+
}
|
|
2744
|
+
const cols = inner(this.chunked, area.sheet);
|
|
2745
|
+
for (let c = start.col; c <= end.col; c++) {
|
|
2746
|
+
let chunks = cols.get(c);
|
|
2747
|
+
if (!chunks) cols.set(c, chunks = /* @__PURE__ */ new Map());
|
|
2748
|
+
for (let k = first2; k <= last; k++) push(chunks, k, entry);
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
/** Items whose areas intersect `range` on `sheet` (each once). */
|
|
2752
|
+
dependents(sheet, range2, out) {
|
|
2753
|
+
const found = out instanceof Set ? out : /* @__PURE__ */ new Set();
|
|
2754
|
+
this.collect(sheet, range2, found);
|
|
2755
|
+
if (Array.isArray(out)) for (const node of found) out.push(node);
|
|
2756
|
+
}
|
|
2757
|
+
collect(sheet, range2, out) {
|
|
2758
|
+
const { start, end } = range2;
|
|
2759
|
+
const check3 = (list) => {
|
|
2760
|
+
if (list) {
|
|
2761
|
+
for (const entry of list) if (rangesIntersect(entry.range, range2)) out.add(entry.node);
|
|
2762
|
+
}
|
|
2763
|
+
};
|
|
2764
|
+
const cells = this.cells.get(sheet);
|
|
2765
|
+
if (cells) {
|
|
2766
|
+
const size = (end.row - start.row + 1) * (end.col - start.col + 1);
|
|
2767
|
+
if (size <= 4096) {
|
|
2768
|
+
for (let r = start.row; r <= end.row; r++) {
|
|
2769
|
+
for (let c = start.col; c <= end.col; c++) {
|
|
2770
|
+
const list = cells.get(cellKey(r, c));
|
|
2771
|
+
if (list) for (const node of list) out.add(node);
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
} else {
|
|
2775
|
+
for (const [key, list] of cells) {
|
|
2776
|
+
const { row: row2, col } = keyToAddress(key);
|
|
2777
|
+
if (row2 >= start.row && row2 <= end.row && col >= start.col && col <= end.col)
|
|
2778
|
+
for (const node of list) out.add(node);
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
const columns = (map, visit2) => {
|
|
2783
|
+
if (!map) return;
|
|
2784
|
+
if (end.col - start.col + 1 <= map.size) {
|
|
2785
|
+
for (let c = start.col; c <= end.col; c++) if (map.has(c)) visit2(c);
|
|
2786
|
+
} else for (const c of map.keys()) if (c >= start.col && c <= end.col) visit2(c);
|
|
2787
|
+
};
|
|
2788
|
+
const chunked = this.chunked.get(sheet);
|
|
2789
|
+
const first2 = start.row >> CHUNK_SHIFT;
|
|
2790
|
+
const last = end.row >> CHUNK_SHIFT;
|
|
2791
|
+
columns(chunked, (c) => {
|
|
2792
|
+
const chunks = chunked?.get(c);
|
|
2793
|
+
if (last - first2 + 1 <= chunks.size) {
|
|
2794
|
+
for (let k = first2; k <= last; k++) check3(chunks.get(k));
|
|
2795
|
+
} else for (const [k, list] of chunks) if (k >= first2 && k <= last) check3(list);
|
|
2796
|
+
});
|
|
2797
|
+
const tall = this.tall.get(sheet);
|
|
2798
|
+
columns(tall, (c) => check3(tall?.get(c)));
|
|
2799
|
+
check3(this.wide.get(sheet));
|
|
2800
|
+
}
|
|
2801
|
+
};
|
|
2802
|
+
|
|
2803
|
+
// xlsx/formula/graph-index.ts
|
|
2804
|
+
var ColumnIndex = class {
|
|
2805
|
+
sheets = /* @__PURE__ */ new Map();
|
|
2806
|
+
constructor(nodes) {
|
|
2807
|
+
for (const node of nodes) {
|
|
2808
|
+
let cols = this.sheets.get(node.sheet);
|
|
2809
|
+
if (!cols) this.sheets.set(node.sheet, cols = /* @__PURE__ */ new Map());
|
|
2810
|
+
let list = cols.get(node.col);
|
|
2811
|
+
if (!list) cols.set(node.col, list = []);
|
|
2812
|
+
list.push(node);
|
|
2813
|
+
}
|
|
2814
|
+
for (const cols of this.sheets.values())
|
|
2815
|
+
for (const list of cols.values()) list.sort((a, b) => a.row - b.row);
|
|
2816
|
+
}
|
|
2817
|
+
nodesIn(area, out) {
|
|
2818
|
+
const cols = this.sheets.get(area.sheet);
|
|
2819
|
+
if (!cols) return;
|
|
2820
|
+
const { start, end } = area.range;
|
|
2821
|
+
const width = end.col - start.col + 1;
|
|
2822
|
+
const scan2 = (list) => {
|
|
2823
|
+
let lo = 0;
|
|
2824
|
+
let hi = list.length;
|
|
2825
|
+
while (lo < hi) {
|
|
2826
|
+
const mid = lo + hi >> 1;
|
|
2827
|
+
if (list[mid].row < start.row) lo = mid + 1;
|
|
2828
|
+
else hi = mid;
|
|
2829
|
+
}
|
|
2830
|
+
for (let i2 = lo; i2 < list.length; i2++) {
|
|
2831
|
+
const node = list[i2];
|
|
2832
|
+
if (node.row > end.row) break;
|
|
2833
|
+
out.push(node);
|
|
2834
|
+
}
|
|
2835
|
+
};
|
|
2836
|
+
if (width <= cols.size) {
|
|
2837
|
+
for (let c = start.col; c <= end.col; c++) {
|
|
2838
|
+
const list = cols.get(c);
|
|
2839
|
+
if (list) scan2(list);
|
|
2840
|
+
}
|
|
2841
|
+
} else {
|
|
2842
|
+
for (const [c, list] of cols) if (c >= start.col && c <= end.col) scan2(list);
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
};
|
|
2846
|
+
var ReverseIndex = class extends AreaIndex {
|
|
2847
|
+
constructor(nodes = []) {
|
|
2848
|
+
super();
|
|
2849
|
+
for (const node of nodes) this.addNode(node);
|
|
2850
|
+
}
|
|
2851
|
+
/** Indexes one more formula's precedents. */
|
|
2852
|
+
addNode(node) {
|
|
2853
|
+
for (const dep of node.deps) this.add(dep, node);
|
|
2854
|
+
for (const dep of node.dynamicDeps) this.add(dep, node);
|
|
2855
|
+
}
|
|
2856
|
+
};
|
|
2857
|
+
|
|
2858
|
+
// xlsx/formula/engine-prepare.ts
|
|
2859
|
+
var CHECK_EVERY = 32;
|
|
2860
|
+
var GraphPreparation = class {
|
|
2861
|
+
constructor(workbook, create) {
|
|
2862
|
+
this.workbook = workbook;
|
|
2863
|
+
this.create = create;
|
|
2864
|
+
}
|
|
2865
|
+
workbook;
|
|
2866
|
+
create;
|
|
2867
|
+
reverse = new ReverseIndex();
|
|
2868
|
+
formulas = { dynamic: [], unvalued: [] };
|
|
2869
|
+
sheet = 0;
|
|
2870
|
+
rows;
|
|
2871
|
+
row = 0;
|
|
2872
|
+
cells;
|
|
2873
|
+
finished = false;
|
|
2874
|
+
/**
|
|
2875
|
+
* Adds formulas to the graph until `timeRemaining` (milliseconds, as an idle deadline reports
|
|
2876
|
+
* them) reaches zero, or until every formula is in. Returns true when the graph is complete.
|
|
2877
|
+
*/
|
|
2878
|
+
run(timeRemaining) {
|
|
2879
|
+
let visited = 0;
|
|
2880
|
+
while (!this.finished) {
|
|
2881
|
+
const cells = this.cells ?? this.nextRow();
|
|
2882
|
+
if (!cells) continue;
|
|
2883
|
+
const next = cells.next();
|
|
2884
|
+
if (next.done) {
|
|
2885
|
+
this.cells = void 0;
|
|
2886
|
+
continue;
|
|
2887
|
+
}
|
|
2888
|
+
const [col, cell] = next.value;
|
|
2889
|
+
if (cell.formula) this.add(this.create(this.sheet, this.row, col, cell), cell);
|
|
2890
|
+
if (timeRemaining && ++visited % CHECK_EVERY === 0 && timeRemaining() <= 0) break;
|
|
2891
|
+
}
|
|
2892
|
+
return this.finished;
|
|
2893
|
+
}
|
|
2894
|
+
add(node, cell) {
|
|
2895
|
+
this.reverse.addNode(node);
|
|
2896
|
+
if (!node.legacy && !node.arrayRange) this.formulas.dynamic.push(node);
|
|
2897
|
+
if (cell.value === null && !node.keepCached) this.formulas.unvalued.push(node);
|
|
2898
|
+
}
|
|
2899
|
+
/** Moves to the next stored row (and sheet), or marks the walk finished. */
|
|
2900
|
+
nextRow() {
|
|
2901
|
+
for (; ; ) {
|
|
2902
|
+
const sheet = this.workbook.sheets[this.sheet];
|
|
2903
|
+
if (!sheet) {
|
|
2904
|
+
this.finished = true;
|
|
2905
|
+
return void 0;
|
|
2906
|
+
}
|
|
2907
|
+
this.rows ??= sheet.rows.entries();
|
|
2908
|
+
const next = this.rows.next();
|
|
2909
|
+
if (!next.done) {
|
|
2910
|
+
this.row = next.value[0];
|
|
2911
|
+
this.cells = next.value[1].entries();
|
|
2912
|
+
return this.cells;
|
|
2913
|
+
}
|
|
2914
|
+
this.rows = void 0;
|
|
2915
|
+
this.sheet++;
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
};
|
|
2919
|
+
|
|
2702
2920
|
// xlsx/formula/text-number.ts
|
|
2703
2921
|
var MONTHS2 = [
|
|
2704
2922
|
"jan",
|
|
@@ -5833,8 +6051,10 @@ var FINANCIAL_FUNCTIONS = [
|
|
|
5833
6051
|
|
|
5834
6052
|
// xlsx/formula/references.ts
|
|
5835
6053
|
function sheetIndex(host, name) {
|
|
6054
|
+
const sheets = host.workbook.sheets;
|
|
6055
|
+
for (let i2 = 0; i2 < sheets.length; i2++) if (sheets[i2]?.name === name) return i2;
|
|
5836
6056
|
const lower2 = name.toLowerCase();
|
|
5837
|
-
return
|
|
6057
|
+
return sheets.findIndex((sheet) => sheet.name.toLowerCase() === lower2);
|
|
5838
6058
|
}
|
|
5839
6059
|
function prefixSheets(host, prefix, current) {
|
|
5840
6060
|
if (!prefix) return [current];
|
|
@@ -7404,9 +7624,9 @@ function readBlock(ctx, area, rows2, cols) {
|
|
|
7404
7624
|
if (host.readBlock) return host.readBlock(area.sheet, range2);
|
|
7405
7625
|
return Matrix.build(rows2, cols, (r, c) => ctx.readCell(area.sheet, row2 + r, col + c));
|
|
7406
7626
|
}
|
|
7407
|
-
function shapedMatrices(ctx, values2,
|
|
7627
|
+
function shapedMatrices(ctx, values2, sameShape2) {
|
|
7408
7628
|
let { rows: rows2, cols } = shapeOf(values2[0] ?? null);
|
|
7409
|
-
if (
|
|
7629
|
+
if (sameShape2) {
|
|
7410
7630
|
for (const value2 of values2) {
|
|
7411
7631
|
const shape2 = shapeOf(value2);
|
|
7412
7632
|
if (shape2.rows !== rows2 || shape2.cols !== cols) fail(ERR.VALUE);
|
|
@@ -7432,12 +7652,12 @@ function shapedMatrices(ctx, values2, sameShape) {
|
|
|
7432
7652
|
});
|
|
7433
7653
|
return { matrices, total: total2, block: rows2 * cols };
|
|
7434
7654
|
}
|
|
7435
|
-
function matchingCells(ctx, pairs, target2,
|
|
7655
|
+
function matchingCells(ctx, pairs, target2, sameShape2) {
|
|
7436
7656
|
const ranges = pairs.map((p) => p.range);
|
|
7437
7657
|
const { matrices, total: total2, block } = shapedMatrices(
|
|
7438
7658
|
ctx,
|
|
7439
7659
|
target2 === void 0 ? ranges : [...ranges, target2],
|
|
7440
|
-
|
|
7660
|
+
sameShape2
|
|
7441
7661
|
);
|
|
7442
7662
|
const tests = pairs.map((p) => makeCriteria(scalar(p.criteria)));
|
|
7443
7663
|
const values2 = matrices[matrices.length - 1];
|
|
@@ -7476,7 +7696,7 @@ function indexedCandidates(pairs, matrices) {
|
|
|
7476
7696
|
}
|
|
7477
7697
|
return void 0;
|
|
7478
7698
|
}
|
|
7479
|
-
var matchingValues = (ctx, pairs, target2,
|
|
7699
|
+
var matchingValues = (ctx, pairs, target2, sameShape2) => matchingCells(ctx, pairs, target2, sameShape2).values;
|
|
7480
7700
|
function criteriaPairs(args, from) {
|
|
7481
7701
|
if ((args.length - from) % 2 !== 0) fail(ERR.VALUE);
|
|
7482
7702
|
const pairs = [];
|
|
@@ -11370,7 +11590,7 @@ var REFERENCE_ARGUMENT = /* @__PURE__ */ new Set([
|
|
|
11370
11590
|
"AREAS",
|
|
11371
11591
|
"ISREF"
|
|
11372
11592
|
]);
|
|
11373
|
-
var
|
|
11593
|
+
var push2 = (c, area) => {
|
|
11374
11594
|
(c.dynamic > 0 ? c.dynamicDeps : c.deps).push(area);
|
|
11375
11595
|
};
|
|
11376
11596
|
function spans(areas) {
|
|
@@ -11396,7 +11616,7 @@ function visit(node, c) {
|
|
|
11396
11616
|
if (!sheets) return;
|
|
11397
11617
|
const range2 = specRange(node.ref);
|
|
11398
11618
|
const target2 = node.spill ? { start: range2.start, end: { ...range2.start } } : range2;
|
|
11399
|
-
for (const sheet of sheets)
|
|
11619
|
+
for (const sheet of sheets) push2(c, { sheet, range: target2 });
|
|
11400
11620
|
return;
|
|
11401
11621
|
}
|
|
11402
11622
|
case "name": {
|
|
@@ -11470,7 +11690,7 @@ function visitBinary(node, c) {
|
|
|
11470
11690
|
const list = c.dynamic > 0 ? c.dynamicDeps : c.deps;
|
|
11471
11691
|
const l = list[list.length - 2];
|
|
11472
11692
|
const r = list[list.length - 1];
|
|
11473
|
-
if (l && r && l.sheet === r.sheet)
|
|
11693
|
+
if (l && r && l.sheet === r.sheet) push2(c, spans([l, r])[0]);
|
|
11474
11694
|
continue;
|
|
11475
11695
|
}
|
|
11476
11696
|
const mentioned = [...c.deps.slice(staticStart), ...c.dynamicDeps.slice(dynamicStart)];
|
|
@@ -11486,7 +11706,7 @@ function addStructured(ref, c) {
|
|
|
11486
11706
|
sheet: c.sheet,
|
|
11487
11707
|
row: c.row,
|
|
11488
11708
|
col: c.col});
|
|
11489
|
-
if (value2 instanceof RefValue) for (const area of value2.areas)
|
|
11709
|
+
if (value2 instanceof RefValue) for (const area of value2.areas) push2(c, area);
|
|
11490
11710
|
}
|
|
11491
11711
|
function analyze(ast, host, sheet, row2, col) {
|
|
11492
11712
|
const c = {
|
|
@@ -11510,171 +11730,207 @@ function analyze(ast, host, sheet, row2, col) {
|
|
|
11510
11730
|
};
|
|
11511
11731
|
}
|
|
11512
11732
|
|
|
11513
|
-
// xlsx/formula/
|
|
11514
|
-
var
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
|
|
11520
|
-
|
|
11733
|
+
// xlsx/formula/formula-shape.ts
|
|
11734
|
+
var isDigit4 = (code) => code >= 48 && code <= 57;
|
|
11735
|
+
function formulaShape(formula) {
|
|
11736
|
+
const starts = [];
|
|
11737
|
+
const ends = [];
|
|
11738
|
+
let hash = 2166136261;
|
|
11739
|
+
for (let i2 = 0; i2 < formula.length; i2++) {
|
|
11740
|
+
let code = formula.charCodeAt(i2);
|
|
11741
|
+
if (isDigit4(code)) {
|
|
11742
|
+
let j = i2 + 1;
|
|
11743
|
+
while (j < formula.length && isDigit4(formula.charCodeAt(j))) j++;
|
|
11744
|
+
starts.push(i2);
|
|
11745
|
+
ends.push(j);
|
|
11746
|
+
i2 = j - 1;
|
|
11747
|
+
code = 0;
|
|
11748
|
+
}
|
|
11749
|
+
hash = Math.imul(hash ^ code, 16777619);
|
|
11750
|
+
}
|
|
11751
|
+
return { hash: hash >>> 0, starts, ends };
|
|
11521
11752
|
}
|
|
11522
|
-
function
|
|
11523
|
-
let
|
|
11524
|
-
|
|
11525
|
-
return
|
|
11753
|
+
function sameText(a, from, b, at, length) {
|
|
11754
|
+
for (let k = 0; k < length; k++)
|
|
11755
|
+
if (a.charCodeAt(from + k) !== b.charCodeAt(at + k)) return false;
|
|
11756
|
+
return true;
|
|
11526
11757
|
}
|
|
11527
|
-
|
|
11528
|
-
|
|
11529
|
-
|
|
11530
|
-
|
|
11531
|
-
|
|
11532
|
-
|
|
11533
|
-
const
|
|
11534
|
-
|
|
11535
|
-
|
|
11536
|
-
|
|
11537
|
-
|
|
11758
|
+
function sameShape(a, as, b, bs) {
|
|
11759
|
+
const runs = as.starts.length;
|
|
11760
|
+
if (runs !== bs.starts.length) return false;
|
|
11761
|
+
let fromA = 0;
|
|
11762
|
+
let fromB = 0;
|
|
11763
|
+
for (let i2 = 0; i2 <= runs; i2++) {
|
|
11764
|
+
const toA = i2 < runs ? as.starts[i2] : a.length;
|
|
11765
|
+
const toB = i2 < runs ? bs.starts[i2] : b.length;
|
|
11766
|
+
if (toA - fromA !== toB - fromB || !sameText(a, fromA, b, fromB, toA - fromA)) return false;
|
|
11767
|
+
fromA = as.ends[i2] ?? 0;
|
|
11768
|
+
fromB = bs.ends[i2] ?? 0;
|
|
11769
|
+
}
|
|
11770
|
+
return true;
|
|
11771
|
+
}
|
|
11772
|
+
function makeTemplate(formula, shape2) {
|
|
11773
|
+
let tokens;
|
|
11774
|
+
let ast;
|
|
11775
|
+
try {
|
|
11776
|
+
tokens = tokenize(formula);
|
|
11777
|
+
ast = parseTokens(tokens);
|
|
11778
|
+
} catch (e) {
|
|
11779
|
+
if (e instanceof RangeError) return new FormulaError(e.message, -1, "#VALUE!");
|
|
11780
|
+
if (e instanceof FormulaError) return e;
|
|
11781
|
+
throw e;
|
|
11782
|
+
}
|
|
11783
|
+
const { starts } = shape2;
|
|
11784
|
+
const slotted = starts.map(() => false);
|
|
11785
|
+
const refs = /* @__PURE__ */ new Map();
|
|
11786
|
+
let run = 0;
|
|
11787
|
+
for (const token of tokens) {
|
|
11788
|
+
const end = token.start + token.text.length;
|
|
11789
|
+
const first2 = run;
|
|
11790
|
+
while (run < starts.length && starts[run] < end) run++;
|
|
11791
|
+
const ref = token.kind === "ref" ? token.ref : void 0;
|
|
11792
|
+
if (!ref || ref.kind === "cols") continue;
|
|
11793
|
+
const count2 = ref.kind === "cell" ? 1 : 2;
|
|
11794
|
+
if (run - first2 < count2) continue;
|
|
11795
|
+
const at = run - count2;
|
|
11796
|
+
const indexes2 = count2 === 1 ? [at] : [at, at + 1];
|
|
11797
|
+
if (indexes2.some((i2) => formula.charCodeAt(starts[i2]) === 48)) continue;
|
|
11798
|
+
for (const i2 of indexes2) slotted[i2] = true;
|
|
11799
|
+
refs.set(ref, count2 === 1 ? { start: at } : { start: at, end: at + 1 });
|
|
11800
|
+
}
|
|
11801
|
+
return { formula, shape: shape2, ast, slotted, refs };
|
|
11802
|
+
}
|
|
11803
|
+
function rowsFor(t, formula, shape2) {
|
|
11804
|
+
if (!sameShape(t.formula, t.shape, formula, shape2)) return void 0;
|
|
11805
|
+
const rows2 = [];
|
|
11806
|
+
for (let i2 = 0; i2 < shape2.starts.length; i2++) {
|
|
11807
|
+
const start = shape2.starts[i2];
|
|
11808
|
+
const length = shape2.ends[i2] - start;
|
|
11809
|
+
if (!t.slotted[i2]) {
|
|
11810
|
+
const own = t.shape.starts[i2];
|
|
11811
|
+
if (t.shape.ends[i2] - own !== length) return void 0;
|
|
11812
|
+
if (!sameText(t.formula, own, formula, start, length)) return void 0;
|
|
11813
|
+
rows2.push(-1);
|
|
11814
|
+
continue;
|
|
11538
11815
|
}
|
|
11539
|
-
|
|
11540
|
-
|
|
11541
|
-
|
|
11542
|
-
|
|
11543
|
-
|
|
11544
|
-
|
|
11816
|
+
if (length > 7 || formula.charCodeAt(start) === 48) return void 0;
|
|
11817
|
+
let row2 = 0;
|
|
11818
|
+
for (let k = start; k < start + length; k++) row2 = row2 * 10 + formula.charCodeAt(k) - 48;
|
|
11819
|
+
if (row2 < 1 || row2 > MAX_ROW + 1) return void 0;
|
|
11820
|
+
rows2.push(row2 - 1);
|
|
11821
|
+
}
|
|
11822
|
+
return rows2;
|
|
11823
|
+
}
|
|
11824
|
+
function shiftSpec(spec2, slots, rows2) {
|
|
11825
|
+
const startRow = rows2[slots.start];
|
|
11826
|
+
const endRow = slots.end === void 0 ? startRow : rows2[slots.end];
|
|
11827
|
+
if (startRow === spec2.start.row && endRow === spec2.end.row) return spec2;
|
|
11828
|
+
const { start: from, end: to } = spec2;
|
|
11829
|
+
const start = { row: startRow, col: from.col, rowAbs: from.rowAbs, colAbs: from.colAbs };
|
|
11830
|
+
if (slots.end === void 0) return { kind: spec2.kind, start, end: start };
|
|
11831
|
+
const end = { row: endRow, col: to.col, rowAbs: to.rowAbs, colAbs: to.colAbs };
|
|
11832
|
+
return { kind: spec2.kind, start, end };
|
|
11833
|
+
}
|
|
11834
|
+
function copyTree(node, t, rows2) {
|
|
11835
|
+
switch (node.type) {
|
|
11836
|
+
case "ref": {
|
|
11837
|
+
const slots = node.ref ? t.refs.get(node.ref) : void 0;
|
|
11838
|
+
if (!slots || !node.ref) return node;
|
|
11839
|
+
const ref = shiftSpec(node.ref, slots, rows2);
|
|
11840
|
+
if (ref === node.ref) return node;
|
|
11841
|
+
const copy2 = { type: "ref" };
|
|
11842
|
+
if (node.prefix) copy2.prefix = node.prefix;
|
|
11843
|
+
copy2.ref = ref;
|
|
11844
|
+
if (node.spill) copy2.spill = true;
|
|
11845
|
+
return copy2;
|
|
11545
11846
|
}
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11551
|
-
return;
|
|
11847
|
+
case "unary":
|
|
11848
|
+
case "percent": {
|
|
11849
|
+
const operand4 = copyTree(node.operand, t, rows2);
|
|
11850
|
+
if (operand4 === node.operand) return node;
|
|
11851
|
+
return node.type === "unary" ? { type: "unary", op: node.op, operand: operand4 } : { type: "percent", operand: operand4 };
|
|
11552
11852
|
}
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
if (
|
|
11557
|
-
|
|
11853
|
+
case "binary": {
|
|
11854
|
+
const left2 = copyTree(node.left, t, rows2);
|
|
11855
|
+
const right2 = copyTree(node.right, t, rows2);
|
|
11856
|
+
if (left2 === node.left && right2 === node.right) return node;
|
|
11857
|
+
return { type: "binary", op: node.op, left: left2, right: right2 };
|
|
11858
|
+
}
|
|
11859
|
+
case "call": {
|
|
11860
|
+
const args = copyAll(node.args, t, rows2);
|
|
11861
|
+
if (args === node.args) return node;
|
|
11862
|
+
return { type: "call", name: node.name, rawName: node.rawName, args };
|
|
11558
11863
|
}
|
|
11864
|
+
case "invoke": {
|
|
11865
|
+
const callee = copyTree(node.callee, t, rows2);
|
|
11866
|
+
const args = copyAll(node.args, t, rows2);
|
|
11867
|
+
if (callee === node.callee && args === node.args) return node;
|
|
11868
|
+
return { type: "invoke", callee, args };
|
|
11869
|
+
}
|
|
11870
|
+
default:
|
|
11871
|
+
return node;
|
|
11559
11872
|
}
|
|
11560
|
-
|
|
11561
|
-
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11873
|
+
}
|
|
11874
|
+
function copyAll(nodes, t, rows2) {
|
|
11875
|
+
let out;
|
|
11876
|
+
for (let i2 = 0; i2 < nodes.length; i2++) {
|
|
11877
|
+
const node = nodes[i2];
|
|
11878
|
+
const copy2 = copyTree(node, t, rows2);
|
|
11879
|
+
if (copy2 !== node && !out) out = nodes.slice(0, i2);
|
|
11880
|
+
out?.push(copy2);
|
|
11881
|
+
}
|
|
11882
|
+
return out ?? nodes;
|
|
11883
|
+
}
|
|
11884
|
+
function fromTemplate(t, formula, shape2) {
|
|
11885
|
+
const rows2 = rowsFor(t, formula, shape2);
|
|
11886
|
+
return rows2 ? copyTree(t.ast, t, rows2) : void 0;
|
|
11887
|
+
}
|
|
11888
|
+
|
|
11889
|
+
// xlsx/formula/parse-cache.ts
|
|
11890
|
+
var MAX_TEMPLATE_LENGTH = 2048;
|
|
11891
|
+
var MAX_ENTRIES = 1e5;
|
|
11892
|
+
var MAX_TEMPLATES = 1e4;
|
|
11893
|
+
var NO_RUNS = { hash: 0, starts: [], ends: [] };
|
|
11894
|
+
var treeOf = (made) => "ast" in made ? made.ast : made;
|
|
11895
|
+
var ParseCache = class {
|
|
11896
|
+
byText = /* @__PURE__ */ new Map();
|
|
11897
|
+
templates = /* @__PURE__ */ new Map();
|
|
11898
|
+
parse(formula) {
|
|
11899
|
+
let ast = this.byText.get(formula);
|
|
11900
|
+
if (ast) return ast;
|
|
11901
|
+
ast = this.parseNew(formula);
|
|
11902
|
+
if (this.byText.size > MAX_ENTRIES) this.byText.clear();
|
|
11903
|
+
this.byText.set(formula, ast);
|
|
11904
|
+
return ast;
|
|
11565
11905
|
}
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
const
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
|
|
11575
|
-
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
11593
|
-
|
|
11594
|
-
for (let c = start.col; c <= end.col; c++) if (map.has(c)) visit2(c);
|
|
11595
|
-
} else for (const c of map.keys()) if (c >= start.col && c <= end.col) visit2(c);
|
|
11596
|
-
};
|
|
11597
|
-
const chunked = this.chunked.get(sheet);
|
|
11598
|
-
const first2 = start.row >> CHUNK_SHIFT;
|
|
11599
|
-
const last = end.row >> CHUNK_SHIFT;
|
|
11600
|
-
columns(chunked, (c) => {
|
|
11601
|
-
const chunks = chunked?.get(c);
|
|
11602
|
-
if (last - first2 + 1 <= chunks.size) {
|
|
11603
|
-
for (let k = first2; k <= last; k++) check3(chunks.get(k));
|
|
11604
|
-
} else for (const [k, list] of chunks) if (k >= first2 && k <= last) check3(list);
|
|
11605
|
-
});
|
|
11606
|
-
const tall = this.tall.get(sheet);
|
|
11607
|
-
columns(tall, (c) => check3(tall?.get(c)));
|
|
11608
|
-
check3(this.wide.get(sheet));
|
|
11609
|
-
}
|
|
11610
|
-
};
|
|
11611
|
-
|
|
11612
|
-
// xlsx/formula/graph-index.ts
|
|
11613
|
-
var ColumnIndex = class {
|
|
11614
|
-
sheets = /* @__PURE__ */ new Map();
|
|
11615
|
-
constructor(nodes) {
|
|
11616
|
-
for (const node of nodes) {
|
|
11617
|
-
let cols = this.sheets.get(node.sheet);
|
|
11618
|
-
if (!cols) this.sheets.set(node.sheet, cols = /* @__PURE__ */ new Map());
|
|
11619
|
-
let list = cols.get(node.col);
|
|
11620
|
-
if (!list) cols.set(node.col, list = []);
|
|
11621
|
-
list.push(node);
|
|
11622
|
-
}
|
|
11623
|
-
for (const cols of this.sheets.values())
|
|
11624
|
-
for (const list of cols.values()) list.sort((a, b) => a.row - b.row);
|
|
11625
|
-
}
|
|
11626
|
-
nodesIn(area, out) {
|
|
11627
|
-
const cols = this.sheets.get(area.sheet);
|
|
11628
|
-
if (!cols) return;
|
|
11629
|
-
const { start, end } = area.range;
|
|
11630
|
-
const width = end.col - start.col + 1;
|
|
11631
|
-
const scan2 = (list) => {
|
|
11632
|
-
let lo = 0;
|
|
11633
|
-
let hi = list.length;
|
|
11634
|
-
while (lo < hi) {
|
|
11635
|
-
const mid = lo + hi >> 1;
|
|
11636
|
-
if (list[mid].row < start.row) lo = mid + 1;
|
|
11637
|
-
else hi = mid;
|
|
11638
|
-
}
|
|
11639
|
-
for (let i2 = lo; i2 < list.length; i2++) {
|
|
11640
|
-
const node = list[i2];
|
|
11641
|
-
if (node.row > end.row) break;
|
|
11642
|
-
out.push(node);
|
|
11643
|
-
}
|
|
11644
|
-
};
|
|
11645
|
-
if (width <= cols.size) {
|
|
11646
|
-
for (let c = start.col; c <= end.col; c++) {
|
|
11647
|
-
const list = cols.get(c);
|
|
11648
|
-
if (list) scan2(list);
|
|
11649
|
-
}
|
|
11650
|
-
} else {
|
|
11651
|
-
for (const [c, list] of cols) if (c >= start.col && c <= end.col) scan2(list);
|
|
11652
|
-
}
|
|
11653
|
-
}
|
|
11654
|
-
};
|
|
11655
|
-
var ReverseIndex = class extends AreaIndex {
|
|
11656
|
-
constructor(nodes) {
|
|
11657
|
-
super();
|
|
11658
|
-
for (const node of nodes) {
|
|
11659
|
-
for (const dep of node.deps) this.add(dep, node);
|
|
11660
|
-
for (const dep of node.dynamicDeps) this.add(dep, node);
|
|
11661
|
-
}
|
|
11662
|
-
}
|
|
11663
|
-
};
|
|
11664
|
-
|
|
11665
|
-
// xlsx/formula/sheet-scan.ts
|
|
11666
|
-
function scanRange(sheet, range2, visit2) {
|
|
11667
|
-
const { start, end } = range2;
|
|
11668
|
-
const rowCount = end.row - start.row + 1;
|
|
11669
|
-
const rows2 = rowCount <= sheet.rows.size * 2 ? null : [...sheet.rows.keys()].filter((r) => r >= start.row && r <= end.row).sort((a, b) => a - b);
|
|
11670
|
-
const visitRow = (r) => {
|
|
11671
|
-
const cells = sheet.rows.get(r);
|
|
11672
|
-
if (!cells || cells.size === 0) return;
|
|
11673
|
-
const colCount = end.col - start.col + 1;
|
|
11674
|
-
if (colCount <= cells.size * 2) {
|
|
11675
|
-
for (let c = start.col; c <= end.col; c++) {
|
|
11676
|
-
const cell = cells.get(c);
|
|
11677
|
-
if (cell) visit2(cell, r, c);
|
|
11906
|
+
parseNew(formula) {
|
|
11907
|
+
if (formula.length > MAX_TEMPLATE_LENGTH) return treeOf(makeTemplate(formula, NO_RUNS));
|
|
11908
|
+
const shape2 = formulaShape(formula);
|
|
11909
|
+
const template = this.templates.get(shape2.hash);
|
|
11910
|
+
const reused = template && fromTemplate(template, formula, shape2);
|
|
11911
|
+
if (reused) return reused;
|
|
11912
|
+
const made = makeTemplate(formula, shape2);
|
|
11913
|
+
if (!template && "ast" in made) {
|
|
11914
|
+
if (this.templates.size > MAX_TEMPLATES) this.templates.clear();
|
|
11915
|
+
this.templates.set(shape2.hash, made);
|
|
11916
|
+
}
|
|
11917
|
+
return treeOf(made);
|
|
11918
|
+
}
|
|
11919
|
+
};
|
|
11920
|
+
|
|
11921
|
+
// xlsx/formula/sheet-scan.ts
|
|
11922
|
+
function scanRange(sheet, range2, visit2) {
|
|
11923
|
+
const { start, end } = range2;
|
|
11924
|
+
const rowCount = end.row - start.row + 1;
|
|
11925
|
+
const rows2 = rowCount <= sheet.rows.size * 2 ? null : [...sheet.rows.keys()].filter((r) => r >= start.row && r <= end.row).sort((a, b) => a - b);
|
|
11926
|
+
const visitRow = (r) => {
|
|
11927
|
+
const cells = sheet.rows.get(r);
|
|
11928
|
+
if (!cells || cells.size === 0) return;
|
|
11929
|
+
const colCount = end.col - start.col + 1;
|
|
11930
|
+
if (colCount <= cells.size * 2) {
|
|
11931
|
+
for (let c = start.col; c <= end.col; c++) {
|
|
11932
|
+
const cell = cells.get(c);
|
|
11933
|
+
if (cell) visit2(cell, r, c);
|
|
11678
11934
|
}
|
|
11679
11935
|
return;
|
|
11680
11936
|
}
|
|
@@ -11798,7 +12054,7 @@ var EngineHost = class {
|
|
|
11798
12054
|
options;
|
|
11799
12055
|
nodes = /* @__PURE__ */ new Map();
|
|
11800
12056
|
footprints = /* @__PURE__ */ new Set();
|
|
11801
|
-
|
|
12057
|
+
parsed = new ParseCache();
|
|
11802
12058
|
boundsCache = /* @__PURE__ */ new Map();
|
|
11803
12059
|
inProgress = /* @__PURE__ */ new Set();
|
|
11804
12060
|
cycles = /* @__PURE__ */ new Set();
|
|
@@ -11822,6 +12078,8 @@ var EngineHost = class {
|
|
|
11822
12078
|
evaluations = 0;
|
|
11823
12079
|
built = false;
|
|
11824
12080
|
needsFull = false;
|
|
12081
|
+
/** No recalculation has run since the workbook was opened: stored values may stand. */
|
|
12082
|
+
fresh = true;
|
|
11825
12083
|
// ---- EvalHost ----
|
|
11826
12084
|
readCell(sheet, row2, col) {
|
|
11827
12085
|
const cell = this.workbook.sheets[sheet]?.rows.get(row2)?.get(col);
|
|
@@ -11910,19 +12168,7 @@ var EngineHost = class {
|
|
|
11910
12168
|
return this.workbook.sheets[sheet]?.rows.get(row2)?.get(col)?.formula;
|
|
11911
12169
|
}
|
|
11912
12170
|
parse(formula) {
|
|
11913
|
-
|
|
11914
|
-
if (!ast) {
|
|
11915
|
-
try {
|
|
11916
|
-
ast = parseFormula(formula);
|
|
11917
|
-
} catch (e) {
|
|
11918
|
-
if (e instanceof RangeError) ast = new FormulaError(e.message, -1, "#VALUE!");
|
|
11919
|
-
else if (!(e instanceof FormulaError)) throw e;
|
|
11920
|
-
else ast = e;
|
|
11921
|
-
}
|
|
11922
|
-
if (this.astCache.size > 1e5) this.astCache.clear();
|
|
11923
|
-
this.astCache.set(formula, ast);
|
|
11924
|
-
}
|
|
11925
|
-
return ast;
|
|
12171
|
+
return this.parsed.parse(formula);
|
|
11926
12172
|
}
|
|
11927
12173
|
now() {
|
|
11928
12174
|
return this.options.now ? this.options.now() : /* @__PURE__ */ new Date();
|
|
@@ -11931,20 +12177,6 @@ var EngineHost = class {
|
|
|
11931
12177
|
return this.options.random ? this.options.random() : Math.random();
|
|
11932
12178
|
}
|
|
11933
12179
|
// ---- graph ----
|
|
11934
|
-
build() {
|
|
11935
|
-
this.nodes.clear();
|
|
11936
|
-
this.footprints.clear();
|
|
11937
|
-
this.footprintIndex = void 0;
|
|
11938
|
-
this.workbook.sheets.forEach((sheet, s) => {
|
|
11939
|
-
for (const [row2, cells] of sheet.rows) {
|
|
11940
|
-
for (const [col, cell] of cells) {
|
|
11941
|
-
if (cell.formula) this.createNode(s, row2, col, cell, true);
|
|
11942
|
-
}
|
|
11943
|
-
}
|
|
11944
|
-
});
|
|
11945
|
-
this.built = true;
|
|
11946
|
-
this.graphChanged();
|
|
11947
|
-
}
|
|
11948
12180
|
createNode(sheet, row2, col, cell, initial) {
|
|
11949
12181
|
const formula = cell.formula ?? "";
|
|
11950
12182
|
const parsed = this.parse(formula);
|
|
@@ -11973,6 +12205,14 @@ var EngineHost = class {
|
|
|
11973
12205
|
map.set(cellKey(row2, col), node);
|
|
11974
12206
|
return node;
|
|
11975
12207
|
}
|
|
12208
|
+
/** Parses a node's text again after a structural edit rewrote it (see `FormulaNode.stale`). */
|
|
12209
|
+
refreshAst(node) {
|
|
12210
|
+
const parsed = this.parse(node.formula);
|
|
12211
|
+
delete node.stale;
|
|
12212
|
+
delete node.parseError;
|
|
12213
|
+
node.ast = parsed instanceof FormulaError ? void 0 : parsed;
|
|
12214
|
+
if (parsed instanceof FormulaError && parsed.code) node.parseError = err(parsed.code);
|
|
12215
|
+
}
|
|
11976
12216
|
removeNode(node, changed) {
|
|
11977
12217
|
const sheet = this.workbook.sheets[node.sheet];
|
|
11978
12218
|
if (node.spill && sheet) {
|
|
@@ -12403,6 +12643,7 @@ var EngineCore = class extends EngineHost {
|
|
|
12403
12643
|
return { host: this, sheet, row: row2, col, scope: void 0, depth: 0, root, legacy };
|
|
12404
12644
|
}
|
|
12405
12645
|
evaluateFormula(node) {
|
|
12646
|
+
if (node.stale) this.refreshAst(node);
|
|
12406
12647
|
if (!node.ast) return node.parseError ?? ERR.NAME;
|
|
12407
12648
|
const ast = node.ast;
|
|
12408
12649
|
const frame = this.frameFor(node.sheet, node.row, node.col, ast, node.legacy);
|
|
@@ -12420,20 +12661,363 @@ var EngineCore = class extends EngineHost {
|
|
|
12420
12661
|
}
|
|
12421
12662
|
};
|
|
12422
12663
|
|
|
12664
|
+
// xlsx/formula/shift-graph.ts
|
|
12665
|
+
var POSITIONAL = /* @__PURE__ */ new Set(["ROW", "COLUMN"]);
|
|
12666
|
+
var DESCRIPTIVE = /* @__PURE__ */ new Set(["FORMULATEXT", "CELL", "SHEET"]);
|
|
12667
|
+
var traitsCache = /* @__PURE__ */ new WeakMap();
|
|
12668
|
+
function astTraits(ast) {
|
|
12669
|
+
const cached = traitsCache.get(ast);
|
|
12670
|
+
if (cached) return cached;
|
|
12671
|
+
const sheets = /* @__PURE__ */ new Set();
|
|
12672
|
+
const traits = { complex: false, opaque: false, positional: false, descriptive: false, sheets };
|
|
12673
|
+
const stack2 = [ast];
|
|
12674
|
+
while (stack2.length) {
|
|
12675
|
+
const node = stack2.pop();
|
|
12676
|
+
switch (node.type) {
|
|
12677
|
+
case "ref":
|
|
12678
|
+
if (node.prefix) {
|
|
12679
|
+
sheets.add(node.prefix.sheet.toLowerCase());
|
|
12680
|
+
if (node.prefix.sheet2 !== void 0) {
|
|
12681
|
+
sheets.add(node.prefix.sheet2.toLowerCase());
|
|
12682
|
+
traits.complex = true;
|
|
12683
|
+
}
|
|
12684
|
+
}
|
|
12685
|
+
break;
|
|
12686
|
+
case "name":
|
|
12687
|
+
if (node.prefix) sheets.add(node.prefix.sheet.toLowerCase());
|
|
12688
|
+
traits.complex = true;
|
|
12689
|
+
break;
|
|
12690
|
+
case "structured":
|
|
12691
|
+
traits.complex = true;
|
|
12692
|
+
break;
|
|
12693
|
+
case "unary":
|
|
12694
|
+
case "percent":
|
|
12695
|
+
stack2.push(node.operand);
|
|
12696
|
+
break;
|
|
12697
|
+
case "binary":
|
|
12698
|
+
stack2.push(node.left, node.right);
|
|
12699
|
+
break;
|
|
12700
|
+
case "call":
|
|
12701
|
+
if (POSITIONAL.has(node.name)) traits.positional = true;
|
|
12702
|
+
if (DESCRIPTIVE.has(node.name)) traits.descriptive = true;
|
|
12703
|
+
if (!getFunction(node.name)) traits.complex = traits.opaque = true;
|
|
12704
|
+
stack2.push(...node.args);
|
|
12705
|
+
break;
|
|
12706
|
+
case "invoke":
|
|
12707
|
+
stack2.push(node.callee, ...node.args);
|
|
12708
|
+
break;
|
|
12709
|
+
}
|
|
12710
|
+
}
|
|
12711
|
+
traitsCache.set(ast, traits);
|
|
12712
|
+
return traits;
|
|
12713
|
+
}
|
|
12714
|
+
function intervalDelta(a, b, shift2) {
|
|
12715
|
+
const { at, count: count2 } = shift2;
|
|
12716
|
+
if (count2 > 0) {
|
|
12717
|
+
if (b < at) return 0;
|
|
12718
|
+
if (a < at) return void 0;
|
|
12719
|
+
return b + count2 > (shift2.axis === "row" ? MAX_ROW : MAX_COL) ? void 0 : count2;
|
|
12720
|
+
}
|
|
12721
|
+
const last = at - count2 - 1;
|
|
12722
|
+
if (b < at) return 0;
|
|
12723
|
+
if (a > last) return count2;
|
|
12724
|
+
return void 0;
|
|
12725
|
+
}
|
|
12726
|
+
function areaDelta(area, sheet, shift2) {
|
|
12727
|
+
if (area.sheet !== sheet) return 0;
|
|
12728
|
+
const { start, end } = area.range;
|
|
12729
|
+
return shift2.axis === "row" ? intervalDelta(start.row, end.row, shift2) : intervalDelta(start.col, end.col, shift2);
|
|
12730
|
+
}
|
|
12731
|
+
function movedRange(range2, axis, delta) {
|
|
12732
|
+
if (delta === 0) return range2;
|
|
12733
|
+
return axis === "row" ? {
|
|
12734
|
+
start: { row: range2.start.row + delta, col: range2.start.col },
|
|
12735
|
+
end: { row: range2.end.row + delta, col: range2.end.col }
|
|
12736
|
+
} : {
|
|
12737
|
+
start: { row: range2.start.row, col: range2.start.col + delta },
|
|
12738
|
+
end: { row: range2.end.row, col: range2.end.col + delta }
|
|
12739
|
+
};
|
|
12740
|
+
}
|
|
12741
|
+
function reachesEdit(areas, sheet, shift2) {
|
|
12742
|
+
for (const area of areas) {
|
|
12743
|
+
if (area.sheet !== sheet) continue;
|
|
12744
|
+
if ((shift2.axis === "row" ? area.range.end.row : area.range.end.col) >= shift2.at) return true;
|
|
12745
|
+
}
|
|
12746
|
+
return false;
|
|
12747
|
+
}
|
|
12748
|
+
function intersectionMoves(area, delta, pos, nodeDelta, axis) {
|
|
12749
|
+
if (delta === nodeDelta) return false;
|
|
12750
|
+
const { start, end } = area.range;
|
|
12751
|
+
const a = axis === "row" ? start.row : start.col;
|
|
12752
|
+
const b = axis === "row" ? end.row : end.col;
|
|
12753
|
+
if (a === b) return false;
|
|
12754
|
+
return pos >= a && pos <= b || pos + nodeDelta >= a + delta && pos + nodeDelta <= b + delta;
|
|
12755
|
+
}
|
|
12756
|
+
|
|
12757
|
+
// xlsx/formula/engine-structure.ts
|
|
12758
|
+
var sameAreas = (a, b) => a.length === b.length && a.every((x, i2) => {
|
|
12759
|
+
const y = b[i2];
|
|
12760
|
+
return x.sheet === y.sheet && sameRange(x.range, y.range);
|
|
12761
|
+
});
|
|
12762
|
+
var EngineStructure = class extends EngineCore {
|
|
12763
|
+
/** Formulas a structural edit left to recalculate (with their dependents) on the next pass. */
|
|
12764
|
+
structuralSeeds = /* @__PURE__ */ new Set();
|
|
12765
|
+
/** Whether the graph describes the workbook as it was before the edit just reported. */
|
|
12766
|
+
graphReady() {
|
|
12767
|
+
return this.built && !this.needsFull;
|
|
12768
|
+
}
|
|
12769
|
+
/** Parses a node's current text again and recomputes its precedents. */
|
|
12770
|
+
reanalyze(node) {
|
|
12771
|
+
const parsed = this.parse(node.formula);
|
|
12772
|
+
delete node.stale;
|
|
12773
|
+
delete node.parseError;
|
|
12774
|
+
if (parsed instanceof FormulaError) {
|
|
12775
|
+
node.ast = void 0;
|
|
12776
|
+
if (parsed.code) node.parseError = err(parsed.code);
|
|
12777
|
+
node.deps = [];
|
|
12778
|
+
node.dynamicDeps = [];
|
|
12779
|
+
return;
|
|
12780
|
+
}
|
|
12781
|
+
node.ast = parsed;
|
|
12782
|
+
const found = analyze(parsed, this, node.sheet, node.row, node.col);
|
|
12783
|
+
node.deps = found.deps;
|
|
12784
|
+
node.dynamicDeps = found.dynamicDeps;
|
|
12785
|
+
node.volatile = found.volatile;
|
|
12786
|
+
node.unsupported = found.unsupported;
|
|
12787
|
+
}
|
|
12788
|
+
/**
|
|
12789
|
+
* Moves the graph for rows or columns inserted or deleted on `sheet`, after the workbook was
|
|
12790
|
+
* changed (cells moved, formulas rewritten). Spills on the sheet, array formulas the edit cuts
|
|
12791
|
+
* and anything unexpected fall back to a rebuild on the next recalculation.
|
|
12792
|
+
*/
|
|
12793
|
+
shiftCells(sheet, shift2) {
|
|
12794
|
+
if (!this.graphReady() || !this.shiftable(sheet, shift2)) {
|
|
12795
|
+
this.invalidate();
|
|
12796
|
+
return;
|
|
12797
|
+
}
|
|
12798
|
+
const ws = this.workbook.sheets[sheet];
|
|
12799
|
+
const own = this.nodes.get(sheet);
|
|
12800
|
+
if (!ws) return;
|
|
12801
|
+
const moved = /* @__PURE__ */ new Map();
|
|
12802
|
+
if (own) {
|
|
12803
|
+
const next = /* @__PURE__ */ new Map();
|
|
12804
|
+
for (const node of own.values()) {
|
|
12805
|
+
const pos = shift2.axis === "row" ? node.row : node.col;
|
|
12806
|
+
const delta = intervalDelta(pos, pos, shift2);
|
|
12807
|
+
if (delta === void 0) {
|
|
12808
|
+
this.dropNode(node);
|
|
12809
|
+
continue;
|
|
12810
|
+
}
|
|
12811
|
+
if (delta !== 0) {
|
|
12812
|
+
moved.set(node, delta);
|
|
12813
|
+
if (shift2.axis === "row") node.row += delta;
|
|
12814
|
+
else node.col += delta;
|
|
12815
|
+
}
|
|
12816
|
+
next.set(cellKey(node.row, node.col), node);
|
|
12817
|
+
}
|
|
12818
|
+
this.nodes.set(sheet, next);
|
|
12819
|
+
}
|
|
12820
|
+
for (const map of this.nodes.values())
|
|
12821
|
+
for (const node of map.values()) {
|
|
12822
|
+
if (!this.shiftNode(node, sheet, shift2, moved.get(node) ?? 0)) {
|
|
12823
|
+
this.invalidate();
|
|
12824
|
+
return;
|
|
12825
|
+
}
|
|
12826
|
+
}
|
|
12827
|
+
this.boundsCache.clear();
|
|
12828
|
+
this.graphChanged();
|
|
12829
|
+
}
|
|
12830
|
+
/** No spill or stale spilled value on the sheet, and no array formula the edit cuts. */
|
|
12831
|
+
shiftable(sheet, shift2) {
|
|
12832
|
+
for (const node of this.footprints) {
|
|
12833
|
+
if (node.sheet !== sheet) continue;
|
|
12834
|
+
if (node.spill || node.blockedSpill) return false;
|
|
12835
|
+
if (node.arrayRange && areaDelta({ sheet, range: node.arrayRange }, sheet, shift2) === void 0)
|
|
12836
|
+
return false;
|
|
12837
|
+
}
|
|
12838
|
+
const ws = this.workbook.sheets[sheet];
|
|
12839
|
+
let spilled = false;
|
|
12840
|
+
ws?.rows.forEach((cells) => {
|
|
12841
|
+
if (!spilled) cells.forEach((cell) => spilled ||= isSpilledCell(cell));
|
|
12842
|
+
});
|
|
12843
|
+
return !spilled;
|
|
12844
|
+
}
|
|
12845
|
+
dropNode(node) {
|
|
12846
|
+
this.structuralSeeds.delete(node);
|
|
12847
|
+
this.cycles.delete(node);
|
|
12848
|
+
this.footprints.delete(node);
|
|
12849
|
+
}
|
|
12850
|
+
/** Updates one formula for the edit; false when the graph cannot follow it. */
|
|
12851
|
+
shiftNode(node, sheet, shift2, nodeDelta) {
|
|
12852
|
+
const cell = this.workbook.sheets[node.sheet]?.rows.get(node.row)?.get(node.col);
|
|
12853
|
+
if (cell?.formula === void 0) return false;
|
|
12854
|
+
if (node.arrayRange) {
|
|
12855
|
+
const delta = areaDelta({ sheet: node.sheet, range: node.arrayRange }, sheet, shift2);
|
|
12856
|
+
if (delta === void 0) return false;
|
|
12857
|
+
node.arrayRange = movedRange(node.arrayRange, shift2.axis, delta);
|
|
12858
|
+
if (!cell.arrayRange || !sameRange(node.arrayRange, normalizeRange(cell.arrayRange)))
|
|
12859
|
+
return false;
|
|
12860
|
+
}
|
|
12861
|
+
const changed = cell.formula !== node.formula;
|
|
12862
|
+
const traits = node.ast && astTraits(node.ast);
|
|
12863
|
+
const reached = reachesEdit(node.deps, sheet, shift2) || reachesEdit(node.dynamicDeps, sheet, shift2);
|
|
12864
|
+
if (!changed && !reached && nodeDelta === 0 && !traits?.descriptive && !traits?.opaque)
|
|
12865
|
+
return true;
|
|
12866
|
+
if (traits?.complex) {
|
|
12867
|
+
node.formula = cell.formula;
|
|
12868
|
+
this.reanalyze(node);
|
|
12869
|
+
this.structuralSeeds.add(node);
|
|
12870
|
+
return true;
|
|
12871
|
+
}
|
|
12872
|
+
const pos = shift2.axis === "row" ? node.row - nodeDelta : node.col - nodeDelta;
|
|
12873
|
+
const moves = { seed: !!traits?.descriptive, moved: false, cut: false };
|
|
12874
|
+
const deps = this.moveAreas(node.deps, sheet, shift2, pos, nodeDelta, moves);
|
|
12875
|
+
const dynamicDeps = this.moveAreas(node.dynamicDeps, sheet, shift2, pos, nodeDelta, moves);
|
|
12876
|
+
const { cut, moved: anyMoved } = moves;
|
|
12877
|
+
let seed = moves.seed;
|
|
12878
|
+
if (cut || changed !== anyMoved) {
|
|
12879
|
+
node.formula = cell.formula;
|
|
12880
|
+
this.reanalyze(node);
|
|
12881
|
+
this.structuralSeeds.add(node);
|
|
12882
|
+
return true;
|
|
12883
|
+
}
|
|
12884
|
+
if (traits?.positional && (anyMoved || nodeDelta !== 0)) seed = true;
|
|
12885
|
+
node.deps = deps;
|
|
12886
|
+
node.dynamicDeps = dynamicDeps;
|
|
12887
|
+
if (changed) {
|
|
12888
|
+
node.formula = cell.formula;
|
|
12889
|
+
node.stale = true;
|
|
12890
|
+
}
|
|
12891
|
+
if (seed) this.structuralSeeds.add(node);
|
|
12892
|
+
return true;
|
|
12893
|
+
}
|
|
12894
|
+
/**
|
|
12895
|
+
* Areas moved for the edit (the same list when none moves). Records in `moves` whether one
|
|
12896
|
+
* moved, one was cut (deleted, widened, pushed off the grid) and whether implicit intersection
|
|
12897
|
+
* with one can now pick another cell.
|
|
12898
|
+
*/
|
|
12899
|
+
moveAreas(list, sheet, shift2, pos, nodeDelta, moves) {
|
|
12900
|
+
let out;
|
|
12901
|
+
for (let i2 = 0; i2 < list.length; i2++) {
|
|
12902
|
+
const area = list[i2];
|
|
12903
|
+
const delta = areaDelta(area, sheet, shift2);
|
|
12904
|
+
if (delta === void 0) {
|
|
12905
|
+
moves.cut = true;
|
|
12906
|
+
continue;
|
|
12907
|
+
}
|
|
12908
|
+
if (intersectionMoves(area, delta, pos, nodeDelta, shift2.axis)) moves.seed = true;
|
|
12909
|
+
if (delta === 0) continue;
|
|
12910
|
+
moves.moved = true;
|
|
12911
|
+
out ??= list.slice();
|
|
12912
|
+
out[i2] = { sheet: area.sheet, range: movedRange(area.range, shift2.axis, delta) };
|
|
12913
|
+
}
|
|
12914
|
+
return out ?? list;
|
|
12915
|
+
}
|
|
12916
|
+
/**
|
|
12917
|
+
* Follows a sheet rename (`from` to `to`, formulas already rewritten): precedents are kept by
|
|
12918
|
+
* sheet index, so only rewritten formulas need their text parsed again, and only formulas that
|
|
12919
|
+
* name the new sheet without having been rewritten (previously unresolved), describe sheets
|
|
12920
|
+
* (CELL, SHEET, FORMULATEXT) or read defined names whose areas changed are recalculated.
|
|
12921
|
+
*/
|
|
12922
|
+
renameSheet(from, to) {
|
|
12923
|
+
if (!this.graphReady()) {
|
|
12924
|
+
this.invalidate();
|
|
12925
|
+
return;
|
|
12926
|
+
}
|
|
12927
|
+
const target2 = to.toLowerCase();
|
|
12928
|
+
let depsChanged = false;
|
|
12929
|
+
for (const map of this.nodes.values())
|
|
12930
|
+
for (const node of map.values()) {
|
|
12931
|
+
const cell = this.workbook.sheets[node.sheet]?.rows.get(node.row)?.get(node.col);
|
|
12932
|
+
if (cell?.formula === void 0) {
|
|
12933
|
+
this.invalidate();
|
|
12934
|
+
return;
|
|
12935
|
+
}
|
|
12936
|
+
const changed = cell.formula !== node.formula;
|
|
12937
|
+
const traits = node.ast && astTraits(node.ast);
|
|
12938
|
+
node.formula = cell.formula;
|
|
12939
|
+
if (traits?.complex || !changed && traits?.sheets.has(target2)) {
|
|
12940
|
+
const deps = node.deps;
|
|
12941
|
+
const dynamicDeps = node.dynamicDeps;
|
|
12942
|
+
this.reanalyze(node);
|
|
12943
|
+
const same4 = sameAreas(deps, node.deps) && sameAreas(dynamicDeps, node.dynamicDeps);
|
|
12944
|
+
if (!same4) depsChanged = true;
|
|
12945
|
+
if (!same4 || !traits?.complex) this.structuralSeeds.add(node);
|
|
12946
|
+
} else if (changed) node.stale = true;
|
|
12947
|
+
if (traits?.descriptive || traits?.opaque) this.structuralSeeds.add(node);
|
|
12948
|
+
}
|
|
12949
|
+
if (depsChanged) this.graphChanged();
|
|
12950
|
+
}
|
|
12951
|
+
/** Takes the formulas queued by structural edits. */
|
|
12952
|
+
takeStructuralSeeds(into) {
|
|
12953
|
+
for (const node of this.structuralSeeds)
|
|
12954
|
+
if (this.nodes.get(node.sheet)?.get(cellKey(node.row, node.col)) === node) into.add(node);
|
|
12955
|
+
this.structuralSeeds.clear();
|
|
12956
|
+
}
|
|
12957
|
+
};
|
|
12958
|
+
|
|
12423
12959
|
// xlsx/formula/engine.ts
|
|
12424
|
-
var Engine = class extends
|
|
12960
|
+
var Engine = class extends EngineStructure {
|
|
12961
|
+
preparation;
|
|
12962
|
+
/** The prepared formulas the first recalculation checks (see `trustsStoredValues`). */
|
|
12963
|
+
prepared;
|
|
12964
|
+
// ---- the graph ----
|
|
12965
|
+
prepare(timeRemaining) {
|
|
12966
|
+
if (this.built || this.needsFull) return true;
|
|
12967
|
+
this.preparation ??= this.startPreparation();
|
|
12968
|
+
if (!this.preparation.run(timeRemaining)) return false;
|
|
12969
|
+
this.finishPreparation(this.preparation);
|
|
12970
|
+
return true;
|
|
12971
|
+
}
|
|
12972
|
+
discardPreparation() {
|
|
12973
|
+
if (!this.fresh || this.needsFull) return;
|
|
12974
|
+
this.preparation = void 0;
|
|
12975
|
+
this.prepared = void 0;
|
|
12976
|
+
this.structuralSeeds.clear();
|
|
12977
|
+
this.nodes.clear();
|
|
12978
|
+
this.footprints.clear();
|
|
12979
|
+
this.graphChanged();
|
|
12980
|
+
this.built = false;
|
|
12981
|
+
}
|
|
12982
|
+
/** Completes the graph, continuing a preparation that is under way. */
|
|
12983
|
+
build() {
|
|
12984
|
+
const preparation = this.preparation ?? this.startPreparation();
|
|
12985
|
+
preparation.run();
|
|
12986
|
+
this.finishPreparation(preparation);
|
|
12987
|
+
}
|
|
12988
|
+
startPreparation() {
|
|
12989
|
+
this.nodes.clear();
|
|
12990
|
+
this.footprints.clear();
|
|
12991
|
+
this.footprintIndex = void 0;
|
|
12992
|
+
this.prepared = void 0;
|
|
12993
|
+
return new GraphPreparation(
|
|
12994
|
+
this.workbook,
|
|
12995
|
+
(s, row2, col, cell) => this.createNode(s, row2, col, cell, true)
|
|
12996
|
+
);
|
|
12997
|
+
}
|
|
12998
|
+
finishPreparation(preparation) {
|
|
12999
|
+
this.preparation = void 0;
|
|
13000
|
+
this.built = true;
|
|
13001
|
+
this.graphChanged();
|
|
13002
|
+
this.reverseIndex = preparation.reverse;
|
|
13003
|
+
this.prepared = preparation.formulas;
|
|
13004
|
+
}
|
|
12425
13005
|
// ---- recalculation ----
|
|
12426
13006
|
recalculateAll() {
|
|
13007
|
+
this.fresh = false;
|
|
13008
|
+
this.prepared = void 0;
|
|
12427
13009
|
if (this.needsFull) this.releaseAllSpills();
|
|
12428
13010
|
if (!this.built || this.needsFull) this.build();
|
|
12429
13011
|
this.needsFull = false;
|
|
13012
|
+
this.structuralSeeds.clear();
|
|
12430
13013
|
this.cycles = /* @__PURE__ */ new Set();
|
|
12431
13014
|
this.run(new Set(this.allNodes()), true);
|
|
12432
13015
|
}
|
|
12433
13016
|
recalculateFrom(changes) {
|
|
12434
13017
|
const seeds = /* @__PURE__ */ new Set();
|
|
12435
|
-
if (
|
|
12436
|
-
this.
|
|
13018
|
+
if (this.fresh && !this.needsFull) {
|
|
13019
|
+
this.fresh = false;
|
|
13020
|
+
if (!this.built) this.build();
|
|
12437
13021
|
if (!this.trustsStoredValues(changes, seeds)) {
|
|
12438
13022
|
this.recalculateAll();
|
|
12439
13023
|
return;
|
|
@@ -12477,6 +13061,7 @@ var Engine = class extends EngineCore {
|
|
|
12477
13061
|
}
|
|
12478
13062
|
}
|
|
12479
13063
|
if (structural) this.graphChanged();
|
|
13064
|
+
this.takeStructuralSeeds(seeds);
|
|
12480
13065
|
const reverse = this.reverse();
|
|
12481
13066
|
for (const area of changed) reverse.dependents(area.sheet, area.range, seeds);
|
|
12482
13067
|
for (const node of this.allNodes()) if (node.volatile) seeds.add(node);
|
|
@@ -12488,13 +13073,18 @@ var Engine = class extends EngineCore {
|
|
|
12488
13073
|
* without a value into `missing`.
|
|
12489
13074
|
*/
|
|
12490
13075
|
trustsStoredValues(changes, missing) {
|
|
13076
|
+
const prepared = this.prepared;
|
|
13077
|
+
this.prepared = void 0;
|
|
13078
|
+
if (!prepared) return false;
|
|
12491
13079
|
const changed = new Set(changes.map((c) => `${c.sheet}:${cellKey(c.row, c.col)}`));
|
|
12492
|
-
|
|
12493
|
-
|
|
12494
|
-
if (
|
|
13080
|
+
const current = (node) => this.nodes.get(node.sheet)?.get(cellKey(node.row, node.col)) === node;
|
|
13081
|
+
for (const node of prepared.dynamic) {
|
|
13082
|
+
if (current(node) && !changed.has(`${node.sheet}:${cellKey(node.row, node.col)}`))
|
|
12495
13083
|
return false;
|
|
13084
|
+
}
|
|
13085
|
+
for (const node of prepared.unvalued) {
|
|
12496
13086
|
const cell = this.workbook.sheets[node.sheet]?.rows.get(node.row)?.get(node.col);
|
|
12497
|
-
if (cell && cell.value === null
|
|
13087
|
+
if (current(node) && cell && cell.value === null) missing.add(node);
|
|
12498
13088
|
}
|
|
12499
13089
|
return true;
|
|
12500
13090
|
}
|
|
@@ -12508,7 +13098,10 @@ var Engine = class extends EngineCore {
|
|
|
12508
13098
|
return !!anchor?.spill && rangeHas(anchor.spill, row2, col);
|
|
12509
13099
|
}
|
|
12510
13100
|
invalidate() {
|
|
13101
|
+
this.structuralSeeds.clear();
|
|
12511
13102
|
this.releaseAllSpills();
|
|
13103
|
+
this.preparation = void 0;
|
|
13104
|
+
this.prepared = void 0;
|
|
12512
13105
|
this.nodes.clear();
|
|
12513
13106
|
this.footprints.clear();
|
|
12514
13107
|
this.graphChanged();
|
|
@@ -12553,7 +13146,7 @@ function createCalcEngine(workbook, options = {}) {
|
|
|
12553
13146
|
return new Engine(workbook, options);
|
|
12554
13147
|
}
|
|
12555
13148
|
|
|
12556
|
-
// xlsx/formula/
|
|
13149
|
+
// xlsx/formula/ref-text.ts
|
|
12557
13150
|
function safeTokens(formula) {
|
|
12558
13151
|
try {
|
|
12559
13152
|
return tokenize(formula);
|
|
@@ -12572,50 +13165,26 @@ function formatRefSpec(spec2) {
|
|
|
12572
13165
|
if (spec2.kind === "cell") return a;
|
|
12573
13166
|
return `${a}:${cornerText(spec2.end, spec2.kind)}`;
|
|
12574
13167
|
}
|
|
12575
|
-
function
|
|
13168
|
+
function rewriteRef(token, ref) {
|
|
12576
13169
|
const prefix = token.prefix?.text ?? "";
|
|
12577
13170
|
if (!ref) return `${prefix}#REF!`;
|
|
12578
13171
|
return `${prefix}${formatRefSpec(ref)}${token.spill ? "#" : ""}`;
|
|
12579
13172
|
}
|
|
12580
13173
|
var sameSpec = (a, b) => a.kind === b.kind && a.start.row === b.start.row && a.start.col === b.start.col && a.end.row === b.end.row && a.end.col === b.end.col;
|
|
12581
|
-
|
|
12582
|
-
|
|
12583
|
-
|
|
12584
|
-
|
|
12585
|
-
|
|
12586
|
-
|
|
12587
|
-
const move = (c) => {
|
|
12588
|
-
const row2 = spec2.kind === "cols" || c.rowAbs ? c.row : c.row + dRow;
|
|
12589
|
-
const col = spec2.kind === "rows" || c.colAbs ? c.col : c.col + dCol;
|
|
12590
|
-
if (row2 < 0 || row2 > MAX_ROW || col < 0 || col > MAX_COL) return void 0;
|
|
12591
|
-
return { ...c, row: row2, col };
|
|
12592
|
-
};
|
|
12593
|
-
const start = move(spec2.start);
|
|
12594
|
-
const end = move(spec2.end);
|
|
12595
|
-
const next = start && end ? { kind: spec2.kind, start, end } : void 0;
|
|
12596
|
-
if (next && sameSpec(next, spec2)) continue;
|
|
12597
|
-
token.text = rewrite(token, next);
|
|
12598
|
-
}
|
|
12599
|
-
return joinTokens(tokens);
|
|
13174
|
+
var needsQuote = (name) => !/^[A-Za-z_¡-][A-Za-z0-9_.¡-]*$/.test(name) || /^[A-Za-z]{1,3}\d+$/.test(name) || /^(?:R\d*C?\d*|C\d*)$/i.test(name) || /^(?:TRUE|FALSE)$/i.test(name);
|
|
13175
|
+
function prefixText(prefix) {
|
|
13176
|
+
const sheets = prefix.sheet2 !== void 0 ? `${prefix.sheet}:${prefix.sheet2}` : prefix.sheet;
|
|
13177
|
+
const book = prefix.book !== void 0 ? `[${prefix.book}]` : "";
|
|
13178
|
+
const quote = needsQuote(prefix.sheet) || prefix.sheet2 !== void 0 && needsQuote(prefix.sheet2);
|
|
13179
|
+
return quote ? `'${(book + sheets).replace(/'/g, "''")}'!` : `${book}${sheets}!`;
|
|
12600
13180
|
}
|
|
12601
|
-
|
|
12602
|
-
|
|
12603
|
-
|
|
12604
|
-
|
|
12605
|
-
|
|
12606
|
-
|
|
12607
|
-
|
|
12608
|
-
const na2 = a >= at ? a + count2 : a;
|
|
12609
|
-
const nb2 = b >= at ? b + count2 : b;
|
|
12610
|
-
if (nb2 > max) return na2 > max ? void 0 : [na2, max];
|
|
12611
|
-
return [na2, nb2];
|
|
12612
|
-
}
|
|
12613
|
-
const n = -count2;
|
|
12614
|
-
const last = at + n - 1;
|
|
12615
|
-
if (a >= at && b <= last) return void 0;
|
|
12616
|
-
const na = a < at ? a : a <= last ? at : a - n;
|
|
12617
|
-
const nb = b < at ? b : b <= last ? at - 1 : b - n;
|
|
12618
|
-
return [na, nb];
|
|
13181
|
+
|
|
13182
|
+
// xlsx/formula/shift-formula.ts
|
|
13183
|
+
var templates = /* @__PURE__ */ new Map();
|
|
13184
|
+
var MAX_TEMPLATES2 = 2e5;
|
|
13185
|
+
function remember(text2, template) {
|
|
13186
|
+
if (templates.size >= MAX_TEMPLATES2) templates.clear();
|
|
13187
|
+
templates.set(text2, template);
|
|
12619
13188
|
}
|
|
12620
13189
|
function mergeSpacedAreas(tokens) {
|
|
12621
13190
|
const out = [];
|
|
@@ -12642,63 +13211,145 @@ function mergeSpacedAreas(tokens) {
|
|
|
12642
13211
|
}
|
|
12643
13212
|
return out;
|
|
12644
13213
|
}
|
|
12645
|
-
function
|
|
12646
|
-
|
|
13214
|
+
function templateOf(formula) {
|
|
13215
|
+
const cached = templates.get(formula);
|
|
13216
|
+
if (cached !== void 0) return cached;
|
|
12647
13217
|
const raw = safeTokens(formula);
|
|
12648
|
-
|
|
12649
|
-
|
|
12650
|
-
|
|
12651
|
-
|
|
12652
|
-
|
|
12653
|
-
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12669
|
-
|
|
12670
|
-
|
|
12671
|
-
|
|
12672
|
-
|
|
12673
|
-
|
|
12674
|
-
|
|
12675
|
-
|
|
13218
|
+
let template = null;
|
|
13219
|
+
if (raw) {
|
|
13220
|
+
template = [];
|
|
13221
|
+
let literal2 = "";
|
|
13222
|
+
for (const token of mergeSpacedAreas(raw)) {
|
|
13223
|
+
if (token.kind !== "ref" && !(token.kind === "name" && token.prefix)) {
|
|
13224
|
+
literal2 += token.text;
|
|
13225
|
+
continue;
|
|
13226
|
+
}
|
|
13227
|
+
if (literal2) template.push(literal2);
|
|
13228
|
+
literal2 = "";
|
|
13229
|
+
const part = { kind: token.kind, text: token.text };
|
|
13230
|
+
if (token.prefix) {
|
|
13231
|
+
part.prefix = token.prefix;
|
|
13232
|
+
if (token.prefix.book === void 0) part.sheet = token.prefix.sheet.toLowerCase();
|
|
13233
|
+
}
|
|
13234
|
+
if (token.ref) part.ref = token.ref;
|
|
13235
|
+
if (token.spill) part.spill = true;
|
|
13236
|
+
template.push(part);
|
|
13237
|
+
}
|
|
13238
|
+
if (literal2) template.push(literal2);
|
|
13239
|
+
}
|
|
13240
|
+
remember(formula, template);
|
|
13241
|
+
return template;
|
|
13242
|
+
}
|
|
13243
|
+
function rewriteTemplate(formula, rewrite) {
|
|
13244
|
+
const template = templateOf(formula);
|
|
13245
|
+
if (!template) return formula;
|
|
13246
|
+
let next;
|
|
13247
|
+
for (let i2 = 0; i2 < template.length; i2++) {
|
|
13248
|
+
const part = template[i2];
|
|
13249
|
+
if (typeof part === "string") continue;
|
|
13250
|
+
const changed = rewrite(part);
|
|
13251
|
+
if (!changed) continue;
|
|
13252
|
+
next ??= template.slice();
|
|
13253
|
+
next[i2] = changed;
|
|
13254
|
+
}
|
|
13255
|
+
if (!next) return formula;
|
|
13256
|
+
const text2 = next.map((part) => typeof part === "string" ? part : part.text).join("");
|
|
13257
|
+
remember(text2, next);
|
|
13258
|
+
return text2;
|
|
13259
|
+
}
|
|
13260
|
+
function shiftInterval(a, b, at, count2, max) {
|
|
13261
|
+
if (count2 > 0) {
|
|
13262
|
+
const na2 = a >= at ? a + count2 : a;
|
|
13263
|
+
const nb2 = b >= at ? b + count2 : b;
|
|
13264
|
+
if (nb2 > max) return na2 > max ? void 0 : [na2, max];
|
|
13265
|
+
return [na2, nb2];
|
|
12676
13266
|
}
|
|
12677
|
-
|
|
13267
|
+
const n = -count2;
|
|
13268
|
+
const last = at + n - 1;
|
|
13269
|
+
if (a >= at && b <= last) return void 0;
|
|
13270
|
+
const na = a < at ? a : a <= last ? at : a - n;
|
|
13271
|
+
const nb = b < at ? b : b <= last ? at - 1 : b - n;
|
|
13272
|
+
return [na, nb];
|
|
12678
13273
|
}
|
|
12679
|
-
|
|
12680
|
-
|
|
12681
|
-
|
|
12682
|
-
const
|
|
12683
|
-
const
|
|
12684
|
-
|
|
13274
|
+
function shiftRef(ref, spec2) {
|
|
13275
|
+
const isRow = spec2.axis === "row";
|
|
13276
|
+
if (isRow && ref.kind === "cols" || !isRow && ref.kind === "rows") return ref;
|
|
13277
|
+
const startFirst = isRow ? ref.start.row <= ref.end.row : ref.start.col <= ref.end.col;
|
|
13278
|
+
const lo = startFirst ? ref.start : ref.end;
|
|
13279
|
+
const hi = startFirst ? ref.end : ref.start;
|
|
13280
|
+
const shifted2 = shiftInterval(
|
|
13281
|
+
isRow ? lo.row : lo.col,
|
|
13282
|
+
isRow ? hi.row : hi.col,
|
|
13283
|
+
spec2.at,
|
|
13284
|
+
spec2.count,
|
|
13285
|
+
isRow ? MAX_ROW : MAX_COL
|
|
13286
|
+
);
|
|
13287
|
+
if (!shifted2) return void 0;
|
|
13288
|
+
const [a, b] = shifted2;
|
|
13289
|
+
const nlo = isRow ? { ...lo, row: a } : { ...lo, col: a };
|
|
13290
|
+
const nhi = isRow ? { ...hi, row: b } : { ...hi, col: b };
|
|
13291
|
+
const next = {
|
|
13292
|
+
kind: ref.kind,
|
|
13293
|
+
start: startFirst ? nlo : nhi,
|
|
13294
|
+
end: startFirst ? nhi : nlo
|
|
13295
|
+
};
|
|
13296
|
+
if (ref.kind === "cell") next.end = next.start;
|
|
13297
|
+
return sameSpec(next, ref) ? ref : next;
|
|
13298
|
+
}
|
|
13299
|
+
function shiftFormula(formula, formulaSheet, spec2) {
|
|
13300
|
+
if (spec2.count === 0) return formula;
|
|
13301
|
+
const sheet = spec2.sheet.toLowerCase();
|
|
13302
|
+
const own = formulaSheet.toLowerCase() === sheet;
|
|
13303
|
+
return rewriteTemplate(formula, (part) => {
|
|
13304
|
+
if (part.kind !== "ref" || !part.ref || (part.prefix ? part.sheet !== sheet : !own))
|
|
13305
|
+
return void 0;
|
|
13306
|
+
const next = shiftRef(part.ref, spec2);
|
|
13307
|
+
if (next === part.ref) return void 0;
|
|
13308
|
+
const out = { kind: "ref", text: rewriteRef(part, next) };
|
|
13309
|
+
if (part.prefix) out.prefix = part.prefix;
|
|
13310
|
+
if (part.sheet !== void 0) out.sheet = part.sheet;
|
|
13311
|
+
if (next) out.ref = next;
|
|
13312
|
+
if (part.spill) out.spill = true;
|
|
13313
|
+
return out;
|
|
13314
|
+
});
|
|
12685
13315
|
}
|
|
12686
13316
|
function renameSheetInFormula(formula, oldName, newName) {
|
|
12687
|
-
const tokens = safeTokens(formula);
|
|
12688
|
-
if (!tokens) return formula;
|
|
12689
13317
|
const lower2 = oldName.toLowerCase();
|
|
12690
|
-
|
|
12691
|
-
const prefix =
|
|
12692
|
-
if (!prefix ||
|
|
12693
|
-
const first2 =
|
|
13318
|
+
return rewriteTemplate(formula, (part) => {
|
|
13319
|
+
const prefix = part.prefix;
|
|
13320
|
+
if (!prefix || part.sheet === void 0) return void 0;
|
|
13321
|
+
const first2 = part.sheet === lower2;
|
|
12694
13322
|
const second = prefix.sheet2?.toLowerCase() === lower2;
|
|
12695
|
-
if (!first2 && !second)
|
|
13323
|
+
if (!first2 && !second) return void 0;
|
|
12696
13324
|
const renamed = { ...prefix, sheet: first2 ? newName : prefix.sheet };
|
|
12697
13325
|
if (prefix.sheet2 !== void 0) renamed.sheet2 = second ? newName : prefix.sheet2;
|
|
12698
13326
|
const text2 = prefixText(renamed);
|
|
12699
|
-
token.text = text2 + token.text.slice(prefix.text.length);
|
|
12700
13327
|
renamed.text = text2;
|
|
12701
|
-
|
|
13328
|
+
const out = { ...part, text: text2 + part.text.slice(prefix.text.length) };
|
|
13329
|
+
out.prefix = renamed;
|
|
13330
|
+
out.sheet = renamed.sheet.toLowerCase();
|
|
13331
|
+
return out;
|
|
13332
|
+
});
|
|
13333
|
+
}
|
|
13334
|
+
|
|
13335
|
+
// xlsx/formula/transform.ts
|
|
13336
|
+
function translateFormula(formula, dRow, dCol) {
|
|
13337
|
+
const tokens = safeTokens(formula);
|
|
13338
|
+
if (!tokens) return formula;
|
|
13339
|
+
for (const token of tokens) {
|
|
13340
|
+
if (token.kind !== "ref" || !token.ref) continue;
|
|
13341
|
+
const spec2 = token.ref;
|
|
13342
|
+
const move = (c) => {
|
|
13343
|
+
const row2 = spec2.kind === "cols" || c.rowAbs ? c.row : c.row + dRow;
|
|
13344
|
+
const col = spec2.kind === "rows" || c.colAbs ? c.col : c.col + dCol;
|
|
13345
|
+
if (row2 < 0 || row2 > MAX_ROW || col < 0 || col > MAX_COL) return void 0;
|
|
13346
|
+
return { ...c, row: row2, col };
|
|
13347
|
+
};
|
|
13348
|
+
const start = move(spec2.start);
|
|
13349
|
+
const end = move(spec2.end);
|
|
13350
|
+
const next = start && end ? { kind: spec2.kind, start, end } : void 0;
|
|
13351
|
+
if (next && sameSpec(next, spec2)) continue;
|
|
13352
|
+
token.text = rewriteRef(token, next);
|
|
12702
13353
|
}
|
|
12703
13354
|
return joinTokens(tokens);
|
|
12704
13355
|
}
|
|
@@ -13022,13 +13673,13 @@ function dataBarLengths(rule, node) {
|
|
|
13022
13673
|
maxLength: rule.maxLength ?? numAttr(bar, "maxLength") ?? 90
|
|
13023
13674
|
};
|
|
13024
13675
|
}
|
|
13025
|
-
function rewriteConditionalExtension(rule,
|
|
13676
|
+
function rewriteConditionalExtension(rule, rewrite) {
|
|
13026
13677
|
if (!rule.extensionXml) return;
|
|
13027
13678
|
const doc = parseXml(rule.extensionXml);
|
|
13028
13679
|
let changed = false;
|
|
13029
13680
|
for (const formula of descendants(doc.documentElement, "f", XM)) {
|
|
13030
13681
|
const before = formula.textContent ?? "";
|
|
13031
|
-
const next =
|
|
13682
|
+
const next = rewrite(before);
|
|
13032
13683
|
if (before !== next) {
|
|
13033
13684
|
formula.textContent = next;
|
|
13034
13685
|
changed = true;
|
|
@@ -14055,13 +14706,13 @@ function linearTrend(values2) {
|
|
|
14055
14706
|
const slope = den ? num2 / den : 0;
|
|
14056
14707
|
return (k) => Number((meanY + slope * (k - meanX)).toPrecision(15));
|
|
14057
14708
|
}
|
|
14058
|
-
var
|
|
14709
|
+
var isDigit5 = (ch) => ch !== void 0 && ch >= "0" && ch <= "9";
|
|
14059
14710
|
function matchTextNumber(text2) {
|
|
14060
14711
|
let end = text2.length;
|
|
14061
|
-
while (end > 0 && !
|
|
14712
|
+
while (end > 0 && !isDigit5(text2[end - 1])) end--;
|
|
14062
14713
|
if (end === 0) return null;
|
|
14063
14714
|
let start = end;
|
|
14064
|
-
while (start > 0 &&
|
|
14715
|
+
while (start > 0 && isDigit5(text2[start - 1])) start--;
|
|
14065
14716
|
return [text2, text2.slice(0, start), text2.slice(start, end), text2.slice(end)];
|
|
14066
14717
|
}
|
|
14067
14718
|
var QUARTER = /^(q|qtr|quarter)(\s?)([1-4])$/i;
|
|
@@ -14244,10 +14895,10 @@ function removeValidationArea(rules, area) {
|
|
|
14244
14895
|
}
|
|
14245
14896
|
|
|
14246
14897
|
// xlsx/edit/conditional-formulas.ts
|
|
14247
|
-
function rewriteConditionalRule(rule,
|
|
14898
|
+
function rewriteConditionalRule(rule, rewrite) {
|
|
14248
14899
|
const safe2 = (formula) => {
|
|
14249
14900
|
try {
|
|
14250
|
-
return
|
|
14901
|
+
return rewrite(formula);
|
|
14251
14902
|
} catch {
|
|
14252
14903
|
return formula;
|
|
14253
14904
|
}
|
|
@@ -14766,7 +15417,7 @@ function shiftPreservedXml(sheet, shift2, moveRange, banded) {
|
|
|
14766
15417
|
(xml) => xml.includes("sqref")
|
|
14767
15418
|
);
|
|
14768
15419
|
}
|
|
14769
|
-
function rewritePreservedFormulas(sheet,
|
|
15420
|
+
function rewritePreservedFormulas(sheet, rewrite) {
|
|
14770
15421
|
editEntries(
|
|
14771
15422
|
sheet,
|
|
14772
15423
|
"extLst",
|
|
@@ -14776,7 +15427,7 @@ function rewritePreservedFormulas(sheet, rewrite2) {
|
|
|
14776
15427
|
const text2 = f6.textContent ?? "";
|
|
14777
15428
|
let next = text2;
|
|
14778
15429
|
try {
|
|
14779
|
-
next =
|
|
15430
|
+
next = rewrite(text2, sheet.name);
|
|
14780
15431
|
} catch {
|
|
14781
15432
|
next = text2;
|
|
14782
15433
|
}
|
|
@@ -14791,46 +15442,46 @@ function rewritePreservedFormulas(sheet, rewrite2) {
|
|
|
14791
15442
|
}
|
|
14792
15443
|
|
|
14793
15444
|
// xlsx/edit/shift-formulas.ts
|
|
14794
|
-
function safe(
|
|
15445
|
+
function safe(rewrite, formula, formulaSheet) {
|
|
14795
15446
|
try {
|
|
14796
|
-
return
|
|
15447
|
+
return rewrite(formula, formulaSheet);
|
|
14797
15448
|
} catch {
|
|
14798
15449
|
return formula;
|
|
14799
15450
|
}
|
|
14800
15451
|
}
|
|
14801
|
-
function rewriteFormulas(workbook,
|
|
14802
|
-
for (const sheet of workbook.sheets) rewriteSheetFormulas(sheet,
|
|
15452
|
+
function rewriteFormulas(workbook, rewrite) {
|
|
15453
|
+
for (const sheet of workbook.sheets) rewriteSheetFormulas(sheet, rewrite);
|
|
14803
15454
|
for (const definedName of workbook.definedNames) {
|
|
14804
15455
|
const local = definedName.localSheet === void 0 ? void 0 : workbook.sheets[definedName.localSheet];
|
|
14805
|
-
definedName.formula = safe(
|
|
15456
|
+
definedName.formula = safe(rewrite, definedName.formula, local?.name ?? "");
|
|
14806
15457
|
}
|
|
14807
15458
|
}
|
|
14808
|
-
function rewriteSheetFormulas(sheet,
|
|
14809
|
-
rewritePreservedFormulas(sheet,
|
|
15459
|
+
function rewriteSheetFormulas(sheet, rewrite) {
|
|
15460
|
+
rewritePreservedFormulas(sheet, rewrite);
|
|
14810
15461
|
{
|
|
14811
15462
|
const name = sheet.name;
|
|
14812
15463
|
for (const table2 of sheet.tables)
|
|
14813
15464
|
for (const column of table2.columns)
|
|
14814
15465
|
if (column.calculatedColumnFormula !== void 0)
|
|
14815
|
-
column.calculatedColumnFormula = safe(
|
|
15466
|
+
column.calculatedColumnFormula = safe(rewrite, column.calculatedColumnFormula, name);
|
|
14816
15467
|
for (const cells of sheet.rows.values())
|
|
14817
15468
|
for (const cell of cells.values())
|
|
14818
|
-
if (cell.formula !== void 0) cell.formula = safe(
|
|
15469
|
+
if (cell.formula !== void 0) cell.formula = safe(rewrite, cell.formula, name);
|
|
14819
15470
|
for (const cf of sheet.conditionalFormats)
|
|
14820
|
-
for (const rule of cf.rules) rewriteConditionalRule(rule, (f6) =>
|
|
15471
|
+
for (const rule of cf.rules) rewriteConditionalRule(rule, (f6) => rewrite(f6, name));
|
|
14821
15472
|
for (const dv of sheet.dataValidations) {
|
|
14822
|
-
if (dv.formula1 !== void 0) dv.formula1 = safe(
|
|
14823
|
-
if (dv.formula2 !== void 0) dv.formula2 = safe(
|
|
15473
|
+
if (dv.formula1 !== void 0) dv.formula1 = safe(rewrite, dv.formula1, name);
|
|
15474
|
+
if (dv.formula2 !== void 0) dv.formula2 = safe(rewrite, dv.formula2, name);
|
|
14824
15475
|
}
|
|
14825
15476
|
for (const link of sheet.hyperlinks)
|
|
14826
15477
|
if (link.location && /![A-Za-z$]/.test(link.location))
|
|
14827
|
-
link.location = safe(
|
|
15478
|
+
link.location = safe(rewrite, link.location, name);
|
|
14828
15479
|
for (const drawing of sheet.drawings) {
|
|
14829
15480
|
if (drawing.kind !== "chart") continue;
|
|
14830
15481
|
for (const series of drawing.series) {
|
|
14831
|
-
if (series.nameRef) series.nameRef = safe(
|
|
14832
|
-
if (series.categoriesRef) series.categoriesRef = safe(
|
|
14833
|
-
if (series.valuesRef) series.valuesRef = safe(
|
|
15482
|
+
if (series.nameRef) series.nameRef = safe(rewrite, series.nameRef, name);
|
|
15483
|
+
if (series.categoriesRef) series.categoriesRef = safe(rewrite, series.categoriesRef, name);
|
|
15484
|
+
if (series.valuesRef) series.valuesRef = safe(rewrite, series.valuesRef, name);
|
|
14834
15485
|
}
|
|
14835
15486
|
}
|
|
14836
15487
|
}
|
|
@@ -15017,7 +15668,7 @@ function shiftAxis(ctx, s, axis, at, count2, insert) {
|
|
|
15017
15668
|
applyAxisShift(ctx, sheet, shift2);
|
|
15018
15669
|
if (insert) inheritFormats(sheet, axis, at, count2);
|
|
15019
15670
|
},
|
|
15020
|
-
{ sheet: s, structural: true }
|
|
15671
|
+
{ sheet: s, structural: true, calc: { kind: "shift", sheet: s, shift: shift2 } }
|
|
15021
15672
|
);
|
|
15022
15673
|
}
|
|
15023
15674
|
var insertRows = (ctx, s, at, count2) => shiftAxis(ctx, s, "row", at, count2, true);
|
|
@@ -16831,6 +17482,14 @@ function setCalcMode(ctx, mode) {
|
|
|
16831
17482
|
|
|
16832
17483
|
// xlsx/edit/session-calc.ts
|
|
16833
17484
|
var isStructural = (step) => step.structural || step.entries.some((entry) => entry.before.kind !== "cells");
|
|
17485
|
+
function hintFor(step, mode) {
|
|
17486
|
+
const hint = step.calc;
|
|
17487
|
+
if (!hint) return void 0;
|
|
17488
|
+
if (hint.kind === "rename")
|
|
17489
|
+
return mode === "undo" ? { kind: "rename", from: hint.to, to: hint.from } : hint;
|
|
17490
|
+
return mode === "undo" ? void 0 : hint;
|
|
17491
|
+
}
|
|
17492
|
+
var settingsOf = (workbook) => `${workbook.iterate ? `${workbook.iterate.count}:${workbook.iterate.delta}` : ""}|${workbook.date1904}`;
|
|
16834
17493
|
var SessionCalculator = class {
|
|
16835
17494
|
constructor(workbook, calc, enabled) {
|
|
16836
17495
|
this.workbook = workbook;
|
|
@@ -16840,43 +17499,113 @@ var SessionCalculator = class {
|
|
|
16840
17499
|
workbook;
|
|
16841
17500
|
calc;
|
|
16842
17501
|
enabled;
|
|
16843
|
-
/** Structural edits
|
|
17502
|
+
/** Structural edits the engine could not follow leave the dependency graph stale (manual mode). */
|
|
16844
17503
|
staleGraph = false;
|
|
17504
|
+
/** Cells changed in manual mode since the last calculation. */
|
|
17505
|
+
dirty = [];
|
|
17506
|
+
/** The settings at the last calculation; undefined before the first. */
|
|
17507
|
+
calculated;
|
|
16845
17508
|
/** Recalculates after an applied, undone or redone step (failures become warnings). */
|
|
16846
|
-
afterStep(step) {
|
|
16847
|
-
if (!this.enabled)
|
|
17509
|
+
afterStep(step, mode = "apply") {
|
|
17510
|
+
if (!this.enabled) {
|
|
17511
|
+
this.calc.discardPreparation();
|
|
17512
|
+
return;
|
|
17513
|
+
}
|
|
17514
|
+
const structural = isStructural(step);
|
|
17515
|
+
const hint = structural ? hintFor(step, mode) : void 0;
|
|
16848
17516
|
if (calcModeOf(this.workbook) === "manual") {
|
|
16849
|
-
if (
|
|
17517
|
+
if (hint && !this.staleGraph && !this.dirty.length) {
|
|
17518
|
+
this.guard(() => this.follow(hint));
|
|
17519
|
+
return;
|
|
17520
|
+
}
|
|
17521
|
+
this.calc.discardPreparation();
|
|
17522
|
+
if (structural) this.staleGraph = true;
|
|
17523
|
+
else this.dirty.push(...touchedCells(step));
|
|
16850
17524
|
return;
|
|
16851
17525
|
}
|
|
16852
|
-
|
|
17526
|
+
if (hint && !this.staleGraph) {
|
|
17527
|
+
this.guard(() => {
|
|
17528
|
+
this.follow(hint);
|
|
17529
|
+
this.calc.recalculateFrom(touchedCells(step));
|
|
17530
|
+
this.calculated = settingsOf(this.workbook);
|
|
17531
|
+
});
|
|
17532
|
+
return;
|
|
17533
|
+
}
|
|
17534
|
+
this.recalc(structural, () => touchedCells(step));
|
|
16853
17535
|
}
|
|
16854
17536
|
/** Recalculates after a change applied outside the history (a collaborator's edit). */
|
|
16855
17537
|
afterExternal(structural, cells) {
|
|
16856
|
-
if (!this.enabled)
|
|
16857
|
-
|
|
17538
|
+
if (!this.enabled || calcModeOf(this.workbook) === "manual") {
|
|
17539
|
+
this.calc.discardPreparation();
|
|
17540
|
+
if (!this.enabled) return;
|
|
16858
17541
|
if (structural) this.staleGraph = true;
|
|
17542
|
+
else this.dirty.push(...cells);
|
|
16859
17543
|
return;
|
|
16860
17544
|
}
|
|
16861
17545
|
this.recalc(structural, () => cells);
|
|
16862
17546
|
}
|
|
16863
|
-
|
|
17547
|
+
follow(hint) {
|
|
17548
|
+
if (hint.kind === "shift") this.calc.shiftCells(hint.sheet, hint.shift);
|
|
17549
|
+
else this.calc.renameSheet(hint.from, hint.to);
|
|
17550
|
+
}
|
|
17551
|
+
guard(run) {
|
|
16864
17552
|
try {
|
|
17553
|
+
run();
|
|
17554
|
+
} catch (error) {
|
|
17555
|
+
const message = `Recalculation failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
17556
|
+
if (!this.workbook.warnings.includes(message)) this.workbook.warnings.push(message);
|
|
17557
|
+
}
|
|
17558
|
+
}
|
|
17559
|
+
/** Builds the dependency graph ahead of the first edit (see `EditSession.prepareCalculation`). */
|
|
17560
|
+
prepare(timeRemaining) {
|
|
17561
|
+
if (!this.enabled || calcModeOf(this.workbook) === "manual" || this.staleGraph) return true;
|
|
17562
|
+
try {
|
|
17563
|
+
return this.calc.prepare(timeRemaining);
|
|
17564
|
+
} catch {
|
|
17565
|
+
this.calc.discardPreparation();
|
|
17566
|
+
return true;
|
|
17567
|
+
}
|
|
17568
|
+
}
|
|
17569
|
+
/**
|
|
17570
|
+
* Before a structural edit the graph can follow in place: finishes a graph being prepared (or
|
|
17571
|
+
* builds it) while it still matches the workbook, so the edit moves it instead of rebuilding.
|
|
17572
|
+
*/
|
|
17573
|
+
beforeStructural() {
|
|
17574
|
+
if (!this.enabled || calcModeOf(this.workbook) === "manual" || this.staleGraph) return;
|
|
17575
|
+
this.prepare();
|
|
17576
|
+
}
|
|
17577
|
+
recalc(structural, cells) {
|
|
17578
|
+
this.guard(() => {
|
|
16865
17579
|
if (this.staleGraph || structural) this.full();
|
|
16866
17580
|
else {
|
|
16867
17581
|
const changed = cells();
|
|
16868
17582
|
if (changed.length) this.calc.recalculateFrom(changed);
|
|
17583
|
+
this.calculated = settingsOf(this.workbook);
|
|
16869
17584
|
}
|
|
16870
|
-
}
|
|
16871
|
-
const message = `Recalculation failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
16872
|
-
if (!this.workbook.warnings.includes(message)) this.workbook.warnings.push(message);
|
|
16873
|
-
}
|
|
17585
|
+
});
|
|
16874
17586
|
}
|
|
16875
|
-
/** Rebuilds the dependency graph and recalculates every formula (F9). */
|
|
17587
|
+
/** Rebuilds the dependency graph and recalculates every formula (Ctrl+Alt+F9). */
|
|
16876
17588
|
full() {
|
|
16877
17589
|
this.staleGraph = false;
|
|
17590
|
+
this.dirty = [];
|
|
16878
17591
|
this.calc.invalidate();
|
|
16879
17592
|
this.calc.recalculateAll();
|
|
17593
|
+
this.calculated = settingsOf(this.workbook);
|
|
17594
|
+
}
|
|
17595
|
+
/**
|
|
17596
|
+
* Calculate Now (F9): the cells changed since the last calculation, the formulas structural
|
|
17597
|
+
* edits queued, their dependents and the volatile functions. Everything when `full`, before
|
|
17598
|
+
* the session's first calculation, after the iteration settings changed or while the graph
|
|
17599
|
+
* is stale.
|
|
17600
|
+
*/
|
|
17601
|
+
now(full) {
|
|
17602
|
+
if (full || this.staleGraph || this.calculated !== settingsOf(this.workbook)) {
|
|
17603
|
+
this.full();
|
|
17604
|
+
return;
|
|
17605
|
+
}
|
|
17606
|
+
const changed = this.dirty;
|
|
17607
|
+
this.dirty = [];
|
|
17608
|
+
this.calc.recalculateFrom(changed);
|
|
16880
17609
|
}
|
|
16881
17610
|
/**
|
|
16882
17611
|
* Recalculates one sheet's formulas and their dependents (Shift+F9); after structural edits
|
|
@@ -20385,12 +21114,12 @@ function renameSheet(ctx, index2, name) {
|
|
|
20385
21114
|
ctx.run(
|
|
20386
21115
|
"Rename sheet",
|
|
20387
21116
|
"sheets",
|
|
20388
|
-
[{ kind: "
|
|
21117
|
+
[{ kind: "refs" }],
|
|
20389
21118
|
() => {
|
|
20390
21119
|
rewriteFormulas(workbook, (formula) => renameSheetInFormula(formula, old, name));
|
|
20391
21120
|
sheet.name = name;
|
|
20392
21121
|
},
|
|
20393
|
-
{ sheet: index2, structural: true }
|
|
21122
|
+
{ sheet: index2, structural: true, calc: { kind: "rename", from: old, to: name } }
|
|
20394
21123
|
);
|
|
20395
21124
|
}
|
|
20396
21125
|
function moveSheet(ctx, from, to) {
|
|
@@ -20766,13 +21495,12 @@ function createEditSession(workbook, options = {}) {
|
|
|
20766
21495
|
for (const listener of [...listeners2]) listener(change);
|
|
20767
21496
|
};
|
|
20768
21497
|
const calculator = new SessionCalculator(workbook, calc, autoRecalc);
|
|
20769
|
-
const recalc = (step) => calculator.afterStep(step);
|
|
20770
|
-
const begin = (label2, kind, info) =>
|
|
20771
|
-
step
|
|
20772
|
-
|
|
20773
|
-
sheet: info.sheet,
|
|
20774
|
-
|
|
20775
|
-
});
|
|
21498
|
+
const recalc = (step, mode = "apply") => calculator.afterStep(step, mode);
|
|
21499
|
+
const begin = (label2, kind, info) => {
|
|
21500
|
+
const step = { label: label2, entries: [], structural: info.structural ?? false };
|
|
21501
|
+
if (info.calc) step.calc = info.calc;
|
|
21502
|
+
return { step, kind, sheet: info.sheet, ranges: [...info.ranges ?? []] };
|
|
21503
|
+
};
|
|
20776
21504
|
const finish = (current) => {
|
|
20777
21505
|
if (!current.step.entries.length) return;
|
|
20778
21506
|
history.push(current.step);
|
|
@@ -20797,10 +21525,12 @@ function createEditSession(workbook, options = {}) {
|
|
|
20797
21525
|
const outer = !open;
|
|
20798
21526
|
const current = open ?? begin(label2, kind, info);
|
|
20799
21527
|
if (!outer) {
|
|
21528
|
+
delete current.step.calc;
|
|
20800
21529
|
if (info.structural) current.step.structural = true;
|
|
20801
21530
|
if (current.sheet === void 0 && info.sheet !== void 0) current.sheet = info.sheet;
|
|
20802
21531
|
current.ranges.push(...info.ranges ?? []);
|
|
20803
21532
|
}
|
|
21533
|
+
if (outer && info.calc) calculator.beforeStructural();
|
|
20804
21534
|
open = current;
|
|
20805
21535
|
const mark = current.step.entries.length;
|
|
20806
21536
|
const befores = scopes.map((scope) => captureScope(workbook, scope));
|
|
@@ -20848,7 +21578,7 @@ function createEditSession(workbook, options = {}) {
|
|
|
20848
21578
|
if (open) throw new Error(`Cannot ${kind} inside a batch`);
|
|
20849
21579
|
const step = kind === "undo" ? history.undo(workbook) : history.redo(workbook);
|
|
20850
21580
|
if (!step) return false;
|
|
20851
|
-
recalc(step);
|
|
21581
|
+
recalc(step, kind);
|
|
20852
21582
|
emit({ kind, label: step.label, structural: step.structural });
|
|
20853
21583
|
return true;
|
|
20854
21584
|
};
|
|
@@ -20927,10 +21657,11 @@ function createEditSession(workbook, options = {}) {
|
|
|
20927
21657
|
setDocumentProperties: (patch) => setDocumentProperties(ctx, patch),
|
|
20928
21658
|
setAutoRecalc: (enabled) => setCalcMode(ctx, enabled ? "auto" : "manual"),
|
|
20929
21659
|
autoRecalc: () => autoRecalc && calcModeOf(workbook) === "auto",
|
|
20930
|
-
calculateNow() {
|
|
20931
|
-
calculator.full
|
|
21660
|
+
calculateNow(options2) {
|
|
21661
|
+
calculator.now(options2?.full ?? false);
|
|
20932
21662
|
emit({ kind: "cells", label: "Calculate now", structural: false });
|
|
20933
21663
|
},
|
|
21664
|
+
prepareCalculation: (opts) => calculator.prepare(opts?.timeRemaining),
|
|
20934
21665
|
calculateSheet(s) {
|
|
20935
21666
|
calculator.sheet(s);
|
|
20936
21667
|
emit({ kind: "cells", label: "Calculate sheet", sheet: s, structural: false });
|