@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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.23
|
|
4
|
+
### C9: comment anchors that follow concurrent edits
|
|
5
|
+
|
|
6
|
+
- **Docs:** `addCommentAnchorActions(body, start, end, id)` anchors a passage with a `COMMENT` custom range (Univer's own builder, so the op has the link family's shape C0 proved); `commentAnchorsOf(body)` reads every anchor back (split pieces joined, Univer's inclusive end as `[start, end)`); `removeCommentAnchorActions` takes a cancelled draft's anchor out; `commentPartAnchor` / `anchorIdOfPartAnchor` are the thread's `part_anchor` (`anchor:<id>`, quote as `label`). Fuzz on the C0 corpora: anchor × every captured family and anchor × anchor, 0 divergences in 180,000 checks at 2,000 seeds; red check without a transform.
|
|
7
|
+
- **Sheets:** `installSheetCommentAnchors(univer)` registers `matrx.mutation.set-comment-anchor`, the `SHEET_MATRX_COMMENT_ANCHORS_PLUGIN` resource and a listener that moves anchors through every applied row/column insert, remove and move (and drops them with their row, column or sheet). `transformCommentAnchor` (own file) is called first by `transformMutation`; the registry declares the id (family `anchor`), and the census exempts our own ids from the Univer scan. Fuzz: 40,000 checks, 0 divergences (it caught the same anchor id on two sheets being treated as one); two headless seats: B5 becomes B6 when a peer inserts a row above, survives save and reload, and is gone on both seats when its row is deleted. The fold installs the anchors too.
|
|
8
|
+
- New export `./sheets/comment-anchors`. Consumer action: call `installSheetCommentAnchors(univer)` before creating a workbook unit that co-edits comments.
|
|
9
|
+
|
|
10
|
+
## 0.8.22
|
|
11
|
+
### C5c: Sheets co-editing — merge divergence fixed, number formats, counts and sheets travel
|
|
12
|
+
|
|
13
|
+
- **Merge divergence across chained row/column deletes, fixed at its cause.** Univer 1.0.4's structural commands only fix the merges that intersect the COMMAND's range on the other axis (any `-by-range` call with a partial range, an API call) and only while its ref-range registration is current (never refreshed after a content load or a remove-merge). A cut merge it skipped stayed put on the sender while every transform moved it, so seats ended a column apart (the session fuzz's merge at column -1 vs 0). Capture now completes the command (`mergeFixupsOwed`): the cut merges still on the sheet are removed right before the structural mutation and re-added at their model position right after it, in the traveling group and on the sender alike. Multi-seat session fuzz: 0 hash mismatches (was 2–18 per run).
|
|
14
|
+
- **Number formats travel** (`sheet.mutation.set.numfmt` / `remove.numfmt`, family `numfmt`): typing a date or a currency no longer rolls back. Ranges follow row/column inserts, removes and moves cell by cell; against another write of the style key `n` (a numfmt, a style with `n`, a style clear, a cell delete) the later-committed op wins.
|
|
15
|
+
- **Row/column counts travel** (`set-worksheet-row-count` / `-column-count`, family `count`): a concurrent insert/remove on that axis shifts the count; two counts at once, the larger wins. "Refresh from table" growing a sheet is no longer rolled back.
|
|
16
|
+
- **Sheets: add, remove, order travel** (family `sheet`): the sheet order is transformed as one more axis. Capture records a removed sheet's index and how many sheets are left (`annotateSheetOps`, side-car `sheetIndex`, `sheetsLeft`); an insert-sheet's styles are inlined (`inlineSheetStyles`). An edit to a sheet removed at the same time is dropped and its author told; a formula naming a removed sheet, and two removes that would leave no sheet, are barriers.
|
|
17
|
+
- **Sort travels** (`reorder-range`, family `sort`): it is a row permutation inside its range, so concurrent edits follow their rows (a cell op inside the sorted columns lands where the sort moved its row; number formats likewise), a row insert keeps the new rows in place, column inserts/removes widen or clip the range. Barriers: two overlapping sorts, a row/column move through the sorted range, a row remove of rows the sort moved. The inverse is the inverted permutation.
|
|
18
|
+
- **Selections: a seat's own row/column/count/sheet change keeps its selection inside the sheet** (API calls set no selection; the editor crashed with "Range is out of bounds"); a remote count/sheet change clamps it too.
|
|
19
|
+
- **Transform speed:** the group transform walks the OT grid iteratively; untouched cell ops pass through by identity (no overlap, no formula, change elsewhere); barrier checks are cached per op; undo-stack rebase reuses each list's traveling shape and compares by identity.
|
|
20
|
+
- **Tests:** new chained TP1 fuzz (`sheet-transform-chain-fuzz.test.ts`, 3–5 real commands per side, plus capture fidelity); the multi-seat session fuzz is seed-repeatable (`createSheetsOtAdapter` hook `stateHash`, a synchronous hash in tests) and asserts zero incidents. `SHEET_TRANSFORMER_VERSION` = `c5c-1`.
|
|
21
|
+
- `SHEETS_COLLAB_PROTO` = 2: a room opened by this build is raised to proto 2 (when its checkpoint is at head) and older tabs open it read-only, so seats with and without merge completion never share a room.
|
|
22
|
+
- Consumer action: none.
|
|
23
|
+
|
|
3
24
|
## 0.8.21
|
|
4
25
|
### C5c: Sheets co-editing — merge divergence fixed, number formats, counts and sheets travel
|
|
5
26
|
|
|
@@ -86,6 +86,9 @@ var SHEET_MUTATIONS = {
|
|
|
86
86
|
"sheet.mutation.insert-sheet": covered("sheet", "index", "sheet"),
|
|
87
87
|
"sheet.mutation.remove-sheet": covered("sheet", "sheetIndex", "sheetsLeft"),
|
|
88
88
|
"sheet.mutation.set-worksheet-order": covered("sheet", "fromOrder", "toOrder"),
|
|
89
|
+
// ── covered (C9): our own cell comment anchors (comment-anchor-transform.ts; not emitted by Univer) ──────
|
|
90
|
+
"matrx.mutation.set-comment-anchor": covered("anchor", "anchorId", "cell"),
|
|
91
|
+
"sheet.mutation.reorder-range": covered("sort", "range", "order"),
|
|
89
92
|
// ── never travels ────────────────────────────────────────────────────────────────────────────────
|
|
90
93
|
"formula.mutation.set-formula-calculation-start": never(FORMULA_RESULT),
|
|
91
94
|
"formula.mutation.set-trigger-formula-calculation-start": never(FORMULA_RESULT),
|
|
@@ -119,7 +122,6 @@ var SHEET_MUTATIONS = {
|
|
|
119
122
|
"thread-comment.mutation.resolve-comment": never(UNIVER_COMMENTS),
|
|
120
123
|
"thread-comment.mutation.delete-comment": never(UNIVER_COMMENTS),
|
|
121
124
|
// ── barriers: X (no transform yet, design §10) ───────────────────────────────────────────────────
|
|
122
|
-
"sheet.mutation.reorder-range": barrier("X", "sort: a permutation, not transformed yet"),
|
|
123
125
|
"sheet.mutation.move-range": barrier("X", "cut-paste carries the sender's cell matrices"),
|
|
124
126
|
"sheet.mutation.set-worksheet-hidden": barrier("X", "sheet-level setting: not in C5a"),
|
|
125
127
|
"sheet.mutation.set-tab-color": barrier("X", "sheet-level setting: not in C5a"),
|
|
@@ -528,6 +530,74 @@ function refSheetsFor(texts, sheets) {
|
|
|
528
530
|
return Object.keys(out).length ? out : void 0;
|
|
529
531
|
}
|
|
530
532
|
|
|
533
|
+
// src/collab/sheets/comment-anchor-transform.ts
|
|
534
|
+
var SET_SHEET_COMMENT_ANCHOR = "matrx.mutation.set-comment-anchor";
|
|
535
|
+
var REMOVE_SHEET = "sheet.mutation.remove-sheet";
|
|
536
|
+
function structuralAxisOp(id, params) {
|
|
537
|
+
const p = params;
|
|
538
|
+
switch (id) {
|
|
539
|
+
case "sheet.mutation.insert-row":
|
|
540
|
+
return p.range ? { axis: "row", op: { kind: "insert", at: p.range.startRow, count: p.range.endRow - p.range.startRow + 1 } } : null;
|
|
541
|
+
case "sheet.mutation.remove-rows":
|
|
542
|
+
return p.range ? { axis: "row", op: { kind: "remove", start: p.range.startRow, count: p.range.endRow - p.range.startRow + 1 } } : null;
|
|
543
|
+
case "sheet.mutation.insert-col":
|
|
544
|
+
return p.range ? { axis: "col", op: { kind: "insert", at: p.range.startColumn, count: p.range.endColumn - p.range.startColumn + 1 } } : null;
|
|
545
|
+
case "sheet.mutation.remove-col":
|
|
546
|
+
return p.range ? { axis: "col", op: { kind: "remove", start: p.range.startColumn, count: p.range.endColumn - p.range.startColumn + 1 } } : null;
|
|
547
|
+
case "sheet.mutation.move-rows":
|
|
548
|
+
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;
|
|
549
|
+
case "sheet.mutation.move-columns":
|
|
550
|
+
return p.sourceRange && p.targetRange ? {
|
|
551
|
+
axis: "col",
|
|
552
|
+
op: { kind: "move", from: p.sourceRange.startColumn, count: p.sourceRange.endColumn - p.sourceRange.startColumn + 1, to: p.targetRange.startColumn }
|
|
553
|
+
} : null;
|
|
554
|
+
default:
|
|
555
|
+
return null;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
function moveSheetAnchorCell(cell, sheet, id, params) {
|
|
559
|
+
if (String(params.subUnitId ?? "") !== sheet) return cell;
|
|
560
|
+
if (id === REMOVE_SHEET) return null;
|
|
561
|
+
const s = structuralAxisOp(id, params);
|
|
562
|
+
if (!s) return cell;
|
|
563
|
+
if (s.axis === "row") {
|
|
564
|
+
const row = mapIndex(s.op, cell.row);
|
|
565
|
+
return row === null ? null : row === cell.row ? cell : { row, col: cell.col };
|
|
566
|
+
}
|
|
567
|
+
const col = mapIndex(s.op, cell.col);
|
|
568
|
+
return col === null ? null : col === cell.col ? cell : { row: cell.row, col };
|
|
569
|
+
}
|
|
570
|
+
function colName(c) {
|
|
571
|
+
let s = "";
|
|
572
|
+
for (let n = c + 1; n > 0; n = Math.floor((n - 1) / 26)) s = String.fromCharCode(65 + (n - 1) % 26) + s;
|
|
573
|
+
return s;
|
|
574
|
+
}
|
|
575
|
+
var sheetCellName = (cell) => `${colName(cell.col)}${cell.row + 1}`;
|
|
576
|
+
function cellOf(m) {
|
|
577
|
+
const c = m.params.cell;
|
|
578
|
+
return c && typeof c.row === "number" && typeof c.col === "number" ? c : null;
|
|
579
|
+
}
|
|
580
|
+
var ok = (op, lost = [], dropped = []) => ({ op, lost, dropped });
|
|
581
|
+
var label = (m) => {
|
|
582
|
+
const c = cellOf(m);
|
|
583
|
+
return `${String(m.params.subUnitId ?? "")}!${c ? sheetCellName(c) : "?"} comment`;
|
|
584
|
+
};
|
|
585
|
+
function transformCommentAnchor(x, y, side) {
|
|
586
|
+
const xa = x.id === SET_SHEET_COMMENT_ANCHOR;
|
|
587
|
+
const ya = y.id === SET_SHEET_COMMENT_ANCHOR;
|
|
588
|
+
if (!xa && !ya) return null;
|
|
589
|
+
if (!xa) return ok([x]);
|
|
590
|
+
if (ya) {
|
|
591
|
+
if (x.params.anchorId !== y.params.anchorId || x.params.subUnitId !== y.params.subUnitId) return ok([x]);
|
|
592
|
+
return side === "left" ? ok([x], [label(y)]) : ok([], [], [label(x)]);
|
|
593
|
+
}
|
|
594
|
+
const cell = cellOf(x);
|
|
595
|
+
if (!cell) return ok([x]);
|
|
596
|
+
const moved = moveSheetAnchorCell(cell, String(x.params.subUnitId ?? ""), y.id, y.params);
|
|
597
|
+
if (!moved) return ok([], [], [label(x)]);
|
|
598
|
+
return ok([moved === cell ? x : { id: x.id, params: { ...x.params, cell: moved } }]);
|
|
599
|
+
}
|
|
600
|
+
|
|
531
601
|
// src/collab/sheets/transform/transform.ts
|
|
532
602
|
var SHEET_TRANSFORMER_VERSION = "c5c-1";
|
|
533
603
|
var ID = {
|
|
@@ -553,21 +623,22 @@ var ID = {
|
|
|
553
623
|
colCount: "sheet.mutation.set-worksheet-column-count",
|
|
554
624
|
insertSheet: "sheet.mutation.insert-sheet",
|
|
555
625
|
removeSheet: "sheet.mutation.remove-sheet",
|
|
556
|
-
sheetOrder: "sheet.mutation.set-worksheet-order"
|
|
626
|
+
sheetOrder: "sheet.mutation.set-worksheet-order",
|
|
627
|
+
sort: "sheet.mutation.reorder-range"
|
|
557
628
|
};
|
|
558
629
|
var PAIR_BARRIERS = {};
|
|
559
630
|
var pairKey = (a, b) => a < b ? `${a}|${b}` : `${b}|${a}`;
|
|
560
631
|
var barrier2 = (reason) => ({ barrier: true, reason });
|
|
561
|
-
var
|
|
632
|
+
var ok2 = (op, lost = [], dropped = []) => ({ op, lost, dropped });
|
|
562
633
|
var flip = (side) => side === "left" ? "right" : "left";
|
|
563
634
|
var sheetOf = (m) => String(m.params.subUnitId ?? "");
|
|
564
|
-
function
|
|
635
|
+
function colName2(c) {
|
|
565
636
|
let s = "";
|
|
566
637
|
for (let n = c + 1; n > 0; n = Math.floor((n - 1) / 26)) s = String.fromCharCode(65 + (n - 1) % 26) + s;
|
|
567
638
|
return s;
|
|
568
639
|
}
|
|
569
|
-
var cellRef = (sheet, row, col) => `${sheet}!${
|
|
570
|
-
var rangeRef = (sheet, r) => `${sheet}!${
|
|
640
|
+
var cellRef = (sheet, row, col) => `${sheet}!${colName2(col)}${row + 1}`;
|
|
641
|
+
var rangeRef = (sheet, r) => `${sheet}!${colName2(r.startColumn)}${r.startRow + 1}:${colName2(r.endColumn)}${r.endRow + 1}`;
|
|
571
642
|
function structuralOf(m) {
|
|
572
643
|
const p = m.params;
|
|
573
644
|
switch (m.id) {
|
|
@@ -822,9 +893,9 @@ function transformCell(X, Y, side) {
|
|
|
822
893
|
return { entries: Object.keys(out).length ? [out, ...tail] : tail, xLost, yLost };
|
|
823
894
|
}
|
|
824
895
|
function transformCellsOverCells(x, y, side) {
|
|
825
|
-
if (sheetOf(x) !== sheetOf(y)) return
|
|
896
|
+
if (sheetOf(x) !== sheetOf(y)) return ok2([x]);
|
|
826
897
|
const ycells = cellsOf(y);
|
|
827
|
-
if (!cellsOverlap(cellsOf(x), ycells)) return
|
|
898
|
+
if (!cellsOverlap(cellsOf(x), ycells)) return ok2([x]);
|
|
828
899
|
const xd = isDerived(x);
|
|
829
900
|
const yd = isDerived(y);
|
|
830
901
|
const eff = derivedSide(x, y, side);
|
|
@@ -850,7 +921,7 @@ function transformCellsOverCells(x, y, side) {
|
|
|
850
921
|
});
|
|
851
922
|
if (why) return barrier2(why);
|
|
852
923
|
const op = passes.filter((p) => !isEmptyMatrix(p)).map((p) => cellsMutation(x, p));
|
|
853
|
-
return
|
|
924
|
+
return ok2(op, lost, dropped);
|
|
854
925
|
}
|
|
855
926
|
var SIDE_CAR_PARAMS = ["refSheets", "previousName", "derived", "sheetIndex", "sheetsLeft"];
|
|
856
927
|
var isDerived = (m) => m.params.derived === true;
|
|
@@ -921,7 +992,7 @@ function cellThrough(sheet, change, r, c) {
|
|
|
921
992
|
return nr === null || nc === null ? null : [nr, nc];
|
|
922
993
|
}
|
|
923
994
|
function cellsOverChange(x, change) {
|
|
924
|
-
if (!hasFormula(x) && (change.kind !== "axis" || change.sheet !== sheetOf(x))) return
|
|
995
|
+
if (!hasFormula(x) && (change.kind !== "axis" || change.sheet !== sheetOf(x))) return ok2([x]);
|
|
925
996
|
const ctx = formulaCtx(x);
|
|
926
997
|
const out = {};
|
|
927
998
|
const dropped = [];
|
|
@@ -950,9 +1021,9 @@ function cellsOverChange(x, change) {
|
|
|
950
1021
|
});
|
|
951
1022
|
if (why) return barrier2(why);
|
|
952
1023
|
const rsAfter = refSheetsAfter(ctx.refSheets, change);
|
|
953
|
-
if (!changed && JSON.stringify(rsAfter ?? null) === JSON.stringify(ctx.refSheets ?? null)) return
|
|
1024
|
+
if (!changed && JSON.stringify(rsAfter ?? null) === JSON.stringify(ctx.refSheets ?? null)) return ok2([x]);
|
|
954
1025
|
const params = { ...withRefSheets(x.params, rsAfter), cellValue: out };
|
|
955
|
-
return
|
|
1026
|
+
return ok2(isEmptyMatrix(out) ? [] : [{ id: x.id, params }], [], dropped);
|
|
956
1027
|
}
|
|
957
1028
|
function rewritesOf(y, change) {
|
|
958
1029
|
if (!hasFormula(y)) return null;
|
|
@@ -999,36 +1070,36 @@ function formulaPair(x, y, side) {
|
|
|
999
1070
|
const fy = familyOf(y.id);
|
|
1000
1071
|
const SET_NAME_BARRIER = "set-defined-name without previousName (capture must record the name it replaces) against formula text";
|
|
1001
1072
|
if (fx === "defname" && fy === "defname") {
|
|
1002
|
-
if (String(x.params.id) !== String(y.params.id)) return
|
|
1073
|
+
if (String(x.params.id) !== String(y.params.id)) return ok2([x]);
|
|
1003
1074
|
const eff = derivedSide(x, y, side);
|
|
1004
|
-
if (eff === "left") return
|
|
1005
|
-
return
|
|
1075
|
+
if (eff === "left") return ok2([x], isDerived(y) ? [] : [`defined name "${String(y.params.name)}"`]);
|
|
1076
|
+
return ok2([], [], isDerived(x) ? [] : [`defined name "${String(x.params.name)}"`]);
|
|
1006
1077
|
}
|
|
1007
1078
|
if (fx === "defname") {
|
|
1008
1079
|
if (fy === "cell") {
|
|
1009
1080
|
if (setNameWithoutPrevious(x) && hasFormula(y)) return barrier2(SET_NAME_BARRIER);
|
|
1010
1081
|
const ch2 = refChangeOf(x);
|
|
1011
|
-
if (!ch2) return
|
|
1082
|
+
if (!ch2) return ok2([x]);
|
|
1012
1083
|
const add = rewritesOf(y, ch2);
|
|
1013
1084
|
if (typeof add === "string") return barrier2(add);
|
|
1014
|
-
return
|
|
1085
|
+
return ok2(add ? [x, add] : [x]);
|
|
1015
1086
|
}
|
|
1016
1087
|
const ch = refChangeOf(y);
|
|
1017
|
-
if (!ch) return
|
|
1088
|
+
if (!ch) return ok2([x]);
|
|
1018
1089
|
const r = definedNameThrough(x, ch);
|
|
1019
|
-
return typeof r === "string" ? barrier2(r) :
|
|
1090
|
+
return typeof r === "string" ? barrier2(r) : ok2([r.op]);
|
|
1020
1091
|
}
|
|
1021
1092
|
if (fy === "defname") {
|
|
1022
1093
|
if (fx === "cell") {
|
|
1023
1094
|
if (setNameWithoutPrevious(y) && hasFormula(x)) return barrier2(SET_NAME_BARRIER);
|
|
1024
1095
|
const ch2 = refChangeOf(y);
|
|
1025
|
-
return ch2 ? cellsOverChange(x, ch2) :
|
|
1096
|
+
return ch2 ? cellsOverChange(x, ch2) : ok2([x]);
|
|
1026
1097
|
}
|
|
1027
1098
|
const ch = refChangeOf(x);
|
|
1028
|
-
if (!ch) return
|
|
1099
|
+
if (!ch) return ok2([x]);
|
|
1029
1100
|
const r = definedNameThrough(y, ch);
|
|
1030
1101
|
if (typeof r === "string") return barrier2(r);
|
|
1031
|
-
return
|
|
1102
|
+
return ok2(r.changed ? [x, asDerived(r.op)] : [x]);
|
|
1032
1103
|
}
|
|
1033
1104
|
if (fx === "cell") {
|
|
1034
1105
|
const ch = refChangeOf(y);
|
|
@@ -1043,7 +1114,7 @@ function formulaPair(x, y, side) {
|
|
|
1043
1114
|
});
|
|
1044
1115
|
const add = rewritesOf(y, ch);
|
|
1045
1116
|
if (typeof add === "string") return barrier2(add);
|
|
1046
|
-
return
|
|
1117
|
+
return ok2(add ? [x, add] : [x], lost);
|
|
1047
1118
|
}
|
|
1048
1119
|
return null;
|
|
1049
1120
|
}
|
|
@@ -1191,20 +1262,20 @@ function numfmtPair(x, y, side, sx, sy) {
|
|
|
1191
1262
|
const nx = isNumfmt(x);
|
|
1192
1263
|
const ny = isNumfmt(y);
|
|
1193
1264
|
if (!nx && !ny) return null;
|
|
1194
|
-
if (nx && sy) return
|
|
1195
|
-
if (ny && sx) return
|
|
1265
|
+
if (nx && sy) return ok2(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsThrough(sy, p.ranges) }))));
|
|
1266
|
+
if (ny && sx) return ok2([x]);
|
|
1196
1267
|
if (nx && ny) {
|
|
1197
|
-
if (side === "left") return
|
|
1268
|
+
if (side === "left") return ok2([x]);
|
|
1198
1269
|
const ys = nfParts(y).flatMap((p) => p.ranges);
|
|
1199
|
-
return
|
|
1270
|
+
return ok2(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsMinus(p.ranges, ys) }))));
|
|
1200
1271
|
}
|
|
1201
1272
|
if (nx && y.id === ID.values) {
|
|
1202
|
-
if (side === "left") return
|
|
1273
|
+
if (side === "left") return ok2([x]);
|
|
1203
1274
|
const ys = nWrites(y);
|
|
1204
|
-
return ys.length ?
|
|
1275
|
+
return ys.length ? ok2(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsMinus(p.ranges, ys) })))) : ok2([x]);
|
|
1205
1276
|
}
|
|
1206
1277
|
if (ny && x.id === ID.values) {
|
|
1207
|
-
if (side === "left") return
|
|
1278
|
+
if (side === "left") return ok2([x]);
|
|
1208
1279
|
const out = {};
|
|
1209
1280
|
const tail = {};
|
|
1210
1281
|
let touched = false;
|
|
@@ -1230,31 +1301,31 @@ function numfmtPair(x, y, side, sx, sy) {
|
|
|
1230
1301
|
}
|
|
1231
1302
|
putCell(out, r, c, v);
|
|
1232
1303
|
});
|
|
1233
|
-
if (!touched) return
|
|
1304
|
+
if (!touched) return ok2([x]);
|
|
1234
1305
|
const ops = [];
|
|
1235
1306
|
if (!isEmptyMatrix(out)) ops.push(cellsMutation(x, out));
|
|
1236
1307
|
if (!isEmptyMatrix(tail)) ops.push({ id: ID.values, params: { subUnitId: sheetOf(x), cellValue: tail } });
|
|
1237
|
-
return
|
|
1308
|
+
return ok2(ops);
|
|
1238
1309
|
}
|
|
1239
|
-
return
|
|
1310
|
+
return ok2([x]);
|
|
1240
1311
|
}
|
|
1241
1312
|
var isCount = (m) => m.id === ID.rowCount || m.id === ID.colCount;
|
|
1242
1313
|
var countAxis = (m) => m.id === ID.rowCount ? "row" : "col";
|
|
1243
1314
|
var countKey = (m) => m.id === ID.rowCount ? "rowCount" : "columnCount";
|
|
1244
1315
|
function countPair(x, y, sy) {
|
|
1245
|
-
if (!isCount(x)) return isCount(y) ?
|
|
1316
|
+
if (!isCount(x)) return isCount(y) ? ok2([x]) : null;
|
|
1246
1317
|
const k = countKey(x);
|
|
1247
1318
|
const v = Number(x.params[k]);
|
|
1248
1319
|
if (sy) {
|
|
1249
|
-
if (sy.axis !== countAxis(x) || sy.op.kind === "move") return
|
|
1320
|
+
if (sy.axis !== countAxis(x) || sy.op.kind === "move") return ok2([x]);
|
|
1250
1321
|
const d = sy.op.kind === "insert" ? sy.op.count : -sy.op.count;
|
|
1251
|
-
return
|
|
1322
|
+
return ok2([{ id: x.id, params: { ...x.params, [k]: Math.max(1, v + d) } }]);
|
|
1252
1323
|
}
|
|
1253
1324
|
if (isCount(y) && y.id === x.id) {
|
|
1254
1325
|
const w = Number(y.params[k]);
|
|
1255
|
-
return
|
|
1326
|
+
return ok2([w > v ? { id: x.id, params: { ...x.params, [k]: w } } : x]);
|
|
1256
1327
|
}
|
|
1257
|
-
return
|
|
1328
|
+
return ok2([x]);
|
|
1258
1329
|
}
|
|
1259
1330
|
var isSheetOp = (m) => m.id === ID.insertSheet || m.id === ID.removeSheet || m.id === ID.sheetOrder;
|
|
1260
1331
|
var sheetIdOf = (m) => m.id === ID.insertSheet ? String(m.params.sheet?.id ?? "") : sheetOf(m);
|
|
@@ -1287,31 +1358,31 @@ function sheetPair(x, y, side) {
|
|
|
1287
1358
|
const b = sheetAxisOf(y);
|
|
1288
1359
|
if (!a || !b) return barrier2("a sheet add or remove without its index (capture must call annotateSheetOps)");
|
|
1289
1360
|
if (x.id === ID.insertSheet && y.id === ID.insertSheet && sheetIdOf(x) === sheetIdOf(y)) {
|
|
1290
|
-
return JSON.stringify(x.params) === JSON.stringify(y.params) ?
|
|
1361
|
+
return JSON.stringify(x.params) === JSON.stringify(y.params) ? ok2([]) : barrier2("the same sheet id added twice with different content");
|
|
1291
1362
|
}
|
|
1292
1363
|
if (x.id === ID.removeSheet && typeof x.params.sheetsLeft === "number" && sheetIdOf(x) !== sheetIdOf(y) && (y.id === ID.removeSheet || y.id === ID.insertSheet)) {
|
|
1293
1364
|
const left = x.params.sheetsLeft + (y.id === ID.insertSheet ? 1 : -1);
|
|
1294
1365
|
if (left < 1) return barrier2("concurrent sheet removes would leave the workbook without a sheet");
|
|
1295
1366
|
const out2 = transformAxis(a, b, side);
|
|
1296
1367
|
if (!out2) return barrier2("sheet order: no transform");
|
|
1297
|
-
return
|
|
1368
|
+
return ok2(out2.map((o) => buildSheetOp({ id: x.id, params: { ...x.params, sheetsLeft: left } }, o)));
|
|
1298
1369
|
}
|
|
1299
1370
|
const out = transformAxis(a, b, side);
|
|
1300
1371
|
if (!out) return barrier2("sheet order: no transform");
|
|
1301
|
-
return
|
|
1372
|
+
return ok2(out.map((o) => buildSheetOp(x, o)), [], out.length === 0 && x.id === ID.sheetOrder ? [`${sheetIdOf(x)}: sheet order`] : []);
|
|
1302
1373
|
}
|
|
1303
1374
|
if (ys) {
|
|
1304
|
-
if (y.id !== ID.removeSheet) return
|
|
1375
|
+
if (y.id !== ID.removeSheet) return ok2([x]);
|
|
1305
1376
|
const gone2 = sheetOf(y);
|
|
1306
1377
|
if (namesSheet(x, gone2)) return barrier2("a formula names a sheet removed at the same time");
|
|
1307
1378
|
if (sheetOf(x) === gone2 && x.id !== ID.setName && x.id !== ID.removeName)
|
|
1308
|
-
return
|
|
1309
|
-
return
|
|
1379
|
+
return ok2([], [], isDerived(x) ? [] : [`${gone2}: the sheet was removed`]);
|
|
1380
|
+
return ok2([x]);
|
|
1310
1381
|
}
|
|
1311
|
-
if (x.id !== ID.removeSheet) return
|
|
1382
|
+
if (x.id !== ID.removeSheet) return ok2([x]);
|
|
1312
1383
|
const gone = sheetOf(x);
|
|
1313
1384
|
if (namesSheet(y, gone)) return barrier2("a formula names a sheet removed at the same time");
|
|
1314
|
-
return
|
|
1385
|
+
return ok2([x], sheetOf(y) === gone && !isDerived(y) && y.id !== ID.setName && y.id !== ID.removeName ? [`${gone}: the sheet was removed`] : []);
|
|
1315
1386
|
}
|
|
1316
1387
|
function annotateSheetOps(group, sheetOrder) {
|
|
1317
1388
|
const order = [...sheetOrder];
|
|
@@ -1350,6 +1421,119 @@ function inlineSheetStyles(sheet, styleOf) {
|
|
|
1350
1421
|
}
|
|
1351
1422
|
return out;
|
|
1352
1423
|
}
|
|
1424
|
+
var isSort = (m) => m.id === ID.sort;
|
|
1425
|
+
function sortOf(m) {
|
|
1426
|
+
const P = /* @__PURE__ */ new Map();
|
|
1427
|
+
for (const [t, src] of Object.entries(m.params.order ?? {})) P.set(Number(t), Number(src));
|
|
1428
|
+
return { range: { ...m.params.range }, P };
|
|
1429
|
+
}
|
|
1430
|
+
var sortQ = (o) => new Map([...o.P].map(([t, s0]) => [s0, t]));
|
|
1431
|
+
function buildSort(template, o) {
|
|
1432
|
+
const order = {};
|
|
1433
|
+
for (const [t, s0] of [...o.P].sort((a, b) => a[0] - b[0])) if (t !== s0) order[t] = s0;
|
|
1434
|
+
if (!Object.keys(order).length || o.range.startRow > o.range.endRow || o.range.startColumn > o.range.endColumn) return [];
|
|
1435
|
+
return [{ id: template.id, params: { ...template.params, range: o.range, order } }];
|
|
1436
|
+
}
|
|
1437
|
+
var inSortCols = (o, c) => c >= o.range.startColumn && c <= o.range.endColumn;
|
|
1438
|
+
function sortThrough(o, st) {
|
|
1439
|
+
const r = o.range;
|
|
1440
|
+
if (st.axis === "col") {
|
|
1441
|
+
if (st.op.kind === "move") {
|
|
1442
|
+
const { from, count, to } = st.op;
|
|
1443
|
+
const touches = !(from + count - 1 < r.startColumn || from > r.endColumn) || to > r.startColumn && to <= r.endColumn;
|
|
1444
|
+
if (touches) return null;
|
|
1445
|
+
const spans3 = spanThrough(st.op, r.startColumn, r.endColumn);
|
|
1446
|
+
return spans3.length === 1 ? { range: { ...r, startColumn: spans3[0][0], endColumn: spans3[0][1] }, P: o.P } : null;
|
|
1447
|
+
}
|
|
1448
|
+
const spans2 = spanThrough(st.op, r.startColumn, r.endColumn);
|
|
1449
|
+
if (!spans2.length) return { range: { ...r, startColumn: 1, endColumn: 0 }, P: /* @__PURE__ */ new Map() };
|
|
1450
|
+
return { range: { ...r, startColumn: spans2[0][0], endColumn: spans2[spans2.length - 1][1] }, P: o.P };
|
|
1451
|
+
}
|
|
1452
|
+
const op = st.op;
|
|
1453
|
+
if (op.kind === "move") {
|
|
1454
|
+
const touches = !(op.from + op.count - 1 < r.startRow || op.from > r.endRow) || op.to > r.startRow && op.to <= r.endRow;
|
|
1455
|
+
if (touches) return null;
|
|
1456
|
+
}
|
|
1457
|
+
if (op.kind === "insert" || op.kind === "move") {
|
|
1458
|
+
const P2 = /* @__PURE__ */ new Map();
|
|
1459
|
+
for (const [t, s0] of o.P) P2.set(mapIndex(op, t), mapIndex(op, s0));
|
|
1460
|
+
const spans2 = spanThrough(op, r.startRow, r.endRow);
|
|
1461
|
+
return { range: { ...r, startRow: spans2[0][0], endRow: spans2[spans2.length - 1][1] }, P: P2 };
|
|
1462
|
+
}
|
|
1463
|
+
const removed = (i) => i >= op.start && i < op.start + op.count;
|
|
1464
|
+
const Q = sortQ(o);
|
|
1465
|
+
const goneTargets = [];
|
|
1466
|
+
for (let i = op.start; i < op.start + op.count; i++) goneTargets.push(Q.get(i) ?? i);
|
|
1467
|
+
goneTargets.sort((a, b) => a - b);
|
|
1468
|
+
const compact = (t) => t - goneTargets.filter((g) => g < t).length;
|
|
1469
|
+
const P = /* @__PURE__ */ new Map();
|
|
1470
|
+
for (const [t, s0] of o.P) if (!removed(s0)) P.set(compact(t), mapIndex(op, s0));
|
|
1471
|
+
const spans = spanThrough(op, r.startRow, r.endRow);
|
|
1472
|
+
if (!spans.length) return { range: { ...r, startRow: 1, endRow: 0 }, P: /* @__PURE__ */ new Map() };
|
|
1473
|
+
return { range: { ...r, startRow: spans[0][0], endRow: spans[spans.length - 1][1] }, P };
|
|
1474
|
+
}
|
|
1475
|
+
function sortPair(x, y, sx, sy) {
|
|
1476
|
+
const xs = isSort(x);
|
|
1477
|
+
const ys = isSort(y);
|
|
1478
|
+
if (!xs && !ys) return null;
|
|
1479
|
+
if (xs && ys) {
|
|
1480
|
+
const a = sortOf(x).range;
|
|
1481
|
+
const b = sortOf(y).range;
|
|
1482
|
+
const overlap = a.startRow <= b.endRow && b.startRow <= a.endRow && a.startColumn <= b.endColumn && b.startColumn <= a.endColumn;
|
|
1483
|
+
return overlap ? barrier2("two sorts of overlapping ranges at once") : ok2([x]);
|
|
1484
|
+
}
|
|
1485
|
+
if (xs) {
|
|
1486
|
+
if (sy) {
|
|
1487
|
+
const t = sortThrough(sortOf(x), sy);
|
|
1488
|
+
return t ? ok2(buildSort(x, t)) : barrier2("a row or column move through a sorted range");
|
|
1489
|
+
}
|
|
1490
|
+
return ok2([x]);
|
|
1491
|
+
}
|
|
1492
|
+
const o = sortOf(y);
|
|
1493
|
+
const Q = sortQ(o);
|
|
1494
|
+
const moved = (r) => r >= o.range.startRow && r <= o.range.endRow && Q.has(r);
|
|
1495
|
+
if (sx) {
|
|
1496
|
+
if (sx.axis === "col") return sx.op.kind === "move" && !sortThrough(o, sx) ? barrier2("a column move through a sorted range") : ok2([x]);
|
|
1497
|
+
if (sx.op.kind === "insert") return ok2([x]);
|
|
1498
|
+
if (sx.op.kind === "move") return sortThrough(o, sx) ? ok2([x]) : barrier2("a row move through a sorted range");
|
|
1499
|
+
const rows = [];
|
|
1500
|
+
let partial = false;
|
|
1501
|
+
for (let i = sx.op.start; i < sx.op.start + sx.op.count; i++) {
|
|
1502
|
+
if (moved(i)) partial = true;
|
|
1503
|
+
rows.push(Q.get(i) ?? i);
|
|
1504
|
+
}
|
|
1505
|
+
if (partial) return barrier2("a row remove against a concurrent sort of those rows");
|
|
1506
|
+
return ok2([x]);
|
|
1507
|
+
}
|
|
1508
|
+
if (x.id === ID.values) {
|
|
1509
|
+
const out = {};
|
|
1510
|
+
let changed = false;
|
|
1511
|
+
forEachCell(cellsOf(x), (r, c, v) => {
|
|
1512
|
+
if (inSortCols(o, c) && moved(r)) {
|
|
1513
|
+
putCell(out, Q.get(r), c, v);
|
|
1514
|
+
changed = true;
|
|
1515
|
+
} else putCell(out, r, c, v);
|
|
1516
|
+
});
|
|
1517
|
+
return changed ? ok2([cellsMutation(x, out)]) : ok2([x]);
|
|
1518
|
+
}
|
|
1519
|
+
if (isNumfmt(x)) {
|
|
1520
|
+
const parts = nfParts(x).map((p) => {
|
|
1521
|
+
const ranges = [];
|
|
1522
|
+
for (const rc of p.ranges) {
|
|
1523
|
+
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) };
|
|
1524
|
+
if (inner.startRow > inner.endRow || inner.startColumn > inner.endColumn) {
|
|
1525
|
+
ranges.push(rc);
|
|
1526
|
+
continue;
|
|
1527
|
+
}
|
|
1528
|
+
ranges.push(...rectMinus(rc, inner));
|
|
1529
|
+
for (let r = inner.startRow; r <= inner.endRow; r++) ranges.push({ ...inner, startRow: Q.get(r) ?? r, endRow: Q.get(r) ?? r });
|
|
1530
|
+
}
|
|
1531
|
+
return { ...p, ranges };
|
|
1532
|
+
});
|
|
1533
|
+
return ok2(nfBuild(x, parts));
|
|
1534
|
+
}
|
|
1535
|
+
return ok2([x]);
|
|
1536
|
+
}
|
|
1353
1537
|
function familyOf(id) {
|
|
1354
1538
|
const e = SHEET_MUTATIONS[id];
|
|
1355
1539
|
return e && e.kind === "covered" ? e.family : "";
|
|
@@ -1364,27 +1548,31 @@ function transformMutation(x, y, side) {
|
|
|
1364
1548
|
if (why) return barrier2(why);
|
|
1365
1549
|
}
|
|
1366
1550
|
}
|
|
1551
|
+
const ca = transformCommentAnchor(x, y, side);
|
|
1552
|
+
if (ca) return ca;
|
|
1367
1553
|
const pb = PAIR_BARRIERS[pairKey(x.id, y.id)];
|
|
1368
1554
|
if (pb) return barrier2(`${x.id} \xD7 ${y.id}: ${pb.reason}${pb.seed === null ? "" : ` (fuzz seed ${pb.seed})`}`);
|
|
1369
1555
|
const sp = sheetPair(x, y, side);
|
|
1370
1556
|
if (sp) return sp;
|
|
1371
1557
|
const fp = formulaPair(x, y, side);
|
|
1372
1558
|
if (fp) return fp;
|
|
1373
|
-
if (sheetOf(x) !== sheetOf(y)) return
|
|
1559
|
+
if (sheetOf(x) !== sheetOf(y)) return ok2([x]);
|
|
1374
1560
|
const fx = familyOf(x.id);
|
|
1375
1561
|
const fy = familyOf(y.id);
|
|
1376
1562
|
const sy = structuralOf(y);
|
|
1377
1563
|
const sx = structuralOf(x);
|
|
1564
|
+
const sortp = sortPair(x, y, sx, sy);
|
|
1565
|
+
if (sortp) return sortp;
|
|
1378
1566
|
const cp = countPair(x, y, sy);
|
|
1379
1567
|
if (cp) return cp;
|
|
1380
1568
|
const np = numfmtPair(x, y, side, sx, sy);
|
|
1381
1569
|
if (np) return np;
|
|
1382
1570
|
if (sx && sy) {
|
|
1383
|
-
if (sx.axis !== sy.axis) return
|
|
1571
|
+
if (sx.axis !== sy.axis) return ok2([x]);
|
|
1384
1572
|
const out = transformAxis(sx.op, sy.op, side);
|
|
1385
1573
|
if (!out) return barrier2(`${x.id} over ${y.id}: moved blocks overlap in part, or the block would split`);
|
|
1386
1574
|
const dropped = out.length === 0 && sx.op.kind === "move" ? [`${sheetOf(x)}: moved ${sx.axis}s`] : [];
|
|
1387
|
-
return
|
|
1575
|
+
return ok2(out.map((o) => buildStructural(x, sx.axis, o)), [], dropped);
|
|
1388
1576
|
}
|
|
1389
1577
|
if (sy) {
|
|
1390
1578
|
if (fx === "merge") {
|
|
@@ -1395,23 +1583,23 @@ function transformMutation(x, y, side) {
|
|
|
1395
1583
|
if (t) kept.push(t);
|
|
1396
1584
|
else dropped.push(rangeRef(sheetOf(x), r));
|
|
1397
1585
|
}
|
|
1398
|
-
return
|
|
1586
|
+
return ok2(kept.length ? [withRanges(x, kept)] : [], [], x.id === ID.addMerge ? dropped : []);
|
|
1399
1587
|
}
|
|
1400
1588
|
if (fx === "size") {
|
|
1401
1589
|
const size = sizeOf(x);
|
|
1402
|
-
if (size.axis !== sy.axis) return
|
|
1590
|
+
if (size.axis !== sy.axis) return ok2([x]);
|
|
1403
1591
|
const next = /* @__PURE__ */ new Map();
|
|
1404
1592
|
for (const [i, v] of size.values) {
|
|
1405
1593
|
const m = mapIndex(sy.op, i);
|
|
1406
1594
|
if (m !== null) next.set(m, v);
|
|
1407
1595
|
}
|
|
1408
1596
|
const built = buildSize(x, next);
|
|
1409
|
-
return
|
|
1597
|
+
return ok2(built ? [built] : []);
|
|
1410
1598
|
}
|
|
1411
|
-
return
|
|
1599
|
+
return ok2([x]);
|
|
1412
1600
|
}
|
|
1413
1601
|
if (sx) {
|
|
1414
|
-
if (fy !== "merge" || y.id !== ID.addMerge) return
|
|
1602
|
+
if (fy !== "merge" || y.id !== ID.addMerge) return ok2([x]);
|
|
1415
1603
|
const remove = [];
|
|
1416
1604
|
const add = [];
|
|
1417
1605
|
for (const r of mergeRanges(y)) {
|
|
@@ -1421,11 +1609,11 @@ function transformMutation(x, y, side) {
|
|
|
1421
1609
|
if (t.range) add.push(t.range);
|
|
1422
1610
|
}
|
|
1423
1611
|
const lostMerges = mergeRanges(y).filter((r) => mergeThrough(sx, r).range === null).map((r) => rangeRef(sheetOf(y), r));
|
|
1424
|
-
if (!remove.length) return
|
|
1612
|
+
if (!remove.length) return ok2([x], lostMerges);
|
|
1425
1613
|
const sheet = sheetOf(x);
|
|
1426
1614
|
const pre = sx.op.kind === "insert" ? [] : [mergeMutation(ID.removeMerge, sheet, remove)];
|
|
1427
1615
|
const mid = sx.op.kind === "insert" ? [mergeMutation(ID.removeMerge, sheet, remove)] : [];
|
|
1428
|
-
return
|
|
1616
|
+
return ok2([...pre, x, ...mid, ...add.length ? [mergeMutation(ID.addMerge, sheet, add)] : []], lostMerges);
|
|
1429
1617
|
}
|
|
1430
1618
|
if (fx === "cell" && fy === "cell") return transformCellsOverCells(x, y, side);
|
|
1431
1619
|
if (fx === "merge" && fy === "merge") {
|
|
@@ -1434,45 +1622,45 @@ function transformMutation(x, y, side) {
|
|
|
1434
1622
|
const hit = (r) => yr.some((q) => intersects(r, q));
|
|
1435
1623
|
const sheet = sheetOf(x);
|
|
1436
1624
|
if (x.id === ID.addMerge && y.id === ID.addMerge) {
|
|
1437
|
-
if (!xr.some(hit)) return
|
|
1625
|
+
if (!xr.some(hit)) return ok2([x]);
|
|
1438
1626
|
if (side === "left") {
|
|
1439
1627
|
const lost = yr.filter((q) => xr.some((r) => intersects(r, q))).map((q) => rangeRef(sheet, q));
|
|
1440
|
-
return
|
|
1628
|
+
return ok2([mergeMutation(ID.removeMerge, sheet, xr.filter(hit)), x], lost);
|
|
1441
1629
|
}
|
|
1442
1630
|
const kept = xr.filter((r) => !hit(r));
|
|
1443
|
-
return
|
|
1631
|
+
return ok2(kept.length ? [withRanges(x, kept)] : [], [], xr.filter(hit).map((r) => rangeRef(sheet, r)));
|
|
1444
1632
|
}
|
|
1445
1633
|
if (x.id === ID.addMerge && y.id === ID.removeMerge) {
|
|
1446
|
-
if (side === "left" || !xr.some(hit)) return
|
|
1634
|
+
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)) : []);
|
|
1447
1635
|
const kept = xr.filter((r) => !hit(r));
|
|
1448
|
-
return
|
|
1636
|
+
return ok2(kept.length ? [withRanges(x, kept)] : [], [], xr.filter(hit).map((r) => rangeRef(sheet, r)));
|
|
1449
1637
|
}
|
|
1450
1638
|
if (x.id === ID.removeMerge && y.id === ID.addMerge) {
|
|
1451
1639
|
const touched = yr.filter((q) => xr.some((r) => intersects(r, q)));
|
|
1452
|
-
if (!touched.length) return
|
|
1453
|
-
if (side === "left") return
|
|
1454
|
-
return
|
|
1640
|
+
if (!touched.length) return ok2([x]);
|
|
1641
|
+
if (side === "left") return ok2([x], touched.map((q) => rangeRef(sheet, q)));
|
|
1642
|
+
return ok2([x, mergeMutation(ID.addMerge, sheet, touched)], [], xr.filter(hit).map((r) => rangeRef(sheet, r)));
|
|
1455
1643
|
}
|
|
1456
|
-
return
|
|
1644
|
+
return ok2([x]);
|
|
1457
1645
|
}
|
|
1458
1646
|
if (fx === "size" && fy === "size") {
|
|
1459
1647
|
const a = sizeOf(x);
|
|
1460
1648
|
const b = sizeOf(y);
|
|
1461
|
-
if (a.axis !== b.axis || a.attr !== b.attr) return
|
|
1649
|
+
if (a.axis !== b.axis || a.attr !== b.attr) return ok2([x]);
|
|
1462
1650
|
if (side === "left") {
|
|
1463
1651
|
const lost = [...a.values.keys()].filter((i) => b.values.has(i)).map((i) => `${sheetOf(x)}: ${a.axis} ${i + 1} ${a.attr}`);
|
|
1464
|
-
return
|
|
1652
|
+
return ok2([x], lost);
|
|
1465
1653
|
}
|
|
1466
1654
|
const next = new Map([...a.values].filter(([i]) => !b.values.has(i)));
|
|
1467
1655
|
const built = buildSize(x, next);
|
|
1468
1656
|
const dropped = [...a.values.keys()].filter((i) => b.values.has(i)).map((i) => `${sheetOf(x)}: ${a.axis} ${i + 1} ${a.attr}`);
|
|
1469
|
-
return
|
|
1657
|
+
return ok2(built ? [built] : [], [], dropped);
|
|
1470
1658
|
}
|
|
1471
1659
|
if (fx === "name" && fy === "name") {
|
|
1472
|
-
if (side === "left") return
|
|
1473
|
-
return
|
|
1660
|
+
if (side === "left") return ok2([x], [`${sheetOf(x)}: name "${String(y.params.name)}"`]);
|
|
1661
|
+
return ok2([], [], [`${sheetOf(x)}: name "${String(x.params.name)}"`]);
|
|
1474
1662
|
}
|
|
1475
|
-
return
|
|
1663
|
+
return ok2([x]);
|
|
1476
1664
|
}
|
|
1477
1665
|
var blocked = (p) => !Array.isArray(p);
|
|
1478
1666
|
function tSeq(xs, ys, side, acc) {
|