@ai-matrx/office 0.8.20 → 0.8.21

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.
@@ -1758,6 +1758,14 @@ var SHEET_MUTATIONS = {
1758
1758
  "sheet.mutation.set-worksheet-row-auto-height": covered("size", "rowsAutoHeightInfo"),
1759
1759
  "sheet.mutation.set-worksheet-col-width": covered("size", "ranges", "colWidth"),
1760
1760
  "sheet.mutation.set-worksheet-name": covered("name", "name"),
1761
+ // ── covered (C5c) ────────────────────────────────────────────────────────────────────────────────
1762
+ "sheet.mutation.set.numfmt": covered("numfmt", "values", "refMap"),
1763
+ "sheet.mutation.remove.numfmt": covered("numfmt", "ranges"),
1764
+ "sheet.mutation.set-worksheet-row-count": covered("count", "rowCount"),
1765
+ "sheet.mutation.set-worksheet-column-count": covered("count", "columnCount"),
1766
+ "sheet.mutation.insert-sheet": covered("sheet", "index", "sheet"),
1767
+ "sheet.mutation.remove-sheet": covered("sheet", "sheetIndex", "sheetsLeft"),
1768
+ "sheet.mutation.set-worksheet-order": covered("sheet", "fromOrder", "toOrder"),
1761
1769
  // ── never travels ────────────────────────────────────────────────────────────────────────────────
1762
1770
  "formula.mutation.set-formula-calculation-start": never(FORMULA_RESULT),
1763
1771
  "formula.mutation.set-trigger-formula-calculation-start": never(FORMULA_RESULT),
@@ -1792,12 +1800,7 @@ var SHEET_MUTATIONS = {
1792
1800
  "thread-comment.mutation.delete-comment": never(UNIVER_COMMENTS),
1793
1801
  // ── barriers: X (no transform yet, design §10) ───────────────────────────────────────────────────
1794
1802
  "sheet.mutation.reorder-range": barrier("X", "sort: a permutation, not transformed yet"),
1795
- "sheet.mutation.set-worksheet-row-count": barrier("X", "absolute row count; needs delta semantics"),
1796
- "sheet.mutation.set-worksheet-column-count": barrier("X", "absolute column count; needs delta semantics"),
1797
- "sheet.mutation.set-worksheet-order": barrier("X", "absolute sheet order; needs move semantics"),
1798
1803
  "sheet.mutation.move-range": barrier("X", "cut-paste carries the sender's cell matrices"),
1799
- "sheet.mutation.insert-sheet": barrier("X", "sheet add: not in C5a"),
1800
- "sheet.mutation.remove-sheet": barrier("X", "sheet remove: not in C5a"),
1801
1804
  "sheet.mutation.set-worksheet-hidden": barrier("X", "sheet-level setting: not in C5a"),
1802
1805
  "sheet.mutation.set-tab-color": barrier("X", "sheet-level setting: not in C5a"),
1803
1806
  "sheet.mutation.set-workbook-name": barrier("X", "workbook-level setting: not in C5a"),
@@ -1812,8 +1815,6 @@ var SHEET_MUTATIONS = {
1812
1815
  "sheet.mutation.set-row-visible": barrier("X", "row visibility: not in C5a"),
1813
1816
  "sheet.mutation.set-col-hidden": barrier("X", "column visibility: not in C5a"),
1814
1817
  "sheet.mutation.set-col-visible": barrier("X", "column visibility: not in C5a"),
1815
- "sheet.mutation.set.numfmt": barrier("X", "number formats by range: not in C5a"),
1816
- "sheet.mutation.remove.numfmt": barrier("X", "number formats by range: not in C5a"),
1817
1818
  "sheet.mutation.add-range-protection": barrier("X", "permissions: not in C5a"),
1818
1819
  "sheet.mutation.set-range-protection": barrier("X", "permissions: not in C5a"),
1819
1820
  "sheet.mutation.delete-range-protection": barrier("X", "permissions: not in C5a"),
@@ -2208,7 +2209,7 @@ function refSheetsFor(texts, sheets) {
2208
2209
  }
2209
2210
 
2210
2211
  // src/collab/sheets/transform/transform.ts
2211
- var SHEET_TRANSFORMER_VERSION = "c5b-1";
2212
+ var SHEET_TRANSFORMER_VERSION = "c5c-1";
2212
2213
  var ID = {
2213
2214
  values: "sheet.mutation.set-range-values",
2214
2215
  insertRow: "sheet.mutation.insert-row",
@@ -2225,7 +2226,14 @@ var ID = {
2225
2226
  colWidth: "sheet.mutation.set-worksheet-col-width",
2226
2227
  name: "sheet.mutation.set-worksheet-name",
2227
2228
  setName: "formula.mutation.set-defined-name",
2228
- removeName: "formula.mutation.remove-defined-name"
2229
+ removeName: "formula.mutation.remove-defined-name",
2230
+ setNumfmt: "sheet.mutation.set.numfmt",
2231
+ removeNumfmt: "sheet.mutation.remove.numfmt",
2232
+ rowCount: "sheet.mutation.set-worksheet-row-count",
2233
+ colCount: "sheet.mutation.set-worksheet-column-count",
2234
+ insertSheet: "sheet.mutation.insert-sheet",
2235
+ removeSheet: "sheet.mutation.remove-sheet",
2236
+ sheetOrder: "sheet.mutation.set-worksheet-order"
2229
2237
  };
2230
2238
  var PAIR_BARRIERS = {};
2231
2239
  var pairKey = (a, b) => a < b ? `${a}|${b}` : `${b}|${a}`;
@@ -2337,6 +2345,20 @@ function mergeThrough(s, m) {
2337
2345
  }
2338
2346
  return { range: m, fixup: false };
2339
2347
  }
2348
+ function mergeFixupsOwed(m, mergesBefore) {
2349
+ const st = structuralOf(m);
2350
+ if (!st) return null;
2351
+ const remove = [];
2352
+ const add = [];
2353
+ for (const q of mergesBefore) {
2354
+ const t = mergeThrough(st, q);
2355
+ if (!t.fixup) continue;
2356
+ remove.push({ startRow: q.startRow, endRow: q.endRow, startColumn: q.startColumn, endColumn: q.endColumn, ...q.rangeType !== void 0 ? { rangeType: q.rangeType } : {} });
2357
+ if (t.range) add.push({ ...t.range });
2358
+ }
2359
+ return remove.length ? { remove, add } : null;
2360
+ }
2361
+ var isStructuralMutation = (m) => structuralOf(m) !== null;
2340
2362
  function exactMergeRemovals(group, merges) {
2341
2363
  const sim = new Map(Object.entries(merges).map(([k, v]) => [k, v.map((r) => ({ ...r }))]));
2342
2364
  const out = [];
@@ -2383,8 +2405,24 @@ function cellsMutation(template, cells) {
2383
2405
  function putCell(cells, r, c, v) {
2384
2406
  (cells[r] ??= {})[c] = v;
2385
2407
  }
2408
+ function cellsOverlap(a, b) {
2409
+ for (const r of Object.keys(a)) {
2410
+ const br = b[r];
2411
+ if (!br) continue;
2412
+ for (const c of Object.keys(a[r] ?? {})) if (c in br) return true;
2413
+ }
2414
+ return false;
2415
+ }
2386
2416
  var isEmptyMatrix = (cells) => Object.values(cells).every((row) => Object.keys(row).length === 0);
2417
+ var cellBarrierCache = /* @__PURE__ */ new WeakMap();
2387
2418
  function cellBarrier(m) {
2419
+ const hit = cellBarrierCache.get(m);
2420
+ if (hit !== void 0) return hit;
2421
+ const why = cellBarrierOf(m);
2422
+ cellBarrierCache.set(m, why);
2423
+ return why;
2424
+ }
2425
+ function cellBarrierOf(m) {
2388
2426
  if (m.params.isOverrideStyle) return "set-range-values with isOverrideStyle (whole-style replace) is not covered";
2389
2427
  let why = null;
2390
2428
  forEachCell(cellsOf(m), (_r, _c, v) => {
@@ -2466,6 +2504,7 @@ function transformCell(X, Y4, side) {
2466
2504
  function transformCellsOverCells(x, y, side) {
2467
2505
  if (sheetOf(x) !== sheetOf(y)) return ok([x]);
2468
2506
  const ycells = cellsOf(y);
2507
+ if (!cellsOverlap(cellsOf(x), ycells)) return ok([x]);
2469
2508
  const xd = isDerived(x);
2470
2509
  const yd = isDerived(y);
2471
2510
  const eff = derivedSide(x, y, side);
@@ -2493,7 +2532,7 @@ function transformCellsOverCells(x, y, side) {
2493
2532
  const op = passes.filter((p) => !isEmptyMatrix(p)).map((p) => cellsMutation(x, p));
2494
2533
  return ok(op, lost, dropped);
2495
2534
  }
2496
- var SIDE_CAR_PARAMS = ["refSheets", "previousName", "derived"];
2535
+ var SIDE_CAR_PARAMS = ["refSheets", "previousName", "derived", "sheetIndex", "sheetsLeft"];
2497
2536
  var isDerived = (m) => m.params.derived === true;
2498
2537
  function derivedSide(x, y, side) {
2499
2538
  const xd = isDerived(x);
@@ -2515,7 +2554,15 @@ function withRefSheets(params, rs) {
2515
2554
  return out;
2516
2555
  }
2517
2556
  var hasFormulaText = (v) => !!v && (isFormulaText(v.f) || typeof v.ref === "string");
2557
+ var hasFormulaCache = /* @__PURE__ */ new WeakMap();
2518
2558
  function hasFormula(m) {
2559
+ const hit = hasFormulaCache.get(m);
2560
+ if (hit !== void 0) return hit;
2561
+ const any = hasFormulaOf(m);
2562
+ hasFormulaCache.set(m, any);
2563
+ return any;
2564
+ }
2565
+ function hasFormulaOf(m) {
2519
2566
  let any = false;
2520
2567
  forEachCell(cellsOf(m), (_r, _c, v) => {
2521
2568
  any ||= hasFormulaText(v);
@@ -2554,15 +2601,18 @@ function cellThrough(sheet, change, r, c) {
2554
2601
  return nr === null || nc === null ? null : [nr, nc];
2555
2602
  }
2556
2603
  function cellsOverChange(x, change) {
2604
+ if (!hasFormula(x) && (change.kind !== "axis" || change.sheet !== sheetOf(x))) return ok([x]);
2557
2605
  const ctx = formulaCtx(x);
2558
2606
  const out = {};
2559
2607
  const dropped = [];
2560
2608
  let why = null;
2609
+ let changed = false;
2561
2610
  forEachCell(cellsOf(x), (r, c, v) => {
2562
2611
  if (why) return;
2563
2612
  const at = cellThrough(sheetOf(x), change, r, c);
2564
2613
  if (!at) {
2565
2614
  dropped.push(cellRef(sheetOf(x), r, c));
2615
+ changed = true;
2566
2616
  return;
2567
2617
  }
2568
2618
  let e = v;
@@ -2573,14 +2623,19 @@ function cellsOverChange(x, change) {
2573
2623
  return;
2574
2624
  }
2575
2625
  e = res.entry;
2626
+ if (res.changed) changed = true;
2576
2627
  }
2628
+ if (at[0] !== r || at[1] !== c) changed = true;
2577
2629
  putCell(out, at[0], at[1], e);
2578
2630
  });
2579
2631
  if (why) return barrier2(why);
2580
- const params = { ...withRefSheets(x.params, refSheetsAfter(ctx.refSheets, change)), cellValue: out };
2632
+ const rsAfter = refSheetsAfter(ctx.refSheets, change);
2633
+ if (!changed && JSON.stringify(rsAfter ?? null) === JSON.stringify(ctx.refSheets ?? null)) return ok([x]);
2634
+ const params = { ...withRefSheets(x.params, rsAfter), cellValue: out };
2581
2635
  return ok(isEmptyMatrix(out) ? [] : [{ id: x.id, params }], [], dropped);
2582
2636
  }
2583
2637
  function rewritesOf(y, change) {
2638
+ if (!hasFormula(y)) return null;
2584
2639
  const ctx = formulaCtx(y);
2585
2640
  const out = {};
2586
2641
  let why = null;
@@ -2726,6 +2781,255 @@ function buildSize(template, values) {
2726
2781
  const value = uniform !== void 0 && [...values.values()].every((v) => v === uniform) ? uniform : Object.fromEntries(values);
2727
2782
  return { id: template.id, params: { ...p, ranges, [field]: value } };
2728
2783
  }
2784
+ var isNumfmt = (m) => m.id === ID.setNumfmt || m.id === ID.removeNumfmt;
2785
+ function nfParts(m) {
2786
+ if (m.id === ID.removeNumfmt) return [{ key: null, ranges: (m.params.ranges ?? []).map((r) => ({ ...r })) }];
2787
+ const values = m.params.values ?? {};
2788
+ return Object.keys(values).map((k) => ({ key: k, ranges: (values[k]?.ranges ?? []).map((r) => ({ ...r })) }));
2789
+ }
2790
+ function nfBuild(m, parts) {
2791
+ const keep = parts.filter((p) => p.ranges.length);
2792
+ if (!keep.length) return [];
2793
+ if (m.id === ID.removeNumfmt) return [{ id: m.id, params: { ...m.params, ranges: keep[0].ranges } }];
2794
+ const values = {};
2795
+ const refMap = {};
2796
+ const srcValues = m.params.values ?? {};
2797
+ const srcRef = m.params.refMap ?? {};
2798
+ for (const p of keep) {
2799
+ values[p.key] = { ...srcValues[p.key], ranges: p.ranges };
2800
+ refMap[p.key] = srcRef[p.key];
2801
+ }
2802
+ return [{ id: m.id, params: { ...m.params, values, refMap } }];
2803
+ }
2804
+ function nfValueAt(m, row, col) {
2805
+ for (const p of nfParts(m))
2806
+ if (p.ranges.some((r) => r.startRow <= row && row <= r.endRow && r.startColumn <= col && col <= r.endColumn)) {
2807
+ if (p.key === null) return null;
2808
+ const ref = (m.params.refMap ?? {})[p.key];
2809
+ return { pattern: ref?.pattern };
2810
+ }
2811
+ return void 0;
2812
+ }
2813
+ function spanThrough(op, lo, hi) {
2814
+ const pieces = [];
2815
+ if (op.kind === "insert") pieces.push([0, op.at - 1, 0], [op.at, Infinity, op.count]);
2816
+ else if (op.kind === "remove") pieces.push([0, op.start - 1, 0], [op.start + op.count, Infinity, -op.count]);
2817
+ else if (op.count <= 0 || op.to >= op.from && op.to <= op.from + op.count) pieces.push([0, Infinity, 0]);
2818
+ else if (op.to > op.from) {
2819
+ const n = op.count;
2820
+ pieces.push([0, op.from - 1, 0], [op.from, op.from + n - 1, op.to - n - op.from], [op.from + n, op.to - 1, -n], [op.to, Infinity, 0]);
2821
+ } else {
2822
+ const n = op.count;
2823
+ pieces.push([0, op.to - 1, 0], [op.to, op.from - 1, n], [op.from, op.from + n - 1, op.to - op.from], [op.from + n, Infinity, 0]);
2824
+ }
2825
+ const out = [];
2826
+ for (const [a, b, d] of pieces) {
2827
+ const x0 = Math.max(a, lo);
2828
+ const x1 = Math.min(b, hi);
2829
+ if (x0 <= x1) out.push([x0 + d, x1 + d]);
2830
+ }
2831
+ out.sort((p, q) => p[0] - q[0]);
2832
+ const merged = [];
2833
+ for (const p of out) {
2834
+ const last = merged[merged.length - 1];
2835
+ if (last && last[1] + 1 >= p[0]) last[1] = Math.max(last[1], p[1]);
2836
+ else merged.push([p[0], p[1]]);
2837
+ }
2838
+ return merged;
2839
+ }
2840
+ function rectsThrough(st, rects) {
2841
+ const [a0, a1] = S(st.axis);
2842
+ const out = [];
2843
+ for (const r of rects) for (const [lo, hi] of spanThrough(st.op, r[a0], r[a1])) out.push({ ...r, [a0]: lo, [a1]: hi });
2844
+ return out;
2845
+ }
2846
+ function rectMinus(a, b) {
2847
+ if (a.startRow > b.endRow || b.startRow > a.endRow || a.startColumn > b.endColumn || b.startColumn > a.endColumn) return [a];
2848
+ const out = [];
2849
+ if (a.startRow < b.startRow) out.push({ ...a, endRow: b.startRow - 1 });
2850
+ if (a.endRow > b.endRow) out.push({ ...a, startRow: b.endRow + 1 });
2851
+ const r0 = Math.max(a.startRow, b.startRow);
2852
+ const r1 = Math.min(a.endRow, b.endRow);
2853
+ if (a.startColumn < b.startColumn) out.push({ ...a, startRow: r0, endRow: r1, endColumn: b.startColumn - 1 });
2854
+ if (a.endColumn > b.endColumn) out.push({ ...a, startRow: r0, endRow: r1, startColumn: b.endColumn + 1 });
2855
+ return out;
2856
+ }
2857
+ function rectsMinus(as, bs) {
2858
+ let cur = as;
2859
+ for (const b of bs) cur = cur.flatMap((a) => rectMinus(a, b));
2860
+ return cur;
2861
+ }
2862
+ function nWrites(m) {
2863
+ const out = [];
2864
+ forEachCell(cellsOf(m), (r, c, v) => {
2865
+ if (v === null || v.s === null || v.s && typeof v.s === "object" && "n" in v.s)
2866
+ out.push({ startRow: r, endRow: r, startColumn: c, endColumn: c });
2867
+ });
2868
+ return out;
2869
+ }
2870
+ function numfmtPair(x, y, side, sx, sy) {
2871
+ const nx = isNumfmt(x);
2872
+ const ny = isNumfmt(y);
2873
+ if (!nx && !ny) return null;
2874
+ if (nx && sy) return ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsThrough(sy, p.ranges) }))));
2875
+ if (ny && sx) return ok([x]);
2876
+ if (nx && ny) {
2877
+ if (side === "left") return ok([x]);
2878
+ const ys = nfParts(y).flatMap((p) => p.ranges);
2879
+ return ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsMinus(p.ranges, ys) }))));
2880
+ }
2881
+ if (nx && y.id === ID.values) {
2882
+ if (side === "left") return ok([x]);
2883
+ const ys = nWrites(y);
2884
+ return ys.length ? ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsMinus(p.ranges, ys) })))) : ok([x]);
2885
+ }
2886
+ if (ny && x.id === ID.values) {
2887
+ if (side === "left") return ok([x]);
2888
+ const out = {};
2889
+ const tail = {};
2890
+ let touched = false;
2891
+ forEachCell(cellsOf(x), (r, c, v) => {
2892
+ const n = nfValueAt(y, r, c);
2893
+ if (n === void 0) return putCell(out, r, c, v);
2894
+ if (v === null || v.s === null) {
2895
+ putCell(out, r, c, v);
2896
+ if (n) {
2897
+ putCell(tail, r, c, { s: { n } });
2898
+ touched = true;
2899
+ }
2900
+ return;
2901
+ }
2902
+ if (v.s && typeof v.s === "object" && "n" in v.s) {
2903
+ const { n: _drop, ...rest } = v.s;
2904
+ const e = { ...v };
2905
+ if (Object.keys(rest).length) e.s = rest;
2906
+ else delete e.s;
2907
+ touched = true;
2908
+ if (Object.keys(e).length) putCell(out, r, c, e);
2909
+ return;
2910
+ }
2911
+ putCell(out, r, c, v);
2912
+ });
2913
+ if (!touched) return ok([x]);
2914
+ const ops = [];
2915
+ if (!isEmptyMatrix(out)) ops.push(cellsMutation(x, out));
2916
+ if (!isEmptyMatrix(tail)) ops.push({ id: ID.values, params: { subUnitId: sheetOf(x), cellValue: tail } });
2917
+ return ok(ops);
2918
+ }
2919
+ return ok([x]);
2920
+ }
2921
+ var isCount = (m) => m.id === ID.rowCount || m.id === ID.colCount;
2922
+ var countAxis = (m) => m.id === ID.rowCount ? "row" : "col";
2923
+ var countKey = (m) => m.id === ID.rowCount ? "rowCount" : "columnCount";
2924
+ function countPair(x, y, sy) {
2925
+ if (!isCount(x)) return isCount(y) ? ok([x]) : null;
2926
+ const k = countKey(x);
2927
+ const v = Number(x.params[k]);
2928
+ if (sy) {
2929
+ if (sy.axis !== countAxis(x) || sy.op.kind === "move") return ok([x]);
2930
+ const d = sy.op.kind === "insert" ? sy.op.count : -sy.op.count;
2931
+ return ok([{ id: x.id, params: { ...x.params, [k]: Math.max(1, v + d) } }]);
2932
+ }
2933
+ if (isCount(y) && y.id === x.id) {
2934
+ const w = Number(y.params[k]);
2935
+ return ok([w > v ? { id: x.id, params: { ...x.params, [k]: w } } : x]);
2936
+ }
2937
+ return ok([x]);
2938
+ }
2939
+ var isSheetOp = (m) => m.id === ID.insertSheet || m.id === ID.removeSheet || m.id === ID.sheetOrder;
2940
+ var sheetIdOf = (m) => m.id === ID.insertSheet ? String(m.params.sheet?.id ?? "") : sheetOf(m);
2941
+ function sheetAxisOf(m) {
2942
+ const p = m.params;
2943
+ if (m.id === ID.insertSheet) return typeof p.index === "number" ? { kind: "insert", at: p.index, count: 1 } : null;
2944
+ if (m.id === ID.removeSheet) return typeof p.sheetIndex === "number" ? { kind: "remove", start: p.sheetIndex, count: 1 } : null;
2945
+ if (m.id === ID.sheetOrder) {
2946
+ const f = Number(p.fromOrder);
2947
+ const t = Number(p.toOrder);
2948
+ return { kind: "move", from: f, count: 1, to: t > f ? t + 1 : t };
2949
+ }
2950
+ return null;
2951
+ }
2952
+ function buildSheetOp(template, op) {
2953
+ if (op.kind === "insert") return { id: template.id, params: { ...template.params, index: op.at } };
2954
+ if (op.kind === "remove") return { id: template.id, params: { ...template.params, sheetIndex: op.start } };
2955
+ return { id: template.id, params: { ...template.params, fromOrder: op.from, toOrder: op.to > op.from ? op.to - 1 : op.to } };
2956
+ }
2957
+ function namesSheet(m, id) {
2958
+ const rs = refSheetsOf(m);
2959
+ return !!rs && Object.values(rs).includes(id) && (m.id === ID.setName || hasFormula(m));
2960
+ }
2961
+ function sheetPair(x, y, side) {
2962
+ const xs = isSheetOp(x);
2963
+ const ys = isSheetOp(y);
2964
+ if (!xs && !ys) return null;
2965
+ if (xs && ys) {
2966
+ const a = sheetAxisOf(x);
2967
+ const b = sheetAxisOf(y);
2968
+ if (!a || !b) return barrier2("a sheet add or remove without its index (capture must call annotateSheetOps)");
2969
+ if (x.id === ID.insertSheet && y.id === ID.insertSheet && sheetIdOf(x) === sheetIdOf(y)) {
2970
+ return JSON.stringify(x.params) === JSON.stringify(y.params) ? ok([]) : barrier2("the same sheet id added twice with different content");
2971
+ }
2972
+ if (x.id === ID.removeSheet && typeof x.params.sheetsLeft === "number" && sheetIdOf(x) !== sheetIdOf(y) && (y.id === ID.removeSheet || y.id === ID.insertSheet)) {
2973
+ const left = x.params.sheetsLeft + (y.id === ID.insertSheet ? 1 : -1);
2974
+ if (left < 1) return barrier2("concurrent sheet removes would leave the workbook without a sheet");
2975
+ const out2 = transformAxis(a, b, side);
2976
+ if (!out2) return barrier2("sheet order: no transform");
2977
+ return ok(out2.map((o) => buildSheetOp({ id: x.id, params: { ...x.params, sheetsLeft: left } }, o)));
2978
+ }
2979
+ const out = transformAxis(a, b, side);
2980
+ if (!out) return barrier2("sheet order: no transform");
2981
+ return ok(out.map((o) => buildSheetOp(x, o)), [], out.length === 0 && x.id === ID.sheetOrder ? [`${sheetIdOf(x)}: sheet order`] : []);
2982
+ }
2983
+ if (ys) {
2984
+ if (y.id !== ID.removeSheet) return ok([x]);
2985
+ const gone2 = sheetOf(y);
2986
+ if (namesSheet(x, gone2)) return barrier2("a formula names a sheet removed at the same time");
2987
+ if (sheetOf(x) === gone2 && x.id !== ID.setName && x.id !== ID.removeName)
2988
+ return ok([], [], isDerived(x) ? [] : [`${gone2}: the sheet was removed`]);
2989
+ return ok([x]);
2990
+ }
2991
+ if (x.id !== ID.removeSheet) return ok([x]);
2992
+ const gone = sheetOf(x);
2993
+ if (namesSheet(y, gone)) return barrier2("a formula names a sheet removed at the same time");
2994
+ return ok([x], sheetOf(y) === gone && !isDerived(y) && y.id !== ID.setName && y.id !== ID.removeName ? [`${gone}: the sheet was removed`] : []);
2995
+ }
2996
+ function annotateSheetOps(group, sheetOrder) {
2997
+ const order = [...sheetOrder];
2998
+ return group.map((m) => {
2999
+ if (m.id === ID.insertSheet) {
3000
+ const index = typeof m.params.index === "number" ? Math.min(m.params.index, order.length) : order.length;
3001
+ order.splice(index, 0, sheetIdOf(m));
3002
+ return index === m.params.index ? m : { id: m.id, params: { ...m.params, index } };
3003
+ }
3004
+ if (m.id === ID.removeSheet) {
3005
+ const i = order.indexOf(sheetOf(m));
3006
+ if (i >= 0) order.splice(i, 1);
3007
+ return i >= 0 ? { id: m.id, params: { ...m.params, sheetIndex: i, sheetsLeft: order.length } } : m;
3008
+ }
3009
+ if (m.id === ID.sheetOrder) {
3010
+ const f = Number(m.params.fromOrder);
3011
+ const [id] = order.splice(f, 1);
3012
+ order.splice(Number(m.params.toOrder), 0, id ?? sheetOf(m));
3013
+ }
3014
+ return m;
3015
+ });
3016
+ }
3017
+ function inlineSheetStyles(sheet, styleOf) {
3018
+ const out = JSON.parse(JSON.stringify(sheet));
3019
+ const fix = (o) => {
3020
+ if (o && typeof o.s === "string") {
3021
+ const st = styleOf(o.s);
3022
+ if (st) o.s = JSON.parse(JSON.stringify(st));
3023
+ }
3024
+ };
3025
+ for (const row of Object.values(out.cellData ?? {})) for (const cell of Object.values(row ?? {})) fix(cell);
3026
+ for (const key of ["rowData", "columnData"]) for (const v of Object.values(out[key] ?? {})) fix(v);
3027
+ if (typeof out.defaultStyle === "string") {
3028
+ const st = styleOf(out.defaultStyle);
3029
+ if (st) out.defaultStyle = JSON.parse(JSON.stringify(st));
3030
+ }
3031
+ return out;
3032
+ }
2729
3033
  function familyOf(id) {
2730
3034
  const e = SHEET_MUTATIONS[id];
2731
3035
  return e && e.kind === "covered" ? e.family : "";
@@ -2742,6 +3046,8 @@ function transformMutation(x, y, side) {
2742
3046
  }
2743
3047
  const pb = PAIR_BARRIERS[pairKey(x.id, y.id)];
2744
3048
  if (pb) return barrier2(`${x.id} \xD7 ${y.id}: ${pb.reason}${pb.seed === null ? "" : ` (fuzz seed ${pb.seed})`}`);
3049
+ const sp = sheetPair(x, y, side);
3050
+ if (sp) return sp;
2745
3051
  const fp = formulaPair(x, y, side);
2746
3052
  if (fp) return fp;
2747
3053
  if (sheetOf(x) !== sheetOf(y)) return ok([x]);
@@ -2749,6 +3055,10 @@ function transformMutation(x, y, side) {
2749
3055
  const fy = familyOf(y.id);
2750
3056
  const sy = structuralOf(y);
2751
3057
  const sx = structuralOf(x);
3058
+ const cp = countPair(x, y, sy);
3059
+ if (cp) return cp;
3060
+ const np = numfmtPair(x, y, side, sx, sy);
3061
+ if (np) return np;
2752
3062
  if (sx && sy) {
2753
3063
  if (sx.axis !== sy.axis) return ok([x]);
2754
3064
  const out = transformAxis(sx.op, sy.op, side);
@@ -2856,22 +3166,45 @@ function tSeq(xs, ys, side, acc) {
2856
3166
  acc.dropped.push(...a.dropped);
2857
3167
  return [a.op, b.op];
2858
3168
  }
3169
+ const outX = [];
3170
+ let curY = ys;
3171
+ for (const x of xs) {
3172
+ let curX = [x];
3173
+ const nextY = [];
3174
+ for (const y of curY) {
3175
+ if (curX.length === 0) {
3176
+ nextY.push(y);
3177
+ continue;
3178
+ }
3179
+ const r = tSeq(curX, [y], side, acc);
3180
+ if (blocked(r)) return r;
3181
+ curX = r[0];
3182
+ for (const m of r[1]) nextY.push(m);
3183
+ }
3184
+ for (const m of curX) outX.push(m);
3185
+ curY = nextY;
3186
+ }
3187
+ return [outX, curY];
3188
+ }
3189
+ function tSeqOld(xs, ys, side, acc) {
3190
+ if (xs.length === 0 || ys.length === 0) return [xs, ys];
3191
+ if (xs.length === 1 && ys.length === 1) return tSeq(xs, ys, side, acc);
2859
3192
  if (xs.length > 1) {
2860
- const first2 = tSeq([xs[0]], ys, side, acc);
3193
+ const first2 = tSeqOld([xs[0]], ys, side, acc);
2861
3194
  if (blocked(first2)) return first2;
2862
- const rest2 = tSeq(xs.slice(1), first2[1], side, acc);
3195
+ const rest2 = tSeqOld(xs.slice(1), first2[1], side, acc);
2863
3196
  if (blocked(rest2)) return rest2;
2864
3197
  return [[...first2[0], ...rest2[0]], rest2[1]];
2865
3198
  }
2866
- const first = tSeq(xs, [ys[0]], side, acc);
3199
+ const first = tSeqOld(xs, [ys[0]], side, acc);
2867
3200
  if (blocked(first)) return first;
2868
- const rest = tSeq(first[0], ys.slice(1), side, acc);
3201
+ const rest = tSeqOld(first[0], ys.slice(1), side, acc);
2869
3202
  if (blocked(rest)) return rest;
2870
3203
  return [rest[0], [...first[1], ...rest[1]]];
2871
3204
  }
2872
3205
  function transformGroup(x, y, side) {
2873
3206
  const acc = { lost: [], dropped: [] };
2874
- const r = tSeq([...x], [...y], side, acc);
3207
+ const r = (process.env.OLD_TSEQ ? tSeqOld : tSeq)([...x], [...y], side, acc);
2875
3208
  if (blocked(r)) return r;
2876
3209
  return { op: r[0], lost: [...new Set(acc.lost)], dropped: [...new Set(acc.dropped)] };
2877
3210
  }
@@ -2941,7 +3274,7 @@ async function sheetsStateHash(snapshot) {
2941
3274
  }
2942
3275
 
2943
3276
  // src/univer/collab/sheets-ot/room.ts
2944
- var SHEETS_COLLAB_PROTO = 1;
3277
+ var SHEETS_COLLAB_PROTO = 2;
2945
3278
  var SHEETS_EDIT_GROUP = "sheets.edit";
2946
3279
  var flip2 = (side) => side === "left" ? "right" : "left";
2947
3280
  var isNoopSheetOp = (op) => op == null || op.length === 0;
@@ -2988,6 +3321,11 @@ function travelingShape(m) {
2988
3321
  }
2989
3322
  return { id: m.id, params };
2990
3323
  }
3324
+ var shapedLists = /* @__PURE__ */ new WeakMap();
3325
+ function cachedShape(list) {
3326
+ const hit = shapedLists.get(list);
3327
+ return hit && hit.src.length === list.length && hit.src.every((m, i) => m === list[i]) ? hit.shaped : null;
3328
+ }
2991
3329
  function rebaseSheetUndoStack(items, remote, unitId) {
2992
3330
  if (isNoopSheetOp(remote)) return 0;
2993
3331
  let dropped = 0;
@@ -2999,7 +3337,11 @@ function rebaseSheetUndoStack(items, remote, unitId) {
2999
3337
  if (!ok2 || !list?.length) continue;
3000
3338
  const isOperation = (id) => !SHEET_MUTATIONS[id] && id.includes(".operation.");
3001
3339
  const operations = list.filter((m) => isOperation(m.id));
3002
- const shaped = list.filter((m) => !isOperation(m.id)).map(travelingShape);
3340
+ let shaped = cachedShape(list);
3341
+ if (!shaped) {
3342
+ shaped = list.filter((m) => !isOperation(m.id)).map(travelingShape);
3343
+ shapedLists.set(list, { src: list.slice(), shaped });
3344
+ }
3003
3345
  if (shaped.some((m) => m === null)) {
3004
3346
  ok2 = false;
3005
3347
  continue;
@@ -3011,8 +3353,10 @@ function rebaseSheetUndoStack(items, remote, unitId) {
3011
3353
  ok2 = false;
3012
3354
  continue;
3013
3355
  }
3014
- if (JSON.stringify(r.op) === JSON.stringify(shaped)) continue;
3015
- item[key] = [...r.op.map((m) => ({ id: m.id, params: { ...forApply(m).params, unitId } })), ...operations];
3356
+ if (r.op.length === shaped.length && r.op.every((m, i2) => m === shaped[i2])) continue;
3357
+ const next = [...r.op.map((m) => ({ id: m.id, params: { ...forApply(m).params, unitId } })), ...operations];
3358
+ shapedLists.set(next, { src: next.slice(), shaped: r.op });
3359
+ item[key] = next;
3016
3360
  } catch {
3017
3361
  ok2 = false;
3018
3362
  }
@@ -3087,7 +3431,7 @@ function createSheetsOtAdapter(port, hooks = {}) {
3087
3431
  });
3088
3432
  });
