@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.
@@ -1685,6 +1685,14 @@ var SHEET_MUTATIONS = {
1685
1685
  "sheet.mutation.set-worksheet-row-auto-height": covered("size", "rowsAutoHeightInfo"),
1686
1686
  "sheet.mutation.set-worksheet-col-width": covered("size", "ranges", "colWidth"),
1687
1687
  "sheet.mutation.set-worksheet-name": covered("name", "name"),
1688
+ // ── covered (C5c) ────────────────────────────────────────────────────────────────────────────────
1689
+ "sheet.mutation.set.numfmt": covered("numfmt", "values", "refMap"),
1690
+ "sheet.mutation.remove.numfmt": covered("numfmt", "ranges"),
1691
+ "sheet.mutation.set-worksheet-row-count": covered("count", "rowCount"),
1692
+ "sheet.mutation.set-worksheet-column-count": covered("count", "columnCount"),
1693
+ "sheet.mutation.insert-sheet": covered("sheet", "index", "sheet"),
1694
+ "sheet.mutation.remove-sheet": covered("sheet", "sheetIndex", "sheetsLeft"),
1695
+ "sheet.mutation.set-worksheet-order": covered("sheet", "fromOrder", "toOrder"),
1688
1696
  // ── never travels ────────────────────────────────────────────────────────────────────────────────
1689
1697
  "formula.mutation.set-formula-calculation-start": never(FORMULA_RESULT),
1690
1698
  "formula.mutation.set-trigger-formula-calculation-start": never(FORMULA_RESULT),
@@ -1719,12 +1727,7 @@ var SHEET_MUTATIONS = {
1719
1727
  "thread-comment.mutation.delete-comment": never(UNIVER_COMMENTS),
1720
1728
  // ── barriers: X (no transform yet, design §10) ───────────────────────────────────────────────────
1721
1729
  "sheet.mutation.reorder-range": barrier("X", "sort: a permutation, not transformed yet"),
1722
- "sheet.mutation.set-worksheet-row-count": barrier("X", "absolute row count; needs delta semantics"),
1723
- "sheet.mutation.set-worksheet-column-count": barrier("X", "absolute column count; needs delta semantics"),
1724
- "sheet.mutation.set-worksheet-order": barrier("X", "absolute sheet order; needs move semantics"),
1725
1730
  "sheet.mutation.move-range": barrier("X", "cut-paste carries the sender's cell matrices"),
1726
- "sheet.mutation.insert-sheet": barrier("X", "sheet add: not in C5a"),
1727
- "sheet.mutation.remove-sheet": barrier("X", "sheet remove: not in C5a"),
1728
1731
  "sheet.mutation.set-worksheet-hidden": barrier("X", "sheet-level setting: not in C5a"),
1729
1732
  "sheet.mutation.set-tab-color": barrier("X", "sheet-level setting: not in C5a"),
1730
1733
  "sheet.mutation.set-workbook-name": barrier("X", "workbook-level setting: not in C5a"),
@@ -1739,8 +1742,6 @@ var SHEET_MUTATIONS = {
1739
1742
  "sheet.mutation.set-row-visible": barrier("X", "row visibility: not in C5a"),
1740
1743
  "sheet.mutation.set-col-hidden": barrier("X", "column visibility: not in C5a"),
1741
1744
  "sheet.mutation.set-col-visible": barrier("X", "column visibility: not in C5a"),
1742
- "sheet.mutation.set.numfmt": barrier("X", "number formats by range: not in C5a"),
1743
- "sheet.mutation.remove.numfmt": barrier("X", "number formats by range: not in C5a"),
1744
1745
  "sheet.mutation.add-range-protection": barrier("X", "permissions: not in C5a"),
1745
1746
  "sheet.mutation.set-range-protection": barrier("X", "permissions: not in C5a"),
1746
1747
  "sheet.mutation.delete-range-protection": barrier("X", "permissions: not in C5a"),
@@ -2144,7 +2145,7 @@ function refSheetsFor(texts, sheets) {
2144
2145
  }
2145
2146
 
2146
2147
  // src/collab/sheets/transform/transform.ts
2147
- var SHEET_TRANSFORMER_VERSION = "c5b-1";
2148
+ var SHEET_TRANSFORMER_VERSION = "c5c-1";
2148
2149
  var ID = {
2149
2150
  values: "sheet.mutation.set-range-values",
2150
2151
  insertRow: "sheet.mutation.insert-row",
@@ -2161,7 +2162,14 @@ var ID = {
2161
2162
  colWidth: "sheet.mutation.set-worksheet-col-width",
2162
2163
  name: "sheet.mutation.set-worksheet-name",
2163
2164
  setName: "formula.mutation.set-defined-name",
2164
- removeName: "formula.mutation.remove-defined-name"
2165
+ removeName: "formula.mutation.remove-defined-name",
2166
+ setNumfmt: "sheet.mutation.set.numfmt",
2167
+ removeNumfmt: "sheet.mutation.remove.numfmt",
2168
+ rowCount: "sheet.mutation.set-worksheet-row-count",
2169
+ colCount: "sheet.mutation.set-worksheet-column-count",
2170
+ insertSheet: "sheet.mutation.insert-sheet",
2171
+ removeSheet: "sheet.mutation.remove-sheet",
2172
+ sheetOrder: "sheet.mutation.set-worksheet-order"
2165
2173
  };
2166
2174
  var PAIR_BARRIERS = {};
2167
2175
  var pairKey = (a, b) => a < b ? `${a}|${b}` : `${b}|${a}`;
@@ -2273,6 +2281,20 @@ function mergeThrough(s, m) {
2273
2281
  }
2274
2282
  return { range: m, fixup: false };
2275
2283
  }
2284
+ function mergeFixupsOwed(m, mergesBefore) {
2285
+ const st = structuralOf(m);
2286
+ if (!st) return null;
2287
+ const remove = [];
2288
+ const add = [];
2289
+ for (const q of mergesBefore) {
2290
+ const t = mergeThrough(st, q);
2291
+ if (!t.fixup) continue;
2292
+ remove.push({ startRow: q.startRow, endRow: q.endRow, startColumn: q.startColumn, endColumn: q.endColumn, ...q.rangeType !== void 0 ? { rangeType: q.rangeType } : {} });
2293
+ if (t.range) add.push({ ...t.range });
2294
+ }
2295
+ return remove.length ? { remove, add } : null;
2296
+ }
2297
+ var isStructuralMutation = (m) => structuralOf(m) !== null;
2276
2298
  function exactMergeRemovals(group, merges) {
2277
2299
  const sim = new Map(Object.entries(merges).map(([k, v]) => [k, v.map((r) => ({ ...r }))]));
2278
2300
  const out = [];
@@ -2319,8 +2341,24 @@ function cellsMutation(template, cells) {
2319
2341
  function putCell(cells, r, c, v) {
2320
2342
  (cells[r] ??= {})[c] = v;
2321
2343
  }
2344
+ function cellsOverlap(a, b) {
2345
+ for (const r of Object.keys(a)) {
2346
+ const br = b[r];
2347
+ if (!br) continue;
2348
+ for (const c of Object.keys(a[r] ?? {})) if (c in br) return true;
2349
+ }
2350
+ return false;
2351
+ }
2322
2352
  var isEmptyMatrix = (cells) => Object.values(cells).every((row) => Object.keys(row).length === 0);
2353
+ var cellBarrierCache = /* @__PURE__ */ new WeakMap();
2323
2354
  function cellBarrier(m) {
2355
+ const hit = cellBarrierCache.get(m);
2356
+ if (hit !== void 0) return hit;
2357
+ const why = cellBarrierOf(m);
2358
+ cellBarrierCache.set(m, why);
2359
+ return why;
2360
+ }
2361
+ function cellBarrierOf(m) {
2324
2362
  if (m.params.isOverrideStyle) return "set-range-values with isOverrideStyle (whole-style replace) is not covered";
2325
2363
  let why = null;
2326
2364
  forEachCell(cellsOf(m), (_r, _c, v) => {
@@ -2402,6 +2440,7 @@ function transformCell(X, Y4, side) {
2402
2440
  function transformCellsOverCells(x, y, side) {
2403
2441
  if (sheetOf(x) !== sheetOf(y)) return ok([x]);
2404
2442
  const ycells = cellsOf(y);
2443
+ if (!cellsOverlap(cellsOf(x), ycells)) return ok([x]);
2405
2444
  const xd = isDerived(x);
2406
2445
  const yd = isDerived(y);
2407
2446
  const eff = derivedSide(x, y, side);
@@ -2429,7 +2468,7 @@ function transformCellsOverCells(x, y, side) {
2429
2468
  const op = passes.filter((p) => !isEmptyMatrix(p)).map((p) => cellsMutation(x, p));
2430
2469
  return ok(op, lost, dropped);
2431
2470
  }
2432
- var SIDE_CAR_PARAMS = ["refSheets", "previousName", "derived"];
2471
+ var SIDE_CAR_PARAMS = ["refSheets", "previousName", "derived", "sheetIndex", "sheetsLeft"];
2433
2472
  var isDerived = (m) => m.params.derived === true;
2434
2473
  function derivedSide(x, y, side) {
2435
2474
  const xd = isDerived(x);
@@ -2451,7 +2490,15 @@ function withRefSheets(params, rs) {
2451
2490
  return out;
2452
2491
  }
2453
2492
  var hasFormulaText = (v) => !!v && (isFormulaText(v.f) || typeof v.ref === "string");
2493
+ var hasFormulaCache = /* @__PURE__ */ new WeakMap();
2454
2494
  function hasFormula(m) {
2495
+ const hit = hasFormulaCache.get(m);
2496
+ if (hit !== void 0) return hit;
2497
+ const any = hasFormulaOf(m);
2498
+ hasFormulaCache.set(m, any);
2499
+ return any;
2500
+ }
2501
+ function hasFormulaOf(m) {
2455
2502
  let any = false;
2456
2503
  forEachCell(cellsOf(m), (_r, _c, v) => {
2457
2504
  any ||= hasFormulaText(v);
@@ -2490,15 +2537,18 @@ function cellThrough(sheet, change, r, c) {
2490
2537
  return nr === null || nc === null ? null : [nr, nc];
2491
2538
  }
2492
2539
  function cellsOverChange(x, change) {
2540
+ if (!hasFormula(x) && (change.kind !== "axis" || change.sheet !== sheetOf(x))) return ok([x]);
2493
2541
  const ctx = formulaCtx(x);
2494
2542
  const out = {};
2495
2543
  const dropped = [];
2496
2544
  let why = null;
2545
+ let changed = false;
2497
2546
  forEachCell(cellsOf(x), (r, c, v) => {
2498
2547
  if (why) return;
2499
2548
  const at = cellThrough(sheetOf(x), change, r, c);
2500
2549
  if (!at) {
2501
2550
  dropped.push(cellRef(sheetOf(x), r, c));
2551
+ changed = true;
2502
2552
  return;
2503
2553
  }
2504
2554
  let e = v;
@@ -2509,14 +2559,19 @@ function cellsOverChange(x, change) {
2509
2559
  return;
2510
2560
  }
2511
2561
  e = res.entry;
2562
+ if (res.changed) changed = true;
2512
2563
  }
2564
+ if (at[0] !== r || at[1] !== c) changed = true;
2513
2565
  putCell(out, at[0], at[1], e);
2514
2566
  });
2515
2567
  if (why) return barrier2(why);
2516
- const params = { ...withRefSheets(x.params, refSheetsAfter(ctx.refSheets, change)), cellValue: out };
2568
+ const rsAfter = refSheetsAfter(ctx.refSheets, change);
2569
+ if (!changed && JSON.stringify(rsAfter ?? null) === JSON.stringify(ctx.refSheets ?? null)) return ok([x]);
2570
+ const params = { ...withRefSheets(x.params, rsAfter), cellValue: out };
2517
2571
  return ok(isEmptyMatrix(out) ? [] : [{ id: x.id, params }], [], dropped);
2518
2572
  }
2519
2573
  function rewritesOf(y, change) {
2574
+ if (!hasFormula(y)) return null;
2520
2575
  const ctx = formulaCtx(y);
2521
2576
  const out = {};
2522
2577
  let why = null;
@@ -2662,6 +2717,255 @@ function buildSize(template, values) {
2662
2717
  const value = uniform !== void 0 && [...values.values()].every((v) => v === uniform) ? uniform : Object.fromEntries(values);
2663
2718
  return { id: template.id, params: { ...p, ranges, [field]: value } };
2664
2719
  }
2720
+ var isNumfmt = (m) => m.id === ID.setNumfmt || m.id === ID.removeNumfmt;
2721
+ function nfParts(m) {
2722
+ if (m.id === ID.removeNumfmt) return [{ key: null, ranges: (m.params.ranges ?? []).map((r) => ({ ...r })) }];
2723
+ const values = m.params.values ?? {};
2724
+ return Object.keys(values).map((k) => ({ key: k, ranges: (values[k]?.ranges ?? []).map((r) => ({ ...r })) }));
2725
+ }
2726
+ function nfBuild(m, parts) {
2727
+ const keep = parts.filter((p) => p.ranges.length);
2728
+ if (!keep.length) return [];
2729
+ if (m.id === ID.removeNumfmt) return [{ id: m.id, params: { ...m.params, ranges: keep[0].ranges } }];
2730
+ const values = {};
2731
+ const refMap = {};
2732
+ const srcValues = m.params.values ?? {};
2733
+ const srcRef = m.params.refMap ?? {};
2734
+ for (const p of keep) {
2735
+ values[p.key] = { ...srcValues[p.key], ranges: p.ranges };
2736
+ refMap[p.key] = srcRef[p.key];
2737
+ }
2738
+ return [{ id: m.id, params: { ...m.params, values, refMap } }];
2739
+ }
2740
+ function nfValueAt(m, row, col) {
2741
+ for (const p of nfParts(m))
2742
+ if (p.ranges.some((r) => r.startRow <= row && row <= r.endRow && r.startColumn <= col && col <= r.endColumn)) {
2743
+ if (p.key === null) return null;
2744
+ const ref = (m.params.refMap ?? {})[p.key];
2745
+ return { pattern: ref?.pattern };
2746
+ }
2747
+ return void 0;
2748
+ }
2749
+ function spanThrough(op, lo, hi) {
2750
+ const pieces = [];
2751
+ if (op.kind === "insert") pieces.push([0, op.at - 1, 0], [op.at, Infinity, op.count]);
2752
+ else if (op.kind === "remove") pieces.push([0, op.start - 1, 0], [op.start + op.count, Infinity, -op.count]);
2753
+ else if (op.count <= 0 || op.to >= op.from && op.to <= op.from + op.count) pieces.push([0, Infinity, 0]);
2754
+ else if (op.to > op.from) {
2755
+ const n = op.count;
2756
+ 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]);
2757
+ } else {
2758
+ const n = op.count;
2759
+ 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]);
2760
+ }
2761
+ const out = [];
2762
+ for (const [a, b, d] of pieces) {
2763
+ const x0 = Math.max(a, lo);
2764
+ const x1 = Math.min(b, hi);
2765
+ if (x0 <= x1) out.push([x0 + d, x1 + d]);
2766
+ }
2767
+ out.sort((p, q) => p[0] - q[0]);
2768
+ const merged = [];
2769
+ for (const p of out) {
2770
+ const last = merged[merged.length - 1];
2771
+ if (last && last[1] + 1 >= p[0]) last[1] = Math.max(last[1], p[1]);
2772
+ else merged.push([p[0], p[1]]);
2773
+ }
2774
+ return merged;
2775
+ }
2776
+ function rectsThrough(st, rects) {
2777
+ const [a0, a1] = S(st.axis);
2778
+ const out = [];
2779
+ for (const r of rects) for (const [lo, hi] of spanThrough(st.op, r[a0], r[a1])) out.push({ ...r, [a0]: lo, [a1]: hi });
2780
+ return out;
2781
+ }
2782
+ function rectMinus(a, b) {
2783
+ if (a.startRow > b.endRow || b.startRow > a.endRow || a.startColumn > b.endColumn || b.startColumn > a.endColumn) return [a];
2784
+ const out = [];
2785
+ if (a.startRow < b.startRow) out.push({ ...a, endRow: b.startRow - 1 });
2786
+ if (a.endRow > b.endRow) out.push({ ...a, startRow: b.endRow + 1 });
2787
+ const r0 = Math.max(a.startRow, b.startRow);
2788
+ const r1 = Math.min(a.endRow, b.endRow);
2789
+ if (a.startColumn < b.startColumn) out.push({ ...a, startRow: r0, endRow: r1, endColumn: b.startColumn - 1 });
2790
+ if (a.endColumn > b.endColumn) out.push({ ...a, startRow: r0, endRow: r1, startColumn: b.endColumn + 1 });
2791
+ return out;
2792
+ }
2793
+ function rectsMinus(as, bs) {
2794
+ let cur = as;
2795
+ for (const b of bs) cur = cur.flatMap((a) => rectMinus(a, b));
2796
+ return cur;
2797
+ }
2798
+ function nWrites(m) {
2799
+ const out = [];
2800
+ forEachCell(cellsOf(m), (r, c, v) => {
2801
+ if (v === null || v.s === null || v.s && typeof v.s === "object" && "n" in v.s)
2802
+ out.push({ startRow: r, endRow: r, startColumn: c, endColumn: c });
2803
+ });
2804
+ return out;
2805
+ }
2806
+ function numfmtPair(x, y, side, sx, sy) {
2807
+ const nx = isNumfmt(x);
2808
+ const ny = isNumfmt(y);
2809
+ if (!nx && !ny) return null;
2810
+ if (nx && sy) return ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsThrough(sy, p.ranges) }))));
2811
+ if (ny && sx) return ok([x]);
2812
+ if (nx && ny) {
2813
+ if (side === "left") return ok([x]);
2814
+ const ys = nfParts(y).flatMap((p) => p.ranges);
2815
+ return ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsMinus(p.ranges, ys) }))));
2816
+ }
2817
+ if (nx && y.id === ID.values) {
2818
+ if (side === "left") return ok([x]);
2819
+ const ys = nWrites(y);
2820
+ return ys.length ? ok(nfBuild(x, nfParts(x).map((p) => ({ ...p, ranges: rectsMinus(p.ranges, ys) })))) : ok([x]);
2821
+ }
2822
+ if (ny && x.id === ID.values) {
2823
+ if (side === "left") return ok([x]);
2824
+ const out = {};
2825
+ const tail = {};
2826
+ let touched = false;
2827
+ forEachCell(cellsOf(x), (r, c, v) => {
2828
+ const n = nfValueAt(y, r, c);
2829
+ if (n === void 0) return putCell(out, r, c, v);
2830
+ if (v === null || v.s === null) {
2831
+ putCell(out, r, c, v);
2832
+ if (n) {
2833
+ putCell(tail, r, c, { s: { n } });
2834
+ touched = true;
2835
+ }
2836
+ return;
2837
+ }
2838
+ if (v.s && typeof v.s === "object" && "n" in v.s) {
2839
+ const { n: _drop, ...rest } = v.s;
2840
+ const e = { ...v };
2841
+ if (Object.keys(rest).length) e.s = rest;
2842
+ else delete e.s;
2843
+ touched = true;
2844
+ if (Object.keys(e).length) putCell(out, r, c, e);
2845
+ return;
2846
+ }
2847
+ putCell(out, r, c, v);
2848
+ });
2849
+ if (!touched) return ok([x]);
2850
+ const ops = [];
2851
+ if (!isEmptyMatrix(out)) ops.push(cellsMutation(x, out));
2852
+ if (!isEmptyMatrix(tail)) ops.push({ id: ID.values, params: { subUnitId: sheetOf(x), cellValue: tail } });
2853
+ return ok(ops);
2854
+ }
2855
+ return ok([x]);
2856
+ }
2857
+ var isCount = (m) => m.id === ID.rowCount || m.id === ID.colCount;
2858
+ var countAxis = (m) => m.id === ID.rowCount ? "row" : "col";
2859
+ var countKey = (m) => m.id === ID.rowCount ? "rowCount" : "columnCount";
2860
+ function countPair(x, y, sy) {
2861
+ if (!isCount(x)) return isCount(y) ? ok([x]) : null;
2862
+ const k = countKey(x);
2863
+ const v = Number(x.params[k]);
2864
+ if (sy) {
2865
+ if (sy.axis !== countAxis(x) || sy.op.kind === "move") return ok([x]);
2866
+ const d = sy.op.kind === "insert" ? sy.op.count : -sy.op.count;
2867
+ return ok([{ id: x.id, params: { ...x.params, [k]: Math.max(1, v + d) } }]);
2868
+ }
2869
+ if (isCount(y) && y.id === x.id) {
2870
+ const w = Number(y.params[k]);
2871
+ return ok([w > v ? { id: x.id, params: { ...x.params, [k]: w } } : x]);
2872
+ }
2873
+ return ok([x]);
2874
+ }
2875
+ var isSheetOp = (m) => m.id === ID.insertSheet || m.id === ID.removeSheet || m.id === ID.sheetOrder;
2876
+ var sheetIdOf = (m) => m.id === ID.insertSheet ? String(m.params.sheet?.id ?? "") : sheetOf(m);
2877
+ function sheetAxisOf(m) {
2878
+ const p = m.params;
2879
+ if (m.id === ID.insertSheet) return typeof p.index === "number" ? { kind: "insert", at: p.index, count: 1 } : null;
2880
+ if (m.id === ID.removeSheet) return typeof p.sheetIndex === "number" ? { kind: "remove", start: p.sheetIndex, count: 1 } : null;
2881
+ if (m.id === ID.sheetOrder) {
2882
+ const f = Number(p.fromOrder);
2883
+ const t = Number(p.toOrder);
2884
+ return { kind: "move", from: f, count: 1, to: t > f ? t + 1 : t };
2885
+ }
2886
+ return null;
2887
+ }
2888
+ function buildSheetOp(template, op) {
2889
+ if (op.kind === "insert") return { id: template.id, params: { ...template.params, index: op.at } };
2890
+ if (op.kind === "remove") return { id: template.id, params: { ...template.params, sheetIndex: op.start } };
2891
+ return { id: template.id, params: { ...template.params, fromOrder: op.from, toOrder: op.to > op.from ? op.to - 1 : op.to } };
2892
+ }
2893
+ function namesSheet(m, id) {
2894
+ const rs = refSheetsOf(m);
2895
+ return !!rs && Object.values(rs).includes(id) && (m.id === ID.setName || hasFormula(m));
2896
+ }
2897
+ function sheetPair(x, y, side) {
2898
+ const xs = isSheetOp(x);
2899
+ const ys = isSheetOp(y);
2900
+ if (!xs && !ys) return null;
2901
+ if (xs && ys) {
2902
+ const a = sheetAxisOf(x);
2903
+ const b = sheetAxisOf(y);
2904
+ if (!a || !b) return barrier2("a sheet add or remove without its index (capture must call annotateSheetOps)");
2905
+ if (x.id === ID.insertSheet && y.id === ID.insertSheet && sheetIdOf(x) === sheetIdOf(y)) {
2906
+ return JSON.stringify(x.params) === JSON.stringify(y.params) ? ok([]) : barrier2("the same sheet id added twice with different content");
2907
+ }
2908
+ if (x.id === ID.removeSheet && typeof x.params.sheetsLeft === "number" && sheetIdOf(x) !== sheetIdOf(y) && (y.id === ID.removeSheet || y.id === ID.insertSheet)) {
2909
+ const left = x.params.sheetsLeft + (y.id === ID.insertSheet ? 1 : -1);
2910
+ if (left < 1) return barrier2("concurrent sheet removes would leave the workbook without a sheet");
2911
+ const out2 = transformAxis(a, b, side);
2912
+ if (!out2) return barrier2("sheet order: no transform");
2913
+ return ok(out2.map((o) => buildSheetOp({ id: x.id, params: { ...x.params, sheetsLeft: left } }, o)));
2914
+ }
2915
+ const out = transformAxis(a, b, side);
2916
+ if (!out) return barrier2("sheet order: no transform");
2917
+ return ok(out.map((o) => buildSheetOp(x, o)), [], out.length === 0 && x.id === ID.sheetOrder ? [`${sheetIdOf(x)}: sheet order`] : []);
2918
+ }
2919
+ if (ys) {
2920
+ if (y.id !== ID.removeSheet) return ok([x]);
2921
+ const gone2 = sheetOf(y);
2922
+ if (namesSheet(x, gone2)) return barrier2("a formula names a sheet removed at the same time");
2923
+ if (sheetOf(x) === gone2 && x.id !== ID.setName && x.id !== ID.removeName)
2924
+ return ok([], [], isDerived(x) ? [] : [`${gone2}: the sheet was removed`]);
2925
+ return ok([x]);
2926
+ }
2927
+ if (x.id !== ID.removeSheet) return ok([x]);
2928
+ const gone = sheetOf(x);
2929
+ if (namesSheet(y, gone)) return barrier2("a formula names a sheet removed at the same time");
2930
+ return ok([x], sheetOf(y) === gone && !isDerived(y) && y.id !== ID.setName && y.id !== ID.removeName ? [`${gone}: the sheet was removed`] : []);
2931
+ }
2932
+ function annotateSheetOps(group, sheetOrder) {
2933
+ const order = [...sheetOrder];
2934
+ return group.map((m) => {
2935
+ if (m.id === ID.insertSheet) {
2936
+ const index = typeof m.params.index === "number" ? Math.min(m.params.index, order.length) : order.length;
2937
+ order.splice(index, 0, sheetIdOf(m));
2938
+ return index === m.params.index ? m : { id: m.id, params: { ...m.params, index } };
2939
+ }
2940
+ if (m.id === ID.removeSheet) {
2941
+ const i = order.indexOf(sheetOf(m));
2942
+ if (i >= 0) order.splice(i, 1);
2943
+ return i >= 0 ? { id: m.id, params: { ...m.params, sheetIndex: i, sheetsLeft: order.length } } : m;
2944
+ }
2945
+ if (m.id === ID.sheetOrder) {
2946
+ const f = Number(m.params.fromOrder);
2947
+ const [id] = order.splice(f, 1);
2948
+ order.splice(Number(m.params.toOrder), 0, id ?? sheetOf(m));
2949
+ }
2950
+ return m;
2951
+ });
2952
+ }
2953
+ function inlineSheetStyles(sheet, styleOf) {
2954
+ const out = JSON.parse(JSON.stringify(sheet));
2955
+ const fix = (o) => {
2956
+ if (o && typeof o.s === "string") {
2957
+ const st = styleOf(o.s);
2958
+ if (st) o.s = JSON.parse(JSON.stringify(st));
2959
+ }
2960
+ };
2961
+ for (const row of Object.values(out.cellData ?? {})) for (const cell of Object.values(row ?? {})) fix(cell);
2962
+ for (const key of ["rowData", "columnData"]) for (const v of Object.values(out[key] ?? {})) fix(v);
2963
+ if (typeof out.defaultStyle === "string") {
2964
+ const st = styleOf(out.defaultStyle);
2965
+ if (st) out.defaultStyle = JSON.parse(JSON.stringify(st));
2966
+ }
2967
+ return out;
2968
+ }
2665
2969
  function familyOf(id) {
2666
2970
  const e = SHEET_MUTATIONS[id];
2667
2971
  return e && e.kind === "covered" ? e.family : "";
@@ -2678,6 +2982,8 @@ function transformMutation(x, y, side) {
2678
2982
  }
2679
2983
  const pb = PAIR_BARRIERS[pairKey(x.id, y.id)];
2680
2984
  if (pb) return barrier2(`${x.id} \xD7 ${y.id}: ${pb.reason}${pb.seed === null ? "" : ` (fuzz seed ${pb.seed})`}`);
2985
+ const sp = sheetPair(x, y, side);
2986
+ if (sp) return sp;
2681
2987
  const fp = formulaPair(x, y, side);
2682
2988
  if (fp) return fp;
2683
2989
  if (sheetOf(x) !== sheetOf(y)) return ok([x]);
@@ -2685,6 +2991,10 @@ function transformMutation(x, y, side) {
2685
2991
  const fy = familyOf(y.id);
2686
2992
  const sy = structuralOf(y);
2687
2993
  const sx = structuralOf(x);
2994
+ const cp = countPair(x, y, sy);
2995
+ if (cp) return cp;
2996
+ const np = numfmtPair(x, y, side, sx, sy);
2997
+ if (np) return np;
2688
2998
  if (sx && sy) {
2689
2999
  if (sx.axis !== sy.axis) return ok([x]);
2690
3000
  const out = transformAxis(sx.op, sy.op, side);
@@ -2792,22 +3102,45 @@ function tSeq(xs, ys, side, acc) {
2792
3102
  acc.dropped.push(...a.dropped);
2793
3103
  return [a.op, b.op];
2794
3104
  }
3105
+ const outX = [];
3106
+ let curY = ys;
3107
+ for (const x of xs) {
3108
+ let curX = [x];
3109
+ const nextY = [];
3110
+ for (const y of curY) {
3111
+ if (curX.length === 0) {
3112
+ nextY.push(y);
3113
+ continue;
3114
+ }
3115
+ const r = tSeq(curX, [y], side, acc);
3116
+ if (blocked(r)) return r;
3117
+ curX = r[0];
3118
+ for (const m of r[1]) nextY.push(m);
3119
+ }
3120
+ for (const m of curX) outX.push(m);
3121
+ curY = nextY;
3122
+ }
3123
+ return [outX, curY];
3124
+ }
3125
+ function tSeqOld(xs, ys, side, acc) {
3126
+ if (xs.length === 0 || ys.length === 0) return [xs, ys];
3127
+ if (xs.length === 1 && ys.length === 1) return tSeq(xs, ys, side, acc);
2795
3128
  if (xs.length > 1) {
2796
- const first2 = tSeq([xs[0]], ys, side, acc);
3129
+ const first2 = tSeqOld([xs[0]], ys, side, acc);
2797
3130
  if (blocked(first2)) return first2;
2798
- const rest2 = tSeq(xs.slice(1), first2[1], side, acc);
3131
+ const rest2 = tSeqOld(xs.slice(1), first2[1], side, acc);
2799
3132
  if (blocked(rest2)) return rest2;
2800
3133
  return [[...first2[0], ...rest2[0]], rest2[1]];
2801
3134
  }
2802
- const first = tSeq(xs, [ys[0]], side, acc);
3135
+ const first = tSeqOld(xs, [ys[0]], side, acc);
2803
3136
  if (blocked(first)) return first;
2804
- const rest = tSeq(first[0], ys.slice(1), side, acc);
3137
+ const rest = tSeqOld(first[0], ys.slice(1), side, acc);
2805
3138
  if (blocked(rest)) return rest;
2806
3139
  return [rest[0], [...first[1], ...rest[1]]];
2807
3140
  }
2808
3141
  function transformGroup(x, y, side) {
2809
3142
  const acc = { lost: [], dropped: [] };
2810
- const r = tSeq([...x], [...y], side, acc);
3143
+ const r = (process.env.OLD_TSEQ ? tSeqOld : tSeq)([...x], [...y], side, acc);
2811
3144
  if (blocked(r)) return r;
2812
3145
  return { op: r[0], lost: [...new Set(acc.lost)], dropped: [...new Set(acc.dropped)] };
2813
3146
  }
@@ -2877,7 +3210,7 @@ async function sheetsStateHash(snapshot) {
2877
3210
  }
2878
3211
 
2879
3212
  // src/univer/collab/sheets-ot/room.ts
2880
- var SHEETS_COLLAB_PROTO = 1;
3213
+ var SHEETS_COLLAB_PROTO = 2;
2881
3214
  var SHEETS_EDIT_GROUP = "sheets.edit";
2882
3215
  var flip2 = (side) => side === "left" ? "right" : "left";
2883
3216
  var isNoopSheetOp = (op) => op == null || op.length === 0;
@@ -2924,6 +3257,11 @@ function travelingShape(m) {
2924
3257
  }
2925
3258
  return { id: m.id, params };
2926
3259
  }
3260
+ var shapedLists = /* @__PURE__ */ new WeakMap();
3261
+ function cachedShape(list) {
3262
+ const hit = shapedLists.get(list);
3263
+ return hit && hit.src.length === list.length && hit.src.every((m, i) => m === list[i]) ? hit.shaped : null;
3264
+ }
2927
3265
  function rebaseSheetUndoStack(items, remote, unitId) {
2928
3266
  if (isNoopSheetOp(remote)) return 0;
2929
3267
  let dropped = 0;
@@ -2935,7 +3273,11 @@ function rebaseSheetUndoStack(items, remote, unitId) {
2935
3273
  if (!ok2 || !list?.length) continue;
2936
3274
  const isOperation = (id) => !SHEET_MUTATIONS[id] && id.includes(".operation.");
2937
3275
  const operations = list.filter((m) => isOperation(m.id));
2938
- const shaped = list.filter((m) => !isOperation(m.id)).map(travelingShape);
3276
+ let shaped = cachedShape(list);
3277
+ if (!shaped) {
3278
+ shaped = list.filter((m) => !isOperation(m.id)).map(travelingShape);
3279
+ shapedLists.set(list, { src: list.slice(), shaped });
3280
+ }
2939
3281
  if (shaped.some((m) => m === null)) {
2940
3282
  ok2 = false;
2941
3283
  continue;
@@ -2947,8 +3289,10 @@ function rebaseSheetUndoStack(items, remote, unitId) {
2947
3289
  ok2 = false;
2948
3290
  continue;
2949
3291
  }
2950
- if (JSON.stringify(r.op) === JSON.stringify(shaped)) continue;
2951
- item[key] = [...r.op.map((m) => ({ id: m.id, params: { ...forApply(m).params, unitId } })), ...operations];
3292
+ if (r.op.length === shaped.length && r.op.every((m, i2) => m === shaped[i2])) continue;
3293
+ const next = [...r.op.map((m) => ({ id: m.id, params: { ...forApply(m).params, unitId } })), ...operations];
3294
+ shapedLists.set(next, { src: next.slice(), shaped: r.op });
3295
+ item[key] = next;
2952
3296
  } catch {
2953
3297
  ok2 = false;
2954
3298
  }
@@ -3023,7 +3367,7 @@ function createSheetsOtAdapter(port, hooks = {}) {
3023
3367
  });
3024
3368
  });
