@ai-matrx/office 0.8.11 → 0.8.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -1
- package/dist/collab-sheets-transform.cjs +457 -39
- package/dist/collab-sheets-transform.cjs.map +1 -1
- package/dist/collab-sheets-transform.d.cts +65 -7
- package/dist/collab-sheets-transform.d.ts +65 -7
- package/dist/collab-sheets-transform.js +463 -36
- package/dist/collab-sheets-transform.js.map +1 -1
- package/dist/docs.cjs +35 -21
- package/dist/docs.cjs.map +1 -1
- package/dist/docs.d.cts +32 -2
- package/dist/docs.d.ts +32 -2
- package/dist/docs.js +16 -2
- package/dist/docs.js.map +1 -1
- package/dist/univer-collab.cjs +201 -5
- package/dist/univer-collab.cjs.map +1 -1
- package/dist/univer-collab.d.cts +71 -2
- package/dist/univer-collab.d.ts +71 -2
- package/dist/univer-collab.js +201 -5
- package/dist/univer-collab.js.map +1 -1
- package/dist/univer.cjs +4 -0
- package/dist/univer.cjs.map +1 -1
- package/dist/univer.d.cts +3 -1
- package/dist/univer.d.ts +3 -1
- package/dist/univer.js +4 -0
- package/dist/univer.js.map +1 -1
- package/package.json +5 -5
|
@@ -6,12 +6,11 @@ var covered = (family, ...allow) => ({ kind: "covered", family, allow: ["subUnit
|
|
|
6
6
|
var never = (reason) => ({ kind: "never-travels", reason });
|
|
7
7
|
var barrier = (until, reason) => ({ kind: "barrier", until, reason });
|
|
8
8
|
var FORMULA_RESULT = "formula engine output; every seat computes it (dropped at capture)";
|
|
9
|
-
var FORMULA = "formula state; C5b rewrites references";
|
|
10
9
|
var RESOURCE = "ranged resource keyed by id; C5c";
|
|
11
10
|
var UNIVER_COMMENTS = "Univer's own thread-comment store; our comments anchor elsewhere (design \xA78)";
|
|
12
11
|
var SHEET_MUTATIONS = {
|
|
13
12
|
// ── covered (C5a) ────────────────────────────────────────────────────────────────────────────────
|
|
14
|
-
"sheet.mutation.set-range-values": covered("cell", "cellValue"),
|
|
13
|
+
"sheet.mutation.set-range-values": covered("cell", "cellValue", "refSheets", "derived"),
|
|
15
14
|
"sheet.mutation.insert-row": covered("structure", "range", "rowInfo"),
|
|
16
15
|
"sheet.mutation.remove-rows": covered("structure", "range"),
|
|
17
16
|
"sheet.mutation.insert-col": covered("structure", "range", "colInfo"),
|
|
@@ -88,16 +87,16 @@ var SHEET_MUTATIONS = {
|
|
|
88
87
|
"sheet.mutation.set-worksheet-protection": barrier("X", "permissions: not in C5a"),
|
|
89
88
|
"sheet.mutation.delete-worksheet-protection": barrier("X", "permissions: not in C5a"),
|
|
90
89
|
"sheet.mutation.set-worksheet-permission-points": barrier("X", "permissions: not in C5a"),
|
|
91
|
-
// ──
|
|
92
|
-
"formula.mutation.set-defined-name":
|
|
93
|
-
"formula.mutation.remove-defined-name":
|
|
94
|
-
"formula.mutation.set-feature-calculation": barrier("
|
|
95
|
-
"formula.mutation.remove-feature-calculation": barrier("
|
|
96
|
-
"formula.mutation.set-other-formula": barrier("
|
|
97
|
-
"formula.mutation.remove-other-formula": barrier("
|
|
98
|
-
"formula.mutation.set-super-table": barrier("
|
|
99
|
-
"formula.mutation.remove-super-table": barrier("
|
|
100
|
-
"formula.mutation.set-super-table-option": barrier("
|
|
90
|
+
// ── formulas (C5b) ───────────────────────────────────────────────────────────────────────────────
|
|
91
|
+
"formula.mutation.set-defined-name": covered("defname", "id", "name", "formulaOrRefString", "formulaOrRefStringWithPrefix", "comment", "localSheetId", "hidden", "refSheets", "previousName", "derived"),
|
|
92
|
+
"formula.mutation.remove-defined-name": covered("defname", "id", "name"),
|
|
93
|
+
"formula.mutation.set-feature-calculation": barrier("X", "a plugin's registered calculation (feature id + dependency ranges); no transform yet"),
|
|
94
|
+
"formula.mutation.remove-feature-calculation": barrier("X", "a plugin's registered calculation; no transform yet"),
|
|
95
|
+
"formula.mutation.set-other-formula": barrier("C5c", "formulas owned by conditional formats and data validation travel with their rule"),
|
|
96
|
+
"formula.mutation.remove-other-formula": barrier("C5c", "formulas owned by conditional formats and data validation travel with their rule"),
|
|
97
|
+
"formula.mutation.set-super-table": barrier("C5c", "table names in structured references belong to tables (C5c)"),
|
|
98
|
+
"formula.mutation.remove-super-table": barrier("C5c", "table names in structured references belong to tables (C5c)"),
|
|
99
|
+
"formula.mutation.set-super-table-option": barrier("C5c", "table names in structured references belong to tables (C5c)"),
|
|
101
100
|
// ── barriers until C5c (ranged resources) ────────────────────────────────────────────────────────
|
|
102
101
|
"sheet.mutation.add-conditional-rule": barrier("C5c", RESOURCE),
|
|
103
102
|
"sheet.mutation.set-conditional-rule": barrier("C5c", RESOURCE),
|
|
@@ -254,8 +253,237 @@ function transformAxis(x, y, side) {
|
|
|
254
253
|
}
|
|
255
254
|
}
|
|
256
255
|
|
|
256
|
+
// src/collab/sheets/transform/formula.ts
|
|
257
|
+
import { Direction, RANGE_TYPE, Rectangle, getIntersectRange } from "@univerjs/core";
|
|
258
|
+
import { LexerTreeBuilder, deserializeRangeWithSheet, generateStringWithSequence, sequenceNodeType, serializeRangeToRefString } from "@univerjs/engine-formula";
|
|
259
|
+
import {
|
|
260
|
+
EffectRefRangId,
|
|
261
|
+
handleIRemoveCol,
|
|
262
|
+
handleIRemoveRow,
|
|
263
|
+
handleInsertCol,
|
|
264
|
+
handleInsertRow,
|
|
265
|
+
handleMoveCols,
|
|
266
|
+
handleMoveRows,
|
|
267
|
+
runRefRangeMutations
|
|
268
|
+
} from "@univerjs/sheets";
|
|
269
|
+
var REF_ERROR = "#REF!";
|
|
270
|
+
var FULL = 16383 * 64;
|
|
271
|
+
var lexer = null;
|
|
272
|
+
var lex = (body) => (lexer ??= new LexerTreeBuilder()).sequenceNodesBuilder(body);
|
|
273
|
+
var isFormulaText = (f) => typeof f === "string" && f.length > 1 && f.startsWith("=");
|
|
274
|
+
var IDENT = /^[A-Za-z_\\][A-Za-z0-9_.\\]*$/;
|
|
275
|
+
var ERROR_TOKEN = /^(?:[^!]+!)?#(?:REF!|NAME\?|VALUE!|DIV\/0!|N\/A|NUM!|NULL!|SPILL!|CALC!)$/i;
|
|
276
|
+
function parse(text) {
|
|
277
|
+
const prefix = text.startsWith("=") ? "=" : "";
|
|
278
|
+
const nodes = lex(text.slice(prefix.length));
|
|
279
|
+
if (!nodes) return "the formula lexer could not read the text";
|
|
280
|
+
for (const n of nodes) {
|
|
281
|
+
if (typeof n === "string") continue;
|
|
282
|
+
if (n.nodeType === sequenceNodeType.TABLE || n.nodeType === sequenceNodeType.FUNCTION && n.token.includes("[")) return "a structured table reference (tables are C5c)";
|
|
283
|
+
if (n.nodeType === sequenceNodeType.FUNCTION && !IDENT.test(n.token) && !ERROR_TOKEN.test(n.token))
|
|
284
|
+
return `the lexer read "${n.token}" as one name (an intersection or a reference it cannot split)`;
|
|
285
|
+
if (n.nodeType === sequenceNodeType.REFERENCE) {
|
|
286
|
+
const d = deserializeRangeWithSheet(n.token);
|
|
287
|
+
if (d.unitId) return "a reference into another workbook";
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return { prefix, nodes };
|
|
291
|
+
}
|
|
292
|
+
function targetSheet(sheetName, ctx) {
|
|
293
|
+
if (!sheetName) return ctx.ownSheet;
|
|
294
|
+
const id = ctx.refSheets?.[sheetName];
|
|
295
|
+
if (id === void 0) return void 0;
|
|
296
|
+
return id ?? "";
|
|
297
|
+
}
|
|
298
|
+
function formulaBarrier(text, ctx) {
|
|
299
|
+
const p = parse(text);
|
|
300
|
+
if (typeof p === "string") return p;
|
|
301
|
+
for (const n of p.nodes) {
|
|
302
|
+
if (typeof n === "string" || n.nodeType !== sequenceNodeType.REFERENCE) continue;
|
|
303
|
+
const { sheetName } = deserializeRangeWithSheet(n.token);
|
|
304
|
+
if (targetSheet(sheetName, ctx) === void 0) return `sheet "${sheetName}" is not in refSheets (capture must call annotateRefSheets)`;
|
|
305
|
+
}
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
function referencedSheetNames(text) {
|
|
309
|
+
const p = parse(text);
|
|
310
|
+
if (typeof p === "string") return [];
|
|
311
|
+
const out = /* @__PURE__ */ new Set();
|
|
312
|
+
for (const n of p.nodes) if (typeof n !== "string" && n.nodeType === sequenceNodeType.REFERENCE) {
|
|
313
|
+
const { sheetName } = deserializeRangeWithSheet(n.token);
|
|
314
|
+
if (sheetName) out.add(sheetName);
|
|
315
|
+
}
|
|
316
|
+
return [...out];
|
|
317
|
+
}
|
|
318
|
+
var fullRowsRange = (start, count) => ({ startRow: start, endRow: start + count - 1, startColumn: 0, endColumn: FULL, rangeType: RANGE_TYPE.ROW });
|
|
319
|
+
var fullColsRange = (start, count) => ({ startRow: 0, endRow: FULL, startColumn: start, endColumn: start + count - 1, rangeType: RANGE_TYPE.COLUMN });
|
|
320
|
+
var startV = (v) => Number.isNaN(v) || v == null ? -Infinity : v;
|
|
321
|
+
var endV = (v) => Number.isNaN(v) || v == null ? Infinity : v;
|
|
322
|
+
function startEnd(r) {
|
|
323
|
+
return { ...r, startRow: startV(r.startRow), endRow: endV(r.endRow), startColumn: startV(r.startColumn), endColumn: endV(r.endColumn) };
|
|
324
|
+
}
|
|
325
|
+
function checkMoveEdge(origin, from) {
|
|
326
|
+
const startRow = startV(origin.startRow), endRow = endV(origin.endRow), startColumn = startV(origin.startColumn), endColumn = endV(origin.endColumn);
|
|
327
|
+
const fromStartRow = startV(from.startRow), fromEndRow = endV(from.endRow), fromStartColumn = startV(from.startColumn), fromEndColumn = endV(from.endColumn);
|
|
328
|
+
const rowsCover = () => origin.rangeType === RANGE_TYPE.COLUMN && from.rangeType === RANGE_TYPE.COLUMN || startRow >= fromStartRow && endRow <= fromEndRow;
|
|
329
|
+
const columnsCover = () => origin.rangeType === RANGE_TYPE.ROW && from.rangeType === RANGE_TYPE.ROW || startColumn >= fromStartColumn && endColumn <= fromEndColumn;
|
|
330
|
+
const allCover = () => origin.rangeType === RANGE_TYPE.ALL && from.rangeType === RANGE_TYPE.ALL;
|
|
331
|
+
if (rowsCover() && columnsCover() || allCover()) return 4;
|
|
332
|
+
if (columnsCover() && startRow >= fromStartRow && startRow <= fromEndRow && endRow > fromEndRow) return 0;
|
|
333
|
+
if (columnsCover() && endRow >= fromStartRow && endRow <= fromEndRow && startRow < fromStartRow) return 1;
|
|
334
|
+
if (rowsCover() && startColumn >= fromStartColumn && startColumn <= fromEndColumn && endColumn > fromEndColumn) return 2;
|
|
335
|
+
if (rowsCover() && endColumn >= fromStartColumn && endColumn <= fromEndColumn && startColumn < fromStartColumn) return 3;
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
function getMoveNewRange(moveEdge, result, from, to, origin, remain) {
|
|
339
|
+
const { startRow, endRow, startColumn, endColumn, rangeType } = startEnd(result);
|
|
340
|
+
const f = startEnd(from);
|
|
341
|
+
const fromRangeType = from.rangeType ?? RANGE_TYPE.NORMAL;
|
|
342
|
+
const t = startEnd(to);
|
|
343
|
+
const rm = startEnd(remain);
|
|
344
|
+
const o = startEnd(origin);
|
|
345
|
+
const originRangeType = origin.rangeType ?? RANGE_TYPE.NORMAL;
|
|
346
|
+
const newRange = { ...origin };
|
|
347
|
+
const rowsCover = () => rangeType === RANGE_TYPE.COLUMN && originRangeType === RANGE_TYPE.COLUMN || startColumn >= o.startColumn && endColumn <= o.endColumn;
|
|
348
|
+
const columnsCover = () => rangeType === RANGE_TYPE.ROW && originRangeType === RANGE_TYPE.ROW || startRow >= o.startRow && endRow <= o.endRow;
|
|
349
|
+
if (moveEdge === 0) {
|
|
350
|
+
if (!rowsCover()) return void 0;
|
|
351
|
+
if (startRow < o.startRow) newRange.startRow = startRow;
|
|
352
|
+
else if (startRow >= o.endRow) newRange.endRow -= f.endRow + 1 - o.startRow;
|
|
353
|
+
else return void 0;
|
|
354
|
+
} else if (moveEdge === 1) {
|
|
355
|
+
if (!rowsCover()) return void 0;
|
|
356
|
+
if (endRow > o.endRow) newRange.endRow = endRow;
|
|
357
|
+
else if (endRow <= o.startRow) newRange.startRow += o.endRow - f.startRow + 1;
|
|
358
|
+
else return void 0;
|
|
359
|
+
} else if (moveEdge === 2) {
|
|
360
|
+
if (!columnsCover()) return void 0;
|
|
361
|
+
if (startColumn < o.startColumn) newRange.startColumn = startColumn;
|
|
362
|
+
else if (startColumn >= o.endColumn) newRange.endColumn -= f.endColumn + 1 - o.startColumn;
|
|
363
|
+
else return void 0;
|
|
364
|
+
} else if (moveEdge === 3) {
|
|
365
|
+
if (!columnsCover()) return void 0;
|
|
366
|
+
if (endColumn > o.endColumn) newRange.endColumn = endColumn;
|
|
367
|
+
else if (endColumn <= o.startColumn) newRange.startColumn += o.endColumn - f.startColumn + 1;
|
|
368
|
+
else return void 0;
|
|
369
|
+
} else if (moveEdge === 4) {
|
|
370
|
+
Object.assign(newRange, { startRow, startColumn, endRow, endColumn });
|
|
371
|
+
} else if (f.startColumn <= o.startColumn && f.endColumn >= o.endColumn || fromRangeType === RANGE_TYPE.ROW && originRangeType === RANGE_TYPE.ROW) {
|
|
372
|
+
const n = f.endRow - f.startRow + 1;
|
|
373
|
+
if (from.endRow < o.startRow) {
|
|
374
|
+
if (t.startRow >= o.startRow) newRange.startRow -= n;
|
|
375
|
+
if (t.startRow >= o.endRow) newRange.endRow -= n;
|
|
376
|
+
} else if (from.startRow > o.endRow) {
|
|
377
|
+
if (t.endRow <= o.endRow) newRange.endRow += n;
|
|
378
|
+
if (t.endRow <= o.startRow) newRange.startRow += n;
|
|
379
|
+
} else if (from.startRow >= o.startRow && from.endRow <= o.endRow) {
|
|
380
|
+
if (t.startRow <= o.startRow) newRange.startRow += n;
|
|
381
|
+
else if (t.startRow >= o.endRow) newRange.endRow -= n;
|
|
382
|
+
}
|
|
383
|
+
} else if (f.startRow <= o.startRow && f.endRow >= o.endRow || fromRangeType === RANGE_TYPE.COLUMN && originRangeType === RANGE_TYPE.COLUMN) {
|
|
384
|
+
const n = f.endColumn - f.startColumn + 1;
|
|
385
|
+
if (from.endColumn < o.startColumn) {
|
|
386
|
+
if (t.startColumn >= o.startColumn) newRange.startColumn -= n;
|
|
387
|
+
if (t.startColumn >= o.endColumn) newRange.endColumn -= n;
|
|
388
|
+
} else if (from.startColumn > o.endColumn) {
|
|
389
|
+
if (t.endColumn <= o.endColumn) newRange.endColumn += n;
|
|
390
|
+
if (t.endColumn <= o.startColumn) newRange.startColumn += n;
|
|
391
|
+
} else if (from.startColumn >= o.startColumn && from.endColumn <= o.endColumn) {
|
|
392
|
+
if (t.startColumn <= o.startColumn) newRange.startColumn += n;
|
|
393
|
+
else if (t.startColumn >= o.endColumn) newRange.endColumn -= n;
|
|
394
|
+
}
|
|
395
|
+
} else {
|
|
396
|
+
Object.assign(newRange, { startRow, startColumn, endRow, endColumn });
|
|
397
|
+
void rm;
|
|
398
|
+
}
|
|
399
|
+
return newRange;
|
|
400
|
+
}
|
|
401
|
+
function moveRange(range, axis, op) {
|
|
402
|
+
const isRow = axis === "row";
|
|
403
|
+
if (op.kind === "insert") {
|
|
404
|
+
const r = isRow ? fullRowsRange(op.at, op.count) : fullColsRange(op.at, op.count);
|
|
405
|
+
const ops2 = isRow ? handleInsertRow({ id: EffectRefRangId.InsertRowCommandId, params: { range: r, unitId: "", subUnitId: "", direction: Direction.DOWN } }, range) : handleInsertCol({ id: EffectRefRangId.InsertColCommandId, params: { range: r, unitId: "", subUnitId: "", direction: Direction.RIGHT } }, range);
|
|
406
|
+
const res2 = runRefRangeMutations(ops2, range);
|
|
407
|
+
return res2 == null ? void 0 : { ...range, ...res2 };
|
|
408
|
+
}
|
|
409
|
+
if (op.kind === "remove") {
|
|
410
|
+
const r = isRow ? fullRowsRange(op.start, op.count) : fullColsRange(op.start, op.count);
|
|
411
|
+
const ops2 = isRow ? handleIRemoveRow({ id: EffectRefRangId.RemoveRowCommandId, params: { range: r } }, range, []) : handleIRemoveCol({ id: EffectRefRangId.RemoveColCommandId, params: { range: r } }, range);
|
|
412
|
+
const res2 = runRefRangeMutations(ops2, range);
|
|
413
|
+
return res2 == null ? REF_ERROR : { ...range, ...res2 };
|
|
414
|
+
}
|
|
415
|
+
const from = isRow ? fullRowsRange(op.from, op.count) : fullColsRange(op.from, op.count);
|
|
416
|
+
const to = isRow ? fullRowsRange(op.to, op.count) : fullColsRange(op.to, op.count);
|
|
417
|
+
const moveEdge = checkMoveEdge(range, from);
|
|
418
|
+
let remain = getIntersectRange(range, from);
|
|
419
|
+
if (isRow) {
|
|
420
|
+
if (remain == null && (from.endRow < range.startRow && to.endRow <= range.startRow || from.startRow > range.endRow && to.startRow > range.endRow)) return void 0;
|
|
421
|
+
} else if (remain == null && (from.endColumn < range.startColumn && to.endColumn <= range.startColumn || from.startColumn > range.endColumn && to.startColumn > range.endColumn)) return void 0;
|
|
422
|
+
remain ??= { startRow: range.startRow, endRow: range.endRow, startColumn: range.startColumn, endColumn: range.endColumn, rangeType: RANGE_TYPE.NORMAL };
|
|
423
|
+
const ops = isRow ? handleMoveRows({ id: EffectRefRangId.MoveRowsCommandId, params: { toRange: to, fromRange: from } }, remain) : handleMoveCols({ id: EffectRefRangId.MoveColsCommandId, params: { toRange: to, fromRange: from } }, remain);
|
|
424
|
+
const res = runRefRangeMutations(ops, remain);
|
|
425
|
+
if (res == null) return REF_ERROR;
|
|
426
|
+
return getMoveNewRange(moveEdge, res, from, to, range, remain);
|
|
427
|
+
}
|
|
428
|
+
function rewriteFormula(text, ctx, change) {
|
|
429
|
+
const p = parse(text);
|
|
430
|
+
if (typeof p === "string") return p;
|
|
431
|
+
const nodes = p.nodes.slice();
|
|
432
|
+
const changedIds = [];
|
|
433
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
434
|
+
const n = nodes[i];
|
|
435
|
+
if (typeof n === "string") continue;
|
|
436
|
+
if (change.kind === "defined-name") {
|
|
437
|
+
if ((n.nodeType === sequenceNodeType.DEFINED_NAME || n.nodeType === sequenceNodeType.FUNCTION) && n.token === change.from) {
|
|
438
|
+
nodes[i] = { ...n, token: change.to ?? REF_ERROR };
|
|
439
|
+
changedIds.push(i);
|
|
440
|
+
}
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
if (n.nodeType !== sequenceNodeType.REFERENCE) continue;
|
|
444
|
+
const { range, sheetName, unitId } = deserializeRangeWithSheet(n.token);
|
|
445
|
+
const target = targetSheet(sheetName, ctx);
|
|
446
|
+
if (target === void 0) return `sheet "${sheetName}" is not in refSheets (capture must call annotateRefSheets)`;
|
|
447
|
+
if (target !== change.sheet) continue;
|
|
448
|
+
let token;
|
|
449
|
+
if (change.kind === "rename") {
|
|
450
|
+
if (!sheetName) continue;
|
|
451
|
+
token = serializeRangeToRefString({ range, sheetName: change.name, unitId });
|
|
452
|
+
} else {
|
|
453
|
+
const moved = moveRange(Rectangle.moveOffset(range, 0, 0), change.axis, change.op);
|
|
454
|
+
if (moved === void 0) continue;
|
|
455
|
+
token = moved === REF_ERROR ? REF_ERROR : serializeRangeToRefString({ range: moved, sheetName: target === ctx.ownSheet && !ctx.keepQualifier ? "" : sheetName, unitId });
|
|
456
|
+
}
|
|
457
|
+
nodes[i] = { ...n, token };
|
|
458
|
+
changedIds.push(i);
|
|
459
|
+
}
|
|
460
|
+
if (!changedIds.length) return { text, changed: false };
|
|
461
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
462
|
+
const n = nodes[i];
|
|
463
|
+
if (typeof n === "string" || n.nodeType !== sequenceNodeType.REFERENCE || changedIds.includes(i)) continue;
|
|
464
|
+
nodes[i] = { ...n, token: serializeRangeToRefString(deserializeRangeWithSheet(n.token)) };
|
|
465
|
+
}
|
|
466
|
+
const out = p.prefix + generateStringWithSequence(nodes);
|
|
467
|
+
return { text: out, changed: out !== text };
|
|
468
|
+
}
|
|
469
|
+
function refSheetsAfter(refSheets, change) {
|
|
470
|
+
if (change.kind !== "rename" || !refSheets) return refSheets;
|
|
471
|
+
const entries = Object.entries(refSheets);
|
|
472
|
+
if (!entries.some(([name, id]) => id === change.sheet || name === change.name)) return refSheets;
|
|
473
|
+
const next = {};
|
|
474
|
+
for (const [name, id] of entries) if (id !== change.sheet && name !== change.name) next[name] = id;
|
|
475
|
+
next[change.name] = change.sheet;
|
|
476
|
+
return next;
|
|
477
|
+
}
|
|
478
|
+
function refSheetsFor(texts, sheets) {
|
|
479
|
+
const byName = new Map(Object.entries(sheets).map(([id, name]) => [name, id]));
|
|
480
|
+
const out = {};
|
|
481
|
+
for (const t of texts) for (const name of referencedSheetNames(t)) out[name] = byName.get(name) ?? null;
|
|
482
|
+
return Object.keys(out).length ? out : void 0;
|
|
483
|
+
}
|
|
484
|
+
|
|
257
485
|
// src/collab/sheets/transform/transform.ts
|
|
258
|
-
var SHEET_TRANSFORMER_VERSION = "
|
|
486
|
+
var SHEET_TRANSFORMER_VERSION = "c5b-1";
|
|
259
487
|
var ID = {
|
|
260
488
|
values: "sheet.mutation.set-range-values",
|
|
261
489
|
insertRow: "sheet.mutation.insert-row",
|
|
@@ -270,7 +498,9 @@ var ID = {
|
|
|
270
498
|
rowIsAuto: "sheet.mutation.set-worksheet-row-is-auto-height",
|
|
271
499
|
rowAutoHeight: "sheet.mutation.set-worksheet-row-auto-height",
|
|
272
500
|
colWidth: "sheet.mutation.set-worksheet-col-width",
|
|
273
|
-
name: "sheet.mutation.set-worksheet-name"
|
|
501
|
+
name: "sheet.mutation.set-worksheet-name",
|
|
502
|
+
setName: "formula.mutation.set-defined-name",
|
|
503
|
+
removeName: "formula.mutation.remove-defined-name"
|
|
274
504
|
};
|
|
275
505
|
var PAIR_BARRIERS = {};
|
|
276
506
|
var pairKey = (a, b) => a < b ? `${a}|${b}` : `${b}|${a}`;
|
|
@@ -335,9 +565,9 @@ function buildStructural(template, axis, op) {
|
|
|
335
565
|
return { id: template.id, params: { ...p, range: { ...p.range, [a0]: start, [a1]: start + op.count - 1 } } };
|
|
336
566
|
}
|
|
337
567
|
function univerMutationInfo(axis, op) {
|
|
338
|
-
const
|
|
568
|
+
const FULL2 = { startRow: 0, endRow: Number.MAX_SAFE_INTEGER, startColumn: 0, endColumn: Number.MAX_SAFE_INTEGER };
|
|
339
569
|
const start = op.kind === "insert" ? op.at : op.start;
|
|
340
|
-
const range = axis === "row" ? { ...
|
|
570
|
+
const range = axis === "row" ? { ...FULL2, startRow: start, endRow: start + op.count - 1 } : { ...FULL2, startColumn: start, endColumn: start + op.count - 1 };
|
|
341
571
|
const id = op.kind === "insert" ? axis === "row" ? ID.insertRow : ID.insertCol : axis === "row" ? ID.removeRows : ID.removeCol;
|
|
342
572
|
return { id, params: { unitId: "", subUnitId: "", range } };
|
|
343
573
|
}
|
|
@@ -404,8 +634,8 @@ function exactMergeRemovals(group, merges) {
|
|
|
404
634
|
var mergeRanges = (m) => m.params.ranges ?? [];
|
|
405
635
|
var withRanges = (m, ranges) => ({ id: m.id, params: { ...m.params, ranges } });
|
|
406
636
|
var mergeMutation = (id, sheet, ranges) => ({ id, params: { subUnitId: sheet, ranges } });
|
|
407
|
-
var CONTENT_KEYS = ["v", "t", "p", "f", "si", "custom"];
|
|
408
|
-
var CONTENT_TOUCH = ["v", "p", "f", "si", "custom"];
|
|
637
|
+
var CONTENT_KEYS = ["v", "t", "p", "f", "si", "custom", "ref", "xf", "ft", "fd"];
|
|
638
|
+
var CONTENT_TOUCH = ["v", "p", "f", "si", "custom", "ref", "xf", "ft", "fd"];
|
|
409
639
|
var KNOWN_CELL_KEYS = /* @__PURE__ */ new Set([...CONTENT_KEYS, "s"]);
|
|
410
640
|
function completeCellContent(entry, post) {
|
|
411
641
|
if (entry === null) return null;
|
|
@@ -435,8 +665,10 @@ function cellBarrier(m) {
|
|
|
435
665
|
forEachCell(cellsOf(m), (_r, _c, v) => {
|
|
436
666
|
if (why || v === null) return;
|
|
437
667
|
for (const k of Object.keys(v)) {
|
|
668
|
+
if (why) break;
|
|
438
669
|
if (!KNOWN_CELL_KEYS.has(k)) why = `cell key "${k}" is not covered`;
|
|
439
|
-
else if (
|
|
670
|
+
else if (k === "si" && v.si != null) why = "shared formula (si): its text lives in a master cell this op does not carry";
|
|
671
|
+
else if (k === "f" && isFormulaText(v.f) || k === "ref" && typeof v.ref === "string") why = formulaBarrier(v[k], formulaCtx(m));
|
|
440
672
|
}
|
|
441
673
|
if (typeof v.s === "string") why = "a style id travels (style ids are seat-local; capture must send the style object)";
|
|
442
674
|
if (!why && CONTENT_TOUCH.some((k) => k in v) && !CONTENT_KEYS.every((k) => k in v || k === "t" && v.v == null))
|
|
@@ -509,6 +741,9 @@ function transformCell(X, Y, side) {
|
|
|
509
741
|
function transformCellsOverCells(x, y, side) {
|
|
510
742
|
if (sheetOf(x) !== sheetOf(y)) return ok([x]);
|
|
511
743
|
const ycells = cellsOf(y);
|
|
744
|
+
const xd = isDerived(x);
|
|
745
|
+
const yd = isDerived(y);
|
|
746
|
+
const eff = derivedSide(x, y, side);
|
|
512
747
|
const passes = [{}];
|
|
513
748
|
const lost = [];
|
|
514
749
|
const dropped = [];
|
|
@@ -520,29 +755,218 @@ function transformCellsOverCells(x, y, side) {
|
|
|
520
755
|
putCell(passes[0], r, c, X);
|
|
521
756
|
return;
|
|
522
757
|
}
|
|
523
|
-
const res = transformCell(X, yRow[c] ?? null,
|
|
758
|
+
const res = transformCell(X, yRow[c] ?? null, eff);
|
|
524
759
|
if (typeof res === "string") {
|
|
525
760
|
why = res;
|
|
526
761
|
return;
|
|
527
762
|
}
|
|
528
763
|
res.entries.forEach((e, i) => putCell(passes[i] ??= {}, r, c, e));
|
|
529
|
-
if (res.xLost) dropped.push(cellRef(sheetOf(x), r, c));
|
|
530
|
-
if (res.yLost) lost.push(cellRef(sheetOf(x), r, c));
|
|
764
|
+
if (res.xLost && !xd) dropped.push(cellRef(sheetOf(x), r, c));
|
|
765
|
+
if (res.yLost && !yd) lost.push(cellRef(sheetOf(x), r, c));
|
|
531
766
|
});
|
|
532
767
|
if (why) return barrier2(why);
|
|
533
768
|
const op = passes.filter((p) => !isEmptyMatrix(p)).map((p) => cellsMutation(x, p));
|
|
534
769
|
return ok(op, lost, dropped);
|
|
535
770
|
}
|
|
536
|
-
|
|
771
|
+
var SIDE_CAR_PARAMS = ["refSheets", "previousName", "derived"];
|
|
772
|
+
var isDerived = (m) => m.params.derived === true;
|
|
773
|
+
function derivedSide(x, y, side) {
|
|
774
|
+
const xd = isDerived(x);
|
|
775
|
+
const yd = isDerived(y);
|
|
776
|
+
return xd === yd ? side : xd ? "right" : "left";
|
|
777
|
+
}
|
|
778
|
+
function forApply(m) {
|
|
779
|
+
if (!SIDE_CAR_PARAMS.some((k) => k in m.params)) return m;
|
|
780
|
+
const params = { ...m.params };
|
|
781
|
+
for (const k of SIDE_CAR_PARAMS) delete params[k];
|
|
782
|
+
return { id: m.id, params };
|
|
783
|
+
}
|
|
784
|
+
var refSheetsOf = (m) => m.params.refSheets;
|
|
785
|
+
var formulaCtx = (m) => ({ ownSheet: sheetOf(m), refSheets: refSheetsOf(m) });
|
|
786
|
+
function withRefSheets(params, rs) {
|
|
787
|
+
const out = { ...params };
|
|
788
|
+
if (rs) out.refSheets = rs;
|
|
789
|
+
else delete out.refSheets;
|
|
790
|
+
return out;
|
|
791
|
+
}
|
|
792
|
+
var hasFormulaText = (v) => !!v && (isFormulaText(v.f) || typeof v.ref === "string");
|
|
793
|
+
function hasFormula(m) {
|
|
794
|
+
let any = false;
|
|
795
|
+
forEachCell(cellsOf(m), (_r, _c, v) => {
|
|
796
|
+
any ||= hasFormulaText(v);
|
|
797
|
+
});
|
|
798
|
+
return any;
|
|
799
|
+
}
|
|
800
|
+
var setNameWithoutPrevious = (m) => m.id === ID.setName && !("previousName" in m.params);
|
|
801
|
+
function refChangeOf(m) {
|
|
802
|
+
const st = structuralOf(m);
|
|
803
|
+
if (st) return { kind: "axis", sheet: sheetOf(m), axis: st.axis, op: st.op };
|
|
804
|
+
if (m.id === ID.name) return { kind: "rename", sheet: sheetOf(m), name: String(m.params.name) };
|
|
805
|
+
if (m.id === ID.removeName) return { kind: "defined-name", from: String(m.params.name), to: null };
|
|
806
|
+
if (m.id === ID.setName && typeof m.params.previousName === "string" && m.params.previousName !== m.params.name)
|
|
807
|
+
return { kind: "defined-name", from: m.params.previousName, to: String(m.params.name) };
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
function rewriteEntry(v, ctx, change) {
|
|
811
|
+
let entry = v;
|
|
812
|
+
let changed = false;
|
|
813
|
+
for (const k of ["f", "ref"]) {
|
|
814
|
+
const t = v[k];
|
|
815
|
+
if (k === "f" ? !isFormulaText(t) : typeof t !== "string") continue;
|
|
816
|
+
const r = rewriteFormula(t, ctx, change);
|
|
817
|
+
if (typeof r === "string") return r;
|
|
818
|
+
if (!r.changed) continue;
|
|
819
|
+
if (k === "ref" && r.text.includes(REF_ERROR)) return "an array formula's range was removed under it";
|
|
820
|
+
entry = { ...entry, [k]: r.text };
|
|
821
|
+
changed = true;
|
|
822
|
+
}
|
|
823
|
+
return { entry, changed };
|
|
824
|
+
}
|
|
825
|
+
function cellThrough(sheet, change, r, c) {
|
|
826
|
+
if (change.kind !== "axis" || change.sheet !== sheet) return [r, c];
|
|
827
|
+
const nr = change.axis === "row" ? mapIndex(change.op, r) : r;
|
|
828
|
+
const nc = change.axis === "col" ? mapIndex(change.op, c) : c;
|
|
829
|
+
return nr === null || nc === null ? null : [nr, nc];
|
|
830
|
+
}
|
|
831
|
+
function cellsOverChange(x, change) {
|
|
832
|
+
const ctx = formulaCtx(x);
|
|
537
833
|
const out = {};
|
|
538
834
|
const dropped = [];
|
|
835
|
+
let why = null;
|
|
539
836
|
forEachCell(cellsOf(x), (r, c, v) => {
|
|
540
|
-
|
|
541
|
-
const
|
|
542
|
-
if (
|
|
543
|
-
|
|
837
|
+
if (why) return;
|
|
838
|
+
const at = cellThrough(sheetOf(x), change, r, c);
|
|
839
|
+
if (!at) {
|
|
840
|
+
dropped.push(cellRef(sheetOf(x), r, c));
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
let e = v;
|
|
844
|
+
if (hasFormulaText(v)) {
|
|
845
|
+
const res = rewriteEntry(v, ctx, change);
|
|
846
|
+
if (typeof res === "string") {
|
|
847
|
+
why = res;
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
e = res.entry;
|
|
851
|
+
}
|
|
852
|
+
putCell(out, at[0], at[1], e);
|
|
853
|
+
});
|
|
854
|
+
if (why) return barrier2(why);
|
|
855
|
+
const params = { ...withRefSheets(x.params, refSheetsAfter(ctx.refSheets, change)), cellValue: out };
|
|
856
|
+
return ok(isEmptyMatrix(out) ? [] : [{ id: x.id, params }], [], dropped);
|
|
857
|
+
}
|
|
858
|
+
function rewritesOf(y, change) {
|
|
859
|
+
const ctx = formulaCtx(y);
|
|
860
|
+
const out = {};
|
|
861
|
+
let why = null;
|
|
862
|
+
forEachCell(cellsOf(y), (r, c, v) => {
|
|
863
|
+
if (why || !hasFormulaText(v)) return;
|
|
864
|
+
const at = cellThrough(sheetOf(y), change, r, c);
|
|
865
|
+
if (!at) return;
|
|
866
|
+
const res = rewriteEntry(v, ctx, change);
|
|
867
|
+
if (typeof res === "string") {
|
|
868
|
+
why = res;
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
if (res.changed) putCell(out, at[0], at[1], contentOf(res.entry));
|
|
872
|
+
});
|
|
873
|
+
if (why) return why;
|
|
874
|
+
if (isEmptyMatrix(out)) return null;
|
|
875
|
+
return { id: ID.values, params: withRefSheets({ subUnitId: sheetOf(y), cellValue: out, derived: true }, refSheetsAfter(ctx.refSheets, change)) };
|
|
876
|
+
}
|
|
877
|
+
var NAME_TEXT_KEYS = ["formulaOrRefString", "formulaOrRefStringWithPrefix"];
|
|
878
|
+
function definedNameThrough(m, change) {
|
|
879
|
+
if (change.kind === "defined-name" || m.id !== ID.setName) return { op: m, changed: false };
|
|
880
|
+
const ctx = { ownSheet: change.sheet, refSheets: refSheetsOf(m), keepQualifier: true };
|
|
881
|
+
const params = { ...m.params };
|
|
882
|
+
let changed = false;
|
|
883
|
+
for (const k of NAME_TEXT_KEYS) {
|
|
884
|
+
if (typeof params[k] !== "string" || !params[k]) continue;
|
|
885
|
+
const r = rewriteFormula(params[k], ctx, change);
|
|
886
|
+
if (typeof r === "string") return r;
|
|
887
|
+
if (r.changed) {
|
|
888
|
+
params[k] = r.text;
|
|
889
|
+
changed = true;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
return { op: { id: m.id, params: withRefSheets(params, refSheetsAfter(ctx.refSheets, change)) }, changed };
|
|
893
|
+
}
|
|
894
|
+
function asDerived(m) {
|
|
895
|
+
return { id: m.id, params: { ...m.params, derived: true } };
|
|
896
|
+
}
|
|
897
|
+
function formulaPair(x, y, side) {
|
|
898
|
+
const fx = familyOf(x.id);
|
|
899
|
+
const fy = familyOf(y.id);
|
|
900
|
+
const SET_NAME_BARRIER = "set-defined-name without previousName (capture must record the name it replaces) against formula text";
|
|
901
|
+
if (fx === "defname" && fy === "defname") {
|
|
902
|
+
if (String(x.params.id) !== String(y.params.id)) return ok([x]);
|
|
903
|
+
const eff = derivedSide(x, y, side);
|
|
904
|
+
if (eff === "left") return ok([x], isDerived(y) ? [] : [`defined name "${String(y.params.name)}"`]);
|
|
905
|
+
return ok([], [], isDerived(x) ? [] : [`defined name "${String(x.params.name)}"`]);
|
|
906
|
+
}
|
|
907
|
+
if (fx === "defname") {
|
|
908
|
+
if (fy === "cell") {
|
|
909
|
+
if (setNameWithoutPrevious(x) && hasFormula(y)) return barrier2(SET_NAME_BARRIER);
|
|
910
|
+
const ch2 = refChangeOf(x);
|
|
911
|
+
if (!ch2) return ok([x]);
|
|
912
|
+
const add = rewritesOf(y, ch2);
|
|
913
|
+
if (typeof add === "string") return barrier2(add);
|
|
914
|
+
return ok(add ? [x, add] : [x]);
|
|
915
|
+
}
|
|
916
|
+
const ch = refChangeOf(y);
|
|
917
|
+
if (!ch) return ok([x]);
|
|
918
|
+
const r = definedNameThrough(x, ch);
|
|
919
|
+
return typeof r === "string" ? barrier2(r) : ok([r.op]);
|
|
920
|
+
}
|
|
921
|
+
if (fy === "defname") {
|
|
922
|
+
if (fx === "cell") {
|
|
923
|
+
if (setNameWithoutPrevious(y) && hasFormula(x)) return barrier2(SET_NAME_BARRIER);
|
|
924
|
+
const ch2 = refChangeOf(y);
|
|
925
|
+
return ch2 ? cellsOverChange(x, ch2) : ok([x]);
|
|
926
|
+
}
|
|
927
|
+
const ch = refChangeOf(x);
|
|
928
|
+
if (!ch) return ok([x]);
|
|
929
|
+
const r = definedNameThrough(y, ch);
|
|
930
|
+
if (typeof r === "string") return barrier2(r);
|
|
931
|
+
return ok(r.changed ? [x, asDerived(r.op)] : [x]);
|
|
932
|
+
}
|
|
933
|
+
if (fx === "cell") {
|
|
934
|
+
const ch = refChangeOf(y);
|
|
935
|
+
return ch ? cellsOverChange(x, ch) : null;
|
|
936
|
+
}
|
|
937
|
+
if (fy === "cell") {
|
|
938
|
+
const ch = refChangeOf(x);
|
|
939
|
+
if (!ch) return null;
|
|
940
|
+
const lost = [];
|
|
941
|
+
forEachCell(cellsOf(y), (r, c) => {
|
|
942
|
+
if (!cellThrough(sheetOf(y), ch, r, c)) lost.push(cellRef(sheetOf(y), r, c));
|
|
943
|
+
});
|
|
944
|
+
const add = rewritesOf(y, ch);
|
|
945
|
+
if (typeof add === "string") return barrier2(add);
|
|
946
|
+
return ok(add ? [x, add] : [x], lost);
|
|
947
|
+
}
|
|
948
|
+
return null;
|
|
949
|
+
}
|
|
950
|
+
var withPrevious = (m, definedNames) => m.id === ID.setName && !("previousName" in m.params) ? { id: m.id, params: { ...m.params, previousName: definedNames[String(m.params.id)] ?? null } } : m;
|
|
951
|
+
function annotateFormulas(group, sheets, definedNames) {
|
|
952
|
+
let changed = false;
|
|
953
|
+
return group.map((m0) => {
|
|
954
|
+
const m = changed && (m0.id === ID.values || m0.id === ID.setName) ? asDerived(m0) : m0;
|
|
955
|
+
if (!changed && refChangeOf(withPrevious(m0, definedNames))) changed = true;
|
|
956
|
+
if (m.id === ID.values) {
|
|
957
|
+
const texts = [];
|
|
958
|
+
forEachCell(cellsOf(m), (_r, _c, v) => {
|
|
959
|
+
if (v && isFormulaText(v.f)) texts.push(v.f);
|
|
960
|
+
if (v && typeof v.ref === "string") texts.push(v.ref);
|
|
961
|
+
});
|
|
962
|
+
return { id: m.id, params: withRefSheets(m.params, refSheetsFor(texts, sheets)) };
|
|
963
|
+
}
|
|
964
|
+
if (m.id === ID.setName) {
|
|
965
|
+
const texts = NAME_TEXT_KEYS.map((k) => m.params[k]).filter((t) => typeof t === "string");
|
|
966
|
+
return { id: m.id, params: { ...withRefSheets(m.params, refSheetsFor(texts, sheets)), previousName: withPrevious(m, definedNames).params.previousName } };
|
|
967
|
+
}
|
|
968
|
+
return m;
|
|
544
969
|
});
|
|
545
|
-
return ok(isEmptyMatrix(out) ? [] : [cellsMutation(x, out)], [], dropped);
|
|
546
970
|
}
|
|
547
971
|
function sizeOf(m) {
|
|
548
972
|
const p = m.params;
|
|
@@ -593,6 +1017,8 @@ function transformMutation(x, y, side) {
|
|
|
593
1017
|
}
|
|
594
1018
|
const pb = PAIR_BARRIERS[pairKey(x.id, y.id)];
|
|
595
1019
|
if (pb) return barrier2(`${x.id} \xD7 ${y.id}: ${pb.reason}${pb.seed === null ? "" : ` (fuzz seed ${pb.seed})`}`);
|
|
1020
|
+
const fp = formulaPair(x, y, side);
|
|
1021
|
+
if (fp) return fp;
|
|
596
1022
|
if (sheetOf(x) !== sheetOf(y)) return ok([x]);
|
|
597
1023
|
const fx = familyOf(x.id);
|
|
598
1024
|
const fy = familyOf(y.id);
|
|
@@ -606,7 +1032,6 @@ function transformMutation(x, y, side) {
|
|
|
606
1032
|
return ok(out.map((o) => buildStructural(x, sx.axis, o)), [], dropped);
|
|
607
1033
|
}
|
|
608
1034
|
if (sy) {
|
|
609
|
-
if (fx === "cell") return transformCellsOverStructural(x, sy);
|
|
610
1035
|
if (fx === "merge") {
|
|
611
1036
|
const kept = [];
|
|
612
1037
|
const dropped = [];
|
|
@@ -631,13 +1056,6 @@ function transformMutation(x, y, side) {
|
|
|
631
1056
|
return ok([x]);
|
|
632
1057
|
}
|
|
633
1058
|
if (sx) {
|
|
634
|
-
if (fy === "cell") {
|
|
635
|
-
const lost = [];
|
|
636
|
-
forEachCell(cellsOf(y), (r, c) => {
|
|
637
|
-
if ((sx.axis === "row" ? mapIndex(sx.op, r) : mapIndex(sx.op, c)) === null) lost.push(cellRef(sheetOf(y), r, c));
|
|
638
|
-
});
|
|
639
|
-
return ok([x], lost);
|
|
640
|
-
}
|
|
641
1059
|
if (fy !== "merge" || y.id !== ID.addMerge) return ok([x]);
|
|
642
1060
|
const remove = [];
|
|
643
1061
|
const add = [];
|
|
@@ -749,15 +1167,24 @@ var sheetTransformer = {
|
|
|
749
1167
|
export {
|
|
750
1168
|
CONTENT_KEYS,
|
|
751
1169
|
PAIR_BARRIERS,
|
|
1170
|
+
REF_ERROR,
|
|
752
1171
|
SHEET_MUTATIONS,
|
|
753
1172
|
SHEET_TRANSFORMER_VERSION,
|
|
1173
|
+
SIDE_CAR_PARAMS,
|
|
754
1174
|
allowParams,
|
|
1175
|
+
annotateFormulas,
|
|
755
1176
|
cellRef,
|
|
756
1177
|
completeCellContent,
|
|
757
1178
|
exactMergeRemovals,
|
|
1179
|
+
forApply,
|
|
1180
|
+
formulaBarrier,
|
|
758
1181
|
isBarrier,
|
|
1182
|
+
isFormulaText,
|
|
759
1183
|
mapIndex,
|
|
760
1184
|
mergeThrough,
|
|
1185
|
+
refSheetsAfter,
|
|
1186
|
+
refSheetsFor,
|
|
1187
|
+
rewriteFormula,
|
|
761
1188
|
sheetTransformer,
|
|
762
1189
|
transformAxis,
|
|
763
1190
|
transformGroup,
|