3089
3433
  }
3090
- return sheetsStateHash(port.snapshot());
3434
+ return (hooks.stateHash ?? sheetsStateHash)(port.snapshot());
3091
3435
  },
3092
3436
  held: () => queue.length,
3093
3437
  rebaseLocalOverHeld(local) {
@@ -3199,6 +3543,8 @@ var VALUES = "sheet.mutation.set-range-values";
3199
3543
  var ADD_MERGE = "sheet.mutation.add-worksheet-merge";
3200
3544
  var REMOVE_MERGE = "sheet.mutation.remove-worksheet-merge";
3201
3545
  var SHEET_NAME = "sheet.mutation.set-worksheet-name";
3546
+ var INSERT_SHEET = "sheet.mutation.insert-sheet";
3547
+ var RESHAPE = /* @__PURE__ */ new Set(["sheet.mutation.set-worksheet-row-count", "sheet.mutation.set-worksheet-column-count", "sheet.mutation.remove-sheet", INSERT_SHEET]);
3202
3548
  var DEPTH_GUARD = /* @__PURE__ */ Symbol.for("ai-matrx.office.sheets.command-depth-guard");
3203
3549
  var json = (v) => v === void 0 ? v : JSON.parse(JSON.stringify(v));
3204
3550
  var flagged = (options) => {
@@ -3235,7 +3581,8 @@ function univerSheetsOtPort(o) {
3235
3581
  for (const [id, d] of Object.entries(map)) out[id] = String(d?.name ?? "");
3236
3582
  return out;
3237
3583
  };
3238
- const openGroup = (label) => ({ label, sheets: sheetNames(), names: definedNames(), mutations: [], inverses: [], notShared: null });
3584
+ const sheetOrder = () => (o.workbook()?.getSheets() ?? []).map((ws) => ws.getSheetId());
3585
+ const openGroup = (label) => ({ label, order: sheetOrder(), sheets: sheetNames(), names: definedNames(), mutations: [], inverses: [], notShared: null });
3239
3586
  const emit = (e) => {
3240
3587
  for (const l of [...listeners]) {
3241
3588
  try {
@@ -3251,7 +3598,8 @@ function univerSheetsOtPort(o) {
3251
3598
  if (!g) return;
3252
3599
  if (g.notShared) emit({ kind: "not_shared", mutationId: g.notShared, label: g.label });
3253
3600
  else if (g.mutations.length) {
3254
- const mutations = annotateFormulas(g.mutations, g.sheets, g.names);
3601
+ const mutations = annotateSheetOps(annotateFormulas(g.mutations, g.sheets, g.names), g.order);
3602
+ if (mutations.some((m) => isStructuralMutation(m) || RESHAPE.has(m.id))) clampSelection();
3255
3603
  const known = g.inverses.every((i) => i !== void 0);
3256
3604
  const inverse = known ? annotateFormulas(g.inverses.slice().reverse().flat(), g.sheets, g.names) : void 0;
3257
3605
  emit({ kind: "group", mutations, ...inverse !== void 0 ? { inverse } : {}, label: g.label });
@@ -3285,7 +3633,27 @@ function univerSheetsOtPort(o) {
3285
3633
  }
3286
3634
  if (info.id === SHEET_NAME) record.name = ws.getName();
3287
3635
  pre.set(p, record);
3636
+ const owed = isStructuralMutation({ id: info.id, params: p }) ? mergeFixupsOwed({ id: info.id, params: p }, record.merges ?? []) : null;
3637
+ if (owed) {
3638
+ runOwn(REMOVE_MERGE, String(p.subUnitId), owed.remove, ADD_MERGE);
3639
+ if (owed.add.length) record.addAfter = owed.add;
3640
+ }
3288
3641
  });
3642
+ const runOwn = (id, sheet, ranges, inverseId) => {
3643
+ const u = unitId();
3644
+ if (!u) return;
3645
+ applying = true;
3646
+ try {
3647
+ cs.syncExecuteCommand(id, { unitId: u, subUnitId: sheet, ranges: json(ranges) }, { onlyLocal: true });
3648
+ } finally {
3649
+ applying = false;
3650
+ }
3651
+ if (!group) group = openGroup(null);
3652
+ if (!group.notShared) {
3653
+ group.mutations.push({ id, params: { subUnitId: sheet, ranges: json(ranges) } });
3654
+ group.inverses.push([{ id: inverseId, params: { subUnitId: sheet, ranges: json(ranges) } }]);
3655
+ }
3656
+ };
3289
3657
  const after = cs.onCommandExecuted((info) => {
3290
3658
  if (info.type !== COMMAND) return;
3291
3659
  const at = tracker.stack.lastIndexOf(info.id);
@@ -3383,6 +3751,8 @@ function univerSheetsOtPort(o) {
3383
3751
  if (!m2) return { m: null, inverse: void 0 };
3384
3752
  return { m: m2, inverse: [{ id: ADD_MERGE, params: { subUnitId: sheet, ranges: json(m2.params.ranges) } }] };
3385
3753
  }
3754
+ if (info.id === INSERT_SHEET && params.sheet && typeof params.sheet === "object")
3755
+ params.sheet = inlineSheetStyles(params.sheet, (id) => o.workbook()?.getStyles().get(id));
3386
3756
  const m = { id: info.id, params };
3387
3757
  switch (info.id) {
3388
3758
  case "sheet.mutation.insert-row":
@@ -3399,8 +3769,7 @@ function univerSheetsOtPort(o) {
3399
3769
  };
3400
3770
  const collab = cs.onMutationExecutedForCollab((info, options) => {
3401
3771
  if (applying || flagged(options) || !mine(info.params)) return;
3402
- const lone = !group;
3403
- if (lone) group = openGroup(null);
3772
+ if (!group) group = openGroup(null);
3404
3773
  const g = group;
3405
3774
  if (!g.notShared) {
3406
3775
  const r = capture(info);
@@ -3410,11 +3779,29 @@ function univerSheetsOtPort(o) {
3410
3779
  g.inverses.push(r.inverse);
3411
3780
  }
3412
3781
  }
3413
- if (lone && tracker.stack.length === 0) settle();
3782
+ const owedAdd = pre.get(info.params)?.addAfter;
3783
+ if (owedAdd?.length) runOwn(ADD_MERGE, String(info.params.subUnitId ?? ""), owedAdd, REMOVE_MERGE);
3784
+ if (tracker.stack.length === 0) settle();
3414
3785
  });
3786
+ const clampSelection = () => {
3787
+ const sel = o.selections;
3788
+ if (!sel) return;
3789
+ try {
3790
+ const sheet = sel.sheetId();
3791
+ const ws = sheet ? o.workbook()?.getSheetBySheetId(sheet) : null;
3792
+ const current = sel.get();
3793
+ if (!ws || !current?.length) return;
3794
+ const rows = ws.getMaxRows?.() ?? Number.MAX_SAFE_INTEGER;
3795
+ const cols = ws.getMaxColumns?.() ?? Number.MAX_SAFE_INTEGER;
3796
+ const next = moveSelectionsThrough(json(current), { id: "", params: {} }, rows, cols);
3797
+ if (JSON.stringify(next) !== JSON.stringify(current)) sel.set(next);
3798
+ } catch (err) {
3799
+ console.warn("[sheets-ot] could not keep this seat's selection inside the sheet after its own row or column change", err);
3800
+ }
3801
+ };
3415
3802
  const followSelection = (m) => {
3416
3803
  const sel = o.selections;
3417
- if (!sel || !axisOpOf(m)) return;
3804
+ if (!sel || !axisOpOf(m) && !RESHAPE.has(m.id)) return;
3418
3805
  try {
3419
3806
  const sheet = String(m.params.subUnitId ?? "");
3420
3807
  if (sel.sheetId() !== sheet) return;