3025
3369
  }
3026
- return sheetsStateHash(port.snapshot());
3370
+ return (hooks.stateHash ?? sheetsStateHash)(port.snapshot());
3027
3371
  },
3028
3372
  held: () => queue.length,
3029
3373
  rebaseLocalOverHeld(local) {
@@ -3135,6 +3479,8 @@ var VALUES = "sheet.mutation.set-range-values";
3135
3479
  var ADD_MERGE = "sheet.mutation.add-worksheet-merge";
3136
3480
  var REMOVE_MERGE = "sheet.mutation.remove-worksheet-merge";
3137
3481
  var SHEET_NAME = "sheet.mutation.set-worksheet-name";
3482
+ var INSERT_SHEET = "sheet.mutation.insert-sheet";
3483
+ var RESHAPE = /* @__PURE__ */ new Set(["sheet.mutation.set-worksheet-row-count", "sheet.mutation.set-worksheet-column-count", "sheet.mutation.remove-sheet", INSERT_SHEET]);
3138
3484
  var DEPTH_GUARD = /* @__PURE__ */ Symbol.for("ai-matrx.office.sheets.command-depth-guard");
3139
3485
  var json = (v) => v === void 0 ? v : JSON.parse(JSON.stringify(v));
3140
3486
  var flagged = (options) => {
@@ -3171,7 +3517,8 @@ function univerSheetsOtPort(o) {
3171
3517
  for (const [id, d] of Object.entries(map)) out[id] = String(d?.name ?? "");
3172
3518
  return out;
3173
3519
  };
3174
- const openGroup = (label) => ({ label, sheets: sheetNames(), names: definedNames(), mutations: [], inverses: [], notShared: null });
3520
+ const sheetOrder = () => (o.workbook()?.getSheets() ?? []).map((ws) => ws.getSheetId());
3521
+ const openGroup = (label) => ({ label, order: sheetOrder(), sheets: sheetNames(), names: definedNames(), mutations: [], inverses: [], notShared: null });
3175
3522
  const emit = (e) => {
3176
3523
  for (const l of [...listeners]) {
3177
3524
  try {
@@ -3187,7 +3534,8 @@ function univerSheetsOtPort(o) {
3187
3534
  if (!g) return;
3188
3535
  if (g.notShared) emit({ kind: "not_shared", mutationId: g.notShared, label: g.label });
3189
3536
  else if (g.mutations.length) {
3190
- const mutations = annotateFormulas(g.mutations, g.sheets, g.names);
3537
+ const mutations = annotateSheetOps(annotateFormulas(g.mutations, g.sheets, g.names), g.order);
3538
+ if (mutations.some((m) => isStructuralMutation(m) || RESHAPE.has(m.id))) clampSelection();
3191
3539
  const known = g.inverses.every((i) => i !== void 0);
3192
3540
  const inverse = known ? annotateFormulas(g.inverses.slice().reverse().flat(), g.sheets, g.names) : void 0;
3193
3541
  emit({ kind: "group", mutations, ...inverse !== void 0 ? { inverse } : {}, label: g.label });
@@ -3221,7 +3569,27 @@ function univerSheetsOtPort(o) {
3221
3569
  }
3222
3570
  if (info.id === SHEET_NAME) record.name = ws.getName();
3223
3571
  pre.set(p, record);
3572
+ const owed = isStructuralMutation({ id: info.id, params: p }) ? mergeFixupsOwed({ id: info.id, params: p }, record.merges ?? []) : null;
3573
+ if (owed) {
3574
+ runOwn(REMOVE_MERGE, String(p.subUnitId), owed.remove, ADD_MERGE);
3575
+ if (owed.add.length) record.addAfter = owed.add;
3576
+ }
3224
3577
  });
3578
+ const runOwn = (id, sheet, ranges, inverseId) => {
3579
+ const u = unitId();
3580
+ if (!u) return;
3581
+ applying = true;
3582
+ try {
3583
+ cs.syncExecuteCommand(id, { unitId: u, subUnitId: sheet, ranges: json(ranges) }, { onlyLocal: true });
3584
+ } finally {
3585
+ applying = false;
3586
+ }
3587
+ if (!group) group = openGroup(null);
3588
+ if (!group.notShared) {
3589
+ group.mutations.push({ id, params: { subUnitId: sheet, ranges: json(ranges) } });
3590
+ group.inverses.push([{ id: inverseId, params: { subUnitId: sheet, ranges: json(ranges) } }]);
3591
+ }
3592
+ };
3225
3593
  const after = cs.onCommandExecuted((info) => {
3226
3594
  if (info.type !== COMMAND) return;
3227
3595
  const at = tracker.stack.lastIndexOf(info.id);
@@ -3319,6 +3687,8 @@ function univerSheetsOtPort(o) {
3319
3687
  if (!m2) return { m: null, inverse: void 0 };
3320
3688
  return { m: m2, inverse: [{ id: ADD_MERGE, params: { subUnitId: sheet, ranges: json(m2.params.ranges) } }] };
3321
3689
  }
3690
+ if (info.id === INSERT_SHEET && params.sheet && typeof params.sheet === "object")
3691
+ params.sheet = inlineSheetStyles(params.sheet, (id) => o.workbook()?.getStyles().get(id));
3322
3692
  const m = { id: info.id, params };
3323
3693
  switch (info.id) {
3324
3694
  case "sheet.mutation.insert-row":
@@ -3335,8 +3705,7 @@ function univerSheetsOtPort(o) {
3335
3705
  };
3336
3706
  const collab = cs.onMutationExecutedForCollab((info, options) => {
3337
3707
  if (applying || flagged(options) || !mine(info.params)) return;
3338
- const lone = !group;
3339
- if (lone) group = openGroup(null);
3708
+ if (!group) group = openGroup(null);
3340
3709
  const g = group;
3341
3710
  if (!g.notShared) {
3342
3711
  const r = capture(info);
@@ -3346,11 +3715,29 @@ function univerSheetsOtPort(o) {
3346
3715
  g.inverses.push(r.inverse);
3347
3716
  }
3348
3717
  }
3349
- if (lone && tracker.stack.length === 0) settle();
3718
+ const owedAdd = pre.get(info.params)?.addAfter;
3719
+ if (owedAdd?.length) runOwn(ADD_MERGE, String(info.params.subUnitId ?? ""), owedAdd, REMOVE_MERGE);
3720
+ if (tracker.stack.length === 0) settle();
3350
3721
  });
3722
+ const clampSelection = () => {
3723
+ const sel = o.selections;
3724
+ if (!sel) return;
3725
+ try {
3726
+ const sheet = sel.sheetId();
3727
+ const ws = sheet ? o.workbook()?.getSheetBySheetId(sheet) : null;
3728
+ const current = sel.get();
3729
+ if (!ws || !current?.length) return;
3730
+ const rows = ws.getMaxRows?.() ?? Number.MAX_SAFE_INTEGER;
3731
+ const cols = ws.getMaxColumns?.() ?? Number.MAX_SAFE_INTEGER;
3732
+ const next = moveSelectionsThrough(json(current), { id: "", params: {} }, rows, cols);
3733
+ if (JSON.stringify(next) !== JSON.stringify(current)) sel.set(next);
3734
+ } catch (err) {
3735
+ console.warn("[sheets-ot] could not keep this seat's selection inside the sheet after its own row or column change", err);
3736
+ }
3737
+ };
3351
3738
  const followSelection = (m) => {
3352
3739
  const sel = o.selections;
3353
- if (!sel || !axisOpOf(m)) return;
3740
+ if (!sel || !axisOpOf(m) && !RESHAPE.has(m.id)) return;
3354
3741
  try {
3355
3742
  const sheet = String(m.params.subUnitId ?? "");
3356
3743
  if (sel.sheetId() !== sheet) return;