@ai-matrx/office 0.8.21 → 0.8.23

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