@ai-matrx/office 0.8.21 → 0.8.23
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 -0
- package/dist/collab-sheets-transform.cjs +259 -71
- package/dist/collab-sheets-transform.cjs.map +1 -1
- package/dist/collab-sheets-transform.d.cts +1 -1
- package/dist/collab-sheets-transform.d.ts +1 -1
- package/dist/collab-sheets-transform.js +259 -71
- package/dist/collab-sheets-transform.js.map +1 -1
- package/dist/docs.cjs +74 -1
- package/dist/docs.cjs.map +1 -1
- package/dist/docs.d.cts +52 -1
- package/dist/docs.d.ts +52 -1
- package/dist/docs.js +73 -0
- package/dist/docs.js.map +1 -1
- package/dist/sheets-comment-anchors.cjs +217 -0
- package/dist/sheets-comment-anchors.cjs.map +1 -0
- package/dist/sheets-comment-anchors.d.cts +52 -0
- package/dist/sheets-comment-anchors.d.ts +52 -0
- package/dist/sheets-comment-anchors.js +217 -0
- package/dist/sheets-comment-anchors.js.map +1 -0
- package/dist/univer-collab.cjs +277 -84
- package/dist/univer-collab.cjs.map +1 -1
- package/dist/univer-collab.js +277 -84
- package/dist/univer-collab.js.map +1 -1
- package/package.json +13 -3
|
@@ -45,7 +45,7 @@ interface SheetRange {
|
|
|
45
45
|
* column width, worksheet name. C5b: formula text in cells (`f`, array `ref`) and defined names. Shared
|
|
46
46
|
* formulas (`si`) stay barriers (see transform.ts cellBarrier); ranged resources are C5c.
|
|
47
47
|
*/
|
|
48
|
-
type SheetFamily = "cell" | "structure" | "merge" | "size" | "name" | "defname" | "numfmt" | "count" | "sheet";
|
|
48
|
+
type SheetFamily = "cell" | "structure" | "merge" | "size" | "name" | "defname" | "numfmt" | "count" | "sheet" | "sort" | "anchor";
|
|
49
49
|
interface CoveredEntry {
|
|
50
50
|
readonly kind: "covered";
|
|
51
51
|
readonly family: SheetFamily;
|
|
@@ -45,7 +45,7 @@ interface SheetRange {
|
|
|
45
45
|
* column width, worksheet name. C5b: formula text in cells (`f`, array `ref`) and defined names. Shared
|
|
46
46
|
* formulas (`si`) stay barriers (see transform.ts cellBarrier); ranged resources are C5c.
|
|
47
47
|
*/
|
|
48
|
-
type SheetFamily = "cell" | "structure" | "merge" | "size" | "name" | "defname" | "numfmt" | "count" | "sheet";
|
|
48
|
+
type SheetFamily = "cell" | "structure" | "merge" | "size" | "name" | "defname" | "numfmt" | "count" | "sheet" | "sort" | "anchor";
|
|
49
49
|
interface CoveredEntry {
|
|
50
50
|
readonly kind: "covered";
|
|
51
51
|
readonly family: SheetFamily;
|
|
@@ -32,6 +32,9 @@ var SHEET_MUTATIONS = {
|
|
|
32
32
|
"sheet.mutation.insert-sheet": covered("sheet", "index", "sheet"),
|
|
33
33
|
"sheet.mutation.remove-sheet": covered("sheet", "sheetIndex", "sheetsLeft"),
|
|
34
34
|
"sheet.mutation.set-worksheet-order": covered("sheet", "fromOrder", "toOrder"),
|
|
35
|
+
// ── covered (C9): our own cell comment anchors (comment-anchor-transform.ts; not emitted by Univer) ──────
|
|
36
|
+
"matrx.mutation.set-comment-anchor": covered("anchor", "anchorId", "cell"),
|
|
37
|
+
"sheet.mutation.reorder-range": covered("sort", "range", "order"),
|
|
35
38
|
// ── never travels ────────────────────────────────────────────────────────────────────────────────
|
|
36
39
|
"formula.mutation.set-formula-calculation-start": never(FORMULA_RESULT),
|
|
37
40
|
"formula.mutation.set-trigger-formula-calculation-start": never(FORMULA_RESULT),
|
|
@@ -65,7 +68,6 @@ var SHEET_MUTATIONS = {
|
|
|
65
68
|
"thread-comment.mutation.resolve-comment": never(UNIVER_COMMENTS),
|
|
66
69
|
"thread-comment.mutation.delete-comment": never(UNIVER_COMMENTS),
|
|
67
70
|
// ── barriers: X (no transform yet, design §10) ───────────────────────────────────────────────────
|
|
68
|
-
"sheet.mutation.reorder-range": barrier("X", "sort: a permutation, not transformed yet"),
|
|
69
71
|
"sheet.mutation.move-range": barrier("X", "cut-paste carries the sender's cell matrices"),
|
|
70
72
|
"sheet.mutation.set-worksheet-hidden": barrier("X", "sheet-level setting: not in C5a"),
|
|
71
73
|
"sheet.mutation.set-tab-color": barrier("X", "sheet-level setting: not in C5a"),
|
|
@@ -483,6 +485,74 @@ function refSheetsFor(texts, sheets) {
|
|
|
483
485
|
return Object.keys(out).length ? out : void 0;
|
|
484
486
|
}
|
|
485
487
|
|
|
488
|
+
// src/collab/sheets/comment-anchor-transform.ts
|
|
489
|
+
var SET_SHEET_COMMENT_ANCHOR = "matrx.mutation.set-comment-anchor";
|
|
490
|
+
var REMOVE_SHEET = "sheet.mutation.remove-sheet";
|
|
491
|
+
function structuralAxisOp(id, params) {
|
|
492
|
+
const p = params;
|
|
493
|
+
switch (id) {
|
|
494
|
+
case "sheet.mutation.insert-row":
|
|
495
|
+
return p.range ? { axis: "row", op: { kind: "insert", at: p.range.startRow, count: p.range.endRow - p.range.startRow + 1 } } : null;
|
|
496
|
+
case "sheet.mutation.remove-rows":
|
|
497
|
+
return p.range ? { axis: "row", op: { kind: "remove", start: p.range.startRow, count: p.range.endRow - p.range.startRow + 1 } } : null;
|
|
498
|
+
case "sheet.mutation.insert-col":
|
|
499
|
+
return p.range ? { axis: "col", op: { kind: "insert", at: p.range.startColumn, count: p.range.endColumn - p.range.startColumn + 1 } } : null;
|
|
500
|
+
case "sheet.mutation.remove-col":
|
|
501
|
+
return p.range ? { axis: "col", op: { kind: "remove", start: p.range.startColumn, count: p.range.endColumn - p.range.startColumn + 1 } } : null;
|
|
502
|
+
case "sheet.mutation.move-rows":
|
|
503
|
+
return p.sourceRange && p.targetRange ? { axis: "row", op: { kind: "move", from: p.sourceRange.startRow, count: p.sourceRange.endRow - p.sourceRange.startRow + 1, to: p.targetRange.startRow } } : null;
|
|
504
|
+
case "sheet.mutation.move-columns":
|
|
505
|
+
return p.sourceRange && p.targetRange ? {
|
|
506
|
+
axis: "col",
|
|
507
|
+
op: { kind: "move", from: p.sourceRange.startColumn, count: p.sourceRange.endColumn - p.sourceRange.startColumn + 1, to: p.targetRange.startColumn }
|
|
508
|
+
} : null;
|
|
509
|
+
default:
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
function moveSheetAnchorCell(cell, sheet, id, params) {
|
|
514
|
+
if (String(params.subUnitId ?? "") !== sheet) return cell;
|
|
515
|
+
if (id === REMOVE_SHEET) return null;
|
|
516
|
+
const s = structuralAxisOp(id, params);
|
|
517
|
+
if (!s) return cell;
|
|
518
|
+
if (s.axis === "row") {
|
|
519
|
+
const row = mapIndex(s.op, cell.row);
|
|
520
|
+
return row === null ? null : row === cell.row ? cell : { row, col: cell.col };
|
|
521
|
+
}
|
|
522
|
+
const col = mapIndex(s.op, cell.col);
|
|
523
|
+
return col === null ? null : col === cell.col ? cell : { row: cell.row, col };
|
|
524
|
+
}
|
|
525
|
+
function colName(c) {
|
|
526
|
+
let s = "";
|
|
527
|
+
for (let n = c + 1; n > 0; n = Math.floor((n - 1) / 26)) s = String.fromCharCode(65 + (n - 1) % 26) + s;
|
|
528
|
+
return s;
|
|
529
|
+
}
|
|
530
|
+
var sheetCellName = (cell) => `${colName(cell.col)}${cell.row + 1}`;
|
|
531
|
+
function cellOf(m) {
|
|
532
|
+
const c = m.params.cell;
|
|
533
|
+
return c && typeof c.row === "number" && typeof c.col === "number" ? c : null;
|
|
534
|
+
}
|
|
535
|
+
var ok = (op, lost = [], dropped = []) => ({ op, lost, dropped });
|
|
536
|
+
var label = (m) => {
|
|
537
|
+
const c = cellOf(m);
|
|
538
|
+
return `${String(m.params.subUnitId ?? "")}!${c ? sheetCellName(c) : "?"} comment`;
|
|
539
|
+
};
|
|
540
|
+
function transformCommentAnchor(x, y, side) {
|
|
541
|
+
const xa = x.id === SET_SHEET_COMMENT_ANCHOR;
|
|
542
|
+
const ya = y.id === SET_SHEET_COMMENT_ANCHOR;
|
|
543
|
+
if (!xa && !ya) return null;
|
|
544
|
+
if (!xa) return ok([x]);
|
|
545
|
+
if (ya) {
|
|
546
|
+
if (x.params.anchorId !== y.params.anchorId || x.params.subUnitId !== y.params.subUnitId) return ok([x]);
|
|
547
|
+
return side === "left" ? ok([x], [label(y)]) : ok([], [], [label(x)]);
|
|
548
|
+
}
|
|
549
|
+
const cell = cellOf(x);
|
|
550
|
+
if (!cell) return ok([x]);
|
|
551
|
+
const moved = moveSheetAnchorCell(cell, String(x.params.subUnitId ?? ""), y.id, y.params);
|
|
552
|
+
if (!moved) return ok([], [], [label(x)]);
|
|
553
|
+
return ok([moved === cell ? x : { id: x.id, params: { ...x.params, cell: moved } }]);
|
|
554
|
+
}
|
|
555
|
+
|
|
486
556
|
// src/collab/sheets/transform/transform.ts
|
|
487
557
|
var SHEET_TRANSFORMER_VERSION = "c5c-1";
|
|
488
558
|
var ID = {
|
|
@@ -508,21 +578,22 @@ var ID = {
|
|
|
508
578
|
colCount: "sheet.mutation.set-worksheet-column-count",
|
|
509
579
|
insertSheet: "sheet.mutation.insert-sheet",
|
|
510
580
|
removeSheet: "sheet.mutation.remove-sheet",
|
|
511
|
-
sheetOrder: "sheet.mutation.set-worksheet-order"
|
|
581
|
+
sheetOrder: "sheet.mutation.set-worksheet-order",
|
|
582
|
+
sort: "sheet.mutation.reorder-range"
|
|
512
583
|
};
|
|
513
584
|
var PAIR_BARRIERS = {};
|
|
514
585
|
var pairKey = (a, b) => a < b ? `${a}|${b}` : `${b}|${a}`;
|
|
515
586
|
var barrier2 = (reason) => ({ barrier: true, reason });
|
|
516
|
-
var
|
|
587
|
+
var ok2 = (op, lost = [], dropped = []) => ({ op, lost, dropped });
|
|
517
588
|
var flip = (side) => side === "left" ? "right" : "left";
|
|
518
589
|
var sheetOf = (m) => String(m.params.subUnitId ?? "");
|
|
519
|
-
function
|
|
590
|
+
function colName2(c) {
|
|
520
591
|
let s = "";
|
|
521
592
|
for (let n = c + 1; n > 0; n = Math.floor((n - 1) / 26)) s = String.fromCharCode(65 + (n - 1) % 26) + s;
|
|
522
593
|
return s;
|
|
523
594
|
}
|
|
524
|
-
var cellRef = (sheet, row, col) => `${sheet}!${
|
|
525
|
-
var rangeRef = (sheet, r) => `${sheet}!${
|
|
595
|
+
var cellRef = (sheet, row, col) => `${sheet}!${colName2(col)}${row + 1}`;
|
|
596
|
+
var rangeRef = (sheet, r) => `${sheet}!${colName2(r.startColumn)}${r.startRow + 1}:${colName2(r.endColumn)}${r.endRow + 1}`;
|
|
526
597
|
function structuralOf(m) {
|
|
527
598
|
const p = m.params;
|
|
528
599
|
switch (m.id) {
|
|
@@ -777,9 +848,9 @@ function transformCell(X, Y, side) {
|
|
|
777
848
|
return { entries: Object.keys(out).length ? [out, ...tail] : tail, xLost, yLost };
|
|
778
849
|
}
|
|
779
850
|
function transformCellsOverCells(x, y, side) {
|
|
780
|
-
if (sheetOf(x) !== sheetOf(y)) return
|
|
851
|
+
if (sheetOf(x) !== sheetOf(y)) return ok2([x]);
|
|
781
852
|
const ycells = cellsOf(y);
|
|
782
|
-
if (!cellsOverlap(cellsOf(x), ycells)) return
|
|
853
|
+
if (!cellsOverlap(cellsOf(x), ycells)) return ok2([x]);
|
|
783
854
|
const xd = isDerived(x);
|
|
784
855
|
const yd = isDerived(y);
|
|
785
856
|
const eff = derivedSide(x, y, side);
|
|
@@ -805,7 +876,7 @@ function transformCellsOverCells(x, y, side) {
|
|
|
805
876
|
});
|
|
806
877
|
if (why) return barrier2(why);
|
|
807
878
|
const op = passes.filter((p) => !isEmptyMatrix(p)).map((p) => cellsMutation(x, p));
|
|
808
|
-
return
|
|
879
|
+
return ok2(op, lost, dropped);
|
|
809
880
|
}
|
|
810
881
|
var SIDE_CAR_PARAMS = ["refSheets", "previousName", "derived", "sheetIndex", "sheetsLeft"];
|
|
811
882
|
var isDerived = (m) => m.params.derived === true;
|
|
@@ -876,7 +947,7 @@ function cellThrough(sheet, change, r, c) {
|
|
|
876
947
|
return nr === null || nc === null ? null : [nr, nc];
|
|
877
948
|
}
|
|
878
949
|
function cellsOverChange(x, change) {
|
|
879
|
-
if (!hasFormula(x) && (change.kind !== "axis" || change.sheet !== sheetOf(x))) return
|
|
950
|
+
if (!hasFormula(x) && (change.kind !== "axis" || change.sheet !== sheetOf(x))) return ok2([x]);
|
|
880
951
|
const ctx = formulaCtx(x);
|
|
881
952
|
const out = {};
|
|
882
953
|
const dropped = [];
|
|
@@ -905,9 +976,9 @@ function cellsOverChange(x, change) {
|
|
|
905
976
|
});
|
|
906
977
|
if (why) return barrier2(why);
|
|
907
978
|
const rsAfter = refSheetsAfter(ctx.refSheets, change);
|
|
908
|
-
if (!changed && JSON.stringify(rsAfter ?? null) === JSON.stringify(ctx.refSheets ?? null)) return
|
|
979
|
+
if (!changed && JSON.stringify(rsAfter ?? null) === JSON.stringify(ctx.refSheets ?? null)) return ok2([x]);
|
|
909
980
|
const params = { ...withRefSheets(x.params, rsAfter), cellValue: out };
|
|
910
|
-
return
|
|
981
|
+
return ok2(isEmptyMatrix(out) ? [] : [{ id: x.id, params }], [], dropped);
|
|
911
982
|
}
|
|
912
983
|
function rewritesOf(y, change) {
|
|
913
984
|
if (!hasFormula(y)) return null;
|
|
@@ -954,36 +1025,36 @@ function formulaPair(x, y, side) {
|
|
|
954
1025
|
const fy = familyOf(y.id);
|
|
955
1026
|
const SET_NAME_BARRIER = "set-defined-name without previousName (capture must record the name it replaces) against formula text";
|
|
956
1027
|
if (fx === "defname" && fy === "defname") {
|
|
957
|
-
if (String(x.params.id) !== String(y.params.id)) return
|
|
1028
|
+
if (String(x.params.id) !== String(y.params.id)) return ok2([x]);
|
|
958
1029
|
const eff = derivedSide(x, y, side);
|
|
959
|
-
if (eff === "left") return
|
|
960
|
-
return
|
|
1030
|
+
if (eff === "left") return ok2([x], isDerived(y) ? [] : [`defined name "${String(y.params.name)}"`]);
|
|
1031
|
+
return ok2([], [], isDerived(x) ? [] : [`defined name "${String(x.params.name)}"`]);
|
|
961
1032
|
}
|
|
962
1033
|
if (fx === "defname") {
|
|
963
1034
|
if (fy === "cell") {
|
|
964
1035
|
if (setNameWithoutPrevious(x) && hasFormula(y)) return barrier2(SET_NAME_BARRIER);
|
|
965
1036
|
const ch2 = refChangeOf(x);
|
|
966
|
-
if (!ch2) return
|
|
1037
|
+
if (!ch2) return ok2([x]);
|
|
967
1038
|
const add = rewritesOf(y, ch2);
|
|
968
1039
|
if (typeof add === "string") return barrier2(add);
|
|
969
|
-
return
|
|
1040
|
+
return ok2(add ? [x, add] : [x]);
|
|
970
1041
|
}
|
|
971
1042
|
const ch = refChangeOf(y);
|
|
972
|
-
if (!ch) return
|
|
1043
|
+
if (!ch) return ok2([x]);
|
|
973
1044
|
const r = definedNameThrough(x, ch);
|
|
974
|
-
return typeof r === "string" ? barrier2(r) :
|
|
1045
|
+
return typeof r === "string" ? barrier2(r) : ok2([r.op]);
|
|
975
1046
|
}
|
|
976
1047
|
if (fy === "defname") {
|
|
977
1048
|
if (fx === "cell") {
|
|
978
1049
|
if (setNameWithoutPrevious(y) && hasFormula(x)) return barrier2(SET_NAME_BARRIER);
|
|
979
1050
|
const ch2 = refChangeOf(y);
|
|
980
|
-
return ch2 ? cellsOverChange(x, ch2) :
|
|
1051
|
+
return ch2 ? cellsOverChange(x, ch2) : ok2([x]);
|
|
981
1052
|
}
|
|
982
1053
|
const ch = refChangeOf(x);
|
|
983
|
-
if (!ch) return
|
|
1054
|
+
if (!ch) return ok2([x]);
|
|
984
1055
|
const r = definedNameThrough(y, ch);
|
|
985
1056
|
if (typeof r === "string") return barrier2(r);
|
|
986
|
-
return
|
|
1057
|
+
return ok2(r.changed ? [x, asDerived(r.op)] : [x]);
|
|
987
1058
|
}
|
|
988
1059
|
if (fx === "cell") {
|
|
989
1060
|
const ch = refChangeOf(y);
|
|
@@ -998,7 +1069,7 @@ function formulaPair(x, y, side) {
|
|
|
998
1069
|
});
|
|
999
1070
|
const add = rewritesOf(y, ch);
|
|
1000
1071
|
if (typeof add === "string") return barrier2(add);
|
|
1001
|
-
return
|
|
1072
|
+
return ok2(add ? [x, add] : [x], lost);
|
|
1002
1073
|
}
|
|
1003
1074
|
return null;
|
|
1004
1075
|
}
|
|
@@ -1146,20 +1217,20 @@ function numfmtPair(x, y, side, sx, sy) {
|
|
|
1146
1217
|
const nx = isNumfmt(x);
|
|
1147
1218
|
const ny = isNumfmt(y);
|
|
1148
1219
|
if (!nx && !ny) return null;
|
|
1149
|
-
if (nx && sy) return
|
|
1150
|
-
if (ny && sx) return
|
|
1220
|
+
if (nx && sy) return ok2(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsThrough(sy, p.ranges) }))));
|
|
1221
|
+
if (ny && sx) return ok2([x]);
|
|
1151
1222
|
if (nx && ny) {
|
|
1152
|
-
if (side === "left") return
|
|
1223
|
+
if (side === "left") return ok2([x]);
|
|
1153
1224
|
const ys = nfParts(y).flatMap((p) => p.ranges);
|
|
1154
|
-
return
|
|
1225
|
+
return ok2(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsMinus(p.ranges, ys) }))));
|
|
1155
1226
|
}
|
|
1156
1227
|
if (nx && y.id === ID.values) {
|
|
1157
|
-
if (side === "left") return
|
|
1228
|
+
if (side === "left") return ok2([x]);
|
|
1158
1229
|
const ys = nWrites(y);
|
|
1159
|
-
return ys.length ?
|
|
1230
|
+
return ys.length ? ok2(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsMinus(p.ranges, ys) })))) : ok2([x]);
|
|
1160
1231
|
}
|
|
1161
1232
|
if (ny && x.id === ID.values) {
|
|
1162
|
-
if (side === "left") return
|
|
1233
|
+
if (side === "left") return ok2([x]);
|
|
1163
1234
|
const out = {};
|
|
1164
1235
|
const tail = {};
|
|
1165
1236
|
let touched = false;
|
|
@@ -1185,31 +1256,31 @@ function numfmtPair(x, y, side, sx, sy) {
|
|
|
1185
1256
|
}
|
|
1186
1257
|
putCell(out, r, c, v);
|
|
1187
1258
|
});
|
|
1188
|
-
if (!touched) return
|
|
1259
|
+
if (!touched) return ok2([x]);
|
|
1189
1260
|
const ops = [];
|
|
1190
1261
|
if (!isEmptyMatrix(out)) ops.push(cellsMutation(x, out));
|
|
1191
1262
|
if (!isEmptyMatrix(tail)) ops.push({ id: ID.values, params: { subUnitId: sheetOf(x), cellValue: tail } });
|
|
1192
|
-
return
|
|
1263
|
+
return ok2(ops);
|
|
1193
1264
|
}
|
|
1194
|
-
return
|
|
1265
|
+
return ok2([x]);
|
|
1195
1266
|
}
|
|
1196
1267
|
var isCount = (m) => m.id === ID.rowCount || m.id === ID.colCount;
|
|
1197
1268
|
var countAxis = (m) => m.id === ID.rowCount ? "row" : "col";
|
|
1198
1269
|
var countKey = (m) => m.id === ID.rowCount ? "rowCount" : "columnCount";
|
|
1199
1270
|
function countPair(x, y, sy) {
|
|
1200
|
-
if (!isCount(x)) return isCount(y) ?
|
|
1271
|
+
if (!isCount(x)) return isCount(y) ? ok2([x]) : null;
|
|
1201
1272
|
const k = countKey(x);
|
|
1202
1273
|
const v = Number(x.params[k]);
|
|
1203
1274
|
if (sy) {
|
|
1204
|
-
if (sy.axis !== countAxis(x) || sy.op.kind === "move") return
|
|
1275
|
+
if (sy.axis !== countAxis(x) || sy.op.kind === "move") return ok2([x]);
|
|
1205
1276
|
const d = sy.op.kind === "insert" ? sy.op.count : -sy.op.count;
|
|
1206
|
-
return
|
|
1277
|
+
return ok2([{ id: x.id, params: { ...x.params, [k]: Math.max(1, v + d) } }]);
|
|
1207
1278
|
}
|
|
1208
1279
|
if (isCount(y) && y.id === x.id) {
|
|
1209
1280
|
const w = Number(y.params[k]);
|
|
1210
|
-
return
|
|
1281
|
+
return ok2([w > v ? { id: x.id, params: { ...x.params, [k]: w } } : x]);
|
|
1211
1282
|
}
|
|
1212
|
-
return
|
|
1283
|
+
return ok2([x]);
|
|
1213
1284
|
}
|
|
1214
1285
|
var isSheetOp = (m) => m.id === ID.insertSheet || m.id === ID.removeSheet || m.id === ID.sheetOrder;
|
|
1215
1286
|
var sheetIdOf = (m) => m.id === ID.insertSheet ? String(m.params.sheet?.id ?? "") : sheetOf(m);
|
|
@@ -1242,31 +1313,31 @@ function sheetPair(x, y, side) {
|
|
|
1242
1313
|
const b = sheetAxisOf(y);
|
|
1243
1314
|
if (!a || !b) return barrier2("a sheet add or remove without its index (capture must call annotateSheetOps)");
|
|
1244
1315
|
if (x.id === ID.insertSheet && y.id === ID.insertSheet && sheetIdOf(x) === sheetIdOf(y)) {
|
|
1245
|
-
return JSON.stringify(x.params) === JSON.stringify(y.params) ?
|
|
1316
|
+
return JSON.stringify(x.params) === JSON.stringify(y.params) ? ok2([]) : barrier2("the same sheet id added twice with different content");
|
|
1246
1317
|
}
|
|
1247
1318
|
if (x.id === ID.removeSheet && typeof x.params.sheetsLeft === "number" && sheetIdOf(x) !== sheetIdOf(y) && (y.id === ID.removeSheet || y.id === ID.insertSheet)) {
|
|
1248
1319
|
const left = x.params.sheetsLeft + (y.id === ID.insertSheet ? 1 : -1);
|
|
1249
1320
|
if (left < 1) return barrier2("concurrent sheet removes would leave the workbook without a sheet");
|
|
1250
1321
|
const out2 = transformAxis(a, b, side);
|
|
1251
1322
|
if (!out2) return barrier2("sheet order: no transform");
|
|
1252
|
-
return
|
|
1323
|
+
return ok2(out2.map((o) => buildSheetOp({ id: x.id, params: { ...x.params, sheetsLeft: left } }, o)));
|
|
1253
1324
|
}
|
|
1254
1325
|
const out = transformAxis(a, b, side);
|
|
1255
1326
|
if (!out) return barrier2("sheet order: no transform");
|
|
1256
|
-
return
|
|
1327
|
+
return ok2(out.map((o) => buildSheetOp(x, o)), [], out.length === 0 && x.id === ID.sheetOrder ? [`${sheetIdOf(x)}: sheet order`] : []);
|
|
1257
1328
|
}
|
|
1258
1329
|
if (ys) {
|
|
1259
|
-
if (y.id !== ID.removeSheet) return
|
|
1330
|
+
if (y.id !== ID.removeSheet) return ok2([x]);
|
|
1260
1331
|
const gone2 = sheetOf(y);
|
|
1261
1332
|
if (namesSheet(x, gone2)) return barrier2("a formula names a sheet removed at the same time");
|
|
1262
1333
|
if (sheetOf(x) === gone2 && x.id !== ID.setName && x.id !== ID.removeName)
|
|
1263
|
-
return
|
|
1264
|
-
return
|
|
1334
|
+
return ok2([], [], isDerived(x) ? [] : [`${gone2}: the sheet was removed`]);
|
|
1335
|
+
return ok2([x]);
|
|
1265
1336
|
}
|
|
1266
|
-
if (x.id !== ID.removeSheet) return
|
|
1337
|
+
if (x.id !== ID.removeSheet) return ok2([x]);
|
|
1267
1338
|
const gone = sheetOf(x);
|
|
1268
1339
|
if (namesSheet(y, gone)) return barrier2("a formula names a sheet removed at the same time");
|
|
1269
|
-
return
|
|
1340
|
+
return ok2([x], sheetOf(y) === gone && !isDerived(y) && y.id !== ID.setName && y.id !== ID.removeName ? [`${gone}: the sheet was removed`] : []);
|
|
1270
1341
|
}
|
|
1271
1342
|
function annotateSheetOps(group, sheetOrder) {
|
|
1272
1343
|
const order = [...sheetOrder];
|
|
@@ -1305,6 +1376,119 @@ function inlineSheetStyles(sheet, styleOf) {
|
|
|
1305
1376
|
}
|
|
1306
1377
|
return out;
|
|
1307
1378
|
}
|
|
1379
|
+
var isSort = (m) => m.id === ID.sort;
|
|
1380
|
+
function sortOf(m) {
|
|
1381
|
+
const P = /* @__PURE__ */ new Map();
|
|
1382
|
+
for (const [t, src] of Object.entries(m.params.order ?? {})) P.set(Number(t), Number(src));
|
|
1383
|
+
return { range: { ...m.params.range }, P };
|
|
1384
|
+
}
|
|
1385
|
+
var sortQ = (o) => new Map([...o.P].map(([t, s0]) => [s0, t]));
|
|
1386
|
+
function buildSort(template, o) {
|
|
1387
|
+
const order = {};
|
|
1388
|
+
for (const [t, s0] of [...o.P].sort((a, b) => a[0] - b[0])) if (t !== s0) order[t] = s0;
|
|
1389
|
+
if (!Object.keys(order).length || o.range.startRow > o.range.endRow || o.range.startColumn > o.range.endColumn) return [];
|
|
1390
|
+
return [{ id: template.id, params: { ...template.params, range: o.range, order } }];
|
|
1391
|
+
}
|
|
1392
|
+
var inSortCols = (o, c) => c >= o.range.startColumn && c <= o.range.endColumn;
|
|
1393
|
+
function sortThrough(o, st) {
|
|
1394
|
+
const r = o.range;
|
|
1395
|
+
if (st.axis === "col") {
|
|
1396
|
+
if (st.op.kind === "move") {
|
|
1397
|
+
const { from, count, to } = st.op;
|
|
1398
|
+
const touches = !(from + count - 1 < r.startColumn || from > r.endColumn) || to > r.startColumn && to <= r.endColumn;
|
|
1399
|
+
if (touches) return null;
|
|
1400
|
+
const spans3 = spanThrough(st.op, r.startColumn, r.endColumn);
|
|
1401
|
+
return spans3.length === 1 ? { range: { ...r, startColumn: spans3[0][0], endColumn: spans3[0][1] }, P: o.P } : null;
|
|
1402
|
+
}
|
|
1403
|
+
const spans2 = spanThrough(st.op, r.startColumn, r.endColumn);
|
|
1404
|
+
if (!spans2.length) return { range: { ...r, startColumn: 1, endColumn: 0 }, P: /* @__PURE__ */ new Map() };
|
|
1405
|
+
return { range: { ...r, startColumn: spans2[0][0], endColumn: spans2[spans2.length - 1][1] }, P: o.P };
|
|
1406
|
+
}
|
|
1407
|
+
const op = st.op;
|
|
1408
|
+
if (op.kind === "move") {
|
|
1409
|
+
const touches = !(op.from + op.count - 1 < r.startRow || op.from > r.endRow) || op.to > r.startRow && op.to <= r.endRow;
|
|
1410
|
+
if (touches) return null;
|
|
1411
|
+
}
|
|
1412
|
+
if (op.kind === "insert" || op.kind === "move") {
|
|
1413
|
+
const P2 = /* @__PURE__ */ new Map();
|
|
1414
|
+
for (const [t, s0] of o.P) P2.set(mapIndex(op, t), mapIndex(op, s0));
|
|
1415
|
+
const spans2 = spanThrough(op, r.startRow, r.endRow);
|
|
1416
|
+
return { range: { ...r, startRow: spans2[0][0], endRow: spans2[spans2.length - 1][1] }, P: P2 };
|
|
1417
|
+
}
|
|
1418
|
+
const removed = (i) => i >= op.start && i < op.start + op.count;
|
|
1419
|
+
const Q = sortQ(o);
|
|
1420
|
+
const goneTargets = [];
|
|
1421
|
+
for (let i = op.start; i < op.start + op.count; i++) goneTargets.push(Q.get(i) ?? i);
|
|
1422
|
+
goneTargets.sort((a, b) => a - b);
|
|
1423
|
+
const compact = (t) => t - goneTargets.filter((g) => g < t).length;
|
|
1424
|
+
const P = /* @__PURE__ */ new Map();
|
|
1425
|
+
for (const [t, s0] of o.P) if (!removed(s0)) P.set(compact(t), mapIndex(op, s0));
|
|
1426
|
+
const spans = spanThrough(op, r.startRow, r.endRow);
|
|
1427
|
+
if (!spans.length) return { range: { ...r, startRow: 1, endRow: 0 }, P: /* @__PURE__ */ new Map() };
|
|
1428
|
+
return { range: { ...r, startRow: spans[0][0], endRow: spans[spans.length - 1][1] }, P };
|
|
1429
|
+
}
|
|
1430
|
+
function sortPair(x, y, sx, sy) {
|
|
1431
|
+
const xs = isSort(x);
|
|
1432
|
+
const ys = isSort(y);
|
|
1433
|
+
if (!xs && !ys) return null;
|
|
1434
|
+
if (xs && ys) {
|
|
1435
|
+
const a = sortOf(x).range;
|
|
1436
|
+
const b = sortOf(y).range;
|
|
1437
|
+
const overlap = a.startRow <= b.endRow && b.startRow <= a.endRow && a.startColumn <= b.endColumn && b.startColumn <= a.endColumn;
|
|
1438
|
+
return overlap ? barrier2("two sorts of overlapping ranges at once") : ok2([x]);
|
|
1439
|
+
}
|
|
1440
|
+
if (xs) {
|
|
1441
|
+
if (sy) {
|
|
1442
|
+
const t = sortThrough(sortOf(x), sy);
|
|
1443
|
+
return t ? ok2(buildSort(x, t)) : barrier2("a row or column move through a sorted range");
|
|
1444
|
+
}
|
|
1445
|
+
return ok2([x]);
|
|
1446
|
+
}
|
|
1447
|
+
const o = sortOf(y);
|
|
1448
|
+
const Q = sortQ(o);
|
|
1449
|
+
const moved = (r) => r >= o.range.startRow && r <= o.range.endRow && Q.has(r);
|
|
1450
|
+
if (sx) {
|
|
1451
|
+
if (sx.axis === "col") return sx.op.kind === "move" && !sortThrough(o, sx) ? barrier2("a column move through a sorted range") : ok2([x]);
|
|
1452
|
+
if (sx.op.kind === "insert") return ok2([x]);
|
|
1453
|
+
if (sx.op.kind === "move") return sortThrough(o, sx) ? ok2([x]) : barrier2("a row move through a sorted range");
|
|
1454
|
+
const rows = [];
|
|
1455
|
+
let partial = false;
|
|
1456
|
+
for (let i = sx.op.start; i < sx.op.start + sx.op.count; i++) {
|
|
1457
|
+
if (moved(i)) partial = true;
|
|
1458
|
+
rows.push(Q.get(i) ?? i);
|
|
1459
|
+
}
|
|
1460
|
+
if (partial) return barrier2("a row remove against a concurrent sort of those rows");
|
|
1461
|
+
return ok2([x]);
|
|
1462
|
+
}
|
|
1463
|
+
if (x.id === ID.values) {
|
|
1464
|
+
const out = {};
|
|
1465
|
+
let changed = false;
|
|
1466
|
+
forEachCell(cellsOf(x), (r, c, v) => {
|
|
1467
|
+
if (inSortCols(o, c) && moved(r)) {
|
|
1468
|
+
putCell(out, Q.get(r), c, v);
|
|
1469
|
+
changed = true;
|
|
1470
|
+
} else putCell(out, r, c, v);
|
|
1471
|
+
});
|
|
1472
|
+
return changed ? ok2([cellsMutation(x, out)]) : ok2([x]);
|
|
1473
|
+
}
|
|
1474
|
+
if (isNumfmt(x)) {
|
|
1475
|
+
const parts = nfParts(x).map((p) => {
|
|
1476
|
+
const ranges = [];
|
|
1477
|
+
for (const rc of p.ranges) {
|
|
1478
|
+
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) };
|
|
1479
|
+
if (inner.startRow > inner.endRow || inner.startColumn > inner.endColumn) {
|
|
1480
|
+
ranges.push(rc);
|
|
1481
|
+
continue;
|
|
1482
|
+
}
|
|
1483
|
+
ranges.push(...rectMinus(rc, inner));
|
|
1484
|
+
for (let r = inner.startRow; r <= inner.endRow; r++) ranges.push({ ...inner, startRow: Q.get(r) ?? r, endRow: Q.get(r) ?? r });
|
|
1485
|
+
}
|
|
1486
|
+
return { ...p, ranges };
|
|
1487
|
+
});
|
|
1488
|
+
return ok2(nfBuild(x, parts));
|
|
1489
|
+
}
|
|
1490
|
+
return ok2([x]);
|
|
1491
|
+
}
|
|
1308
1492
|
function familyOf(id) {
|
|
1309
1493
|
const e = SHEET_MUTATIONS[id];
|
|
1310
1494
|
return e && e.kind === "covered" ? e.family : "";
|
|
@@ -1319,27 +1503,31 @@ function transformMutation(x, y, side) {
|
|
|
1319
1503
|
if (why) return barrier2(why);
|
|
1320
1504
|
}
|
|
1321
1505
|
}
|
|
1506
|
+
const ca = transformCommentAnchor(x, y, side);
|
|
1507
|
+
if (ca) return ca;
|
|
1322
1508
|
const pb = PAIR_BARRIERS[pairKey(x.id, y.id)];
|
|
1323
1509
|
if (pb) return barrier2(`${x.id} \xD7 ${y.id}: ${pb.reason}${pb.seed === null ? "" : ` (fuzz seed ${pb.seed})`}`);
|
|
1324
1510
|
const sp = sheetPair(x, y, side);
|
|
1325
1511
|
if (sp) return sp;
|
|
1326
1512
|
const fp = formulaPair(x, y, side);
|
|
1327
1513
|
if (fp) return fp;
|
|
1328
|
-
if (sheetOf(x) !== sheetOf(y)) return
|
|
1514
|
+
if (sheetOf(x) !== sheetOf(y)) return ok2([x]);
|
|
1329
1515
|
const fx = familyOf(x.id);
|
|
1330
1516
|
const fy = familyOf(y.id);
|
|
1331
1517
|
const sy = structuralOf(y);
|
|
1332
1518
|
const sx = structuralOf(x);
|
|
1519
|
+
const sortp = sortPair(x, y, sx, sy);
|
|
1520
|
+
if (sortp) return sortp;
|
|
1333
1521
|
const cp = countPair(x, y, sy);
|
|
1334
1522
|
if (cp) return cp;
|
|
1335
1523
|
const np = numfmtPair(x, y, side, sx, sy);
|
|
1336
1524
|
if (np) return np;
|
|
1337
1525
|
if (sx && sy) {
|
|
1338
|
-
if (sx.axis !== sy.axis) return
|
|
1526
|
+
if (sx.axis !== sy.axis) return ok2([x]);
|
|
1339
1527
|
const out = transformAxis(sx.op, sy.op, side);
|
|
1340
1528
|
if (!out) return barrier2(`${x.id} over ${y.id}: moved blocks overlap in part, or the block would split`);
|
|
1341
1529
|
const dropped = out.length === 0 && sx.op.kind === "move" ? [`${sheetOf(x)}: moved ${sx.axis}s`] : [];
|
|
1342
|
-
return
|
|
1530
|
+
return ok2(out.map((o) => buildStructural(x, sx.axis, o)), [], dropped);
|
|
1343
1531
|
}
|
|
1344
1532
|
if (sy) {
|
|
1345
1533
|
if (fx === "merge") {
|
|
@@ -1350,23 +1538,23 @@ function transformMutation(x, y, side) {
|
|
|
1350
1538
|
if (t) kept.push(t);
|
|
1351
1539
|
else dropped.push(rangeRef(sheetOf(x), r));
|
|
1352
1540
|
}
|
|
1353
|
-
return
|
|
1541
|
+
return ok2(kept.length ? [withRanges(x, kept)] : [], [], x.id === ID.addMerge ? dropped : []);
|
|
1354
1542
|
}
|
|
1355
1543
|
if (fx === "size") {
|
|
1356
1544
|
const size = sizeOf(x);
|
|
1357
|
-
if (size.axis !== sy.axis) return
|
|
1545
|
+
if (size.axis !== sy.axis) return ok2([x]);
|
|
1358
1546
|
const next = /* @__PURE__ */ new Map();
|
|
1359
1547
|
for (const [i, v] of size.values) {
|
|
1360
1548
|
const m = mapIndex(sy.op, i);
|
|
1361
1549
|
if (m !== null) next.set(m, v);
|
|
1362
1550
|
}
|
|
1363
1551
|
const built = buildSize(x, next);
|
|
1364
|
-
return
|
|
1552
|
+
return ok2(built ? [built] : []);
|
|
1365
1553
|
}
|
|
1366
|
-
return
|
|
1554
|
+
return ok2([x]);
|
|
1367
1555
|
}
|
|
1368
1556
|
if (sx) {
|
|
1369
|
-
if (fy !== "merge" || y.id !== ID.addMerge) return
|
|
1557
|
+
if (fy !== "merge" || y.id !== ID.addMerge) return ok2([x]);
|
|
1370
1558
|
const remove = [];
|
|
1371
1559
|
const add = [];
|
|
1372
1560
|
for (const r of mergeRanges(y)) {
|
|
@@ -1376,11 +1564,11 @@ function transformMutation(x, y, side) {
|
|
|
1376
1564
|
if (t.range) add.push(t.range);
|
|
1377
1565
|
}
|
|
1378
1566
|
const lostMerges = mergeRanges(y).filter((r) => mergeThrough(sx, r).range === null).map((r) => rangeRef(sheetOf(y), r));
|
|
1379
|
-
if (!remove.length) return
|
|
1567
|
+
if (!remove.length) return ok2([x], lostMerges);
|
|
1380
1568
|
const sheet = sheetOf(x);
|
|
1381
1569
|
const pre = sx.op.kind === "insert" ? [] : [mergeMutation(ID.removeMerge, sheet, remove)];
|
|
1382
1570
|
const mid = sx.op.kind === "insert" ? [mergeMutation(ID.removeMerge, sheet, remove)] : [];
|
|
1383
|
-
return
|
|
1571
|
+
return ok2([...pre, x, ...mid, ...add.length ? [mergeMutation(ID.addMerge, sheet, add)] : []], lostMerges);
|
|
1384
1572
|
}
|
|
1385
1573
|
if (fx === "cell" && fy === "cell") return transformCellsOverCells(x, y, side);
|
|
1386
1574
|
if (fx === "merge" && fy === "merge") {
|
|
@@ -1389,45 +1577,45 @@ function transformMutation(x, y, side) {
|
|
|
1389
1577
|
const hit = (r) => yr.some((q) => intersects(r, q));
|
|
1390
1578
|
const sheet = sheetOf(x);
|
|
1391
1579
|
if (x.id === ID.addMerge && y.id === ID.addMerge) {
|
|
1392
|
-
if (!xr.some(hit)) return
|
|
1580
|
+
if (!xr.some(hit)) return ok2([x]);
|
|
1393
1581
|
if (side === "left") {
|
|
1394
1582
|
const lost = yr.filter((q) => xr.some((r) => intersects(r, q))).map((q) => rangeRef(sheet, q));
|
|
1395
|
-
return
|
|
1583
|
+
return ok2([mergeMutation(ID.removeMerge, sheet, xr.filter(hit)), x], lost);
|
|
1396
1584
|
}
|
|
1397
1585
|
const kept = xr.filter((r) => !hit(r));
|
|
1398
|
-
return
|
|
1586
|
+
return ok2(kept.length ? [withRanges(x, kept)] : [], [], xr.filter(hit).map((r) => rangeRef(sheet, r)));
|
|
1399
1587
|
}
|
|
1400
1588
|
if (x.id === ID.addMerge && y.id === ID.removeMerge) {
|
|
1401
|
-
if (side === "left" || !xr.some(hit)) return
|
|
1589
|
+
if (side === "left" || !xr.some(hit)) return ok2([x], side === "left" && xr.some(hit) ? yr.filter((q) => xr.some((r) => intersects(r, q))).map((q) => rangeRef(sheet, q)) : []);
|
|
1402
1590
|
const kept = xr.filter((r) => !hit(r));
|
|
1403
|
-
return
|
|
1591
|
+
return ok2(kept.length ? [withRanges(x, kept)] : [], [], xr.filter(hit).map((r) => rangeRef(sheet, r)));
|
|
1404
1592
|
}
|
|
1405
1593
|
if (x.id === ID.removeMerge && y.id === ID.addMerge) {
|
|
1406
1594
|
const touched = yr.filter((q) => xr.some((r) => intersects(r, q)));
|
|
1407
|
-
if (!touched.length) return
|
|
1408
|
-
if (side === "left") return
|
|
1409
|
-
return
|
|
1595
|
+
if (!touched.length) return ok2([x]);
|
|
1596
|
+
if (side === "left") return ok2([x], touched.map((q) => rangeRef(sheet, q)));
|
|
1597
|
+
return ok2([x, mergeMutation(ID.addMerge, sheet, touched)], [], xr.filter(hit).map((r) => rangeRef(sheet, r)));
|
|
1410
1598
|
}
|
|
1411
|
-
return
|
|
1599
|
+
return ok2([x]);
|
|
1412
1600
|
}
|
|
1413
1601
|
if (fx === "size" && fy === "size") {
|
|
1414
1602
|
const a = sizeOf(x);
|
|
1415
1603
|
const b = sizeOf(y);
|
|
1416
|
-
if (a.axis !== b.axis || a.attr !== b.attr) return
|
|
1604
|
+
if (a.axis !== b.axis || a.attr !== b.attr) return ok2([x]);
|
|
1417
1605
|
if (side === "left") {
|
|
1418
1606
|
const lost = [...a.values.keys()].filter((i) => b.values.has(i)).map((i) => `${sheetOf(x)}: ${a.axis} ${i + 1} ${a.attr}`);
|
|
1419
|
-
return
|
|
1607
|
+
return ok2([x], lost);
|
|
1420
1608
|
}
|
|
1421
1609
|
const next = new Map([...a.values].filter(([i]) => !b.values.has(i)));
|
|
1422
1610
|
const built = buildSize(x, next);
|
|
1423
1611
|
const dropped = [...a.values.keys()].filter((i) => b.values.has(i)).map((i) => `${sheetOf(x)}: ${a.axis} ${i + 1} ${a.attr}`);
|
|
1424
|
-
return
|
|
1612
|
+
return ok2(built ? [built] : [], [], dropped);
|
|
1425
1613
|
}
|
|
1426
1614
|
if (fx === "name" && fy === "name") {
|
|
1427
|
-
if (side === "left") return
|
|
1428
|
-
return
|
|
1615
|
+
if (side === "left") return ok2([x], [`${sheetOf(x)}: name "${String(y.params.name)}"`]);
|
|
1616
|
+
return ok2([], [], [`${sheetOf(x)}: name "${String(x.params.name)}"`]);
|
|
1429
1617
|
}
|
|
1430
|
-
return
|
|
1618
|
+
return ok2([x]);
|
|
1431
1619
|
}
|
|
1432
1620
|
var blocked = (p) => !Array.isArray(p);
|
|
1433
1621
|
function tSeq(xs, ys, side, acc) {
|