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