@ai-matrx/office 0.8.13 → 0.8.15
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 +28 -0
- package/dist/docs.cjs +91 -2
- package/dist/docs.cjs.map +1 -1
- package/dist/docs.d.cts +29 -1
- package/dist/docs.d.ts +29 -1
- package/dist/docs.js +89 -0
- package/dist/docs.js.map +1 -1
- package/dist/univer-collab.cjs +1922 -27
- package/dist/univer-collab.cjs.map +1 -1
- package/dist/univer-collab.d.cts +293 -6
- package/dist/univer-collab.d.ts +293 -6
- package/dist/univer-collab.js +1937 -27
- package/dist/univer-collab.js.map +1 -1
- package/package.json +4 -4
package/dist/univer-collab.cjs
CHANGED
|
@@ -37,30 +37,44 @@ __export(collab_exports, {
|
|
|
37
37
|
DOC_LOCAL_KEYS: () => DOC_LOCAL_KEYS,
|
|
38
38
|
RICH_TEXT_EDITING: () => RICH_TEXT_EDITING,
|
|
39
39
|
SENDER_VIEW_PARAMS: () => SENDER_VIEW_PARAMS,
|
|
40
|
+
SHEETS_COLLAB_PROTO: () => SHEETS_COLLAB_PROTO,
|
|
41
|
+
SHEETS_EDIT_GROUP: () => SHEETS_EDIT_GROUP,
|
|
40
42
|
WorkbookCollabSession: () => WorkbookCollabSession,
|
|
41
43
|
applyDocsOp: () => applyDocsOp,
|
|
42
44
|
canonicalDocsSnapshot: () => canonicalDocsSnapshot,
|
|
43
45
|
canonicalDocsString: () => canonicalDocsString,
|
|
44
46
|
canonicalKeys: () => canonicalKeys,
|
|
47
|
+
canonicalSheet: () => canonicalSheet,
|
|
48
|
+
canonicalSheetString: () => canonicalSheetString,
|
|
45
49
|
composeDocsOps: () => composeDocsOps,
|
|
50
|
+
createSheetsOtAdapter: () => createSheetsOtAdapter,
|
|
51
|
+
decodeSheetOp: () => decodeSheetOp,
|
|
46
52
|
docsStateHash: () => docsStateHash,
|
|
47
53
|
documentOtFactory: () => documentOtFactory,
|
|
48
54
|
documentUsesOrderedRoom: () => documentUsesOrderedRoom,
|
|
49
55
|
dropEmptyStyleRetains: () => dropEmptyStyleRetains,
|
|
56
|
+
encodeSheetOp: () => encodeSheetOp,
|
|
50
57
|
invertDocsOp: () => invertDocsOp,
|
|
51
58
|
isCellEditorScratch: () => isCellEditorScratch,
|
|
52
59
|
isNoopDocsOp: () => isNoopDocsOp,
|
|
53
60
|
normalizeDocsOp: () => normalizeDocsOp,
|
|
54
61
|
openDocsOtRoom: () => openDocsOtRoom,
|
|
62
|
+
openSheetsOtRoom: () => openSheetsOtRoom,
|
|
63
|
+
rebaseSheetUndoStack: () => rebaseSheetUndoStack,
|
|
55
64
|
rebaseUndoStack: () => rebaseUndoStack,
|
|
56
65
|
restoreDocumentSnapshot: () => restoreDocumentSnapshot,
|
|
66
|
+
sheetsStateHash: () => sheetsStateHash,
|
|
57
67
|
stampCovered: () => stampCovered,
|
|
58
68
|
stampDeterministicIds: () => stampDeterministicIds,
|
|
69
|
+
startWorkbookOtRoom: () => startWorkbookOtRoom,
|
|
59
70
|
stripSenderView: () => stripSenderView,
|
|
60
71
|
takeCovered: () => takeCovered,
|
|
61
72
|
transformDocsOp: () => transformDocsOp,
|
|
73
|
+
transformSheetOp: () => transformSheetOp,
|
|
62
74
|
transformTextX: () => transformTextX,
|
|
63
|
-
undoStacksOf: () => undoStacksOf
|
|
75
|
+
undoStacksOf: () => undoStacksOf,
|
|
76
|
+
univerSheetsOtPort: () => univerSheetsOtPort,
|
|
77
|
+
workbookUsesOrderedRoom: () => workbookUsesOrderedRoom
|
|
64
78
|
});
|
|
65
79
|
module.exports = __toCommonJS(collab_exports);
|
|
66
80
|
|
|
@@ -71,8 +85,8 @@ var import_collab = require("@ai-matrx/data/realtime/collab");
|
|
|
71
85
|
|
|
72
86
|
// src/univer/collab/covered.ts
|
|
73
87
|
var COLLAB_COVERED_KEY = "__matrxCollabCovered";
|
|
74
|
-
function stampCovered(snapshot,
|
|
75
|
-
return { ...snapshot, [COLLAB_COVERED_KEY]: [...
|
|
88
|
+
function stampCovered(snapshot, covered2) {
|
|
89
|
+
return { ...snapshot, [COLLAB_COVERED_KEY]: [...covered2] };
|
|
76
90
|
}
|
|
77
91
|
function takeCovered(snapshot) {
|
|
78
92
|
if (!snapshot || typeof snapshot !== "object" || !(COLLAB_COVERED_KEY in snapshot)) {
|
|
@@ -212,10 +226,10 @@ var WorkbookCollabSession = class {
|
|
|
212
226
|
*/
|
|
213
227
|
coveredNow() {
|
|
214
228
|
if (!this.doc) return [];
|
|
215
|
-
const
|
|
229
|
+
const covered2 = this.options.base?.covered();
|
|
216
230
|
const out = [];
|
|
217
231
|
for (const op of this.doc.getArray(MUTATIONS_ARRAY_KEY).toArray()) {
|
|
218
|
-
if (op.eid && (this.applied.has(op.eid) ||
|
|
232
|
+
if (op.eid && (this.applied.has(op.eid) || covered2?.has(op.eid))) out.push(op.eid);
|
|
219
233
|
}
|
|
220
234
|
return out;
|
|
221
235
|
}
|
|
@@ -225,11 +239,11 @@ var WorkbookCollabSession = class {
|
|
|
225
239
|
* by position — an entry that arrived while the save was in flight is not in the snapshot and stays.
|
|
226
240
|
* Only the elected saver calls this; peers receive it as a delete (never replayed).
|
|
227
241
|
*/
|
|
228
|
-
checkpoint(snapshotId,
|
|
242
|
+
checkpoint(snapshotId, covered2) {
|
|
229
243
|
if (!this.doc) return;
|
|
230
244
|
const yArray = this.doc.getArray(MUTATIONS_ARRAY_KEY);
|
|
231
245
|
const control = this.doc.getMap(CONTROL_MAP_KEY);
|
|
232
|
-
const drop = new Set(
|
|
246
|
+
const drop = new Set(covered2);
|
|
233
247
|
const signal = { snapshotId, by: this.options.clientId };
|
|
234
248
|
this.doc.transact(() => {
|
|
235
249
|
const entries = yArray.toArray();
|
|
@@ -353,10 +367,10 @@ var WorkbookCollabSession = class {
|
|
|
353
367
|
return;
|
|
354
368
|
}
|
|
355
369
|
}
|
|
356
|
-
const
|
|
370
|
+
const covered2 = base?.covered();
|
|
357
371
|
for (const op of entries) {
|
|
358
372
|
if (op.eid) {
|
|
359
|
-
if (this.applied.has(op.eid) ||
|
|
373
|
+
if (this.applied.has(op.eid) || covered2?.has(op.eid)) continue;
|
|
360
374
|
this.applied.add(op.eid);
|
|
361
375
|
} else {
|
|
362
376
|
if (this.appliedRefs.has(op)) continue;
|
|
@@ -495,13 +509,13 @@ function dropEmptyStyleRetains(op) {
|
|
|
495
509
|
e: v.e.map((a) => {
|
|
496
510
|
const b = a.body;
|
|
497
511
|
if (a.t !== "r" || !b || a.coverType === 1) return a;
|
|
498
|
-
const
|
|
512
|
+
const runs2 = (b.textRuns ?? []).filter((r) => r.ts && Object.keys(r.ts).length);
|
|
499
513
|
const other = Object.keys(b).filter(
|
|
500
514
|
(k) => k !== "textRuns" && k !== "dataStream" && !(Array.isArray(b[k]) && b[k].length === 0)
|
|
501
515
|
);
|
|
502
|
-
if (!
|
|
503
|
-
if (b.textRuns === void 0 ||
|
|
504
|
-
return { ...a, body: { ...b, textRuns:
|
|
516
|
+
if (!runs2.length && !other.length && !b.dataStream && !a.rangeUpdates?.length) return { t: "r", len: a.len };
|
|
517
|
+
if (b.textRuns === void 0 || runs2.length === b.textRuns.length) return a;
|
|
518
|
+
return { ...a, body: { ...b, textRuns: runs2 } };
|
|
505
519
|
})
|
|
506
520
|
};
|
|
507
521
|
}
|
|
@@ -825,23 +839,23 @@ function transformTextX(xIn, yIn, side, lost = []) {
|
|
|
825
839
|
const yIds = valueIds(y);
|
|
826
840
|
const conflicts = new Set([...valueIds(x)].filter((id) => yIds.has(id)));
|
|
827
841
|
const X = new It(conflicts.size && !xLeft ? withoutValueRangeMetadata(x, conflicts) : x);
|
|
828
|
-
const
|
|
842
|
+
const Y4 = new It(conflicts.size && xLeft ? withoutValueRangeMetadata(y, conflicts) : y);
|
|
829
843
|
const decos = addedDecorations(y).map((d) => ({ ...d, pieces: [] }));
|
|
830
844
|
const out = [];
|
|
831
845
|
let inPos = 0;
|
|
832
846
|
let outPos = 0;
|
|
833
|
-
while (X.hasNext() ||
|
|
834
|
-
if (X.peekType() === "i" && (xLeft ||
|
|
847
|
+
while (X.hasNext() || Y4.hasNext()) {
|
|
848
|
+
if (X.peekType() === "i" && (xLeft || Y4.peekType() !== "i")) {
|
|
835
849
|
const a = X.next();
|
|
836
|
-
if (
|
|
850
|
+
if (Y4.inZone()) {
|
|
837
851
|
lost.push({ rule: "R1", side: "insert", len: a.len, ...a.body?.dataStream !== void 0 ? { text: a.body.dataStream } : {} });
|
|
838
852
|
continue;
|
|
839
853
|
}
|
|
840
854
|
if (a.valueRangeId && conflicts.has(a.valueRangeId) && !xLeft) continue;
|
|
841
855
|
push(out, a);
|
|
842
856
|
outPos += a.len;
|
|
843
|
-
} else if (
|
|
844
|
-
const b =
|
|
857
|
+
} else if (Y4.peekType() === "i") {
|
|
858
|
+
const b = Y4.next();
|
|
845
859
|
if (X.inZone()) {
|
|
846
860
|
push(out, { t: "d", len: b.len, tz: [[0, b.len - 1]] });
|
|
847
861
|
lost.push({ rule: "R1", side: "delete", len: b.len, ...b.body?.dataStream !== void 0 ? { text: b.body.dataStream } : {} });
|
|
@@ -855,9 +869,9 @@ function transformTextX(xIn, yIn, side, lost = []) {
|
|
|
855
869
|
}
|
|
856
870
|
inPos += b.len;
|
|
857
871
|
} else {
|
|
858
|
-
const len = Math.min(X.peekLength(),
|
|
872
|
+
const len = Math.min(X.peekLength(), Y4.peekLength());
|
|
859
873
|
const a = X.next(len);
|
|
860
|
-
const b =
|
|
874
|
+
const b = Y4.next(len);
|
|
861
875
|
if (b.t === "d") continue;
|
|
862
876
|
if (a.t === "d") {
|
|
863
877
|
push(out, a);
|
|
@@ -952,9 +966,9 @@ function sortDeep(v) {
|
|
|
952
966
|
return v;
|
|
953
967
|
}
|
|
954
968
|
var sameTs = (a, b) => JSON.stringify(sortDeep(a ?? {})) === JSON.stringify(sortDeep(b ?? {}));
|
|
955
|
-
function canonicalRuns(
|
|
969
|
+
function canonicalRuns(runs2) {
|
|
956
970
|
const out = [];
|
|
957
|
-
for (const r of [...
|
|
971
|
+
for (const r of [...runs2 ?? []].sort((x, y) => x.st - y.st)) {
|
|
958
972
|
if (r.ed <= r.st) continue;
|
|
959
973
|
const ts = sortDeep(r.ts ?? {});
|
|
960
974
|
if (Object.keys(ts).length === 0) continue;
|
|
@@ -1066,25 +1080,25 @@ function rebaseUndoStack(items, remote) {
|
|
|
1066
1080
|
let dropped = 0;
|
|
1067
1081
|
for (let i = items.length - 1; i >= 0; i--) {
|
|
1068
1082
|
const item = items[i];
|
|
1069
|
-
let
|
|
1083
|
+
let ok2 = true;
|
|
1070
1084
|
for (const list of [item.undoMutations, item.redoMutations]) {
|
|
1071
1085
|
for (const m of list ?? []) {
|
|
1072
1086
|
if (m.id !== RICH_TEXT_EDITING) continue;
|
|
1073
1087
|
try {
|
|
1074
1088
|
if (touchesPageSetup(m.params.actions) && touchesPageSetup(remote)) throw new Error("page setup");
|
|
1075
1089
|
const r = transformDocsOp(m.params.actions, remote, "left");
|
|
1076
|
-
if (isNoopDocsOp(r.op))
|
|
1090
|
+
if (isNoopDocsOp(r.op)) ok2 = false;
|
|
1077
1091
|
else {
|
|
1078
1092
|
m.params = { ...m.params, actions: r.op };
|
|
1079
1093
|
delete m.params.textRanges;
|
|
1080
1094
|
delete m.params.layoutState;
|
|
1081
1095
|
}
|
|
1082
1096
|
} catch {
|
|
1083
|
-
|
|
1097
|
+
ok2 = false;
|
|
1084
1098
|
}
|
|
1085
1099
|
}
|
|
1086
1100
|
}
|
|
1087
|
-
if (!
|
|
1101
|
+
if (!ok2) {
|
|
1088
1102
|
items.splice(i, 1);
|
|
1089
1103
|
dropped++;
|
|
1090
1104
|
}
|
|
@@ -1608,4 +1622,1885 @@ async function restoreDocumentSnapshot(args, deps = {}) {
|
|
|
1608
1622
|
const row = await d.saveRow(args);
|
|
1609
1623
|
return { via: "saved", snapshotId: row.id };
|
|
1610
1624
|
}
|
|
1625
|
+
|
|
1626
|
+
// src/univer/collab/sheets-ot/room.ts
|
|
1627
|
+
var import_collab5 = require("@ai-matrx/data/realtime/collab");
|
|
1628
|
+
|
|
1629
|
+
// src/collab/sheets/transform/types.ts
|
|
1630
|
+
var isBarrier = (r) => r.barrier === true;
|
|
1631
|
+
|
|
1632
|
+
// src/collab/sheets/transform/registry.ts
|
|
1633
|
+
var covered = (family, ...allow) => ({ kind: "covered", family, allow: ["subUnitId", ...allow] });
|
|
1634
|
+
var never = (reason) => ({ kind: "never-travels", reason });
|
|
1635
|
+
var barrier = (until, reason) => ({ kind: "barrier", until, reason });
|
|
1636
|
+
var FORMULA_RESULT = "formula engine output; every seat computes it (dropped at capture)";
|
|
1637
|
+
var RESOURCE = "ranged resource keyed by id; C5c";
|
|
1638
|
+
var UNIVER_COMMENTS = "Univer's own thread-comment store; our comments anchor elsewhere (design \xA78)";
|
|
1639
|
+
var SHEET_MUTATIONS = {
|
|
1640
|
+
// ── covered (C5a) ────────────────────────────────────────────────────────────────────────────────
|
|
1641
|
+
"sheet.mutation.set-range-values": covered("cell", "cellValue", "refSheets", "derived"),
|
|
1642
|
+
"sheet.mutation.insert-row": covered("structure", "range", "rowInfo"),
|
|
1643
|
+
"sheet.mutation.remove-rows": covered("structure", "range"),
|
|
1644
|
+
"sheet.mutation.insert-col": covered("structure", "range", "colInfo"),
|
|
1645
|
+
"sheet.mutation.remove-col": covered("structure", "range"),
|
|
1646
|
+
"sheet.mutation.move-rows": covered("structure", "sourceRange", "targetRange"),
|
|
1647
|
+
"sheet.mutation.move-columns": covered("structure", "sourceRange", "targetRange"),
|
|
1648
|
+
"sheet.mutation.add-worksheet-merge": covered("merge", "ranges"),
|
|
1649
|
+
"sheet.mutation.remove-worksheet-merge": covered("merge", "ranges"),
|
|
1650
|
+
"sheet.mutation.set-worksheet-row-height": covered("size", "ranges", "rowHeight"),
|
|
1651
|
+
"sheet.mutation.set-worksheet-row-is-auto-height": covered("size", "ranges", "autoHeightInfo"),
|
|
1652
|
+
"sheet.mutation.set-worksheet-row-auto-height": covered("size", "rowsAutoHeightInfo"),
|
|
1653
|
+
"sheet.mutation.set-worksheet-col-width": covered("size", "ranges", "colWidth"),
|
|
1654
|
+
"sheet.mutation.set-worksheet-name": covered("name", "name"),
|
|
1655
|
+
// ── never travels ────────────────────────────────────────────────────────────────────────────────
|
|
1656
|
+
"formula.mutation.set-formula-calculation-start": never(FORMULA_RESULT),
|
|
1657
|
+
"formula.mutation.set-trigger-formula-calculation-start": never(FORMULA_RESULT),
|
|
1658
|
+
"formula.mutation.set-formula-calculation-stop": never(FORMULA_RESULT),
|
|
1659
|
+
"formula.mutation.set-formula-calculation-notification": never(FORMULA_RESULT),
|
|
1660
|
+
"formula.mutation.set-formula-calculation-result": never(FORMULA_RESULT),
|
|
1661
|
+
"formula.mutation.set-array-formula-data": never(FORMULA_RESULT),
|
|
1662
|
+
"formula.mutation.set-formula-data": never(FORMULA_RESULT),
|
|
1663
|
+
"formula.mutation.set-image-formula-data": never(FORMULA_RESULT),
|
|
1664
|
+
"formula.mutation.set-formula-string-batch-calculation": never(FORMULA_RESULT),
|
|
1665
|
+
"formula.mutation.set-formula-string-batch-calculation-result": never(FORMULA_RESULT),
|
|
1666
|
+
"formula.mutation.set-formula-dependency-calculation": never(FORMULA_RESULT),
|
|
1667
|
+
"formula.mutation.set-formula-dependency-calculation-result": never(FORMULA_RESULT),
|
|
1668
|
+
"formula.mutation.set-cell-formula-dependency-calculation": never(FORMULA_RESULT),
|
|
1669
|
+
"formula.mutation.set-cell-formula-dependency-calculation-result": never(FORMULA_RESULT),
|
|
1670
|
+
"formula.mutation.set-query-formula-dependency": never(FORMULA_RESULT),
|
|
1671
|
+
"formula.mutation.set-query-formula-dependency-result": never(FORMULA_RESULT),
|
|
1672
|
+
"formula.mutation.set-query-formula-dependency-all": never(FORMULA_RESULT),
|
|
1673
|
+
"formula.mutation.set-query-formula-dependency-all-result": never(FORMULA_RESULT),
|
|
1674
|
+
"formula.mutation.register-function": never("registers a function body on this seat's engine"),
|
|
1675
|
+
"sheet.mutation.data-validation-formula-mark-dirty": never("dirty mark"),
|
|
1676
|
+
"sheet.mutation.mark-dirty-filter-change": never("dirty mark"),
|
|
1677
|
+
"sheet.mutation.re-calc-filter": never("filter recalculation result"),
|
|
1678
|
+
"sheet.mutation.toggle-note-popup": never("popup state"),
|
|
1679
|
+
"sheet.operation.clear-drawing-transformer": never("drawing selection handles (declared as a mutation)"),
|
|
1680
|
+
"sheet.mutation.copy-worksheet-end": never("end marker of a copy; the copy travels as insert-sheet"),
|
|
1681
|
+
"sheet.mutation.empty": never("no content"),
|
|
1682
|
+
"thread-comment.mutation.add-comment": never(UNIVER_COMMENTS),
|
|
1683
|
+
"thread-comment.mutation.update-comment": never(UNIVER_COMMENTS),
|
|
1684
|
+
"thread-comment.mutation.update-comment-ref": never(UNIVER_COMMENTS),
|
|
1685
|
+
"thread-comment.mutation.resolve-comment": never(UNIVER_COMMENTS),
|
|
1686
|
+
"thread-comment.mutation.delete-comment": never(UNIVER_COMMENTS),
|
|
1687
|
+
// ── barriers: X (no transform yet, design §10) ───────────────────────────────────────────────────
|
|
1688
|
+
"sheet.mutation.reorder-range": barrier("X", "sort: a permutation, not transformed yet"),
|
|
1689
|
+
"sheet.mutation.set-worksheet-row-count": barrier("X", "absolute row count; needs delta semantics"),
|
|
1690
|
+
"sheet.mutation.set-worksheet-column-count": barrier("X", "absolute column count; needs delta semantics"),
|
|
1691
|
+
"sheet.mutation.set-worksheet-order": barrier("X", "absolute sheet order; needs move semantics"),
|
|
1692
|
+
"sheet.mutation.move-range": barrier("X", "cut-paste carries the sender's cell matrices"),
|
|
1693
|
+
"sheet.mutation.insert-sheet": barrier("X", "sheet add: not in C5a"),
|
|
1694
|
+
"sheet.mutation.remove-sheet": barrier("X", "sheet remove: not in C5a"),
|
|
1695
|
+
"sheet.mutation.set-worksheet-hidden": barrier("X", "sheet-level setting: not in C5a"),
|
|
1696
|
+
"sheet.mutation.set-tab-color": barrier("X", "sheet-level setting: not in C5a"),
|
|
1697
|
+
"sheet.mutation.set-workbook-name": barrier("X", "workbook-level setting: not in C5a"),
|
|
1698
|
+
"sheet.mutation.set-worksheet-right-to-left": barrier("X", "sheet-level setting: not in C5a"),
|
|
1699
|
+
"sheet.mutation.toggle-gridlines": barrier("X", "sheet-level setting: not in C5a"),
|
|
1700
|
+
"sheet.mutation.set-gridlines-color": barrier("X", "sheet-level setting: not in C5a"),
|
|
1701
|
+
"sheet.mutation.set-worksheet-default-style": barrier("X", "sheet-level setting: not in C5a"),
|
|
1702
|
+
"sheet.mutation.set-frozen": barrier("X", "absolute frozen indices: not in C5a"),
|
|
1703
|
+
"sheet.mutation.set-row-data": barrier("X", "row properties by index: not in C5a"),
|
|
1704
|
+
"sheet.mutation.set-col-data": barrier("X", "column properties by index: not in C5a"),
|
|
1705
|
+
"sheet.mutation.set-row-hidden": barrier("X", "row visibility: not in C5a"),
|
|
1706
|
+
"sheet.mutation.set-row-visible": barrier("X", "row visibility: not in C5a"),
|
|
1707
|
+
"sheet.mutation.set-col-hidden": barrier("X", "column visibility: not in C5a"),
|
|
1708
|
+
"sheet.mutation.set-col-visible": barrier("X", "column visibility: not in C5a"),
|
|
1709
|
+
"sheet.mutation.set.numfmt": barrier("X", "number formats by range: not in C5a"),
|
|
1710
|
+
"sheet.mutation.remove.numfmt": barrier("X", "number formats by range: not in C5a"),
|
|
1711
|
+
"sheet.mutation.add-range-protection": barrier("X", "permissions: not in C5a"),
|
|
1712
|
+
"sheet.mutation.set-range-protection": barrier("X", "permissions: not in C5a"),
|
|
1713
|
+
"sheet.mutation.delete-range-protection": barrier("X", "permissions: not in C5a"),
|
|
1714
|
+
"sheet.mutation.add-worksheet-protection": barrier("X", "permissions: not in C5a"),
|
|
1715
|
+
"sheet.mutation.set-worksheet-protection": barrier("X", "permissions: not in C5a"),
|
|
1716
|
+
"sheet.mutation.delete-worksheet-protection": barrier("X", "permissions: not in C5a"),
|
|
1717
|
+
"sheet.mutation.set-worksheet-permission-points": barrier("X", "permissions: not in C5a"),
|
|
1718
|
+
// ── formulas (C5b) ───────────────────────────────────────────────────────────────────────────────
|
|
1719
|
+
"formula.mutation.set-defined-name": covered("defname", "id", "name", "formulaOrRefString", "formulaOrRefStringWithPrefix", "comment", "localSheetId", "hidden", "refSheets", "previousName", "derived"),
|
|
1720
|
+
"formula.mutation.remove-defined-name": covered("defname", "id", "name"),
|
|
1721
|
+
"formula.mutation.set-feature-calculation": barrier("X", "a plugin's registered calculation (feature id + dependency ranges); no transform yet"),
|
|
1722
|
+
"formula.mutation.remove-feature-calculation": barrier("X", "a plugin's registered calculation; no transform yet"),
|
|
1723
|
+
"formula.mutation.set-other-formula": barrier("C5c", "formulas owned by conditional formats and data validation travel with their rule"),
|
|
1724
|
+
"formula.mutation.remove-other-formula": barrier("C5c", "formulas owned by conditional formats and data validation travel with their rule"),
|
|
1725
|
+
"formula.mutation.set-super-table": barrier("C5c", "table names in structured references belong to tables (C5c)"),
|
|
1726
|
+
"formula.mutation.remove-super-table": barrier("C5c", "table names in structured references belong to tables (C5c)"),
|
|
1727
|
+
"formula.mutation.set-super-table-option": barrier("C5c", "table names in structured references belong to tables (C5c)"),
|
|
1728
|
+
// ── barriers until C5c (ranged resources) ────────────────────────────────────────────────────────
|
|
1729
|
+
"sheet.mutation.add-conditional-rule": barrier("C5c", RESOURCE),
|
|
1730
|
+
"sheet.mutation.set-conditional-rule": barrier("C5c", RESOURCE),
|
|
1731
|
+
"sheet.mutation.delete-conditional-rule": barrier("C5c", RESOURCE),
|
|
1732
|
+
"sheet.mutation.move-conditional-rule": barrier("C5c", "conditional-format priority (ordered list)"),
|
|
1733
|
+
"data-validation.mutation.addRule": barrier("C5c", RESOURCE),
|
|
1734
|
+
"data-validation.mutation.updateRule": barrier("C5c", RESOURCE),
|
|
1735
|
+
"data-validation.mutation.removeRule": barrier("C5c", RESOURCE),
|
|
1736
|
+
"sheet.mutation.set-filter-range": barrier("C5c", RESOURCE),
|
|
1737
|
+
"sheet.mutation.set-filter-criteria": barrier("C5c", RESOURCE),
|
|
1738
|
+
"sheet.mutation.remove-filter": barrier("C5c", RESOURCE),
|
|
1739
|
+
"sheet.mutation.add-table": barrier("C5c", RESOURCE),
|
|
1740
|
+
"sheet.mutation.delete-table": barrier("C5c", RESOURCE),
|
|
1741
|
+
"sheet.mutation.set-sheet-table": barrier("C5c", RESOURCE),
|
|
1742
|
+
"sheet.mutation.set-table-filter": barrier("C5c", RESOURCE),
|
|
1743
|
+
"sheet.mutation.move-table": barrier("C5c", RESOURCE),
|
|
1744
|
+
"sheets.mutation.add-hyper-link": barrier("C5c", RESOURCE),
|
|
1745
|
+
"sheets.mutation.remove-hyper-link": barrier("C5c", RESOURCE),
|
|
1746
|
+
"sheets.mutation.update-hyper-link": barrier("C5c", RESOURCE),
|
|
1747
|
+
"sheets.mutation.update-hyper-link-ref": barrier("C5c", RESOURCE),
|
|
1748
|
+
"sheets.mutation.update-rich-hyper-link": barrier("C5c", RESOURCE),
|
|
1749
|
+
"sheet.mutation.update-note": barrier("C5c", RESOURCE),
|
|
1750
|
+
"sheet.mutation.remove-note": barrier("C5c", RESOURCE),
|
|
1751
|
+
"sheet.mutation.update-note-position": barrier("C5c", RESOURCE),
|
|
1752
|
+
"sheet.mutation.set-drawing-apply": barrier("C5c", RESOURCE),
|
|
1753
|
+
"sheet.mutation.set-worksheet-background-image": barrier("C5c", RESOURCE),
|
|
1754
|
+
"sheet.mutation.add-range-theme": barrier("C5c", RESOURCE),
|
|
1755
|
+
"sheet.mutation.set-range-theme": barrier("C5c", RESOURCE),
|
|
1756
|
+
"sheet.mutation.remove-range-theme": barrier("C5c", RESOURCE),
|
|
1757
|
+
"sheet.mutation.set-worksheet-range-theme-style": barrier("C5c", RESOURCE),
|
|
1758
|
+
"sheet.mutation.remove-worksheet-range-theme-style": barrier("C5c", RESOURCE),
|
|
1759
|
+
"sheet.mutation.register-worksheet-range-theme-style": barrier("C5c", RESOURCE),
|
|
1760
|
+
"sheet.mutation.unregister-worksheet-range-theme-style": barrier("C5c", RESOURCE)
|
|
1761
|
+
};
|
|
1762
|
+
function allowParams(id, params) {
|
|
1763
|
+
const entry = SHEET_MUTATIONS[id];
|
|
1764
|
+
if (!entry || entry.kind !== "covered") return null;
|
|
1765
|
+
const out = {};
|
|
1766
|
+
for (const f of entry.allow) if (params[f] !== void 0) out[f] = params[f];
|
|
1767
|
+
return out;
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
// src/collab/sheets/transform/transform.ts
|
|
1771
|
+
var import_sheets2 = require("@univerjs/sheets");
|
|
1772
|
+
|
|
1773
|
+
// src/collab/sheets/transform/axis.ts
|
|
1774
|
+
function isNoopMove(op) {
|
|
1775
|
+
return op.count <= 0 || op.to >= op.from && op.to <= op.from + op.count;
|
|
1776
|
+
}
|
|
1777
|
+
function movedBlockStart(op) {
|
|
1778
|
+
return op.to > op.from ? op.to - op.count : op.to;
|
|
1779
|
+
}
|
|
1780
|
+
function mapIndex(op, i) {
|
|
1781
|
+
switch (op.kind) {
|
|
1782
|
+
case "insert":
|
|
1783
|
+
return i >= op.at ? i + op.count : i;
|
|
1784
|
+
case "remove":
|
|
1785
|
+
if (i < op.start) return i;
|
|
1786
|
+
if (i < op.start + op.count) return null;
|
|
1787
|
+
return i - op.count;
|
|
1788
|
+
case "move": {
|
|
1789
|
+
if (isNoopMove(op)) return i;
|
|
1790
|
+
const { from, count, to } = op;
|
|
1791
|
+
if (i >= from && i < from + count) return movedBlockStart(op) + (i - from);
|
|
1792
|
+
if (to > from) return i >= from + count && i < to ? i - count : i;
|
|
1793
|
+
return i >= to && i < from ? i + count : i;
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
function runs(indices) {
|
|
1798
|
+
const sorted = [...new Set(indices)].sort((a, b) => a - b);
|
|
1799
|
+
const out = [];
|
|
1800
|
+
for (const i of sorted) {
|
|
1801
|
+
const last = out[out.length - 1];
|
|
1802
|
+
if (last && last.start + last.count === i) last.count++;
|
|
1803
|
+
else out.push({ start: i, count: 1 });
|
|
1804
|
+
}
|
|
1805
|
+
return out;
|
|
1806
|
+
}
|
|
1807
|
+
function mapGapThroughMove(p, mv) {
|
|
1808
|
+
const { from, count, to } = mv;
|
|
1809
|
+
if (p > from && p < from + count) return movedBlockStart(mv) + (p - from);
|
|
1810
|
+
const g = p <= from ? p : p - count;
|
|
1811
|
+
const tg = to <= from ? to : to - count;
|
|
1812
|
+
return g <= tg ? g : g + count;
|
|
1813
|
+
}
|
|
1814
|
+
function transformAxis(x, y, side) {
|
|
1815
|
+
if (y.kind === "move" && isNoopMove(y)) return [x];
|
|
1816
|
+
if (x.kind === "move" && isNoopMove(x)) return [];
|
|
1817
|
+
switch (x.kind) {
|
|
1818
|
+
case "insert": {
|
|
1819
|
+
if (y.kind === "insert") {
|
|
1820
|
+
if (x.at < y.at || x.at === y.at && side === "left") return [x];
|
|
1821
|
+
return [{ ...x, at: x.at + y.count }];
|
|
1822
|
+
}
|
|
1823
|
+
if (y.kind === "remove") {
|
|
1824
|
+
if (x.at <= y.start) return [x];
|
|
1825
|
+
if (x.at >= y.start + y.count) return [{ ...x, at: x.at - y.count }];
|
|
1826
|
+
return [{ ...x, at: y.start }];
|
|
1827
|
+
}
|
|
1828
|
+
return [{ ...x, at: mapGapThroughMove(x.at, y) }];
|
|
1829
|
+
}
|
|
1830
|
+
case "remove": {
|
|
1831
|
+
const kept = [];
|
|
1832
|
+
for (let i = x.start; i < x.start + x.count; i++) {
|
|
1833
|
+
const m = mapIndex(y, i);
|
|
1834
|
+
if (m !== null) kept.push(m);
|
|
1835
|
+
}
|
|
1836
|
+
if (y.kind === "insert" || y.kind === "remove" || y.kind === "move") {
|
|
1837
|
+
return runs(kept).reverse().map((r) => ({ kind: "remove", start: r.start, count: r.count }));
|
|
1838
|
+
}
|
|
1839
|
+
return null;
|
|
1840
|
+
}
|
|
1841
|
+
case "move": {
|
|
1842
|
+
if (y.kind === "insert") {
|
|
1843
|
+
const inside = y.at > x.from && y.at < x.from + x.count;
|
|
1844
|
+
const from = inside || y.at > x.from ? x.from : x.from + y.count;
|
|
1845
|
+
const count = inside ? x.count + y.count : x.count;
|
|
1846
|
+
const to2 = x.to >= y.at ? x.to + y.count : x.to;
|
|
1847
|
+
const out2 = { kind: "move", from, count, to: to2 };
|
|
1848
|
+
return isNoopMove(out2) ? [] : [out2];
|
|
1849
|
+
}
|
|
1850
|
+
if (y.kind === "remove") {
|
|
1851
|
+
const kept = [];
|
|
1852
|
+
for (let i = x.from; i < x.from + x.count; i++) {
|
|
1853
|
+
const m = mapIndex(y, i);
|
|
1854
|
+
if (m !== null) kept.push(m);
|
|
1855
|
+
}
|
|
1856
|
+
if (kept.length === 0) return [];
|
|
1857
|
+
const r2 = runs(kept);
|
|
1858
|
+
if (r2.length !== 1) return null;
|
|
1859
|
+
const to2 = x.to <= y.start ? x.to : x.to >= y.start + y.count ? x.to - y.count : y.start;
|
|
1860
|
+
const out2 = { kind: "move", from: r2[0].start, count: r2[0].count, to: to2 };
|
|
1861
|
+
return isNoopMove(out2) ? [] : [out2];
|
|
1862
|
+
}
|
|
1863
|
+
const overlap = Math.min(x.from + x.count, y.from + y.count) - Math.max(x.from, y.from);
|
|
1864
|
+
if (overlap > 0) {
|
|
1865
|
+
if (x.from !== y.from || x.count !== y.count) return null;
|
|
1866
|
+
if (side === "right") return [];
|
|
1867
|
+
const out2 = { kind: "move", from: movedBlockStart(y), count: x.count, to: mapGapThroughMove(x.to, y) };
|
|
1868
|
+
return isNoopMove(out2) ? [] : [out2];
|
|
1869
|
+
}
|
|
1870
|
+
const mapped = [];
|
|
1871
|
+
for (let i = x.from; i < x.from + x.count; i++) mapped.push(mapIndex(y, i));
|
|
1872
|
+
const r = runs(mapped);
|
|
1873
|
+
if (r.length !== 1) return null;
|
|
1874
|
+
let to;
|
|
1875
|
+
if (x.to > y.from && x.to < y.from + y.count) to = movedBlockStart(y) + (x.to - y.from);
|
|
1876
|
+
else to = mapGapThroughMove(x.to, y) + (x.to === y.to && side === "right" ? y.count : 0);
|
|
1877
|
+
const out = { kind: "move", from: r[0].start, count: r[0].count, to };
|
|
1878
|
+
if (to > out.from && to < out.from + out.count) return null;
|
|
1879
|
+
return isNoopMove(out) ? [] : [out];
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
// src/collab/sheets/transform/formula.ts
|
|
1885
|
+
var import_core3 = require("@univerjs/core");
|
|
1886
|
+
var import_engine_formula = require("@univerjs/engine-formula");
|
|
1887
|
+
var import_sheets = require("@univerjs/sheets");
|
|
1888
|
+
var REF_ERROR = "#REF!";
|
|
1889
|
+
var FULL = 16383 * 64;
|
|
1890
|
+
var lexer = null;
|
|
1891
|
+
var lex = (body) => (lexer ??= new import_engine_formula.LexerTreeBuilder()).sequenceNodesBuilder(body);
|
|
1892
|
+
var isFormulaText = (f) => typeof f === "string" && f.length > 1 && f.startsWith("=");
|
|
1893
|
+
var IDENT = /^[A-Za-z_\\][A-Za-z0-9_.\\]*$/;
|
|
1894
|
+
var ERROR_TOKEN = /^(?:[^!]+!)?#(?:REF!|NAME\?|VALUE!|DIV\/0!|N\/A|NUM!|NULL!|SPILL!|CALC!)$/i;
|
|
1895
|
+
function parse(text) {
|
|
1896
|
+
const prefix = text.startsWith("=") ? "=" : "";
|
|
1897
|
+
const nodes = lex(text.slice(prefix.length));
|
|
1898
|
+
if (!nodes) return "the formula lexer could not read the text";
|
|
1899
|
+
for (const n of nodes) {
|
|
1900
|
+
if (typeof n === "string") continue;
|
|
1901
|
+
if (n.nodeType === import_engine_formula.sequenceNodeType.TABLE || n.nodeType === import_engine_formula.sequenceNodeType.FUNCTION && n.token.includes("[")) return "a structured table reference (tables are C5c)";
|
|
1902
|
+
if (n.nodeType === import_engine_formula.sequenceNodeType.FUNCTION && !IDENT.test(n.token) && !ERROR_TOKEN.test(n.token))
|
|
1903
|
+
return `the lexer read "${n.token}" as one name (an intersection or a reference it cannot split)`;
|
|
1904
|
+
if (n.nodeType === import_engine_formula.sequenceNodeType.REFERENCE) {
|
|
1905
|
+
const d = (0, import_engine_formula.deserializeRangeWithSheet)(n.token);
|
|
1906
|
+
if (d.unitId) return "a reference into another workbook";
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
return { prefix, nodes };
|
|
1910
|
+
}
|
|
1911
|
+
function targetSheet(sheetName, ctx) {
|
|
1912
|
+
if (!sheetName) return ctx.ownSheet;
|
|
1913
|
+
const id = ctx.refSheets?.[sheetName];
|
|
1914
|
+
if (id === void 0) return void 0;
|
|
1915
|
+
return id ?? "";
|
|
1916
|
+
}
|
|
1917
|
+
function formulaBarrier(text, ctx) {
|
|
1918
|
+
const p = parse(text);
|
|
1919
|
+
if (typeof p === "string") return p;
|
|
1920
|
+
for (const n of p.nodes) {
|
|
1921
|
+
if (typeof n === "string" || n.nodeType !== import_engine_formula.sequenceNodeType.REFERENCE) continue;
|
|
1922
|
+
const { sheetName } = (0, import_engine_formula.deserializeRangeWithSheet)(n.token);
|
|
1923
|
+
if (targetSheet(sheetName, ctx) === void 0) return `sheet "${sheetName}" is not in refSheets (capture must call annotateRefSheets)`;
|
|
1924
|
+
}
|
|
1925
|
+
return null;
|
|
1926
|
+
}
|
|
1927
|
+
function referencedSheetNames(text) {
|
|
1928
|
+
const p = parse(text);
|
|
1929
|
+
if (typeof p === "string") return [];
|
|
1930
|
+
const out = /* @__PURE__ */ new Set();
|
|
1931
|
+
for (const n of p.nodes) if (typeof n !== "string" && n.nodeType === import_engine_formula.sequenceNodeType.REFERENCE) {
|
|
1932
|
+
const { sheetName } = (0, import_engine_formula.deserializeRangeWithSheet)(n.token);
|
|
1933
|
+
if (sheetName) out.add(sheetName);
|
|
1934
|
+
}
|
|
1935
|
+
return [...out];
|
|
1936
|
+
}
|
|
1937
|
+
var fullRowsRange = (start, count) => ({ startRow: start, endRow: start + count - 1, startColumn: 0, endColumn: FULL, rangeType: import_core3.RANGE_TYPE.ROW });
|
|
1938
|
+
var fullColsRange = (start, count) => ({ startRow: 0, endRow: FULL, startColumn: start, endColumn: start + count - 1, rangeType: import_core3.RANGE_TYPE.COLUMN });
|
|
1939
|
+
var startV = (v) => Number.isNaN(v) || v == null ? -Infinity : v;
|
|
1940
|
+
var endV = (v) => Number.isNaN(v) || v == null ? Infinity : v;
|
|
1941
|
+
function startEnd(r) {
|
|
1942
|
+
return { ...r, startRow: startV(r.startRow), endRow: endV(r.endRow), startColumn: startV(r.startColumn), endColumn: endV(r.endColumn) };
|
|
1943
|
+
}
|
|
1944
|
+
function checkMoveEdge(origin, from) {
|
|
1945
|
+
const startRow = startV(origin.startRow), endRow = endV(origin.endRow), startColumn = startV(origin.startColumn), endColumn = endV(origin.endColumn);
|
|
1946
|
+
const fromStartRow = startV(from.startRow), fromEndRow = endV(from.endRow), fromStartColumn = startV(from.startColumn), fromEndColumn = endV(from.endColumn);
|
|
1947
|
+
const rowsCover = () => origin.rangeType === import_core3.RANGE_TYPE.COLUMN && from.rangeType === import_core3.RANGE_TYPE.COLUMN || startRow >= fromStartRow && endRow <= fromEndRow;
|
|
1948
|
+
const columnsCover = () => origin.rangeType === import_core3.RANGE_TYPE.ROW && from.rangeType === import_core3.RANGE_TYPE.ROW || startColumn >= fromStartColumn && endColumn <= fromEndColumn;
|
|
1949
|
+
const allCover = () => origin.rangeType === import_core3.RANGE_TYPE.ALL && from.rangeType === import_core3.RANGE_TYPE.ALL;
|
|
1950
|
+
if (rowsCover() && columnsCover() || allCover()) return 4;
|
|
1951
|
+
if (columnsCover() && startRow >= fromStartRow && startRow <= fromEndRow && endRow > fromEndRow) return 0;
|
|
1952
|
+
if (columnsCover() && endRow >= fromStartRow && endRow <= fromEndRow && startRow < fromStartRow) return 1;
|
|
1953
|
+
if (rowsCover() && startColumn >= fromStartColumn && startColumn <= fromEndColumn && endColumn > fromEndColumn) return 2;
|
|
1954
|
+
if (rowsCover() && endColumn >= fromStartColumn && endColumn <= fromEndColumn && startColumn < fromStartColumn) return 3;
|
|
1955
|
+
return null;
|
|
1956
|
+
}
|
|
1957
|
+
function getMoveNewRange(moveEdge, result, from, to, origin, remain) {
|
|
1958
|
+
const { startRow, endRow, startColumn, endColumn, rangeType } = startEnd(result);
|
|
1959
|
+
const f = startEnd(from);
|
|
1960
|
+
const fromRangeType = from.rangeType ?? import_core3.RANGE_TYPE.NORMAL;
|
|
1961
|
+
const t = startEnd(to);
|
|
1962
|
+
const rm = startEnd(remain);
|
|
1963
|
+
const o = startEnd(origin);
|
|
1964
|
+
const originRangeType = origin.rangeType ?? import_core3.RANGE_TYPE.NORMAL;
|
|
1965
|
+
const newRange = { ...origin };
|
|
1966
|
+
const rowsCover = () => rangeType === import_core3.RANGE_TYPE.COLUMN && originRangeType === import_core3.RANGE_TYPE.COLUMN || startColumn >= o.startColumn && endColumn <= o.endColumn;
|
|
1967
|
+
const columnsCover = () => rangeType === import_core3.RANGE_TYPE.ROW && originRangeType === import_core3.RANGE_TYPE.ROW || startRow >= o.startRow && endRow <= o.endRow;
|
|
1968
|
+
if (moveEdge === 0) {
|
|
1969
|
+
if (!rowsCover()) return void 0;
|
|
1970
|
+
if (startRow < o.startRow) newRange.startRow = startRow;
|
|
1971
|
+
else if (startRow >= o.endRow) newRange.endRow -= f.endRow + 1 - o.startRow;
|
|
1972
|
+
else return void 0;
|
|
1973
|
+
} else if (moveEdge === 1) {
|
|
1974
|
+
if (!rowsCover()) return void 0;
|
|
1975
|
+
if (endRow > o.endRow) newRange.endRow = endRow;
|
|
1976
|
+
else if (endRow <= o.startRow) newRange.startRow += o.endRow - f.startRow + 1;
|
|
1977
|
+
else return void 0;
|
|
1978
|
+
} else if (moveEdge === 2) {
|
|
1979
|
+
if (!columnsCover()) return void 0;
|
|
1980
|
+
if (startColumn < o.startColumn) newRange.startColumn = startColumn;
|
|
1981
|
+
else if (startColumn >= o.endColumn) newRange.endColumn -= f.endColumn + 1 - o.startColumn;
|
|
1982
|
+
else return void 0;
|
|
1983
|
+
} else if (moveEdge === 3) {
|
|
1984
|
+
if (!columnsCover()) return void 0;
|
|
1985
|
+
if (endColumn > o.endColumn) newRange.endColumn = endColumn;
|
|
1986
|
+
else if (endColumn <= o.startColumn) newRange.startColumn += o.endColumn - f.startColumn + 1;
|
|
1987
|
+
else return void 0;
|
|
1988
|
+
} else if (moveEdge === 4) {
|
|
1989
|
+
Object.assign(newRange, { startRow, startColumn, endRow, endColumn });
|
|
1990
|
+
} else if (f.startColumn <= o.startColumn && f.endColumn >= o.endColumn || fromRangeType === import_core3.RANGE_TYPE.ROW && originRangeType === import_core3.RANGE_TYPE.ROW) {
|
|
1991
|
+
const n = f.endRow - f.startRow + 1;
|
|
1992
|
+
if (from.endRow < o.startRow) {
|
|
1993
|
+
if (t.startRow >= o.startRow) newRange.startRow -= n;
|
|
1994
|
+
if (t.startRow >= o.endRow) newRange.endRow -= n;
|
|
1995
|
+
} else if (from.startRow > o.endRow) {
|
|
1996
|
+
if (t.endRow <= o.endRow) newRange.endRow += n;
|
|
1997
|
+
if (t.endRow <= o.startRow) newRange.startRow += n;
|
|
1998
|
+
} else if (from.startRow >= o.startRow && from.endRow <= o.endRow) {
|
|
1999
|
+
if (t.startRow <= o.startRow) newRange.startRow += n;
|
|
2000
|
+
else if (t.startRow >= o.endRow) newRange.endRow -= n;
|
|
2001
|
+
}
|
|
2002
|
+
} else if (f.startRow <= o.startRow && f.endRow >= o.endRow || fromRangeType === import_core3.RANGE_TYPE.COLUMN && originRangeType === import_core3.RANGE_TYPE.COLUMN) {
|
|
2003
|
+
const n = f.endColumn - f.startColumn + 1;
|
|
2004
|
+
if (from.endColumn < o.startColumn) {
|
|
2005
|
+
if (t.startColumn >= o.startColumn) newRange.startColumn -= n;
|
|
2006
|
+
if (t.startColumn >= o.endColumn) newRange.endColumn -= n;
|
|
2007
|
+
} else if (from.startColumn > o.endColumn) {
|
|
2008
|
+
if (t.endColumn <= o.endColumn) newRange.endColumn += n;
|
|
2009
|
+
if (t.endColumn <= o.startColumn) newRange.startColumn += n;
|
|
2010
|
+
} else if (from.startColumn >= o.startColumn && from.endColumn <= o.endColumn) {
|
|
2011
|
+
if (t.startColumn <= o.startColumn) newRange.startColumn += n;
|
|
2012
|
+
else if (t.startColumn >= o.endColumn) newRange.endColumn -= n;
|
|
2013
|
+
}
|
|
2014
|
+
} else {
|
|
2015
|
+
Object.assign(newRange, { startRow, startColumn, endRow, endColumn });
|
|
2016
|
+
void rm;
|
|
2017
|
+
}
|
|
2018
|
+
return newRange;
|
|
2019
|
+
}
|
|
2020
|
+
function moveRange(range, axis, op) {
|
|
2021
|
+
const isRow = axis === "row";
|
|
2022
|
+
if (op.kind === "insert") {
|
|
2023
|
+
const r = isRow ? fullRowsRange(op.at, op.count) : fullColsRange(op.at, op.count);
|
|
2024
|
+
const ops2 = isRow ? (0, import_sheets.handleInsertRow)({ id: import_sheets.EffectRefRangId.InsertRowCommandId, params: { range: r, unitId: "", subUnitId: "", direction: import_core3.Direction.DOWN } }, range) : (0, import_sheets.handleInsertCol)({ id: import_sheets.EffectRefRangId.InsertColCommandId, params: { range: r, unitId: "", subUnitId: "", direction: import_core3.Direction.RIGHT } }, range);
|
|
2025
|
+
const res2 = (0, import_sheets.runRefRangeMutations)(ops2, range);
|
|
2026
|
+
return res2 == null ? void 0 : { ...range, ...res2 };
|
|
2027
|
+
}
|
|
2028
|
+
if (op.kind === "remove") {
|
|
2029
|
+
const r = isRow ? fullRowsRange(op.start, op.count) : fullColsRange(op.start, op.count);
|
|
2030
|
+
const ops2 = isRow ? (0, import_sheets.handleIRemoveRow)({ id: import_sheets.EffectRefRangId.RemoveRowCommandId, params: { range: r } }, range, []) : (0, import_sheets.handleIRemoveCol)({ id: import_sheets.EffectRefRangId.RemoveColCommandId, params: { range: r } }, range);
|
|
2031
|
+
const res2 = (0, import_sheets.runRefRangeMutations)(ops2, range);
|
|
2032
|
+
return res2 == null ? REF_ERROR : { ...range, ...res2 };
|
|
2033
|
+
}
|
|
2034
|
+
const from = isRow ? fullRowsRange(op.from, op.count) : fullColsRange(op.from, op.count);
|
|
2035
|
+
const to = isRow ? fullRowsRange(op.to, op.count) : fullColsRange(op.to, op.count);
|
|
2036
|
+
const moveEdge = checkMoveEdge(range, from);
|
|
2037
|
+
let remain = (0, import_core3.getIntersectRange)(range, from);
|
|
2038
|
+
if (isRow) {
|
|
2039
|
+
if (remain == null && (from.endRow < range.startRow && to.endRow <= range.startRow || from.startRow > range.endRow && to.startRow > range.endRow)) return void 0;
|
|
2040
|
+
} else if (remain == null && (from.endColumn < range.startColumn && to.endColumn <= range.startColumn || from.startColumn > range.endColumn && to.startColumn > range.endColumn)) return void 0;
|
|
2041
|
+
remain ??= { startRow: range.startRow, endRow: range.endRow, startColumn: range.startColumn, endColumn: range.endColumn, rangeType: import_core3.RANGE_TYPE.NORMAL };
|
|
2042
|
+
const ops = isRow ? (0, import_sheets.handleMoveRows)({ id: import_sheets.EffectRefRangId.MoveRowsCommandId, params: { toRange: to, fromRange: from } }, remain) : (0, import_sheets.handleMoveCols)({ id: import_sheets.EffectRefRangId.MoveColsCommandId, params: { toRange: to, fromRange: from } }, remain);
|
|
2043
|
+
const res = (0, import_sheets.runRefRangeMutations)(ops, remain);
|
|
2044
|
+
if (res == null) return REF_ERROR;
|
|
2045
|
+
return getMoveNewRange(moveEdge, res, from, to, range, remain);
|
|
2046
|
+
}
|
|
2047
|
+
function rewriteFormula(text, ctx, change) {
|
|
2048
|
+
const p = parse(text);
|
|
2049
|
+
if (typeof p === "string") return p;
|
|
2050
|
+
const nodes = p.nodes.slice();
|
|
2051
|
+
const changedIds = [];
|
|
2052
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
2053
|
+
const n = nodes[i];
|
|
2054
|
+
if (typeof n === "string") continue;
|
|
2055
|
+
if (change.kind === "defined-name") {
|
|
2056
|
+
if ((n.nodeType === import_engine_formula.sequenceNodeType.DEFINED_NAME || n.nodeType === import_engine_formula.sequenceNodeType.FUNCTION) && n.token === change.from) {
|
|
2057
|
+
nodes[i] = { ...n, token: change.to ?? REF_ERROR };
|
|
2058
|
+
changedIds.push(i);
|
|
2059
|
+
}
|
|
2060
|
+
continue;
|
|
2061
|
+
}
|
|
2062
|
+
if (n.nodeType !== import_engine_formula.sequenceNodeType.REFERENCE) continue;
|
|
2063
|
+
const { range, sheetName, unitId } = (0, import_engine_formula.deserializeRangeWithSheet)(n.token);
|
|
2064
|
+
const target = targetSheet(sheetName, ctx);
|
|
2065
|
+
if (target === void 0) return `sheet "${sheetName}" is not in refSheets (capture must call annotateRefSheets)`;
|
|
2066
|
+
if (target !== change.sheet) continue;
|
|
2067
|
+
let token;
|
|
2068
|
+
if (change.kind === "rename") {
|
|
2069
|
+
if (!sheetName) continue;
|
|
2070
|
+
token = (0, import_engine_formula.serializeRangeToRefString)({ range, sheetName: change.name, unitId });
|
|
2071
|
+
} else {
|
|
2072
|
+
const moved = moveRange(import_core3.Rectangle.moveOffset(range, 0, 0), change.axis, change.op);
|
|
2073
|
+
if (moved === void 0) continue;
|
|
2074
|
+
token = moved === REF_ERROR ? REF_ERROR : (0, import_engine_formula.serializeRangeToRefString)({ range: moved, sheetName: target === ctx.ownSheet && !ctx.keepQualifier ? "" : sheetName, unitId });
|
|
2075
|
+
}
|
|
2076
|
+
nodes[i] = { ...n, token };
|
|
2077
|
+
changedIds.push(i);
|
|
2078
|
+
}
|
|
2079
|
+
if (!changedIds.length) return { text, changed: false };
|
|
2080
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
2081
|
+
const n = nodes[i];
|
|
2082
|
+
if (typeof n === "string" || n.nodeType !== import_engine_formula.sequenceNodeType.REFERENCE || changedIds.includes(i)) continue;
|
|
2083
|
+
nodes[i] = { ...n, token: (0, import_engine_formula.serializeRangeToRefString)((0, import_engine_formula.deserializeRangeWithSheet)(n.token)) };
|
|
2084
|
+
}
|
|
2085
|
+
const out = p.prefix + (0, import_engine_formula.generateStringWithSequence)(nodes);
|
|
2086
|
+
return { text: out, changed: out !== text };
|
|
2087
|
+
}
|
|
2088
|
+
function refSheetsAfter(refSheets, change) {
|
|
2089
|
+
if (change.kind !== "rename" || !refSheets) return refSheets;
|
|
2090
|
+
const entries = Object.entries(refSheets);
|
|
2091
|
+
if (!entries.some(([name, id]) => id === change.sheet || name === change.name)) return refSheets;
|
|
2092
|
+
const next = {};
|
|
2093
|
+
for (const [name, id] of entries) if (id !== change.sheet && name !== change.name) next[name] = id;
|
|
2094
|
+
next[change.name] = change.sheet;
|
|
2095
|
+
return next;
|
|
2096
|
+
}
|
|
2097
|
+
function refSheetsFor(texts, sheets) {
|
|
2098
|
+
const byName = new Map(Object.entries(sheets).map(([id, name]) => [name, id]));
|
|
2099
|
+
const out = {};
|
|
2100
|
+
for (const t of texts) for (const name of referencedSheetNames(t)) out[name] = byName.get(name) ?? null;
|
|
2101
|
+
return Object.keys(out).length ? out : void 0;
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
// src/collab/sheets/transform/transform.ts
|
|
2105
|
+
var SHEET_TRANSFORMER_VERSION = "c5b-1";
|
|
2106
|
+
var ID = {
|
|
2107
|
+
values: "sheet.mutation.set-range-values",
|
|
2108
|
+
insertRow: "sheet.mutation.insert-row",
|
|
2109
|
+
removeRows: "sheet.mutation.remove-rows",
|
|
2110
|
+
insertCol: "sheet.mutation.insert-col",
|
|
2111
|
+
removeCol: "sheet.mutation.remove-col",
|
|
2112
|
+
moveRows: "sheet.mutation.move-rows",
|
|
2113
|
+
moveCols: "sheet.mutation.move-columns",
|
|
2114
|
+
addMerge: "sheet.mutation.add-worksheet-merge",
|
|
2115
|
+
removeMerge: "sheet.mutation.remove-worksheet-merge",
|
|
2116
|
+
rowHeight: "sheet.mutation.set-worksheet-row-height",
|
|
2117
|
+
rowIsAuto: "sheet.mutation.set-worksheet-row-is-auto-height",
|
|
2118
|
+
rowAutoHeight: "sheet.mutation.set-worksheet-row-auto-height",
|
|
2119
|
+
colWidth: "sheet.mutation.set-worksheet-col-width",
|
|
2120
|
+
name: "sheet.mutation.set-worksheet-name",
|
|
2121
|
+
setName: "formula.mutation.set-defined-name",
|
|
2122
|
+
removeName: "formula.mutation.remove-defined-name"
|
|
2123
|
+
};
|
|
2124
|
+
var PAIR_BARRIERS = {};
|
|
2125
|
+
var pairKey = (a, b) => a < b ? `${a}|${b}` : `${b}|${a}`;
|
|
2126
|
+
var barrier2 = (reason) => ({ barrier: true, reason });
|
|
2127
|
+
var ok = (op, lost = [], dropped = []) => ({ op, lost, dropped });
|
|
2128
|
+
var flip = (side) => side === "left" ? "right" : "left";
|
|
2129
|
+
var sheetOf = (m) => String(m.params.subUnitId ?? "");
|
|
2130
|
+
function colName(c) {
|
|
2131
|
+
let s = "";
|
|
2132
|
+
for (let n = c + 1; n > 0; n = Math.floor((n - 1) / 26)) s = String.fromCharCode(65 + (n - 1) % 26) + s;
|
|
2133
|
+
return s;
|
|
2134
|
+
}
|
|
2135
|
+
var cellRef = (sheet, row, col) => `${sheet}!${colName(col)}${row + 1}`;
|
|
2136
|
+
var rangeRef = (sheet, r) => `${sheet}!${colName(r.startColumn)}${r.startRow + 1}:${colName(r.endColumn)}${r.endRow + 1}`;
|
|
2137
|
+
function structuralOf(m) {
|
|
2138
|
+
const p = m.params;
|
|
2139
|
+
switch (m.id) {
|
|
2140
|
+
case ID.insertRow:
|
|
2141
|
+
return { axis: "row", op: { kind: "insert", at: p.range.startRow, count: p.range.endRow - p.range.startRow + 1 } };
|
|
2142
|
+
case ID.removeRows:
|
|
2143
|
+
return { axis: "row", op: { kind: "remove", start: p.range.startRow, count: p.range.endRow - p.range.startRow + 1 } };
|
|
2144
|
+
case ID.insertCol:
|
|
2145
|
+
return { axis: "col", op: { kind: "insert", at: p.range.startColumn, count: p.range.endColumn - p.range.startColumn + 1 } };
|
|
2146
|
+
case ID.removeCol:
|
|
2147
|
+
return { axis: "col", op: { kind: "remove", start: p.range.startColumn, count: p.range.endColumn - p.range.startColumn + 1 } };
|
|
2148
|
+
case ID.moveRows:
|
|
2149
|
+
return {
|
|
2150
|
+
axis: "row",
|
|
2151
|
+
op: { kind: "move", from: p.sourceRange.startRow, count: p.sourceRange.endRow - p.sourceRange.startRow + 1, to: p.targetRange.startRow }
|
|
2152
|
+
};
|
|
2153
|
+
case ID.moveCols:
|
|
2154
|
+
return {
|
|
2155
|
+
axis: "col",
|
|
2156
|
+
op: {
|
|
2157
|
+
kind: "move",
|
|
2158
|
+
from: p.sourceRange.startColumn,
|
|
2159
|
+
count: p.sourceRange.endColumn - p.sourceRange.startColumn + 1,
|
|
2160
|
+
to: p.targetRange.startColumn
|
|
2161
|
+
}
|
|
2162
|
+
};
|
|
2163
|
+
default:
|
|
2164
|
+
return null;
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
var S = (axis) => axis === "row" ? ["startRow", "endRow"] : ["startColumn", "endColumn"];
|
|
2168
|
+
function buildStructural(template, axis, op) {
|
|
2169
|
+
const [a0, a1] = S(axis);
|
|
2170
|
+
const p = template.params;
|
|
2171
|
+
if (op.kind === "move") {
|
|
2172
|
+
const src = p.sourceRange;
|
|
2173
|
+
const tgt = p.targetRange;
|
|
2174
|
+
return {
|
|
2175
|
+
id: template.id,
|
|
2176
|
+
params: {
|
|
2177
|
+
...p,
|
|
2178
|
+
sourceRange: { ...src, [a0]: op.from, [a1]: op.from + op.count - 1 },
|
|
2179
|
+
targetRange: { ...tgt, [a0]: op.to, [a1]: op.to + op.count - 1 }
|
|
2180
|
+
}
|
|
2181
|
+
};
|
|
2182
|
+
}
|
|
2183
|
+
const start = op.kind === "insert" ? op.at : op.start;
|
|
2184
|
+
return { id: template.id, params: { ...p, range: { ...p.range, [a0]: start, [a1]: start + op.count - 1 } } };
|
|
2185
|
+
}
|
|
2186
|
+
function univerMutationInfo(axis, op) {
|
|
2187
|
+
const FULL2 = { startRow: 0, endRow: Number.MAX_SAFE_INTEGER, startColumn: 0, endColumn: Number.MAX_SAFE_INTEGER };
|
|
2188
|
+
const start = op.kind === "insert" ? op.at : op.start;
|
|
2189
|
+
const range = axis === "row" ? { ...FULL2, startRow: start, endRow: start + op.count - 1 } : { ...FULL2, startColumn: start, endColumn: start + op.count - 1 };
|
|
2190
|
+
const id = op.kind === "insert" ? axis === "row" ? ID.insertRow : ID.insertCol : axis === "row" ? ID.removeRows : ID.removeCol;
|
|
2191
|
+
return { id, params: { unitId: "", subUnitId: "", range } };
|
|
2192
|
+
}
|
|
2193
|
+
var intersects = (a, b) => a.startRow <= b.endRow && b.startRow <= a.endRow && a.startColumn <= b.endColumn && b.startColumn <= a.endColumn;
|
|
2194
|
+
var isSingleCell = (r) => r.startRow === r.endRow && r.startColumn === r.endColumn;
|
|
2195
|
+
function mergeThrough(s, m) {
|
|
2196
|
+
const [a0, a1] = S(s.axis);
|
|
2197
|
+
const lo = m[a0];
|
|
2198
|
+
const hi = m[a1];
|
|
2199
|
+
const op = s.op;
|
|
2200
|
+
if (op.kind === "insert") {
|
|
2201
|
+
const fixup = lo < op.at && op.at <= hi;
|
|
2202
|
+
return { range: (0, import_sheets2.adjustRangeOnMutation)(m, univerMutationInfo(s.axis, op)), fixup };
|
|
2203
|
+
}
|
|
2204
|
+
if (op.kind === "remove") {
|
|
2205
|
+
const e = op.start + op.count - 1;
|
|
2206
|
+
if (e < lo || op.start > hi) return { range: (0, import_sheets2.adjustRangeOnMutation)(m, univerMutationInfo(s.axis, op)), fixup: false };
|
|
2207
|
+
if (op.start <= lo && e >= hi) return { range: null, fixup: true };
|
|
2208
|
+
const r = { ...m };
|
|
2209
|
+
if (op.start >= lo && e <= hi) r[a1] = hi - op.count;
|
|
2210
|
+
else if (op.start < lo) {
|
|
2211
|
+
r[a0] = op.start;
|
|
2212
|
+
r[a1] = hi - op.count;
|
|
2213
|
+
} else r[a1] = op.start - 1;
|
|
2214
|
+
return { range: isSingleCell(r) ? null : r, fixup: true };
|
|
2215
|
+
}
|
|
2216
|
+
const fe = op.from + op.count - 1;
|
|
2217
|
+
if (hi < op.from || lo > fe) {
|
|
2218
|
+
const r = { ...m };
|
|
2219
|
+
if (op.from < lo && op.to > hi) {
|
|
2220
|
+
r[a0] = lo - op.count;
|
|
2221
|
+
r[a1] = hi - op.count;
|
|
2222
|
+
} else if (op.from > hi && op.to <= lo) {
|
|
2223
|
+
r[a0] = lo + op.count;
|
|
2224
|
+
r[a1] = hi + op.count;
|
|
2225
|
+
}
|
|
2226
|
+
return { range: r, fixup: false };
|
|
2227
|
+
}
|
|
2228
|
+
if (lo >= op.from && hi <= fe) {
|
|
2229
|
+
const r = { ...m, [a0]: mapIndex(op, lo), [a1]: mapIndex(op, hi) };
|
|
2230
|
+
return { range: r, fixup: true };
|
|
2231
|
+
}
|
|
2232
|
+
return { range: m, fixup: false };
|
|
2233
|
+
}
|
|
2234
|
+
function exactMergeRemovals(group, merges) {
|
|
2235
|
+
const sim = new Map(Object.entries(merges).map(([k, v]) => [k, v.map((r) => ({ ...r }))]));
|
|
2236
|
+
const out = [];
|
|
2237
|
+
for (const m of group) {
|
|
2238
|
+
const sheet = sheetOf(m);
|
|
2239
|
+
const cur = sim.get(sheet) ?? [];
|
|
2240
|
+
if (m.id === ID.removeMerge) {
|
|
2241
|
+
const hit = cur.filter((q) => mergeRanges(m).some((r) => intersects(r, q)));
|
|
2242
|
+
sim.set(sheet, cur.filter((q) => !hit.includes(q)));
|
|
2243
|
+
if (hit.length) out.push(withRanges(m, hit.map((r) => ({ ...r }))));
|
|
2244
|
+
continue;
|
|
2245
|
+
}
|
|
2246
|
+
if (m.id === ID.addMerge) sim.set(sheet, [...cur, ...mergeRanges(m).map((r) => ({ ...r }))]);
|
|
2247
|
+
const st = structuralOf(m);
|
|
2248
|
+
if (st) sim.set(sheet, cur.map((q) => mergeThrough(st, q).range).filter((q) => q !== null));
|
|
2249
|
+
out.push(m);
|
|
2250
|
+
}
|
|
2251
|
+
return out;
|
|
2252
|
+
}
|
|
2253
|
+
var mergeRanges = (m) => m.params.ranges ?? [];
|
|
2254
|
+
var withRanges = (m, ranges) => ({ id: m.id, params: { ...m.params, ranges } });
|
|
2255
|
+
var mergeMutation = (id, sheet, ranges) => ({ id, params: { subUnitId: sheet, ranges } });
|
|
2256
|
+
var CONTENT_KEYS = ["v", "t", "p", "f", "si", "custom", "ref", "xf", "ft", "fd"];
|
|
2257
|
+
var CONTENT_TOUCH = ["v", "p", "f", "si", "custom", "ref", "xf", "ft", "fd"];
|
|
2258
|
+
var KNOWN_CELL_KEYS = /* @__PURE__ */ new Set([...CONTENT_KEYS, "s"]);
|
|
2259
|
+
function completeCellContent(entry, post) {
|
|
2260
|
+
if (entry === null) return null;
|
|
2261
|
+
if (!CONTENT_TOUCH.some((k) => k in entry)) return entry;
|
|
2262
|
+
const out = {};
|
|
2263
|
+
for (const k of CONTENT_KEYS) out[k] = post && post[k] !== void 0 ? post[k] : null;
|
|
2264
|
+
if (out.v === null) delete out.t;
|
|
2265
|
+
if ("s" in entry) out.s = entry.s;
|
|
2266
|
+
return out;
|
|
2267
|
+
}
|
|
2268
|
+
function cellsOf(m) {
|
|
2269
|
+
return m.params.cellValue ?? {};
|
|
2270
|
+
}
|
|
2271
|
+
function forEachCell(cells, fn) {
|
|
2272
|
+
for (const r of Object.keys(cells)) for (const c of Object.keys(cells[r] ?? {})) fn(Number(r), Number(c), cells[r][c] ?? null);
|
|
2273
|
+
}
|
|
2274
|
+
function cellsMutation(template, cells) {
|
|
2275
|
+
return { id: template.id, params: { ...template.params, cellValue: cells } };
|
|
2276
|
+
}
|
|
2277
|
+
function putCell(cells, r, c, v) {
|
|
2278
|
+
(cells[r] ??= {})[c] = v;
|
|
2279
|
+
}
|
|
2280
|
+
var isEmptyMatrix = (cells) => Object.values(cells).every((row) => Object.keys(row).length === 0);
|
|
2281
|
+
function cellBarrier(m) {
|
|
2282
|
+
if (m.params.isOverrideStyle) return "set-range-values with isOverrideStyle (whole-style replace) is not covered";
|
|
2283
|
+
let why = null;
|
|
2284
|
+
forEachCell(cellsOf(m), (_r, _c, v) => {
|
|
2285
|
+
if (why || v === null) return;
|
|
2286
|
+
for (const k of Object.keys(v)) {
|
|
2287
|
+
if (why) break;
|
|
2288
|
+
if (!KNOWN_CELL_KEYS.has(k)) why = `cell key "${k}" is not covered`;
|
|
2289
|
+
else if (k === "si" && v.si != null) why = "shared formula (si): its text lives in a master cell this op does not carry";
|
|
2290
|
+
else if (k === "f" && isFormulaText(v.f) || k === "ref" && typeof v.ref === "string") why = formulaBarrier(v[k], formulaCtx(m));
|
|
2291
|
+
}
|
|
2292
|
+
if (typeof v.s === "string") why = "a style id travels (style ids are seat-local; capture must send the style object)";
|
|
2293
|
+
if (!why && CONTENT_TOUCH.some((k) => k in v) && !CONTENT_KEYS.every((k) => k in v || k === "t" && v.v == null))
|
|
2294
|
+
why = "cell content is not completed (capture must call completeCellContent)";
|
|
2295
|
+
});
|
|
2296
|
+
return why;
|
|
2297
|
+
}
|
|
2298
|
+
var hasContent = (v) => CONTENT_TOUCH.some((k) => k in v);
|
|
2299
|
+
var contentOf = (v) => {
|
|
2300
|
+
const out = {};
|
|
2301
|
+
for (const k of Object.keys(v)) if (k !== "s") out[k] = v[k];
|
|
2302
|
+
return out;
|
|
2303
|
+
};
|
|
2304
|
+
var richText = (v) => v.p != null;
|
|
2305
|
+
function styleKeys(s) {
|
|
2306
|
+
const out = [];
|
|
2307
|
+
for (const k of Object.keys(s)) {
|
|
2308
|
+
if (k === "bd" && s.bd && typeof s.bd === "object") for (const side of Object.keys(s.bd)) out.push(`bd.${side}`);
|
|
2309
|
+
else out.push(k);
|
|
2310
|
+
}
|
|
2311
|
+
return out;
|
|
2312
|
+
}
|
|
2313
|
+
function withoutStyleKeys(s, drop) {
|
|
2314
|
+
const out = {};
|
|
2315
|
+
for (const k of Object.keys(s)) {
|
|
2316
|
+
if (k === "bd" && s.bd && typeof s.bd === "object") {
|
|
2317
|
+
const bd = {};
|
|
2318
|
+
for (const side of Object.keys(s.bd)) if (!drop.has(`bd.${side}`)) bd[side] = s.bd[side];
|
|
2319
|
+
if (Object.keys(bd).length) out.bd = bd;
|
|
2320
|
+
} else if (!drop.has(k)) out[k] = s[k];
|
|
2321
|
+
}
|
|
2322
|
+
return Object.keys(out).length ? out : null;
|
|
2323
|
+
}
|
|
2324
|
+
function transformCell(X, Y4, side) {
|
|
2325
|
+
if (X === null || Y4 === null) {
|
|
2326
|
+
if (side === "left") return { entries: [X], xLost: false, yLost: true };
|
|
2327
|
+
return X === null ? { entries: [null, Y4], xLost: true, yLost: false } : { entries: [], xLost: true, yLost: false };
|
|
2328
|
+
}
|
|
2329
|
+
if (hasContent(X) && richText(X) && "s" in Y4 || hasContent(Y4) && richText(Y4) && "s" in X)
|
|
2330
|
+
return "rich-text content concurrent with a style change on the same cell is not covered";
|
|
2331
|
+
const out = {};
|
|
2332
|
+
let xLost = false;
|
|
2333
|
+
let yLost = false;
|
|
2334
|
+
if (hasContent(X)) {
|
|
2335
|
+
if (!hasContent(Y4) || side === "left") Object.assign(out, contentOf(X));
|
|
2336
|
+
else xLost = true;
|
|
2337
|
+
if (hasContent(Y4) && side === "left") yLost = true;
|
|
2338
|
+
}
|
|
2339
|
+
const tail = [];
|
|
2340
|
+
if ("s" in X) {
|
|
2341
|
+
const xs = X.s;
|
|
2342
|
+
const ys = "s" in Y4 ? Y4.s : void 0;
|
|
2343
|
+
if (ys === void 0 || side === "left") {
|
|
2344
|
+
if (xs !== void 0) out.s = xs;
|
|
2345
|
+
if (ys !== void 0) yLost = true;
|
|
2346
|
+
} else if (ys === null) {
|
|
2347
|
+
xLost = true;
|
|
2348
|
+
} else if (xs === null) {
|
|
2349
|
+
out.s = null;
|
|
2350
|
+
tail.push({ s: ys });
|
|
2351
|
+
xLost = true;
|
|
2352
|
+
} else {
|
|
2353
|
+
const kept = withoutStyleKeys(xs, new Set(styleKeys(ys)));
|
|
2354
|
+
if (kept) out.s = kept;
|
|
2355
|
+
if (styleKeys(xs).length !== styleKeys(kept ?? {}).length) xLost = true;
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
return { entries: Object.keys(out).length ? [out, ...tail] : tail, xLost, yLost };
|
|
2359
|
+
}
|
|
2360
|
+
function transformCellsOverCells(x, y, side) {
|
|
2361
|
+
if (sheetOf(x) !== sheetOf(y)) return ok([x]);
|
|
2362
|
+
const ycells = cellsOf(y);
|
|
2363
|
+
const xd = isDerived(x);
|
|
2364
|
+
const yd = isDerived(y);
|
|
2365
|
+
const eff = derivedSide(x, y, side);
|
|
2366
|
+
const passes = [{}];
|
|
2367
|
+
const lost = [];
|
|
2368
|
+
const dropped = [];
|
|
2369
|
+
let why = null;
|
|
2370
|
+
forEachCell(cellsOf(x), (r, c, X) => {
|
|
2371
|
+
if (why) return;
|
|
2372
|
+
const yRow = ycells[r];
|
|
2373
|
+
if (!yRow || !(String(c) in yRow)) {
|
|
2374
|
+
putCell(passes[0], r, c, X);
|
|
2375
|
+
return;
|
|
2376
|
+
}
|
|
2377
|
+
const res = transformCell(X, yRow[c] ?? null, eff);
|
|
2378
|
+
if (typeof res === "string") {
|
|
2379
|
+
why = res;
|
|
2380
|
+
return;
|
|
2381
|
+
}
|
|
2382
|
+
res.entries.forEach((e, i) => putCell(passes[i] ??= {}, r, c, e));
|
|
2383
|
+
if (res.xLost && !xd) dropped.push(cellRef(sheetOf(x), r, c));
|
|
2384
|
+
if (res.yLost && !yd) lost.push(cellRef(sheetOf(x), r, c));
|
|
2385
|
+
});
|
|
2386
|
+
if (why) return barrier2(why);
|
|
2387
|
+
const op = passes.filter((p) => !isEmptyMatrix(p)).map((p) => cellsMutation(x, p));
|
|
2388
|
+
return ok(op, lost, dropped);
|
|
2389
|
+
}
|
|
2390
|
+
var SIDE_CAR_PARAMS = ["refSheets", "previousName", "derived"];
|
|
2391
|
+
var isDerived = (m) => m.params.derived === true;
|
|
2392
|
+
function derivedSide(x, y, side) {
|
|
2393
|
+
const xd = isDerived(x);
|
|
2394
|
+
const yd = isDerived(y);
|
|
2395
|
+
return xd === yd ? side : xd ? "right" : "left";
|
|
2396
|
+
}
|
|
2397
|
+
function forApply(m) {
|
|
2398
|
+
if (!SIDE_CAR_PARAMS.some((k) => k in m.params)) return m;
|
|
2399
|
+
const params = { ...m.params };
|
|
2400
|
+
for (const k of SIDE_CAR_PARAMS) delete params[k];
|
|
2401
|
+
return { id: m.id, params };
|
|
2402
|
+
}
|
|
2403
|
+
var refSheetsOf = (m) => m.params.refSheets;
|
|
2404
|
+
var formulaCtx = (m) => ({ ownSheet: sheetOf(m), refSheets: refSheetsOf(m) });
|
|
2405
|
+
function withRefSheets(params, rs) {
|
|
2406
|
+
const out = { ...params };
|
|
2407
|
+
if (rs) out.refSheets = rs;
|
|
2408
|
+
else delete out.refSheets;
|
|
2409
|
+
return out;
|
|
2410
|
+
}
|
|
2411
|
+
var hasFormulaText = (v) => !!v && (isFormulaText(v.f) || typeof v.ref === "string");
|
|
2412
|
+
function hasFormula(m) {
|
|
2413
|
+
let any = false;
|
|
2414
|
+
forEachCell(cellsOf(m), (_r, _c, v) => {
|
|
2415
|
+
any ||= hasFormulaText(v);
|
|
2416
|
+
});
|
|
2417
|
+
return any;
|
|
2418
|
+
}
|
|
2419
|
+
var setNameWithoutPrevious = (m) => m.id === ID.setName && !("previousName" in m.params);
|
|
2420
|
+
function refChangeOf(m) {
|
|
2421
|
+
const st = structuralOf(m);
|
|
2422
|
+
if (st) return { kind: "axis", sheet: sheetOf(m), axis: st.axis, op: st.op };
|
|
2423
|
+
if (m.id === ID.name) return { kind: "rename", sheet: sheetOf(m), name: String(m.params.name) };
|
|
2424
|
+
if (m.id === ID.removeName) return { kind: "defined-name", from: String(m.params.name), to: null };
|
|
2425
|
+
if (m.id === ID.setName && typeof m.params.previousName === "string" && m.params.previousName !== m.params.name)
|
|
2426
|
+
return { kind: "defined-name", from: m.params.previousName, to: String(m.params.name) };
|
|
2427
|
+
return null;
|
|
2428
|
+
}
|
|
2429
|
+
function rewriteEntry(v, ctx, change) {
|
|
2430
|
+
let entry = v;
|
|
2431
|
+
let changed = false;
|
|
2432
|
+
for (const k of ["f", "ref"]) {
|
|
2433
|
+
const t = v[k];
|
|
2434
|
+
if (k === "f" ? !isFormulaText(t) : typeof t !== "string") continue;
|
|
2435
|
+
const r = rewriteFormula(t, ctx, change);
|
|
2436
|
+
if (typeof r === "string") return r;
|
|
2437
|
+
if (!r.changed) continue;
|
|
2438
|
+
if (k === "ref" && r.text.includes(REF_ERROR)) return "an array formula's range was removed under it";
|
|
2439
|
+
entry = { ...entry, [k]: r.text };
|
|
2440
|
+
changed = true;
|
|
2441
|
+
}
|
|
2442
|
+
return { entry, changed };
|
|
2443
|
+
}
|
|
2444
|
+
function cellThrough(sheet, change, r, c) {
|
|
2445
|
+
if (change.kind !== "axis" || change.sheet !== sheet) return [r, c];
|
|
2446
|
+
const nr = change.axis === "row" ? mapIndex(change.op, r) : r;
|
|
2447
|
+
const nc = change.axis === "col" ? mapIndex(change.op, c) : c;
|
|
2448
|
+
return nr === null || nc === null ? null : [nr, nc];
|
|
2449
|
+
}
|
|
2450
|
+
function cellsOverChange(x, change) {
|
|
2451
|
+
const ctx = formulaCtx(x);
|
|
2452
|
+
const out = {};
|
|
2453
|
+
const dropped = [];
|
|
2454
|
+
let why = null;
|
|
2455
|
+
forEachCell(cellsOf(x), (r, c, v) => {
|
|
2456
|
+
if (why) return;
|
|
2457
|
+
const at = cellThrough(sheetOf(x), change, r, c);
|
|
2458
|
+
if (!at) {
|
|
2459
|
+
dropped.push(cellRef(sheetOf(x), r, c));
|
|
2460
|
+
return;
|
|
2461
|
+
}
|
|
2462
|
+
let e = v;
|
|
2463
|
+
if (hasFormulaText(v)) {
|
|
2464
|
+
const res = rewriteEntry(v, ctx, change);
|
|
2465
|
+
if (typeof res === "string") {
|
|
2466
|
+
why = res;
|
|
2467
|
+
return;
|
|
2468
|
+
}
|
|
2469
|
+
e = res.entry;
|
|
2470
|
+
}
|
|
2471
|
+
putCell(out, at[0], at[1], e);
|
|
2472
|
+
});
|
|
2473
|
+
if (why) return barrier2(why);
|
|
2474
|
+
const params = { ...withRefSheets(x.params, refSheetsAfter(ctx.refSheets, change)), cellValue: out };
|
|
2475
|
+
return ok(isEmptyMatrix(out) ? [] : [{ id: x.id, params }], [], dropped);
|
|
2476
|
+
}
|
|
2477
|
+
function rewritesOf(y, change) {
|
|
2478
|
+
const ctx = formulaCtx(y);
|
|
2479
|
+
const out = {};
|
|
2480
|
+
let why = null;
|
|
2481
|
+
forEachCell(cellsOf(y), (r, c, v) => {
|
|
2482
|
+
if (why || !hasFormulaText(v)) return;
|
|
2483
|
+
const at = cellThrough(sheetOf(y), change, r, c);
|
|
2484
|
+
if (!at) return;
|
|
2485
|
+
const res = rewriteEntry(v, ctx, change);
|
|
2486
|
+
if (typeof res === "string") {
|
|
2487
|
+
why = res;
|
|
2488
|
+
return;
|
|
2489
|
+
}
|
|
2490
|
+
if (res.changed) putCell(out, at[0], at[1], contentOf(res.entry));
|
|
2491
|
+
});
|
|
2492
|
+
if (why) return why;
|
|
2493
|
+
if (isEmptyMatrix(out)) return null;
|
|
2494
|
+
return { id: ID.values, params: withRefSheets({ subUnitId: sheetOf(y), cellValue: out, derived: true }, refSheetsAfter(ctx.refSheets, change)) };
|
|
2495
|
+
}
|
|
2496
|
+
var NAME_TEXT_KEYS = ["formulaOrRefString", "formulaOrRefStringWithPrefix"];
|
|
2497
|
+
function definedNameThrough(m, change) {
|
|
2498
|
+
if (change.kind === "defined-name" || m.id !== ID.setName) return { op: m, changed: false };
|
|
2499
|
+
const ctx = { ownSheet: change.sheet, refSheets: refSheetsOf(m), keepQualifier: true };
|
|
2500
|
+
const params = { ...m.params };
|
|
2501
|
+
let changed = false;
|
|
2502
|
+
for (const k of NAME_TEXT_KEYS) {
|
|
2503
|
+
if (typeof params[k] !== "string" || !params[k]) continue;
|
|
2504
|
+
const r = rewriteFormula(params[k], ctx, change);
|
|
2505
|
+
if (typeof r === "string") return r;
|
|
2506
|
+
if (r.changed) {
|
|
2507
|
+
params[k] = r.text;
|
|
2508
|
+
changed = true;
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
return { op: { id: m.id, params: withRefSheets(params, refSheetsAfter(ctx.refSheets, change)) }, changed };
|
|
2512
|
+
}
|
|
2513
|
+
function asDerived(m) {
|
|
2514
|
+
return { id: m.id, params: { ...m.params, derived: true } };
|
|
2515
|
+
}
|
|
2516
|
+
function formulaPair(x, y, side) {
|
|
2517
|
+
const fx = familyOf(x.id);
|
|
2518
|
+
const fy = familyOf(y.id);
|
|
2519
|
+
const SET_NAME_BARRIER = "set-defined-name without previousName (capture must record the name it replaces) against formula text";
|
|
2520
|
+
if (fx === "defname" && fy === "defname") {
|
|
2521
|
+
if (String(x.params.id) !== String(y.params.id)) return ok([x]);
|
|
2522
|
+
const eff = derivedSide(x, y, side);
|
|
2523
|
+
if (eff === "left") return ok([x], isDerived(y) ? [] : [`defined name "${String(y.params.name)}"`]);
|
|
2524
|
+
return ok([], [], isDerived(x) ? [] : [`defined name "${String(x.params.name)}"`]);
|
|
2525
|
+
}
|
|
2526
|
+
if (fx === "defname") {
|
|
2527
|
+
if (fy === "cell") {
|
|
2528
|
+
if (setNameWithoutPrevious(x) && hasFormula(y)) return barrier2(SET_NAME_BARRIER);
|
|
2529
|
+
const ch2 = refChangeOf(x);
|
|
2530
|
+
if (!ch2) return ok([x]);
|
|
2531
|
+
const add = rewritesOf(y, ch2);
|
|
2532
|
+
if (typeof add === "string") return barrier2(add);
|
|
2533
|
+
return ok(add ? [x, add] : [x]);
|
|
2534
|
+
}
|
|
2535
|
+
const ch = refChangeOf(y);
|
|
2536
|
+
if (!ch) return ok([x]);
|
|
2537
|
+
const r = definedNameThrough(x, ch);
|
|
2538
|
+
return typeof r === "string" ? barrier2(r) : ok([r.op]);
|
|
2539
|
+
}
|
|
2540
|
+
if (fy === "defname") {
|
|
2541
|
+
if (fx === "cell") {
|
|
2542
|
+
if (setNameWithoutPrevious(y) && hasFormula(x)) return barrier2(SET_NAME_BARRIER);
|
|
2543
|
+
const ch2 = refChangeOf(y);
|
|
2544
|
+
return ch2 ? cellsOverChange(x, ch2) : ok([x]);
|
|
2545
|
+
}
|
|
2546
|
+
const ch = refChangeOf(x);
|
|
2547
|
+
if (!ch) return ok([x]);
|
|
2548
|
+
const r = definedNameThrough(y, ch);
|
|
2549
|
+
if (typeof r === "string") return barrier2(r);
|
|
2550
|
+
return ok(r.changed ? [x, asDerived(r.op)] : [x]);
|
|
2551
|
+
}
|
|
2552
|
+
if (fx === "cell") {
|
|
2553
|
+
const ch = refChangeOf(y);
|
|
2554
|
+
return ch ? cellsOverChange(x, ch) : null;
|
|
2555
|
+
}
|
|
2556
|
+
if (fy === "cell") {
|
|
2557
|
+
const ch = refChangeOf(x);
|
|
2558
|
+
if (!ch) return null;
|
|
2559
|
+
const lost = [];
|
|
2560
|
+
forEachCell(cellsOf(y), (r, c) => {
|
|
2561
|
+
if (!cellThrough(sheetOf(y), ch, r, c)) lost.push(cellRef(sheetOf(y), r, c));
|
|
2562
|
+
});
|
|
2563
|
+
const add = rewritesOf(y, ch);
|
|
2564
|
+
if (typeof add === "string") return barrier2(add);
|
|
2565
|
+
return ok(add ? [x, add] : [x], lost);
|
|
2566
|
+
}
|
|
2567
|
+
return null;
|
|
2568
|
+
}
|
|
2569
|
+
var withPrevious = (m, definedNames) => m.id === ID.setName && !("previousName" in m.params) ? { id: m.id, params: { ...m.params, previousName: definedNames[String(m.params.id)] ?? null } } : m;
|
|
2570
|
+
function annotateFormulas(group, sheets, definedNames) {
|
|
2571
|
+
let changed = false;
|
|
2572
|
+
return group.map((m0) => {
|
|
2573
|
+
const m = changed && (m0.id === ID.values || m0.id === ID.setName) ? asDerived(m0) : m0;
|
|
2574
|
+
if (!changed && refChangeOf(withPrevious(m0, definedNames))) changed = true;
|
|
2575
|
+
if (m.id === ID.values) {
|
|
2576
|
+
const texts = [];
|
|
2577
|
+
forEachCell(cellsOf(m), (_r, _c, v) => {
|
|
2578
|
+
if (v && isFormulaText(v.f)) texts.push(v.f);
|
|
2579
|
+
if (v && typeof v.ref === "string") texts.push(v.ref);
|
|
2580
|
+
});
|
|
2581
|
+
return { id: m.id, params: withRefSheets(m.params, refSheetsFor(texts, sheets)) };
|
|
2582
|
+
}
|
|
2583
|
+
if (m.id === ID.setName) {
|
|
2584
|
+
const texts = NAME_TEXT_KEYS.map((k) => m.params[k]).filter((t) => typeof t === "string");
|
|
2585
|
+
return { id: m.id, params: { ...withRefSheets(m.params, refSheetsFor(texts, sheets)), previousName: withPrevious(m, definedNames).params.previousName } };
|
|
2586
|
+
}
|
|
2587
|
+
return m;
|
|
2588
|
+
});
|
|
2589
|
+
}
|
|
2590
|
+
function sizeOf(m) {
|
|
2591
|
+
const p = m.params;
|
|
2592
|
+
const values = /* @__PURE__ */ new Map();
|
|
2593
|
+
if (m.id === ID.rowAutoHeight) {
|
|
2594
|
+
for (const { row, autoHeight } of p.rowsAutoHeightInfo ?? []) values.set(row, autoHeight);
|
|
2595
|
+
return { axis: "row", attr: "ah", values };
|
|
2596
|
+
}
|
|
2597
|
+
const axis = m.id === ID.colWidth ? "col" : "row";
|
|
2598
|
+
const field = m.id === ID.colWidth ? "colWidth" : m.id === ID.rowHeight ? "rowHeight" : "autoHeightInfo";
|
|
2599
|
+
const value = p[field];
|
|
2600
|
+
const [a0, a1] = S(axis);
|
|
2601
|
+
for (const r of p.ranges ?? [])
|
|
2602
|
+
for (let i = r[a0]; i <= r[a1]; i++) {
|
|
2603
|
+
if (typeof value === "number") values.set(i, value);
|
|
2604
|
+
else if (m.id === ID.rowIsAuto) values.set(i, value?.[i]);
|
|
2605
|
+
else if (value?.[i] != null) values.set(i, value[i]);
|
|
2606
|
+
}
|
|
2607
|
+
return { axis, attr: m.id === ID.colWidth ? "w" : m.id === ID.rowHeight ? "h" : "ia", values };
|
|
2608
|
+
}
|
|
2609
|
+
function buildSize(template, values) {
|
|
2610
|
+
if (values.size === 0) return null;
|
|
2611
|
+
const p = template.params;
|
|
2612
|
+
if (template.id === ID.rowAutoHeight)
|
|
2613
|
+
return { id: template.id, params: { ...p, rowsAutoHeightInfo: [...values].sort((a, b) => a[0] - b[0]).map(([row, autoHeight]) => ({ row, autoHeight })) } };
|
|
2614
|
+
const axis = template.id === ID.colWidth ? "col" : "row";
|
|
2615
|
+
const field = template.id === ID.colWidth ? "colWidth" : template.id === ID.rowHeight ? "rowHeight" : "autoHeightInfo";
|
|
2616
|
+
const [a0, a1] = S(axis);
|
|
2617
|
+
const first = (p.ranges ?? [])[0] ?? { startRow: 0, endRow: 0, startColumn: 0, endColumn: 0 };
|
|
2618
|
+
const ranges = runs(values.keys()).map((r) => ({ ...first, [a0]: r.start, [a1]: r.start + r.count - 1 }));
|
|
2619
|
+
const uniform = typeof p[field] === "number" ? p[field] : void 0;
|
|
2620
|
+
const value = uniform !== void 0 && [...values.values()].every((v) => v === uniform) ? uniform : Object.fromEntries(values);
|
|
2621
|
+
return { id: template.id, params: { ...p, ranges, [field]: value } };
|
|
2622
|
+
}
|
|
2623
|
+
function familyOf(id) {
|
|
2624
|
+
const e = SHEET_MUTATIONS[id];
|
|
2625
|
+
return e && e.kind === "covered" ? e.family : "";
|
|
2626
|
+
}
|
|
2627
|
+
function transformMutation(x, y, side) {
|
|
2628
|
+
for (const m of [x, y]) {
|
|
2629
|
+
const e = SHEET_MUTATIONS[m.id];
|
|
2630
|
+
if (!e) return barrier2(`${m.id} is not in the registry`);
|
|
2631
|
+
if (e.kind !== "covered") return barrier2(`${m.id}: ${e.kind === "barrier" ? `barrier until ${e.until} (${e.reason})` : "never travels"}`);
|
|
2632
|
+
if (m.id === ID.values) {
|
|
2633
|
+
const why = cellBarrier(m);
|
|
2634
|
+
if (why) return barrier2(why);
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
const pb = PAIR_BARRIERS[pairKey(x.id, y.id)];
|
|
2638
|
+
if (pb) return barrier2(`${x.id} \xD7 ${y.id}: ${pb.reason}${pb.seed === null ? "" : ` (fuzz seed ${pb.seed})`}`);
|
|
2639
|
+
const fp = formulaPair(x, y, side);
|
|
2640
|
+
if (fp) return fp;
|
|
2641
|
+
if (sheetOf(x) !== sheetOf(y)) return ok([x]);
|
|
2642
|
+
const fx = familyOf(x.id);
|
|
2643
|
+
const fy = familyOf(y.id);
|
|
2644
|
+
const sy = structuralOf(y);
|
|
2645
|
+
const sx = structuralOf(x);
|
|
2646
|
+
if (sx && sy) {
|
|
2647
|
+
if (sx.axis !== sy.axis) return ok([x]);
|
|
2648
|
+
const out = transformAxis(sx.op, sy.op, side);
|
|
2649
|
+
if (!out) return barrier2(`${x.id} over ${y.id}: moved blocks overlap in part, or the block would split`);
|
|
2650
|
+
const dropped = out.length === 0 && sx.op.kind === "move" ? [`${sheetOf(x)}: moved ${sx.axis}s`] : [];
|
|
2651
|
+
return ok(out.map((o) => buildStructural(x, sx.axis, o)), [], dropped);
|
|
2652
|
+
}
|
|
2653
|
+
if (sy) {
|
|
2654
|
+
if (fx === "merge") {
|
|
2655
|
+
const kept = [];
|
|
2656
|
+
const dropped = [];
|
|
2657
|
+
for (const r of mergeRanges(x)) {
|
|
2658
|
+
const t = mergeThrough(sy, r).range;
|
|
2659
|
+
if (t) kept.push(t);
|
|
2660
|
+
else dropped.push(rangeRef(sheetOf(x), r));
|
|
2661
|
+
}
|
|
2662
|
+
return ok(kept.length ? [withRanges(x, kept)] : [], [], x.id === ID.addMerge ? dropped : []);
|
|
2663
|
+
}
|
|
2664
|
+
if (fx === "size") {
|
|
2665
|
+
const size = sizeOf(x);
|
|
2666
|
+
if (size.axis !== sy.axis) return ok([x]);
|
|
2667
|
+
const next = /* @__PURE__ */ new Map();
|
|
2668
|
+
for (const [i, v] of size.values) {
|
|
2669
|
+
const m = mapIndex(sy.op, i);
|
|
2670
|
+
if (m !== null) next.set(m, v);
|
|
2671
|
+
}
|
|
2672
|
+
const built = buildSize(x, next);
|
|
2673
|
+
return ok(built ? [built] : []);
|
|
2674
|
+
}
|
|
2675
|
+
return ok([x]);
|
|
2676
|
+
}
|
|
2677
|
+
if (sx) {
|
|
2678
|
+
if (fy !== "merge" || y.id !== ID.addMerge) return ok([x]);
|
|
2679
|
+
const remove = [];
|
|
2680
|
+
const add = [];
|
|
2681
|
+
for (const r of mergeRanges(y)) {
|
|
2682
|
+
const t = mergeThrough(sx, r);
|
|
2683
|
+
if (!t.fixup) continue;
|
|
2684
|
+
remove.push(r);
|
|
2685
|
+
if (t.range) add.push(t.range);
|
|
2686
|
+
}
|
|
2687
|
+
const lostMerges = mergeRanges(y).filter((r) => mergeThrough(sx, r).range === null).map((r) => rangeRef(sheetOf(y), r));
|
|
2688
|
+
if (!remove.length) return ok([x], lostMerges);
|
|
2689
|
+
const sheet = sheetOf(x);
|
|
2690
|
+
const pre = sx.op.kind === "insert" ? [] : [mergeMutation(ID.removeMerge, sheet, remove)];
|
|
2691
|
+
const mid = sx.op.kind === "insert" ? [mergeMutation(ID.removeMerge, sheet, remove)] : [];
|
|
2692
|
+
return ok([...pre, x, ...mid, ...add.length ? [mergeMutation(ID.addMerge, sheet, add)] : []], lostMerges);
|
|
2693
|
+
}
|
|
2694
|
+
if (fx === "cell" && fy === "cell") return transformCellsOverCells(x, y, side);
|
|
2695
|
+
if (fx === "merge" && fy === "merge") {
|
|
2696
|
+
const xr = mergeRanges(x);
|
|
2697
|
+
const yr = mergeRanges(y);
|
|
2698
|
+
const hit = (r) => yr.some((q) => intersects(r, q));
|
|
2699
|
+
const sheet = sheetOf(x);
|
|
2700
|
+
if (x.id === ID.addMerge && y.id === ID.addMerge) {
|
|
2701
|
+
if (!xr.some(hit)) return ok([x]);
|
|
2702
|
+
if (side === "left") {
|
|
2703
|
+
const lost = yr.filter((q) => xr.some((r) => intersects(r, q))).map((q) => rangeRef(sheet, q));
|
|
2704
|
+
return ok([mergeMutation(ID.removeMerge, sheet, xr.filter(hit)), x], lost);
|
|
2705
|
+
}
|
|
2706
|
+
const kept = xr.filter((r) => !hit(r));
|
|
2707
|
+
return ok(kept.length ? [withRanges(x, kept)] : [], [], xr.filter(hit).map((r) => rangeRef(sheet, r)));
|
|
2708
|
+
}
|
|
2709
|
+
if (x.id === ID.addMerge && y.id === ID.removeMerge) {
|
|
2710
|
+
if (side === "left" || !xr.some(hit)) return ok([x], side === "left" && xr.some(hit) ? yr.filter((q) => xr.some((r) => intersects(r, q))).map((q) => rangeRef(sheet, q)) : []);
|
|
2711
|
+
const kept = xr.filter((r) => !hit(r));
|
|
2712
|
+
return ok(kept.length ? [withRanges(x, kept)] : [], [], xr.filter(hit).map((r) => rangeRef(sheet, r)));
|
|
2713
|
+
}
|
|
2714
|
+
if (x.id === ID.removeMerge && y.id === ID.addMerge) {
|
|
2715
|
+
const touched = yr.filter((q) => xr.some((r) => intersects(r, q)));
|
|
2716
|
+
if (!touched.length) return ok([x]);
|
|
2717
|
+
if (side === "left") return ok([x], touched.map((q) => rangeRef(sheet, q)));
|
|
2718
|
+
return ok([x, mergeMutation(ID.addMerge, sheet, touched)], [], xr.filter(hit).map((r) => rangeRef(sheet, r)));
|
|
2719
|
+
}
|
|
2720
|
+
return ok([x]);
|
|
2721
|
+
}
|
|
2722
|
+
if (fx === "size" && fy === "size") {
|
|
2723
|
+
const a = sizeOf(x);
|
|
2724
|
+
const b = sizeOf(y);
|
|
2725
|
+
if (a.axis !== b.axis || a.attr !== b.attr) return ok([x]);
|
|
2726
|
+
if (side === "left") {
|
|
2727
|
+
const lost = [...a.values.keys()].filter((i) => b.values.has(i)).map((i) => `${sheetOf(x)}: ${a.axis} ${i + 1} ${a.attr}`);
|
|
2728
|
+
return ok([x], lost);
|
|
2729
|
+
}
|
|
2730
|
+
const next = new Map([...a.values].filter(([i]) => !b.values.has(i)));
|
|
2731
|
+
const built = buildSize(x, next);
|
|
2732
|
+
const dropped = [...a.values.keys()].filter((i) => b.values.has(i)).map((i) => `${sheetOf(x)}: ${a.axis} ${i + 1} ${a.attr}`);
|
|
2733
|
+
return ok(built ? [built] : [], [], dropped);
|
|
2734
|
+
}
|
|
2735
|
+
if (fx === "name" && fy === "name") {
|
|
2736
|
+
if (side === "left") return ok([x], [`${sheetOf(x)}: name "${String(y.params.name)}"`]);
|
|
2737
|
+
return ok([], [], [`${sheetOf(x)}: name "${String(x.params.name)}"`]);
|
|
2738
|
+
}
|
|
2739
|
+
return ok([x]);
|
|
2740
|
+
}
|
|
2741
|
+
var blocked = (p) => !Array.isArray(p);
|
|
2742
|
+
function tSeq(xs, ys, side, acc) {
|
|
2743
|
+
if (xs.length === 0 || ys.length === 0) return [xs, ys];
|
|
2744
|
+
if (xs.length === 1 && ys.length === 1) {
|
|
2745
|
+
const a = transformMutation(xs[0], ys[0], side);
|
|
2746
|
+
if (isBarrier(a)) return a;
|
|
2747
|
+
const b = transformMutation(ys[0], xs[0], flip(side));
|
|
2748
|
+
if (isBarrier(b)) return b;
|
|
2749
|
+
acc.lost.push(...a.lost);
|
|
2750
|
+
acc.dropped.push(...a.dropped);
|
|
2751
|
+
return [a.op, b.op];
|
|
2752
|
+
}
|
|
2753
|
+
if (xs.length > 1) {
|
|
2754
|
+
const first2 = tSeq([xs[0]], ys, side, acc);
|
|
2755
|
+
if (blocked(first2)) return first2;
|
|
2756
|
+
const rest2 = tSeq(xs.slice(1), first2[1], side, acc);
|
|
2757
|
+
if (blocked(rest2)) return rest2;
|
|
2758
|
+
return [[...first2[0], ...rest2[0]], rest2[1]];
|
|
2759
|
+
}
|
|
2760
|
+
const first = tSeq(xs, [ys[0]], side, acc);
|
|
2761
|
+
if (blocked(first)) return first;
|
|
2762
|
+
const rest = tSeq(first[0], ys.slice(1), side, acc);
|
|
2763
|
+
if (blocked(rest)) return rest;
|
|
2764
|
+
return [rest[0], [...first[1], ...rest[1]]];
|
|
2765
|
+
}
|
|
2766
|
+
function transformGroup(x, y, side) {
|
|
2767
|
+
const acc = { lost: [], dropped: [] };
|
|
2768
|
+
const r = tSeq([...x], [...y], side, acc);
|
|
2769
|
+
if (blocked(r)) return r;
|
|
2770
|
+
return { op: r[0], lost: [...new Set(acc.lost)], dropped: [...new Set(acc.dropped)] };
|
|
2771
|
+
}
|
|
2772
|
+
|
|
2773
|
+
// src/univer/collab/sheets-ot/state-hash.ts
|
|
2774
|
+
var SHEET_LOCAL_SHEET_KEYS = ["zoomRatio", "scrollTop", "scrollLeft", "selections", "__collab"];
|
|
2775
|
+
var SHEET_LOCAL_KEYS = ["id", "rev", "__matrxCollabCovered", "__collab"];
|
|
2776
|
+
function sortDeep2(v) {
|
|
2777
|
+
if (Array.isArray(v)) return v.map(sortDeep2);
|
|
2778
|
+
if (v && typeof v === "object") {
|
|
2779
|
+
const out = {};
|
|
2780
|
+
for (const k of Object.keys(v).sort()) {
|
|
2781
|
+
const x = v[k];
|
|
2782
|
+
if (x === void 0 || x === null) continue;
|
|
2783
|
+
if (Array.isArray(x) && x.length === 0) continue;
|
|
2784
|
+
if (x && typeof x === "object" && !Array.isArray(x) && Object.keys(x).length === 0) continue;
|
|
2785
|
+
out[k] = sortDeep2(x);
|
|
2786
|
+
}
|
|
2787
|
+
return out;
|
|
2788
|
+
}
|
|
2789
|
+
return v;
|
|
2790
|
+
}
|
|
2791
|
+
function parsedResource(data) {
|
|
2792
|
+
if (typeof data !== "string") return data;
|
|
2793
|
+
try {
|
|
2794
|
+
return JSON.parse(data);
|
|
2795
|
+
} catch {
|
|
2796
|
+
return data;
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
function canonicalSheet(snapshot) {
|
|
2800
|
+
const s = structuredClone(snapshot ?? {});
|
|
2801
|
+
for (const k of SHEET_LOCAL_KEYS) delete s[k];
|
|
2802
|
+
const styles = s.styles ?? {};
|
|
2803
|
+
const deref = (v) => typeof v === "string" && styles[v] ? sortDeep2(styles[v]) : v;
|
|
2804
|
+
delete s.styles;
|
|
2805
|
+
for (const sheet of Object.values(s.sheets ?? {})) {
|
|
2806
|
+
for (const k of SHEET_LOCAL_SHEET_KEYS) delete sheet[k];
|
|
2807
|
+
if (sheet.defaultStyle) sheet.defaultStyle = deref(sheet.defaultStyle);
|
|
2808
|
+
for (const key of ["rowData", "columnData"]) for (const v of Object.values(sheet[key] ?? {})) if (v?.s) v.s = deref(v.s);
|
|
2809
|
+
const cd = sheet.cellData ?? {};
|
|
2810
|
+
for (const row of Object.keys(cd)) {
|
|
2811
|
+
for (const col of Object.keys(cd[row] ?? {})) {
|
|
2812
|
+
const c = cd[row][col];
|
|
2813
|
+
if (c?.s) c.s = deref(c.s);
|
|
2814
|
+
if (c && (c.f || c.si)) {
|
|
2815
|
+
delete c.v;
|
|
2816
|
+
delete c.t;
|
|
2817
|
+
}
|
|
2818
|
+
if (!c || Object.keys(sortDeep2(c)).length === 0) delete cd[row][col];
|
|
2819
|
+
}
|
|
2820
|
+
if (Object.keys(cd[row] ?? {}).length === 0) delete cd[row];
|
|
2821
|
+
}
|
|
2822
|
+
if (Array.isArray(sheet.mergeData))
|
|
2823
|
+
sheet.mergeData = sheet.mergeData.map((m) => JSON.stringify(sortDeep2(m))).sort().map((j) => JSON.parse(j));
|
|
2824
|
+
}
|
|
2825
|
+
if (Array.isArray(s.resources))
|
|
2826
|
+
s.resources = s.resources.map((r) => ({ name: r.name, data: sortDeep2(parsedResource(r.data)) })).filter((r) => r.data != null && r.data !== "" && !(typeof r.data === "object" && Object.keys(r.data).length === 0)).sort((a, b) => String(a.name).localeCompare(String(b.name)));
|
|
2827
|
+
if (Array.isArray(s.definedNames)) s.definedNames = [...s.definedNames].sort((x, y) => String(x.id).localeCompare(String(y.id)));
|
|
2828
|
+
return sortDeep2(s);
|
|
2829
|
+
}
|
|
2830
|
+
var canonicalSheetString = (snapshot) => JSON.stringify(canonicalSheet(snapshot));
|
|
2831
|
+
async function sheetsStateHash(snapshot) {
|
|
2832
|
+
const bytes = new TextEncoder().encode(canonicalSheetString(snapshot));
|
|
2833
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
|
|
2834
|
+
return Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
// src/univer/collab/sheets-ot/room.ts
|
|
2838
|
+
var SHEETS_COLLAB_PROTO = 1;
|
|
2839
|
+
var SHEETS_EDIT_GROUP = "sheets.edit";
|
|
2840
|
+
var flip2 = (side) => side === "left" ? "right" : "left";
|
|
2841
|
+
var isNoopSheetOp = (op) => op == null || op.length === 0;
|
|
2842
|
+
function transformSheetOp(x, y, side) {
|
|
2843
|
+
if (isNoopSheetOp(x) || isNoopSheetOp(y)) return { op: isNoopSheetOp(x) ? null : x, lost: [], dropped: [] };
|
|
2844
|
+
const r = transformGroup(x, y, side);
|
|
2845
|
+
if (isBarrier(r)) return r;
|
|
2846
|
+
const back = transformGroup(y, x, flip2(side));
|
|
2847
|
+
const lost = [.../* @__PURE__ */ new Set([...r.lost, ...isBarrier(back) ? [] : back.dropped])];
|
|
2848
|
+
return { op: r.op.length ? r.op : null, lost, dropped: r.dropped };
|
|
2849
|
+
}
|
|
2850
|
+
function encodeSheetOp(op) {
|
|
2851
|
+
return canonicalKeys([{ cmd: SHEETS_EDIT_GROUP, mutations: (op ?? []).map((m) => ({ id: m.id, params: m.params })) }]);
|
|
2852
|
+
}
|
|
2853
|
+
function decodeSheetOp(groups) {
|
|
2854
|
+
const out = [];
|
|
2855
|
+
for (const g of groups) for (const m of g.mutations) out.push({ id: m.id, params: m.params ?? {} });
|
|
2856
|
+
return out.length ? out : null;
|
|
2857
|
+
}
|
|
2858
|
+
function undoStacksOf2(service) {
|
|
2859
|
+
const s = service;
|
|
2860
|
+
if (!s || !(s._undoStacks instanceof Map) || !(s._redoStacks instanceof Map)) return null;
|
|
2861
|
+
return { undo: s._undoStacks, redo: s._redoStacks };
|
|
2862
|
+
}
|
|
2863
|
+
var CONTENT_TOUCH2 = CONTENT_KEYS.filter((k) => k !== "t");
|
|
2864
|
+
function travelingShape(m) {
|
|
2865
|
+
const params = allowParams(m.id, m.params);
|
|
2866
|
+
if (!params) return null;
|
|
2867
|
+
if (m.params.isOverrideStyle) return null;
|
|
2868
|
+
if (m.id === "sheet.mutation.set-range-values") {
|
|
2869
|
+
const cells = structuredClone(params.cellValue ?? {});
|
|
2870
|
+
for (const row of Object.values(cells))
|
|
2871
|
+
for (const [c, v] of Object.entries(row)) {
|
|
2872
|
+
if (!v) continue;
|
|
2873
|
+
if (typeof v.s === "string") return null;
|
|
2874
|
+
if (!CONTENT_TOUCH2.some((k) => k in v)) continue;
|
|
2875
|
+
const full = {};
|
|
2876
|
+
for (const k of CONTENT_KEYS) full[k] = v[k] !== void 0 ? v[k] : null;
|
|
2877
|
+
if (full.v === null) delete full.t;
|
|
2878
|
+
if ("s" in v) full.s = v.s;
|
|
2879
|
+
row[c] = full;
|
|
2880
|
+
}
|
|
2881
|
+
return { id: m.id, params: { ...params, cellValue: cells } };
|
|
2882
|
+
}
|
|
2883
|
+
return { id: m.id, params };
|
|
2884
|
+
}
|
|
2885
|
+
function rebaseSheetUndoStack(items, remote, unitId) {
|
|
2886
|
+
if (isNoopSheetOp(remote)) return 0;
|
|
2887
|
+
let dropped = 0;
|
|
2888
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
2889
|
+
const item = items[i];
|
|
2890
|
+
let ok2 = true;
|
|
2891
|
+
for (const key of ["undoMutations", "redoMutations"]) {
|
|
2892
|
+
const list = item[key];
|
|
2893
|
+
if (!ok2 || !list?.length) continue;
|
|
2894
|
+
const isOperation = (id) => !SHEET_MUTATIONS[id] && id.includes(".operation.");
|
|
2895
|
+
const operations = list.filter((m) => isOperation(m.id));
|
|
2896
|
+
const shaped = list.filter((m) => !isOperation(m.id)).map(travelingShape);
|
|
2897
|
+
if (shaped.some((m) => m === null)) {
|
|
2898
|
+
ok2 = false;
|
|
2899
|
+
continue;
|
|
2900
|
+
}
|
|
2901
|
+
if (!shaped.length) continue;
|
|
2902
|
+
try {
|
|
2903
|
+
const r = transformGroup(shaped, remote, "left");
|
|
2904
|
+
if (isBarrier(r) || r.op.length === 0) {
|
|
2905
|
+
ok2 = false;
|
|
2906
|
+
continue;
|
|
2907
|
+
}
|
|
2908
|
+
if (JSON.stringify(r.op) === JSON.stringify(shaped)) continue;
|
|
2909
|
+
item[key] = [...r.op.map((m) => ({ id: m.id, params: { ...forApply(m).params, unitId } })), ...operations];
|
|
2910
|
+
} catch {
|
|
2911
|
+
ok2 = false;
|
|
2912
|
+
}
|
|
2913
|
+
}
|
|
2914
|
+
if (!ok2) {
|
|
2915
|
+
items.splice(i, 1);
|
|
2916
|
+
dropped++;
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
return dropped;
|
|
2920
|
+
}
|
|
2921
|
+
function createSheetsOtAdapter(port, hooks = {}) {
|
|
2922
|
+
let queue = [];
|
|
2923
|
+
let draining = false;
|
|
2924
|
+
const applyNow = (op) => {
|
|
2925
|
+
for (const m of op) port.applyRemote(m);
|
|
2926
|
+
let dropped = 0;
|
|
2927
|
+
for (const t of port.undoTargets()) {
|
|
2928
|
+
const stacks = undoStacksOf2(t.service);
|
|
2929
|
+
if (!stacks) continue;
|
|
2930
|
+
for (const map of [stacks.undo, stacks.redo]) {
|
|
2931
|
+
const items = map.get(t.unitId);
|
|
2932
|
+
if (items?.length) dropped += rebaseSheetUndoStack(items, op, t.unitId);
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
hooks.onUndoRebased?.(dropped);
|
|
2936
|
+
port.markDirty();
|
|
2937
|
+
};
|
|
2938
|
+
const adapter = {
|
|
2939
|
+
version: SHEET_TRANSFORMER_VERSION,
|
|
2940
|
+
transform: (x, y, side) => transformSheetOp(x, y, side),
|
|
2941
|
+
compose: (a, b) => [...a ?? [], ...b ?? []],
|
|
2942
|
+
isNoop: isNoopSheetOp,
|
|
2943
|
+
encode: encodeSheetOp,
|
|
2944
|
+
decode: decodeSheetOp,
|
|
2945
|
+
apply(op) {
|
|
2946
|
+
if (isNoopSheetOp(op)) return true;
|
|
2947
|
+
if (port.busy() || queue.length) {
|
|
2948
|
+
queue.push(op);
|
|
2949
|
+
if (!draining) {
|
|
2950
|
+
draining = true;
|
|
2951
|
+
port.whenIdle(() => {
|
|
2952
|
+
draining = false;
|
|
2953
|
+
const held = queue;
|
|
2954
|
+
queue = [];
|
|
2955
|
+
for (const q of held) applyNow(q);
|
|
2956
|
+
});
|
|
2957
|
+
}
|
|
2958
|
+
return true;
|
|
2959
|
+
}
|
|
2960
|
+
applyNow(op);
|
|
2961
|
+
return true;
|
|
2962
|
+
},
|
|
2963
|
+
async load(snapshot) {
|
|
2964
|
+
queue = [];
|
|
2965
|
+
const current = port.snapshot();
|
|
2966
|
+
if (!(current && snapshot && canonicalSheetString(current) === canonicalSheetString(snapshot))) port.load(snapshot);
|
|
2967
|
+
for (const t of port.undoTargets()) {
|
|
2968
|
+
const stacks = undoStacksOf2(t.service);
|
|
2969
|
+
stacks?.undo.delete(t.unitId);
|
|
2970
|
+
stacks?.redo.delete(t.unitId);
|
|
2971
|
+
}
|
|
2972
|
+
},
|
|
2973
|
+
snapshot: () => port.snapshot(),
|
|
2974
|
+
async hash() {
|
|
2975
|
+
if (port.busy() || queue.length) {
|
|
2976
|
+
await new Promise((resolve) => {
|
|
2977
|
+
const done = setTimeout(resolve, 5e3);
|
|
2978
|
+
port.whenIdle(() => {
|
|
2979
|
+
clearTimeout(done);
|
|
2980
|
+
setTimeout(resolve, 0);
|
|
2981
|
+
});
|
|
2982
|
+
});
|
|
2983
|
+
}
|
|
2984
|
+
return sheetsStateHash(port.snapshot());
|
|
2985
|
+
},
|
|
2986
|
+
held: () => queue.length,
|
|
2987
|
+
rebaseLocalOverHeld(local) {
|
|
2988
|
+
let op = local;
|
|
2989
|
+
const next = [];
|
|
2990
|
+
for (const q of queue) {
|
|
2991
|
+
const l2 = transformSheetOp(op, q, "left");
|
|
2992
|
+
const q2 = transformSheetOp(q, op, "right");
|
|
2993
|
+
if ("barrier" in l2 || "barrier" in q2) return "barrier";
|
|
2994
|
+
op = l2.op ?? [];
|
|
2995
|
+
if (q2.op?.length) next.push(q2.op);
|
|
2996
|
+
}
|
|
2997
|
+
queue = next;
|
|
2998
|
+
return op;
|
|
2999
|
+
},
|
|
3000
|
+
clearHeld() {
|
|
3001
|
+
queue = [];
|
|
3002
|
+
}
|
|
3003
|
+
};
|
|
3004
|
+
return adapter;
|
|
3005
|
+
}
|
|
3006
|
+
function openSheetsOtRoom(o) {
|
|
3007
|
+
const { port } = o;
|
|
3008
|
+
let session = null;
|
|
3009
|
+
const adapter = createSheetsOtAdapter(port);
|
|
3010
|
+
const notice = (n) => {
|
|
3011
|
+
try {
|
|
3012
|
+
o.onNotice?.(n);
|
|
3013
|
+
} catch (err) {
|
|
3014
|
+
console.warn("[sheets-ot] notice handler failed", err);
|
|
3015
|
+
}
|
|
3016
|
+
};
|
|
3017
|
+
const onLocal = (e) => {
|
|
3018
|
+
if (!session) return;
|
|
3019
|
+
if (e.kind === "not_shared") {
|
|
3020
|
+
notice({ kind: "not_shared", mutationId: e.mutationId });
|
|
3021
|
+
adapter.clearHeld();
|
|
3022
|
+
session.rebuild(`not_shared:${e.mutationId}`);
|
|
3023
|
+
return;
|
|
3024
|
+
}
|
|
3025
|
+
if (!e.mutations.length) return;
|
|
3026
|
+
for (const m of e.mutations) {
|
|
3027
|
+
if (SHEET_MUTATIONS[m.id]?.kind !== "covered") {
|
|
3028
|
+
notice({ kind: "not_shared", mutationId: m.id });
|
|
3029
|
+
adapter.clearHeld();
|
|
3030
|
+
session.rebuild(`not_shared:${m.id}`);
|
|
3031
|
+
return;
|
|
3032
|
+
}
|
|
3033
|
+
}
|
|
3034
|
+
let op = e.mutations;
|
|
3035
|
+
let inverse = e.inverse;
|
|
3036
|
+
if (adapter.held()) {
|
|
3037
|
+
inverse = void 0;
|
|
3038
|
+
const r = adapter.rebaseLocalOverHeld(op);
|
|
3039
|
+
if (r === "barrier") {
|
|
3040
|
+
adapter.clearHeld();
|
|
3041
|
+
session.rebuild("held_barrier");
|
|
3042
|
+
return;
|
|
3043
|
+
}
|
|
3044
|
+
op = r;
|
|
3045
|
+
if (!op.length) return;
|
|
3046
|
+
}
|
|
3047
|
+
if (!session.local(op, { ...inverse !== void 0 ? { inverse } : {}, label: e.label ?? SHEETS_EDIT_GROUP })) notice({ kind: "not_live" });
|
|
3048
|
+
};
|
|
3049
|
+
const unsubLocal = port.onLocal(onLocal);
|
|
3050
|
+
session = (0, import_collab5.openOpSession)({
|
|
3051
|
+
transport: o.transport,
|
|
3052
|
+
adapter,
|
|
3053
|
+
proto: SHEETS_COLLAB_PROTO,
|
|
3054
|
+
clientId: o.clientId,
|
|
3055
|
+
...o.presence ? { presence: o.presence } : {},
|
|
3056
|
+
onNotice: (n) => notice(n),
|
|
3057
|
+
...o.onIncident ? { onIncident: o.onIncident } : {},
|
|
3058
|
+
...o.onStatus ? { onStatus: o.onStatus } : {}
|
|
3059
|
+
});
|
|
3060
|
+
const isSaver = () => {
|
|
3061
|
+
if (!o.presence) return true;
|
|
3062
|
+
return o.presence.peers().every((p) => p.clientId === o.clientId || p.clientId > o.clientId);
|
|
3063
|
+
};
|
|
3064
|
+
return {
|
|
3065
|
+
session,
|
|
3066
|
+
isSaver,
|
|
3067
|
+
async write(reason) {
|
|
3068
|
+
if (!session) return false;
|
|
3069
|
+
if (reason !== "manual" && !isSaver()) return false;
|
|
3070
|
+
const out = await session.save();
|
|
3071
|
+
if (out.saved) return true;
|
|
3072
|
+
if (out.reason === "not_quiet" || out.reason === "changed") setTimeout(() => port.markDirty(), 1500);
|
|
3073
|
+
return false;
|
|
3074
|
+
},
|
|
3075
|
+
async replace(snapshot) {
|
|
3076
|
+
port.load(snapshot);
|
|
3077
|
+
const loaded = port.snapshot();
|
|
3078
|
+
if (!loaded) throw new Error("The workbook is not open in this tab.");
|
|
3079
|
+
const stateHash = await sheetsStateHash(loaded);
|
|
3080
|
+
await o.replace({ snapshot: loaded, stateHash, clientId: o.clientId });
|
|
3081
|
+
},
|
|
3082
|
+
stop() {
|
|
3083
|
+
unsubLocal();
|
|
3084
|
+
session?.close();
|
|
3085
|
+
}
|
|
3086
|
+
};
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
// src/univer/collab/sheets-ot/univer-port.ts
|
|
3090
|
+
var COMMAND = 0;
|
|
3091
|
+
var MUTATION = 2;
|
|
3092
|
+
var VALUES = "sheet.mutation.set-range-values";
|
|
3093
|
+
var ADD_MERGE = "sheet.mutation.add-worksheet-merge";
|
|
3094
|
+
var REMOVE_MERGE = "sheet.mutation.remove-worksheet-merge";
|
|
3095
|
+
var SHEET_NAME = "sheet.mutation.set-worksheet-name";
|
|
3096
|
+
var DEPTH_GUARD = /* @__PURE__ */ Symbol.for("ai-matrx.office.sheets.command-depth-guard");
|
|
3097
|
+
var json = (v) => v === void 0 ? v : JSON.parse(JSON.stringify(v));
|
|
3098
|
+
var flagged = (options) => {
|
|
3099
|
+
const o = options;
|
|
3100
|
+
return !!(o?.onlyLocal || o?.fromCollab);
|
|
3101
|
+
};
|
|
3102
|
+
function univerSheetsOtPort(o) {
|
|
3103
|
+
const cs = o.commandService;
|
|
3104
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
3105
|
+
const idle = [];
|
|
3106
|
+
const pre = /* @__PURE__ */ new WeakMap();
|
|
3107
|
+
const tracker = { stack: [], settle: () => settle() };
|
|
3108
|
+
let group = null;
|
|
3109
|
+
let applying = false;
|
|
3110
|
+
const unitId = () => o.workbook()?.getUnitId() ?? null;
|
|
3111
|
+
const mine = (params) => {
|
|
3112
|
+
const u = unitId();
|
|
3113
|
+
return !!u && !!params && typeof params === "object" && params.unitId === u;
|
|
3114
|
+
};
|
|
3115
|
+
const styleObject = (s) => {
|
|
3116
|
+
if (typeof s !== "string") return s;
|
|
3117
|
+
const found = o.workbook()?.getStyles().get(s);
|
|
3118
|
+
return found ? json(found) : s;
|
|
3119
|
+
};
|
|
3120
|
+
const sheetNames = () => {
|
|
3121
|
+
const out = {};
|
|
3122
|
+
for (const ws of o.workbook()?.getSheets() ?? []) out[ws.getSheetId()] = ws.getName();
|
|
3123
|
+
return out;
|
|
3124
|
+
};
|
|
3125
|
+
const definedNames = () => {
|
|
3126
|
+
const u = unitId();
|
|
3127
|
+
const map = u && o.definedNames?.(u) || {};
|
|
3128
|
+
const out = {};
|
|
3129
|
+
for (const [id, d] of Object.entries(map)) out[id] = String(d?.name ?? "");
|
|
3130
|
+
return out;
|
|
3131
|
+
};
|
|
3132
|
+
const openGroup = (label) => ({ label, sheets: sheetNames(), names: definedNames(), mutations: [], inverses: [], notShared: null });
|
|
3133
|
+
const emit = (e) => {
|
|
3134
|
+
for (const l of [...listeners]) {
|
|
3135
|
+
try {
|
|
3136
|
+
l(e);
|
|
3137
|
+
} catch (err) {
|
|
3138
|
+
console.warn("[sheets-ot] local change handler failed", err);
|
|
3139
|
+
}
|
|
3140
|
+
}
|
|
3141
|
+
};
|
|
3142
|
+
const flush = () => {
|
|
3143
|
+
const g = group;
|
|
3144
|
+
group = null;
|
|
3145
|
+
if (!g) return;
|
|
3146
|
+
if (g.notShared) emit({ kind: "not_shared", mutationId: g.notShared, label: g.label });
|
|
3147
|
+
else if (g.mutations.length) {
|
|
3148
|
+
const mutations = annotateFormulas(g.mutations, g.sheets, g.names);
|
|
3149
|
+
const known = g.inverses.every((i) => i !== void 0);
|
|
3150
|
+
const inverse = known ? annotateFormulas(g.inverses.slice().reverse().flat(), g.sheets, g.names) : void 0;
|
|
3151
|
+
emit({ kind: "group", mutations, ...inverse !== void 0 ? { inverse } : {}, label: g.label });
|
|
3152
|
+
}
|
|
3153
|
+
};
|
|
3154
|
+
function settle() {
|
|
3155
|
+
if (tracker.stack.length === 0) flush();
|
|
3156
|
+
if (tracker.stack.length === 0 && !group) for (const fn of idle.splice(0)) fn();
|
|
3157
|
+
}
|
|
3158
|
+
const before = cs.beforeCommandExecuted((info, options) => {
|
|
3159
|
+
if (info.type === COMMAND) {
|
|
3160
|
+
if (tracker.stack.length === 0 && !group) group = openGroup(info.id);
|
|
3161
|
+
tracker.stack.push(info.id);
|
|
3162
|
+
return;
|
|
3163
|
+
}
|
|
3164
|
+
if (info.type !== MUTATION || applying || flagged(options) || !mine(info.params)) return;
|
|
3165
|
+
const p = info.params;
|
|
3166
|
+
const ws = o.workbook()?.getSheetBySheetId(String(p.subUnitId ?? ""));
|
|
3167
|
+
if (!ws) return;
|
|
3168
|
+
const record = { merges: json(ws.getMergeData() ?? []) };
|
|
3169
|
+
if (info.id === VALUES) {
|
|
3170
|
+
record.cells = /* @__PURE__ */ new Map();
|
|
3171
|
+
const cells = p.cellValue ?? {};
|
|
3172
|
+
for (const r of Object.keys(cells))
|
|
3173
|
+
for (const c of Object.keys(cells[r] ?? {})) {
|
|
3174
|
+
const raw = ws.getCellRaw(Number(r), Number(c));
|
|
3175
|
+
const copy = raw ? json(raw) : null;
|
|
3176
|
+
if (copy && "s" in copy) copy.s = styleObject(copy.s);
|
|
3177
|
+
record.cells.set(`${r}:${c}`, copy);
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
if (info.id === SHEET_NAME) record.name = ws.getName();
|
|
3181
|
+
pre.set(p, record);
|
|
3182
|
+
});
|
|
3183
|
+
const after = cs.onCommandExecuted((info) => {
|
|
3184
|
+
if (info.type !== COMMAND) return;
|
|
3185
|
+
const at = tracker.stack.lastIndexOf(info.id);
|
|
3186
|
+
if (at >= 0) tracker.stack.splice(at, 1);
|
|
3187
|
+
settle();
|
|
3188
|
+
});
|
|
3189
|
+
const guarded = cs;
|
|
3190
|
+
if (!guarded[DEPTH_GUARD] && typeof cs.executeCommand === "function") {
|
|
3191
|
+
const trackers = /* @__PURE__ */ new Set();
|
|
3192
|
+
guarded[DEPTH_GUARD] = trackers;
|
|
3193
|
+
const original = cs.executeCommand.bind(cs);
|
|
3194
|
+
cs.executeCommand = async (id, params, options) => {
|
|
3195
|
+
const depths = new Map([...trackers].map((t) => [t, t.stack.length]));
|
|
3196
|
+
try {
|
|
3197
|
+
return await original(id, params, options);
|
|
3198
|
+
} finally {
|
|
3199
|
+
for (const [t, d] of depths) {
|
|
3200
|
+
if (t.stack.length > d) {
|
|
3201
|
+
t.stack.length = d;
|
|
3202
|
+
t.settle();
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
};
|
|
3207
|
+
}
|
|
3208
|
+
guarded[DEPTH_GUARD]?.add(tracker);
|
|
3209
|
+
const capture = (info) => {
|
|
3210
|
+
const entry = SHEET_MUTATIONS[info.id];
|
|
3211
|
+
if (!entry) {
|
|
3212
|
+
console.warn(`[sheets-ot] ${info.id} is not in the sheet mutation registry; it cannot be shared`);
|
|
3213
|
+
return { m: null, inverse: void 0, notShared: info.id };
|
|
3214
|
+
}
|
|
3215
|
+
if (entry.kind === "never-travels") return { m: null, inverse: void 0 };
|
|
3216
|
+
if (entry.kind === "barrier") return { m: null, inverse: void 0, notShared: info.id };
|
|
3217
|
+
const raw = json(info.params);
|
|
3218
|
+
const before2 = pre.get(info.params) ?? {};
|
|
3219
|
+
const params = allowParams(info.id, raw);
|
|
3220
|
+
if (!params) return { m: null, inverse: void 0, notShared: info.id };
|
|
3221
|
+
const sheet = String(params.subUnitId ?? "");
|
|
3222
|
+
const ws = o.workbook()?.getSheetBySheetId(sheet);
|
|
3223
|
+
if (info.id === VALUES) {
|
|
3224
|
+
const cells = params.cellValue ?? {};
|
|
3225
|
+
const invCells = {};
|
|
3226
|
+
let invKnown = !!before2.cells;
|
|
3227
|
+
for (const r of Object.keys(cells))
|
|
3228
|
+
for (const c of Object.keys(cells[r] ?? {})) {
|
|
3229
|
+
let e = cells[r][c] ?? null;
|
|
3230
|
+
const p = before2.cells?.get(`${r}:${c}`) ?? null;
|
|
3231
|
+
if (e && "s" in e) {
|
|
3232
|
+
e = { ...e, s: styleObject(e.s) };
|
|
3233
|
+
if (raw.isOverrideStyle) {
|
|
3234
|
+
const next = e.s && typeof e.s === "object" ? e.s : {};
|
|
3235
|
+
const prev = p?.s && typeof p.s === "object" ? p.s : {};
|
|
3236
|
+
const merged = { ...next };
|
|
3237
|
+
for (const k of Object.keys(prev)) if (!(k in next)) merged[k] = null;
|
|
3238
|
+
e.s = Object.keys(merged).length ? merged : null;
|
|
3239
|
+
}
|
|
3240
|
+
}
|
|
3241
|
+
const post = ws?.getCellRaw(Number(r), Number(c)) ?? null;
|
|
3242
|
+
const done = completeCellContent(e, post ? json(post) : null);
|
|
3243
|
+
cells[r][c] = done;
|
|
3244
|
+
if (!invKnown) continue;
|
|
3245
|
+
let inv;
|
|
3246
|
+
if (done === null) inv = p ? { ...fullContent(p), ...p.s !== void 0 ? { s: p.s } : {} } : null;
|
|
3247
|
+
else {
|
|
3248
|
+
inv = {};
|
|
3249
|
+
if (CONTENT_KEYS.some((k) => k !== "t" && k in done)) Object.assign(inv, fullContent(p));
|
|
3250
|
+
if ("s" in done) inv.s = p?.s ?? null;
|
|
3251
|
+
}
|
|
3252
|
+
(invCells[r] ??= {})[c] = inv;
|
|
3253
|
+
}
|
|
3254
|
+
return {
|
|
3255
|
+
m: { id: info.id, params: { ...params, cellValue: cells } },
|
|
3256
|
+
inverse: invKnown ? [{ id: VALUES, params: { subUnitId: sheet, cellValue: invCells } }] : void 0
|
|
3257
|
+
};
|
|
3258
|
+
}
|
|
3259
|
+
if (info.id === REMOVE_MERGE) {
|
|
3260
|
+
const exact = exactMergeRemovals([{ id: info.id, params }], { [sheet]: before2.merges ?? ws?.getMergeData() ?? [] });
|
|
3261
|
+
const m2 = exact[0] ?? null;
|
|
3262
|
+
if (!m2) return { m: null, inverse: void 0 };
|
|
3263
|
+
return { m: m2, inverse: [{ id: ADD_MERGE, params: { subUnitId: sheet, ranges: json(m2.params.ranges) } }] };
|
|
3264
|
+
}
|
|
3265
|
+
const m = { id: info.id, params };
|
|
3266
|
+
switch (info.id) {
|
|
3267
|
+
case "sheet.mutation.insert-row":
|
|
3268
|
+
return { m, inverse: [{ id: "sheet.mutation.remove-rows", params: { subUnitId: sheet, range: json(params.range) } }] };
|
|
3269
|
+
case "sheet.mutation.insert-col":
|
|
3270
|
+
return { m, inverse: [{ id: "sheet.mutation.remove-col", params: { subUnitId: sheet, range: json(params.range) } }] };
|
|
3271
|
+
case ADD_MERGE:
|
|
3272
|
+
return { m, inverse: [{ id: REMOVE_MERGE, params: { subUnitId: sheet, ranges: json(params.ranges) } }] };
|
|
3273
|
+
case SHEET_NAME:
|
|
3274
|
+
return { m, inverse: before2.name !== void 0 ? [{ id: SHEET_NAME, params: { subUnitId: sheet, name: before2.name } }] : void 0 };
|
|
3275
|
+
default:
|
|
3276
|
+
return { m, inverse: void 0 };
|
|
3277
|
+
}
|
|
3278
|
+
};
|
|
3279
|
+
const collab = cs.onMutationExecutedForCollab((info, options) => {
|
|
3280
|
+
if (applying || flagged(options) || !mine(info.params)) return;
|
|
3281
|
+
const lone = !group;
|
|
3282
|
+
if (lone) group = openGroup(null);
|
|
3283
|
+
const g = group;
|
|
3284
|
+
if (!g.notShared) {
|
|
3285
|
+
const r = capture(info);
|
|
3286
|
+
if (r.notShared) g.notShared = r.notShared;
|
|
3287
|
+
else if (r.m) {
|
|
3288
|
+
g.mutations.push(r.m);
|
|
3289
|
+
g.inverses.push(r.inverse);
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
if (lone && tracker.stack.length === 0) settle();
|
|
3293
|
+
});
|
|
3294
|
+
return {
|
|
3295
|
+
onLocal(listener) {
|
|
3296
|
+
listeners.add(listener);
|
|
3297
|
+
return () => void listeners.delete(listener);
|
|
3298
|
+
},
|
|
3299
|
+
busy: () => tracker.stack.length > 0 || group !== null,
|
|
3300
|
+
whenIdle(fn) {
|
|
3301
|
+
if (tracker.stack.length === 0 && !group) fn();
|
|
3302
|
+
else idle.push(fn);
|
|
3303
|
+
},
|
|
3304
|
+
applyRemote(m) {
|
|
3305
|
+
const u = unitId();
|
|
3306
|
+
if (!u) throw new Error("no workbook is mounted");
|
|
3307
|
+
const a = forApply(m);
|
|
3308
|
+
applying = true;
|
|
3309
|
+
try {
|
|
3310
|
+
const ok2 = cs.syncExecuteCommand(a.id, { ...json(a.params), unitId: u }, { onlyLocal: true, fromCollab: true });
|
|
3311
|
+
if (ok2 === false) throw new Error(`"${m.id}" was refused by the editor`);
|
|
3312
|
+
} finally {
|
|
3313
|
+
applying = false;
|
|
3314
|
+
}
|
|
3315
|
+
},
|
|
3316
|
+
snapshot() {
|
|
3317
|
+
const wb = o.workbook();
|
|
3318
|
+
if (!wb) return null;
|
|
3319
|
+
const saved = o.saveUnit?.(wb.getUnitId()) ?? wb.getSnapshot();
|
|
3320
|
+
return saved ? json(saved) : null;
|
|
3321
|
+
},
|
|
3322
|
+
load(snapshot) {
|
|
3323
|
+
group = null;
|
|
3324
|
+
applying = true;
|
|
3325
|
+
try {
|
|
3326
|
+
o.load(snapshot);
|
|
3327
|
+
} finally {
|
|
3328
|
+
applying = false;
|
|
3329
|
+
}
|
|
3330
|
+
},
|
|
3331
|
+
undoTargets() {
|
|
3332
|
+
const u = unitId();
|
|
3333
|
+
const service = o.undoRedo?.();
|
|
3334
|
+
return u && service ? [{ service, unitId: u }] : [];
|
|
3335
|
+
},
|
|
3336
|
+
markDirty: () => o.markDirty(),
|
|
3337
|
+
dispose() {
|
|
3338
|
+
before.dispose();
|
|
3339
|
+
after.dispose();
|
|
3340
|
+
collab.dispose();
|
|
3341
|
+
guarded[DEPTH_GUARD]?.delete(tracker);
|
|
3342
|
+
listeners.clear();
|
|
3343
|
+
}
|
|
3344
|
+
};
|
|
3345
|
+
}
|
|
3346
|
+
function fullContent(cell) {
|
|
3347
|
+
const out = {};
|
|
3348
|
+
for (const k of CONTENT_KEYS) out[k] = cell && cell[k] !== void 0 ? cell[k] : null;
|
|
3349
|
+
if (out.v === null) delete out.t;
|
|
3350
|
+
return out;
|
|
3351
|
+
}
|
|
3352
|
+
|
|
3353
|
+
// src/sheets/workbook-ot-room.ts
|
|
3354
|
+
var Y3 = __toESM(require("yjs"), 1);
|
|
3355
|
+
var import_awareness3 = require("y-protocols/awareness");
|
|
3356
|
+
var import_collab6 = require("@ai-matrx/data/realtime/collab");
|
|
3357
|
+
|
|
3358
|
+
// src/sheets/ports.ts
|
|
3359
|
+
var SLOT2 = /* @__PURE__ */ Symbol.for("ai-matrx.office.sheets-host");
|
|
3360
|
+
var slot2 = () => {
|
|
3361
|
+
const g = globalThis;
|
|
3362
|
+
return g[SLOT2] ??= {};
|
|
3363
|
+
};
|
|
3364
|
+
function getSheetsHost() {
|
|
3365
|
+
const ports = slot2().ports;
|
|
3366
|
+
if (!ports) throw new Error("@ai-matrx/office/sheets: configureSheetsHost(ports) was not called before the workbook service ran.");
|
|
3367
|
+
return ports;
|
|
3368
|
+
}
|
|
3369
|
+
|
|
3370
|
+
// src/sheets/workbook-service.ts
|
|
3371
|
+
var import_api2 = require("@ai-matrx/api");
|
|
3372
|
+
var import_auth2 = require("@ai-matrx/auth");
|
|
3373
|
+
var import_db2 = require("@ai-matrx/data/db");
|
|
3374
|
+
var db3 = () => getSheetsHost().getSupabase();
|
|
3375
|
+
async function getLatestSnapshot(workbookId) {
|
|
3376
|
+
const { data, error } = await db3().schema("workbench").from("udt_workbook_snapshots").select("*").eq("workbook_id", workbookId).order("created_at", { ascending: false }).limit(1).maybeSingle();
|
|
3377
|
+
if (error) return { success: false, error: error.message };
|
|
3378
|
+
return { success: true, data: data ?? null };
|
|
3379
|
+
}
|
|
3380
|
+
async function saveSnapshot(args) {
|
|
3381
|
+
const { data: userData } = await (0, import_auth2.getClaimsUser)(db3());
|
|
3382
|
+
const { data: workbook, error: workbookError } = await db3().schema("workbench").from("udt_workbooks").select("organization_id").eq("id", args.workbookId).single();
|
|
3383
|
+
if (workbookError) return { success: false, error: workbookError.message };
|
|
3384
|
+
const { data, error } = await db3().schema("workbench").from("udt_workbook_snapshots").insert({
|
|
3385
|
+
organization_id: workbook.organization_id,
|
|
3386
|
+
workbook_id: args.workbookId,
|
|
3387
|
+
snapshot: args.snapshot,
|
|
3388
|
+
label: args.label ?? null,
|
|
3389
|
+
origin: args.origin ?? "autosave",
|
|
3390
|
+
created_by: userData?.user?.id ?? null
|
|
3391
|
+
}).select("*").single();
|
|
3392
|
+
if (error) return { success: false, error: error.message };
|
|
3393
|
+
await db3().schema("workbench").from("udt_workbooks").update({ updated_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", args.workbookId);
|
|
3394
|
+
return { success: true, data };
|
|
3395
|
+
}
|
|
3396
|
+
|
|
3397
|
+
// src/sheets/workbook-ot-room.ts
|
|
3398
|
+
var db4 = () => getSheetsHost().getSupabase();
|
|
3399
|
+
async function loadSnapshotRow2(workbookId, ref) {
|
|
3400
|
+
if (ref === "none") {
|
|
3401
|
+
const res = await getLatestSnapshot(workbookId);
|
|
3402
|
+
if (!res.success) throw new Error(res.error);
|
|
3403
|
+
return res.data?.snapshot ?? null;
|
|
3404
|
+
}
|
|
3405
|
+
const { data, error } = await getSheetsHost().getSupabase().schema("workbench").from("udt_workbook_snapshots").select("snapshot").eq("id", ref).maybeSingle();
|
|
3406
|
+
if (error) throw new Error(error.message);
|
|
3407
|
+
if (!data) throw new Error(`The saved version ${ref} of this workbook is missing.`);
|
|
3408
|
+
return data.snapshot ?? null;
|
|
3409
|
+
}
|
|
3410
|
+
async function workbookUsesOrderedRoom(workbookId, knob, isNewWorkbook) {
|
|
3411
|
+
try {
|
|
3412
|
+
if (await (0, import_collab6.collabRoomExists)(db4(), workbookId)) return true;
|
|
3413
|
+
} catch (err) {
|
|
3414
|
+
console.warn("[workbook] could not ask whether this workbook has a co-editing room; opening the relay room", err);
|
|
3415
|
+
return false;
|
|
3416
|
+
}
|
|
3417
|
+
if (knob === "all") return true;
|
|
3418
|
+
if (knob === "new") return isNewWorkbook();
|
|
3419
|
+
return false;
|
|
3420
|
+
}
|
|
3421
|
+
function pickColor3(uid) {
|
|
3422
|
+
const palette = ["#ef4444", "#f59e0b", "#10b981", "#3b82f6", "#8b5cf6", "#ec4899", "#14b8a6", "#f97316"];
|
|
3423
|
+
let h = 2166136261;
|
|
3424
|
+
for (let i = 0; i < uid.length; i++) {
|
|
3425
|
+
h ^= uid.charCodeAt(i);
|
|
3426
|
+
h = Math.imul(h, 16777619);
|
|
3427
|
+
}
|
|
3428
|
+
return palette[Math.abs(h) % palette.length] ?? "#ec4899";
|
|
3429
|
+
}
|
|
3430
|
+
async function startWorkbookOtRoom(port, o) {
|
|
3431
|
+
const latest = await getLatestSnapshot(o.workbookId);
|
|
3432
|
+
if (!latest.success) throw new Error(latest.error);
|
|
3433
|
+
if (!latest.data) {
|
|
3434
|
+
const mounted = port.snapshot();
|
|
3435
|
+
if (mounted) {
|
|
3436
|
+
const saved = await saveSnapshot({ workbookId: o.workbookId, snapshot: mounted, origin: "autosave" });
|
|
3437
|
+
if (!saved.success) throw new Error(saved.error);
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
const doc = new Y3.Doc();
|
|
3441
|
+
const awareness = new import_awareness3.Awareness(doc);
|
|
3442
|
+
awareness.setLocalState({
|
|
3443
|
+
uid: o.uid,
|
|
3444
|
+
clientId: o.clientId,
|
|
3445
|
+
name: o.displayName ?? o.uid.slice(0, 8),
|
|
3446
|
+
color: pickColor3(o.uid),
|
|
3447
|
+
sheetId: null,
|
|
3448
|
+
row: null,
|
|
3449
|
+
col: null,
|
|
3450
|
+
ts: Date.now()
|
|
3451
|
+
});
|
|
3452
|
+
const publishAwareness = () => o.onAwareness?.(new Map(awareness.getStates()));
|
|
3453
|
+
awareness.on("change", publishAwareness);
|
|
3454
|
+
const provider = new import_collab6.SupabaseYjsProvider({
|
|
3455
|
+
workbookId: o.workbookId,
|
|
3456
|
+
clientId: o.clientId,
|
|
3457
|
+
doc,
|
|
3458
|
+
awareness,
|
|
3459
|
+
...o.readAntiEntropyIntervalMs ? { readAntiEntropyIntervalMs: o.readAntiEntropyIntervalMs } : {}
|
|
3460
|
+
});
|
|
3461
|
+
await provider.connect();
|
|
3462
|
+
publishAwareness();
|
|
3463
|
+
const client = db4();
|
|
3464
|
+
const room = openSheetsOtRoom({
|
|
3465
|
+
port,
|
|
3466
|
+
clientId: o.clientId,
|
|
3467
|
+
presence: (0, import_collab6.awarenessOpPresence)(awareness),
|
|
3468
|
+
transport: (0, import_collab6.supabaseOpTransport)({
|
|
3469
|
+
client,
|
|
3470
|
+
roomId: o.workbookId,
|
|
3471
|
+
kind: "univer_sheet",
|
|
3472
|
+
store: {
|
|
3473
|
+
loadSnapshot: (ref) => loadSnapshotRow2(o.workbookId, ref),
|
|
3474
|
+
async writeSnapshot(snapshot) {
|
|
3475
|
+
const res = await saveSnapshot({ workbookId: o.workbookId, snapshot, origin: "autosave" });
|
|
3476
|
+
if (!res.success) throw new Error(res.error);
|
|
3477
|
+
return res.data.id;
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3480
|
+
}),
|
|
3481
|
+
replace: ({ snapshot, stateHash, clientId }) => (0, import_collab6.collabReplace)(client, { roomId: o.workbookId, snapshot, stateHash, origin: "restore", clientId }),
|
|
3482
|
+
...o.onNotice ? { onNotice: o.onNotice } : {},
|
|
3483
|
+
...o.onIncident ? { onIncident: o.onIncident } : {},
|
|
3484
|
+
...o.onStatus ? { onStatus: o.onStatus } : {}
|
|
3485
|
+
});
|
|
3486
|
+
await room.session.ready;
|
|
3487
|
+
return {
|
|
3488
|
+
session: room.session,
|
|
3489
|
+
isSaver: () => room.isSaver(),
|
|
3490
|
+
write: (reason) => room.write(reason),
|
|
3491
|
+
replace: (snapshot) => room.replace(snapshot),
|
|
3492
|
+
setCursor(c) {
|
|
3493
|
+
const current = awareness.getLocalState() ?? {};
|
|
3494
|
+
awareness.setLocalState({ ...current, sheetId: c.sheetId, row: c.row, col: c.col, ts: Date.now() });
|
|
3495
|
+
},
|
|
3496
|
+
stop() {
|
|
3497
|
+
room.stop();
|
|
3498
|
+
port.dispose?.();
|
|
3499
|
+
awareness.off("change", publishAwareness);
|
|
3500
|
+
provider.disconnect();
|
|
3501
|
+
awareness.destroy();
|
|
3502
|
+
doc.destroy();
|
|
3503
|
+
}
|
|
3504
|
+
};
|
|
3505
|
+
}
|
|
1611
3506
|
//# sourceMappingURL=univer-collab.cjs.map
|