@ai-matrx/office 0.8.20 → 0.8.22
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/CHANGELOG.md +21 -2
- package/dist/collab-sheets-transform.cjs +471 -17
- package/dist/collab-sheets-transform.cjs.map +1 -1
- package/dist/collab-sheets-transform.d.cts +32 -4
- package/dist/collab-sheets-transform.d.ts +32 -4
- package/dist/collab-sheets-transform.js +471 -17
- package/dist/collab-sheets-transform.js.map +1 -1
- package/dist/univer-collab.cjs +536 -28
- package/dist/univer-collab.cjs.map +1 -1
- package/dist/univer-collab.d.cts +6 -1
- package/dist/univer-collab.d.ts +6 -1
- package/dist/univer-collab.js +536 -28
- package/dist/univer-collab.js.map +1 -1
- package/package.json +4 -4
|
@@ -24,6 +24,15 @@ var SHEET_MUTATIONS = {
|
|
|
24
24
|
"sheet.mutation.set-worksheet-row-auto-height": covered("size", "rowsAutoHeightInfo"),
|
|
25
25
|
"sheet.mutation.set-worksheet-col-width": covered("size", "ranges", "colWidth"),
|
|
26
26
|
"sheet.mutation.set-worksheet-name": covered("name", "name"),
|
|
27
|
+
// ── covered (C5c) ────────────────────────────────────────────────────────────────────────────────
|
|
28
|
+
"sheet.mutation.set.numfmt": covered("numfmt", "values", "refMap"),
|
|
29
|
+
"sheet.mutation.remove.numfmt": covered("numfmt", "ranges"),
|
|
30
|
+
"sheet.mutation.set-worksheet-row-count": covered("count", "rowCount"),
|
|
31
|
+
"sheet.mutation.set-worksheet-column-count": covered("count", "columnCount"),
|
|
32
|
+
"sheet.mutation.insert-sheet": covered("sheet", "index", "sheet"),
|
|
33
|
+
"sheet.mutation.remove-sheet": covered("sheet", "sheetIndex", "sheetsLeft"),
|
|
34
|
+
"sheet.mutation.set-worksheet-order": covered("sheet", "fromOrder", "toOrder"),
|
|
35
|
+
"sheet.mutation.reorder-range": covered("sort", "range", "order"),
|
|
27
36
|
// ── never travels ────────────────────────────────────────────────────────────────────────────────
|
|
28
37
|
"formula.mutation.set-formula-calculation-start": never(FORMULA_RESULT),
|
|
29
38
|
"formula.mutation.set-trigger-formula-calculation-start": never(FORMULA_RESULT),
|
|
@@ -57,13 +66,7 @@ var SHEET_MUTATIONS = {
|
|
|
57
66
|
"thread-comment.mutation.resolve-comment": never(UNIVER_COMMENTS),
|
|
58
67
|
"thread-comment.mutation.delete-comment": never(UNIVER_COMMENTS),
|
|
59
68
|
// ── barriers: X (no transform yet, design §10) ───────────────────────────────────────────────────
|
|
60
|
-
"sheet.mutation.reorder-range": barrier("X", "sort: a permutation, not transformed yet"),
|
|
61
|
-
"sheet.mutation.set-worksheet-row-count": barrier("X", "absolute row count; needs delta semantics"),
|
|
62
|
-
"sheet.mutation.set-worksheet-column-count": barrier("X", "absolute column count; needs delta semantics"),
|
|
63
|
-
"sheet.mutation.set-worksheet-order": barrier("X", "absolute sheet order; needs move semantics"),
|
|
64
69
|
"sheet.mutation.move-range": barrier("X", "cut-paste carries the sender's cell matrices"),
|
|
65
|
-
"sheet.mutation.insert-sheet": barrier("X", "sheet add: not in C5a"),
|
|
66
|
-
"sheet.mutation.remove-sheet": barrier("X", "sheet remove: not in C5a"),
|
|
67
70
|
"sheet.mutation.set-worksheet-hidden": barrier("X", "sheet-level setting: not in C5a"),
|
|
68
71
|
"sheet.mutation.set-tab-color": barrier("X", "sheet-level setting: not in C5a"),
|
|
69
72
|
"sheet.mutation.set-workbook-name": barrier("X", "workbook-level setting: not in C5a"),
|
|
@@ -78,8 +81,6 @@ var SHEET_MUTATIONS = {
|
|
|
78
81
|
"sheet.mutation.set-row-visible": barrier("X", "row visibility: not in C5a"),
|
|
79
82
|
"sheet.mutation.set-col-hidden": barrier("X", "column visibility: not in C5a"),
|
|
80
83
|
"sheet.mutation.set-col-visible": barrier("X", "column visibility: not in C5a"),
|
|
81
|
-
"sheet.mutation.set.numfmt": barrier("X", "number formats by range: not in C5a"),
|
|
82
|
-
"sheet.mutation.remove.numfmt": barrier("X", "number formats by range: not in C5a"),
|
|
83
84
|
"sheet.mutation.add-range-protection": barrier("X", "permissions: not in C5a"),
|
|
84
85
|
"sheet.mutation.set-range-protection": barrier("X", "permissions: not in C5a"),
|
|
85
86
|
"sheet.mutation.delete-range-protection": barrier("X", "permissions: not in C5a"),
|
|
@@ -483,7 +484,7 @@ function refSheetsFor(texts, sheets) {
|
|
|
483
484
|
}
|
|
484
485
|
|
|
485
486
|
// src/collab/sheets/transform/transform.ts
|
|
486
|
-
var SHEET_TRANSFORMER_VERSION = "
|
|
487
|
+
var SHEET_TRANSFORMER_VERSION = "c5c-1";
|
|
487
488
|
var ID = {
|
|
488
489
|
values: "sheet.mutation.set-range-values",
|
|
489
490
|
insertRow: "sheet.mutation.insert-row",
|
|
@@ -500,7 +501,15 @@ var ID = {
|
|
|
500
501
|
colWidth: "sheet.mutation.set-worksheet-col-width",
|
|
501
502
|
name: "sheet.mutation.set-worksheet-name",
|
|
502
503
|
setName: "formula.mutation.set-defined-name",
|
|
503
|
-
removeName: "formula.mutation.remove-defined-name"
|
|
504
|
+
removeName: "formula.mutation.remove-defined-name",
|
|
505
|
+
setNumfmt: "sheet.mutation.set.numfmt",
|
|
506
|
+
removeNumfmt: "sheet.mutation.remove.numfmt",
|
|
507
|
+
rowCount: "sheet.mutation.set-worksheet-row-count",
|
|
508
|
+
colCount: "sheet.mutation.set-worksheet-column-count",
|
|
509
|
+
insertSheet: "sheet.mutation.insert-sheet",
|
|
510
|
+
removeSheet: "sheet.mutation.remove-sheet",
|
|
511
|
+
sheetOrder: "sheet.mutation.set-worksheet-order",
|
|
512
|
+
sort: "sheet.mutation.reorder-range"
|
|
504
513
|
};
|
|
505
514
|
var PAIR_BARRIERS = {};
|
|
506
515
|
var pairKey = (a, b) => a < b ? `${a}|${b}` : `${b}|${a}`;
|
|
@@ -612,6 +621,20 @@ function mergeThrough(s, m) {
|
|
|
612
621
|
}
|
|
613
622
|
return { range: m, fixup: false };
|
|
614
623
|
}
|
|
624
|
+
function mergeFixupsOwed(m, mergesBefore) {
|
|
625
|
+
const st = structuralOf(m);
|
|
626
|
+
if (!st) return null;
|
|
627
|
+
const remove = [];
|
|
628
|
+
const add = [];
|
|
629
|
+
for (const q of mergesBefore) {
|
|
630
|
+
const t = mergeThrough(st, q);
|
|
631
|
+
if (!t.fixup) continue;
|
|
632
|
+
remove.push({ startRow: q.startRow, endRow: q.endRow, startColumn: q.startColumn, endColumn: q.endColumn, ...q.rangeType !== void 0 ? { rangeType: q.rangeType } : {} });
|
|
633
|
+
if (t.range) add.push({ ...t.range });
|
|
634
|
+
}
|
|
635
|
+
return remove.length ? { remove, add } : null;
|
|
636
|
+
}
|
|
637
|
+
var isStructuralMutation = (m) => structuralOf(m) !== null;
|
|
615
638
|
function exactMergeRemovals(group, merges) {
|
|
616
639
|
const sim = new Map(Object.entries(merges).map(([k, v]) => [k, v.map((r) => ({ ...r }))]));
|
|
617
640
|
const out = [];
|
|
@@ -658,8 +681,24 @@ function cellsMutation(template, cells) {
|
|
|
658
681
|
function putCell(cells, r, c, v) {
|
|
659
682
|
(cells[r] ??= {})[c] = v;
|
|
660
683
|
}
|
|
684
|
+
function cellsOverlap(a, b) {
|
|
685
|
+
for (const r of Object.keys(a)) {
|
|
686
|
+
const br = b[r];
|
|
687
|
+
if (!br) continue;
|
|
688
|
+
for (const c of Object.keys(a[r] ?? {})) if (c in br) return true;
|
|
689
|
+
}
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
661
692
|
var isEmptyMatrix = (cells) => Object.values(cells).every((row) => Object.keys(row).length === 0);
|
|
693
|
+
var cellBarrierCache = /* @__PURE__ */ new WeakMap();
|
|
662
694
|
function cellBarrier(m) {
|
|
695
|
+
const hit = cellBarrierCache.get(m);
|
|
696
|
+
if (hit !== void 0) return hit;
|
|
697
|
+
const why = cellBarrierOf(m);
|
|
698
|
+
cellBarrierCache.set(m, why);
|
|
699
|
+
return why;
|
|
700
|
+
}
|
|
701
|
+
function cellBarrierOf(m) {
|
|
663
702
|
if (m.params.isOverrideStyle) return "set-range-values with isOverrideStyle (whole-style replace) is not covered";
|
|
664
703
|
let why = null;
|
|
665
704
|
forEachCell(cellsOf(m), (_r, _c, v) => {
|
|
@@ -741,6 +780,7 @@ function transformCell(X, Y, side) {
|
|
|
741
780
|
function transformCellsOverCells(x, y, side) {
|
|
742
781
|
if (sheetOf(x) !== sheetOf(y)) return ok([x]);
|
|
743
782
|
const ycells = cellsOf(y);
|
|
783
|
+
if (!cellsOverlap(cellsOf(x), ycells)) return ok([x]);
|
|
744
784
|
const xd = isDerived(x);
|
|
745
785
|
const yd = isDerived(y);
|
|
746
786
|
const eff = derivedSide(x, y, side);
|
|
@@ -768,7 +808,7 @@ function transformCellsOverCells(x, y, side) {
|
|
|
768
808
|
const op = passes.filter((p) => !isEmptyMatrix(p)).map((p) => cellsMutation(x, p));
|
|
769
809
|
return ok(op, lost, dropped);
|
|
770
810
|
}
|
|
771
|
-
var SIDE_CAR_PARAMS = ["refSheets", "previousName", "derived"];
|
|
811
|
+
var SIDE_CAR_PARAMS = ["refSheets", "previousName", "derived", "sheetIndex", "sheetsLeft"];
|
|
772
812
|
var isDerived = (m) => m.params.derived === true;
|
|
773
813
|
function derivedSide(x, y, side) {
|
|
774
814
|
const xd = isDerived(x);
|
|
@@ -790,7 +830,15 @@ function withRefSheets(params, rs) {
|
|
|
790
830
|
return out;
|
|
791
831
|
}
|
|
792
832
|
var hasFormulaText = (v) => !!v && (isFormulaText(v.f) || typeof v.ref === "string");
|
|
833
|
+
var hasFormulaCache = /* @__PURE__ */ new WeakMap();
|
|
793
834
|
function hasFormula(m) {
|
|
835
|
+
const hit = hasFormulaCache.get(m);
|
|
836
|
+
if (hit !== void 0) return hit;
|
|
837
|
+
const any = hasFormulaOf(m);
|
|
838
|
+
hasFormulaCache.set(m, any);
|
|
839
|
+
return any;
|
|
840
|
+
}
|
|
841
|
+
function hasFormulaOf(m) {
|
|
794
842
|
let any = false;
|
|
795
843
|
forEachCell(cellsOf(m), (_r, _c, v) => {
|
|
796
844
|
any ||= hasFormulaText(v);
|
|
@@ -829,15 +877,18 @@ function cellThrough(sheet, change, r, c) {
|
|
|
829
877
|
return nr === null || nc === null ? null : [nr, nc];
|
|
830
878
|
}
|
|
831
879
|
function cellsOverChange(x, change) {
|
|
880
|
+
if (!hasFormula(x) && (change.kind !== "axis" || change.sheet !== sheetOf(x))) return ok([x]);
|
|
832
881
|
const ctx = formulaCtx(x);
|
|
833
882
|
const out = {};
|
|
834
883
|
const dropped = [];
|
|
835
884
|
let why = null;
|
|
885
|
+
let changed = false;
|
|
836
886
|
forEachCell(cellsOf(x), (r, c, v) => {
|
|
837
887
|
if (why) return;
|
|
838
888
|
const at = cellThrough(sheetOf(x), change, r, c);
|
|
839
889
|
if (!at) {
|
|
840
890
|
dropped.push(cellRef(sheetOf(x), r, c));
|
|
891
|
+
changed = true;
|
|
841
892
|
return;
|
|
842
893
|
}
|
|
843
894
|
let e = v;
|
|
@@ -848,14 +899,19 @@ function cellsOverChange(x, change) {
|
|
|
848
899
|
return;
|
|
849
900
|
}
|
|
850
901
|
e = res.entry;
|
|
902
|
+
if (res.changed) changed = true;
|
|
851
903
|
}
|
|
904
|
+
if (at[0] !== r || at[1] !== c) changed = true;
|
|
852
905
|
putCell(out, at[0], at[1], e);
|
|
853
906
|
});
|
|
854
907
|
if (why) return barrier2(why);
|
|
855
|
-
const
|
|
908
|
+
const rsAfter = refSheetsAfter(ctx.refSheets, change);
|
|
909
|
+
if (!changed && JSON.stringify(rsAfter ?? null) === JSON.stringify(ctx.refSheets ?? null)) return ok([x]);
|
|
910
|
+
const params = { ...withRefSheets(x.params, rsAfter), cellValue: out };
|
|
856
911
|
return ok(isEmptyMatrix(out) ? [] : [{ id: x.id, params }], [], dropped);
|
|
857
912
|
}
|
|
858
913
|
function rewritesOf(y, change) {
|
|
914
|
+
if (!hasFormula(y)) return null;
|
|
859
915
|
const ctx = formulaCtx(y);
|
|
860
916
|
const out = {};
|
|
861
917
|
let why = null;
|
|
@@ -1001,6 +1057,368 @@ function buildSize(template, values) {
|
|
|
1001
1057
|
const value = uniform !== void 0 && [...values.values()].every((v) => v === uniform) ? uniform : Object.fromEntries(values);
|
|
1002
1058
|
return { id: template.id, params: { ...p, ranges, [field]: value } };
|
|
1003
1059
|
}
|
|
1060
|
+
var isNumfmt = (m) => m.id === ID.setNumfmt || m.id === ID.removeNumfmt;
|
|
1061
|
+
function nfParts(m) {
|
|
1062
|
+
if (m.id === ID.removeNumfmt) return [{ key: null, ranges: (m.params.ranges ?? []).map((r) => ({ ...r })) }];
|
|
1063
|
+
const values = m.params.values ?? {};
|
|
1064
|
+
return Object.keys(values).map((k) => ({ key: k, ranges: (values[k]?.ranges ?? []).map((r) => ({ ...r })) }));
|
|
1065
|
+
}
|
|
1066
|
+
function nfBuild(m, parts) {
|
|
1067
|
+
const keep = parts.filter((p) => p.ranges.length);
|
|
1068
|
+
if (!keep.length) return [];
|
|
1069
|
+
if (m.id === ID.removeNumfmt) return [{ id: m.id, params: { ...m.params, ranges: keep[0].ranges } }];
|
|
1070
|
+
const values = {};
|
|
1071
|
+
const refMap = {};
|
|
1072
|
+
const srcValues = m.params.values ?? {};
|
|
1073
|
+
const srcRef = m.params.refMap ?? {};
|
|
1074
|
+
for (const p of keep) {
|
|
1075
|
+
values[p.key] = { ...srcValues[p.key], ranges: p.ranges };
|
|
1076
|
+
refMap[p.key] = srcRef[p.key];
|
|
1077
|
+
}
|
|
1078
|
+
return [{ id: m.id, params: { ...m.params, values, refMap } }];
|
|
1079
|
+
}
|
|
1080
|
+
function nfValueAt(m, row, col) {
|
|
1081
|
+
for (const p of nfParts(m))
|
|
1082
|
+
if (p.ranges.some((r) => r.startRow <= row && row <= r.endRow && r.startColumn <= col && col <= r.endColumn)) {
|
|
1083
|
+
if (p.key === null) return null;
|
|
1084
|
+
const ref = (m.params.refMap ?? {})[p.key];
|
|
1085
|
+
return { pattern: ref?.pattern };
|
|
1086
|
+
}
|
|
1087
|
+
return void 0;
|
|
1088
|
+
}
|
|
1089
|
+
function spanThrough(op, lo, hi) {
|
|
1090
|
+
const pieces = [];
|
|
1091
|
+
if (op.kind === "insert") pieces.push([0, op.at - 1, 0], [op.at, Infinity, op.count]);
|
|
1092
|
+
else if (op.kind === "remove") pieces.push([0, op.start - 1, 0], [op.start + op.count, Infinity, -op.count]);
|
|
1093
|
+
else if (op.count <= 0 || op.to >= op.from && op.to <= op.from + op.count) pieces.push([0, Infinity, 0]);
|
|
1094
|
+
else if (op.to > op.from) {
|
|
1095
|
+
const n = op.count;
|
|
1096
|
+
pieces.push([0, op.from - 1, 0], [op.from, op.from + n - 1, op.to - n - op.from], [op.from + n, op.to - 1, -n], [op.to, Infinity, 0]);
|
|
1097
|
+
} else {
|
|
1098
|
+
const n = op.count;
|
|
1099
|
+
pieces.push([0, op.to - 1, 0], [op.to, op.from - 1, n], [op.from, op.from + n - 1, op.to - op.from], [op.from + n, Infinity, 0]);
|
|
1100
|
+
}
|
|
1101
|
+
const out = [];
|
|
1102
|
+
for (const [a, b, d] of pieces) {
|
|
1103
|
+
const x0 = Math.max(a, lo);
|
|
1104
|
+
const x1 = Math.min(b, hi);
|
|
1105
|
+
if (x0 <= x1) out.push([x0 + d, x1 + d]);
|
|
1106
|
+
}
|
|
1107
|
+
out.sort((p, q) => p[0] - q[0]);
|
|
1108
|
+
const merged = [];
|
|
1109
|
+
for (const p of out) {
|
|
1110
|
+
const last = merged[merged.length - 1];
|
|
1111
|
+
if (last && last[1] + 1 >= p[0]) last[1] = Math.max(last[1], p[1]);
|
|
1112
|
+
else merged.push([p[0], p[1]]);
|
|
1113
|
+
}
|
|
1114
|
+
return merged;
|
|
1115
|
+
}
|
|
1116
|
+
function rectsThrough(st, rects) {
|
|
1117
|
+
const [a0, a1] = S(st.axis);
|
|
1118
|
+
const out = [];
|
|
1119
|
+
for (const r of rects) for (const [lo, hi] of spanThrough(st.op, r[a0], r[a1])) out.push({ ...r, [a0]: lo, [a1]: hi });
|
|
1120
|
+
return out;
|
|
1121
|
+
}
|
|
1122
|
+
function rectMinus(a, b) {
|
|
1123
|
+
if (a.startRow > b.endRow || b.startRow > a.endRow || a.startColumn > b.endColumn || b.startColumn > a.endColumn) return [a];
|
|
1124
|
+
const out = [];
|
|
1125
|
+
if (a.startRow < b.startRow) out.push({ ...a, endRow: b.startRow - 1 });
|
|
1126
|
+
if (a.endRow > b.endRow) out.push({ ...a, startRow: b.endRow + 1 });
|
|
1127
|
+
const r0 = Math.max(a.startRow, b.startRow);
|
|
1128
|
+
const r1 = Math.min(a.endRow, b.endRow);
|
|
1129
|
+
if (a.startColumn < b.startColumn) out.push({ ...a, startRow: r0, endRow: r1, endColumn: b.startColumn - 1 });
|
|
1130
|
+
if (a.endColumn > b.endColumn) out.push({ ...a, startRow: r0, endRow: r1, startColumn: b.endColumn + 1 });
|
|
1131
|
+
return out;
|
|
1132
|
+
}
|
|
1133
|
+
function rectsMinus(as, bs) {
|
|
1134
|
+
let cur = as;
|
|
1135
|
+
for (const b of bs) cur = cur.flatMap((a) => rectMinus(a, b));
|
|
1136
|
+
return cur;
|
|
1137
|
+
}
|
|
1138
|
+
function nWrites(m) {
|
|
1139
|
+
const out = [];
|
|
1140
|
+
forEachCell(cellsOf(m), (r, c, v) => {
|
|
1141
|
+
if (v === null || v.s === null || v.s && typeof v.s === "object" && "n" in v.s)
|
|
1142
|
+
out.push({ startRow: r, endRow: r, startColumn: c, endColumn: c });
|
|
1143
|
+
});
|
|
1144
|
+
return out;
|
|
1145
|
+
}
|
|
1146
|
+
function numfmtPair(x, y, side, sx, sy) {
|
|
1147
|
+
const nx = isNumfmt(x);
|
|
1148
|
+
const ny = isNumfmt(y);
|
|
1149
|
+
if (!nx && !ny) return null;
|
|
1150
|
+
if (nx && sy) return ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsThrough(sy, p.ranges) }))));
|
|
1151
|
+
if (ny && sx) return ok([x]);
|
|
1152
|
+
if (nx && ny) {
|
|
1153
|
+
if (side === "left") return ok([x]);
|
|
1154
|
+
const ys = nfParts(y).flatMap((p) => p.ranges);
|
|
1155
|
+
return ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsMinus(p.ranges, ys) }))));
|
|
1156
|
+
}
|
|
1157
|
+
if (nx && y.id === ID.values) {
|
|
1158
|
+
if (side === "left") return ok([x]);
|
|
1159
|
+
const ys = nWrites(y);
|
|
1160
|
+
return ys.length ? ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsMinus(p.ranges, ys) })))) : ok([x]);
|
|
1161
|
+
}
|
|
1162
|
+
if (ny && x.id === ID.values) {
|
|
1163
|
+
if (side === "left") return ok([x]);
|
|
1164
|
+
const out = {};
|
|
1165
|
+
const tail = {};
|
|
1166
|
+
let touched = false;
|
|
1167
|
+
forEachCell(cellsOf(x), (r, c, v) => {
|
|
1168
|
+
const n = nfValueAt(y, r, c);
|
|
1169
|
+
if (n === void 0) return putCell(out, r, c, v);
|
|
1170
|
+
if (v === null || v.s === null) {
|
|
1171
|
+
putCell(out, r, c, v);
|
|
1172
|
+
if (n) {
|
|
1173
|
+
putCell(tail, r, c, { s: { n } });
|
|
1174
|
+
touched = true;
|
|
1175
|
+
}
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
if (v.s && typeof v.s === "object" && "n" in v.s) {
|
|
1179
|
+
const { n: _drop, ...rest } = v.s;
|
|
1180
|
+
const e = { ...v };
|
|
1181
|
+
if (Object.keys(rest).length) e.s = rest;
|
|
1182
|
+
else delete e.s;
|
|
1183
|
+
touched = true;
|
|
1184
|
+
if (Object.keys(e).length) putCell(out, r, c, e);
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
putCell(out, r, c, v);
|
|
1188
|
+
});
|
|
1189
|
+
if (!touched) return ok([x]);
|
|
1190
|
+
const ops = [];
|
|
1191
|
+
if (!isEmptyMatrix(out)) ops.push(cellsMutation(x, out));
|
|
1192
|
+
if (!isEmptyMatrix(tail)) ops.push({ id: ID.values, params: { subUnitId: sheetOf(x), cellValue: tail } });
|
|
1193
|
+
return ok(ops);
|
|
1194
|
+
}
|
|
1195
|
+
return ok([x]);
|
|
1196
|
+
}
|
|
1197
|
+
var isCount = (m) => m.id === ID.rowCount || m.id === ID.colCount;
|
|
1198
|
+
var countAxis = (m) => m.id === ID.rowCount ? "row" : "col";
|
|
1199
|
+
var countKey = (m) => m.id === ID.rowCount ? "rowCount" : "columnCount";
|
|
1200
|
+
function countPair(x, y, sy) {
|
|
1201
|
+
if (!isCount(x)) return isCount(y) ? ok([x]) : null;
|
|
1202
|
+
const k = countKey(x);
|
|
1203
|
+
const v = Number(x.params[k]);
|
|
1204
|
+
if (sy) {
|
|
1205
|
+
if (sy.axis !== countAxis(x) || sy.op.kind === "move") return ok([x]);
|
|
1206
|
+
const d = sy.op.kind === "insert" ? sy.op.count : -sy.op.count;
|
|
1207
|
+
return ok([{ id: x.id, params: { ...x.params, [k]: Math.max(1, v + d) } }]);
|
|
1208
|
+
}
|
|
1209
|
+
if (isCount(y) && y.id === x.id) {
|
|
1210
|
+
const w = Number(y.params[k]);
|
|
1211
|
+
return ok([w > v ? { id: x.id, params: { ...x.params, [k]: w } } : x]);
|
|
1212
|
+
}
|
|
1213
|
+
return ok([x]);
|
|
1214
|
+
}
|
|
1215
|
+
var isSheetOp = (m) => m.id === ID.insertSheet || m.id === ID.removeSheet || m.id === ID.sheetOrder;
|
|
1216
|
+
var sheetIdOf = (m) => m.id === ID.insertSheet ? String(m.params.sheet?.id ?? "") : sheetOf(m);
|
|
1217
|
+
function sheetAxisOf(m) {
|
|
1218
|
+
const p = m.params;
|
|
1219
|
+
if (m.id === ID.insertSheet) return typeof p.index === "number" ? { kind: "insert", at: p.index, count: 1 } : null;
|
|
1220
|
+
if (m.id === ID.removeSheet) return typeof p.sheetIndex === "number" ? { kind: "remove", start: p.sheetIndex, count: 1 } : null;
|
|
1221
|
+
if (m.id === ID.sheetOrder) {
|
|
1222
|
+
const f = Number(p.fromOrder);
|
|
1223
|
+
const t = Number(p.toOrder);
|
|
1224
|
+
return { kind: "move", from: f, count: 1, to: t > f ? t + 1 : t };
|
|
1225
|
+
}
|
|
1226
|
+
return null;
|
|
1227
|
+
}
|
|
1228
|
+
function buildSheetOp(template, op) {
|
|
1229
|
+
if (op.kind === "insert") return { id: template.id, params: { ...template.params, index: op.at } };
|
|
1230
|
+
if (op.kind === "remove") return { id: template.id, params: { ...template.params, sheetIndex: op.start } };
|
|
1231
|
+
return { id: template.id, params: { ...template.params, fromOrder: op.from, toOrder: op.to > op.from ? op.to - 1 : op.to } };
|
|
1232
|
+
}
|
|
1233
|
+
function namesSheet(m, id) {
|
|
1234
|
+
const rs = refSheetsOf(m);
|
|
1235
|
+
return !!rs && Object.values(rs).includes(id) && (m.id === ID.setName || hasFormula(m));
|
|
1236
|
+
}
|
|
1237
|
+
function sheetPair(x, y, side) {
|
|
1238
|
+
const xs = isSheetOp(x);
|
|
1239
|
+
const ys = isSheetOp(y);
|
|
1240
|
+
if (!xs && !ys) return null;
|
|
1241
|
+
if (xs && ys) {
|
|
1242
|
+
const a = sheetAxisOf(x);
|
|
1243
|
+
const b = sheetAxisOf(y);
|
|
1244
|
+
if (!a || !b) return barrier2("a sheet add or remove without its index (capture must call annotateSheetOps)");
|
|
1245
|
+
if (x.id === ID.insertSheet && y.id === ID.insertSheet && sheetIdOf(x) === sheetIdOf(y)) {
|
|
1246
|
+
return JSON.stringify(x.params) === JSON.stringify(y.params) ? ok([]) : barrier2("the same sheet id added twice with different content");
|
|
1247
|
+
}
|
|
1248
|
+
if (x.id === ID.removeSheet && typeof x.params.sheetsLeft === "number" && sheetIdOf(x) !== sheetIdOf(y) && (y.id === ID.removeSheet || y.id === ID.insertSheet)) {
|
|
1249
|
+
const left = x.params.sheetsLeft + (y.id === ID.insertSheet ? 1 : -1);
|
|
1250
|
+
if (left < 1) return barrier2("concurrent sheet removes would leave the workbook without a sheet");
|
|
1251
|
+
const out2 = transformAxis(a, b, side);
|
|
1252
|
+
if (!out2) return barrier2("sheet order: no transform");
|
|
1253
|
+
return ok(out2.map((o) => buildSheetOp({ id: x.id, params: { ...x.params, sheetsLeft: left } }, o)));
|
|
1254
|
+
}
|
|
1255
|
+
const out = transformAxis(a, b, side);
|
|
1256
|
+
if (!out) return barrier2("sheet order: no transform");
|
|
1257
|
+
return ok(out.map((o) => buildSheetOp(x, o)), [], out.length === 0 && x.id === ID.sheetOrder ? [`${sheetIdOf(x)}: sheet order`] : []);
|
|
1258
|
+
}
|
|
1259
|
+
if (ys) {
|
|
1260
|
+
if (y.id !== ID.removeSheet) return ok([x]);
|
|
1261
|
+
const gone2 = sheetOf(y);
|
|
1262
|
+
if (namesSheet(x, gone2)) return barrier2("a formula names a sheet removed at the same time");
|
|
1263
|
+
if (sheetOf(x) === gone2 && x.id !== ID.setName && x.id !== ID.removeName)
|
|
1264
|
+
return ok([], [], isDerived(x) ? [] : [`${gone2}: the sheet was removed`]);
|
|
1265
|
+
return ok([x]);
|
|
1266
|
+
}
|
|
1267
|
+
if (x.id !== ID.removeSheet) return ok([x]);
|
|
1268
|
+
const gone = sheetOf(x);
|
|
1269
|
+
if (namesSheet(y, gone)) return barrier2("a formula names a sheet removed at the same time");
|
|
1270
|
+
return ok([x], sheetOf(y) === gone && !isDerived(y) && y.id !== ID.setName && y.id !== ID.removeName ? [`${gone}: the sheet was removed`] : []);
|
|
1271
|
+
}
|
|
1272
|
+
function annotateSheetOps(group, sheetOrder) {
|
|
1273
|
+
const order = [...sheetOrder];
|
|
1274
|
+
return group.map((m) => {
|
|
1275
|
+
if (m.id === ID.insertSheet) {
|
|
1276
|
+
const index = typeof m.params.index === "number" ? Math.min(m.params.index, order.length) : order.length;
|
|
1277
|
+
order.splice(index, 0, sheetIdOf(m));
|
|
1278
|
+
return index === m.params.index ? m : { id: m.id, params: { ...m.params, index } };
|
|
1279
|
+
}
|
|
1280
|
+
if (m.id === ID.removeSheet) {
|
|
1281
|
+
const i = order.indexOf(sheetOf(m));
|
|
1282
|
+
if (i >= 0) order.splice(i, 1);
|
|
1283
|
+
return i >= 0 ? { id: m.id, params: { ...m.params, sheetIndex: i, sheetsLeft: order.length } } : m;
|
|
1284
|
+
}
|
|
1285
|
+
if (m.id === ID.sheetOrder) {
|
|
1286
|
+
const f = Number(m.params.fromOrder);
|
|
1287
|
+
const [id] = order.splice(f, 1);
|
|
1288
|
+
order.splice(Number(m.params.toOrder), 0, id ?? sheetOf(m));
|
|
1289
|
+
}
|
|
1290
|
+
return m;
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
function inlineSheetStyles(sheet, styleOf) {
|
|
1294
|
+
const out = JSON.parse(JSON.stringify(sheet));
|
|
1295
|
+
const fix = (o) => {
|
|
1296
|
+
if (o && typeof o.s === "string") {
|
|
1297
|
+
const st = styleOf(o.s);
|
|
1298
|
+
if (st) o.s = JSON.parse(JSON.stringify(st));
|
|
1299
|
+
}
|
|
1300
|
+
};
|
|
1301
|
+
for (const row of Object.values(out.cellData ?? {})) for (const cell of Object.values(row ?? {})) fix(cell);
|
|
1302
|
+
for (const key of ["rowData", "columnData"]) for (const v of Object.values(out[key] ?? {})) fix(v);
|
|
1303
|
+
if (typeof out.defaultStyle === "string") {
|
|
1304
|
+
const st = styleOf(out.defaultStyle);
|
|
1305
|
+
if (st) out.defaultStyle = JSON.parse(JSON.stringify(st));
|
|
1306
|
+
}
|
|
1307
|
+
return out;
|
|
1308
|
+
}
|
|
1309
|
+
var isSort = (m) => m.id === ID.sort;
|
|
1310
|
+
function sortOf(m) {
|
|
1311
|
+
const P = /* @__PURE__ */ new Map();
|
|
1312
|
+
for (const [t, src] of Object.entries(m.params.order ?? {})) P.set(Number(t), Number(src));
|
|
1313
|
+
return { range: { ...m.params.range }, P };
|
|
1314
|
+
}
|
|
1315
|
+
var sortQ = (o) => new Map([...o.P].map(([t, s0]) => [s0, t]));
|
|
1316
|
+
function buildSort(template, o) {
|
|
1317
|
+
const order = {};
|
|
1318
|
+
for (const [t, s0] of [...o.P].sort((a, b) => a[0] - b[0])) if (t !== s0) order[t] = s0;
|
|
1319
|
+
if (!Object.keys(order).length || o.range.startRow > o.range.endRow || o.range.startColumn > o.range.endColumn) return [];
|
|
1320
|
+
return [{ id: template.id, params: { ...template.params, range: o.range, order } }];
|
|
1321
|
+
}
|
|
1322
|
+
var inSortCols = (o, c) => c >= o.range.startColumn && c <= o.range.endColumn;
|
|
1323
|
+
function sortThrough(o, st) {
|
|
1324
|
+
const r = o.range;
|
|
1325
|
+
if (st.axis === "col") {
|
|
1326
|
+
if (st.op.kind === "move") {
|
|
1327
|
+
const { from, count, to } = st.op;
|
|
1328
|
+
const touches = !(from + count - 1 < r.startColumn || from > r.endColumn) || to > r.startColumn && to <= r.endColumn;
|
|
1329
|
+
if (touches) return null;
|
|
1330
|
+
const spans3 = spanThrough(st.op, r.startColumn, r.endColumn);
|
|
1331
|
+
return spans3.length === 1 ? { range: { ...r, startColumn: spans3[0][0], endColumn: spans3[0][1] }, P: o.P } : null;
|
|
1332
|
+
}
|
|
1333
|
+
const spans2 = spanThrough(st.op, r.startColumn, r.endColumn);
|
|
1334
|
+
if (!spans2.length) return { range: { ...r, startColumn: 1, endColumn: 0 }, P: /* @__PURE__ */ new Map() };
|
|
1335
|
+
return { range: { ...r, startColumn: spans2[0][0], endColumn: spans2[spans2.length - 1][1] }, P: o.P };
|
|
1336
|
+
}
|
|
1337
|
+
const op = st.op;
|
|
1338
|
+
if (op.kind === "move") {
|
|
1339
|
+
const touches = !(op.from + op.count - 1 < r.startRow || op.from > r.endRow) || op.to > r.startRow && op.to <= r.endRow;
|
|
1340
|
+
if (touches) return null;
|
|
1341
|
+
}
|
|
1342
|
+
if (op.kind === "insert" || op.kind === "move") {
|
|
1343
|
+
const P2 = /* @__PURE__ */ new Map();
|
|
1344
|
+
for (const [t, s0] of o.P) P2.set(mapIndex(op, t), mapIndex(op, s0));
|
|
1345
|
+
const spans2 = spanThrough(op, r.startRow, r.endRow);
|
|
1346
|
+
return { range: { ...r, startRow: spans2[0][0], endRow: spans2[spans2.length - 1][1] }, P: P2 };
|
|
1347
|
+
}
|
|
1348
|
+
const removed = (i) => i >= op.start && i < op.start + op.count;
|
|
1349
|
+
const Q = sortQ(o);
|
|
1350
|
+
const goneTargets = [];
|
|
1351
|
+
for (let i = op.start; i < op.start + op.count; i++) goneTargets.push(Q.get(i) ?? i);
|
|
1352
|
+
goneTargets.sort((a, b) => a - b);
|
|
1353
|
+
const compact = (t) => t - goneTargets.filter((g) => g < t).length;
|
|
1354
|
+
const P = /* @__PURE__ */ new Map();
|
|
1355
|
+
for (const [t, s0] of o.P) if (!removed(s0)) P.set(compact(t), mapIndex(op, s0));
|
|
1356
|
+
const spans = spanThrough(op, r.startRow, r.endRow);
|
|
1357
|
+
if (!spans.length) return { range: { ...r, startRow: 1, endRow: 0 }, P: /* @__PURE__ */ new Map() };
|
|
1358
|
+
return { range: { ...r, startRow: spans[0][0], endRow: spans[spans.length - 1][1] }, P };
|
|
1359
|
+
}
|
|
1360
|
+
function sortPair(x, y, sx, sy) {
|
|
1361
|
+
const xs = isSort(x);
|
|
1362
|
+
const ys = isSort(y);
|
|
1363
|
+
if (!xs && !ys) return null;
|
|
1364
|
+
if (xs && ys) {
|
|
1365
|
+
const a = sortOf(x).range;
|
|
1366
|
+
const b = sortOf(y).range;
|
|
1367
|
+
const overlap = a.startRow <= b.endRow && b.startRow <= a.endRow && a.startColumn <= b.endColumn && b.startColumn <= a.endColumn;
|
|
1368
|
+
return overlap ? barrier2("two sorts of overlapping ranges at once") : ok([x]);
|
|
1369
|
+
}
|
|
1370
|
+
if (xs) {
|
|
1371
|
+
if (sy) {
|
|
1372
|
+
const t = sortThrough(sortOf(x), sy);
|
|
1373
|
+
return t ? ok(buildSort(x, t)) : barrier2("a row or column move through a sorted range");
|
|
1374
|
+
}
|
|
1375
|
+
return ok([x]);
|
|
1376
|
+
}
|
|
1377
|
+
const o = sortOf(y);
|
|
1378
|
+
const Q = sortQ(o);
|
|
1379
|
+
const moved = (r) => r >= o.range.startRow && r <= o.range.endRow && Q.has(r);
|
|
1380
|
+
if (sx) {
|
|
1381
|
+
if (sx.axis === "col") return sx.op.kind === "move" && !sortThrough(o, sx) ? barrier2("a column move through a sorted range") : ok([x]);
|
|
1382
|
+
if (sx.op.kind === "insert") return ok([x]);
|
|
1383
|
+
if (sx.op.kind === "move") return sortThrough(o, sx) ? ok([x]) : barrier2("a row move through a sorted range");
|
|
1384
|
+
const rows = [];
|
|
1385
|
+
let partial = false;
|
|
1386
|
+
for (let i = sx.op.start; i < sx.op.start + sx.op.count; i++) {
|
|
1387
|
+
if (moved(i)) partial = true;
|
|
1388
|
+
rows.push(Q.get(i) ?? i);
|
|
1389
|
+
}
|
|
1390
|
+
if (partial) return barrier2("a row remove against a concurrent sort of those rows");
|
|
1391
|
+
return ok([x]);
|
|
1392
|
+
}
|
|
1393
|
+
if (x.id === ID.values) {
|
|
1394
|
+
const out = {};
|
|
1395
|
+
let changed = false;
|
|
1396
|
+
forEachCell(cellsOf(x), (r, c, v) => {
|
|
1397
|
+
if (inSortCols(o, c) && moved(r)) {
|
|
1398
|
+
putCell(out, Q.get(r), c, v);
|
|
1399
|
+
changed = true;
|
|
1400
|
+
} else putCell(out, r, c, v);
|
|
1401
|
+
});
|
|
1402
|
+
return changed ? ok([cellsMutation(x, out)]) : ok([x]);
|
|
1403
|
+
}
|
|
1404
|
+
if (isNumfmt(x)) {
|
|
1405
|
+
const parts = nfParts(x).map((p) => {
|
|
1406
|
+
const ranges = [];
|
|
1407
|
+
for (const rc of p.ranges) {
|
|
1408
|
+
const inner = { ...rc, startRow: Math.max(rc.startRow, o.range.startRow), endRow: Math.min(rc.endRow, o.range.endRow), startColumn: Math.max(rc.startColumn, o.range.startColumn), endColumn: Math.min(rc.endColumn, o.range.endColumn) };
|
|
1409
|
+
if (inner.startRow > inner.endRow || inner.startColumn > inner.endColumn) {
|
|
1410
|
+
ranges.push(rc);
|
|
1411
|
+
continue;
|
|
1412
|
+
}
|
|
1413
|
+
ranges.push(...rectMinus(rc, inner));
|
|
1414
|
+
for (let r = inner.startRow; r <= inner.endRow; r++) ranges.push({ ...inner, startRow: Q.get(r) ?? r, endRow: Q.get(r) ?? r });
|
|
1415
|
+
}
|
|
1416
|
+
return { ...p, ranges };
|
|
1417
|
+
});
|
|
1418
|
+
return ok(nfBuild(x, parts));
|
|
1419
|
+
}
|
|
1420
|
+
return ok([x]);
|
|
1421
|
+
}
|
|
1004
1422
|
function familyOf(id) {
|
|
1005
1423
|
const e = SHEET_MUTATIONS[id];
|
|
1006
1424
|
return e && e.kind === "covered" ? e.family : "";
|
|
@@ -1017,6 +1435,8 @@ function transformMutation(x, y, side) {
|
|
|
1017
1435
|
}
|
|
1018
1436
|
const pb = PAIR_BARRIERS[pairKey(x.id, y.id)];
|
|
1019
1437
|
if (pb) return barrier2(`${x.id} \xD7 ${y.id}: ${pb.reason}${pb.seed === null ? "" : ` (fuzz seed ${pb.seed})`}`);
|
|
1438
|
+
const sp = sheetPair(x, y, side);
|
|
1439
|
+
if (sp) return sp;
|
|
1020
1440
|
const fp = formulaPair(x, y, side);
|
|
1021
1441
|
if (fp) return fp;
|
|
1022
1442
|
if (sheetOf(x) !== sheetOf(y)) return ok([x]);
|
|
@@ -1024,6 +1444,12 @@ function transformMutation(x, y, side) {
|
|
|
1024
1444
|
const fy = familyOf(y.id);
|
|
1025
1445
|
const sy = structuralOf(y);
|
|
1026
1446
|
const sx = structuralOf(x);
|
|
1447
|
+
const sortp = sortPair(x, y, sx, sy);
|
|
1448
|
+
if (sortp) return sortp;
|
|
1449
|
+
const cp = countPair(x, y, sy);
|
|
1450
|
+
if (cp) return cp;
|
|
1451
|
+
const np = numfmtPair(x, y, side, sx, sy);
|
|
1452
|
+
if (np) return np;
|
|
1027
1453
|
if (sx && sy) {
|
|
1028
1454
|
if (sx.axis !== sy.axis) return ok([x]);
|
|
1029
1455
|
const out = transformAxis(sx.op, sy.op, side);
|
|
@@ -1131,22 +1557,45 @@ function tSeq(xs, ys, side, acc) {
|
|
|
1131
1557
|
acc.dropped.push(...a.dropped);
|
|
1132
1558
|
return [a.op, b.op];
|
|
1133
1559
|
}
|
|
1560
|
+
const outX = [];
|
|
1561
|
+
let curY = ys;
|
|
1562
|
+
for (const x of xs) {
|
|
1563
|
+
let curX = [x];
|
|
1564
|
+
const nextY = [];
|
|
1565
|
+
for (const y of curY) {
|
|
1566
|
+
if (curX.length === 0) {
|
|
1567
|
+
nextY.push(y);
|
|
1568
|
+
continue;
|
|
1569
|
+
}
|
|
1570
|
+
const r = tSeq(curX, [y], side, acc);
|
|
1571
|
+
if (blocked(r)) return r;
|
|
1572
|
+
curX = r[0];
|
|
1573
|
+
for (const m of r[1]) nextY.push(m);
|
|
1574
|
+
}
|
|
1575
|
+
for (const m of curX) outX.push(m);
|
|
1576
|
+
curY = nextY;
|
|
1577
|
+
}
|
|
1578
|
+
return [outX, curY];
|
|
1579
|
+
}
|
|
1580
|
+
function tSeqOld(xs, ys, side, acc) {
|
|
1581
|
+
if (xs.length === 0 || ys.length === 0) return [xs, ys];
|
|
1582
|
+
if (xs.length === 1 && ys.length === 1) return tSeq(xs, ys, side, acc);
|
|
1134
1583
|
if (xs.length > 1) {
|
|
1135
|
-
const first2 =
|
|
1584
|
+
const first2 = tSeqOld([xs[0]], ys, side, acc);
|
|
1136
1585
|
if (blocked(first2)) return first2;
|
|
1137
|
-
const rest2 =
|
|
1586
|
+
const rest2 = tSeqOld(xs.slice(1), first2[1], side, acc);
|
|
1138
1587
|
if (blocked(rest2)) return rest2;
|
|
1139
1588
|
return [[...first2[0], ...rest2[0]], rest2[1]];
|
|
1140
1589
|
}
|
|
1141
|
-
const first =
|
|
1590
|
+
const first = tSeqOld(xs, [ys[0]], side, acc);
|
|
1142
1591
|
if (blocked(first)) return first;
|
|
1143
|
-
const rest =
|
|
1592
|
+
const rest = tSeqOld(first[0], ys.slice(1), side, acc);
|
|
1144
1593
|
if (blocked(rest)) return rest;
|
|
1145
1594
|
return [rest[0], [...first[1], ...rest[1]]];
|
|
1146
1595
|
}
|
|
1147
1596
|
function transformGroup(x, y, side) {
|
|
1148
1597
|
const acc = { lost: [], dropped: [] };
|
|
1149
|
-
const r = tSeq([...x], [...y], side, acc);
|
|
1598
|
+
const r = (process.env.OLD_TSEQ ? tSeqOld : tSeq)([...x], [...y], side, acc);
|
|
1150
1599
|
if (blocked(r)) return r;
|
|
1151
1600
|
return { op: r[0], lost: [...new Set(acc.lost)], dropped: [...new Set(acc.dropped)] };
|
|
1152
1601
|
}
|
|
@@ -1173,19 +1622,24 @@ export {
|
|
|
1173
1622
|
SIDE_CAR_PARAMS,
|
|
1174
1623
|
allowParams,
|
|
1175
1624
|
annotateFormulas,
|
|
1625
|
+
annotateSheetOps,
|
|
1176
1626
|
cellRef,
|
|
1177
1627
|
completeCellContent,
|
|
1178
1628
|
exactMergeRemovals,
|
|
1179
1629
|
forApply,
|
|
1180
1630
|
formulaBarrier,
|
|
1631
|
+
inlineSheetStyles,
|
|
1181
1632
|
isBarrier,
|
|
1182
1633
|
isFormulaText,
|
|
1634
|
+
isStructuralMutation,
|
|
1183
1635
|
mapIndex,
|
|
1636
|
+
mergeFixupsOwed,
|
|
1184
1637
|
mergeThrough,
|
|
1185
1638
|
refSheetsAfter,
|
|
1186
1639
|
refSheetsFor,
|
|
1187
1640
|
rewriteFormula,
|
|
1188
1641
|
sheetTransformer,
|
|
1642
|
+
spanThrough,
|
|
1189
1643
|
transformAxis,
|
|
1190
1644
|
transformGroup,
|
|
1191
1645
|
transformMutation
|