@veltra/sheet 2.0.0 → 2.1.1

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.
Files changed (203) hide show
  1. package/dist/index.d.ts +4 -25
  2. package/dist/index.js +3 -22
  3. package/dist/tools/builtin.js +279 -8
  4. package/dist/tools/context.d.ts +54 -11
  5. package/dist/tools/context.js +28 -5
  6. package/dist/tools/download.js +68 -0
  7. package/dist/tools/export.worker.d.ts +16 -0
  8. package/dist/tools/export.worker.js +29 -0
  9. package/dist/tools/registry.d.ts +7 -4
  10. package/dist/tools/registry.js +1 -3
  11. package/dist/types/index.d.ts +1 -0
  12. package/dist/types/sheet.d.ts +6 -5
  13. package/dist/vue/formula-bar.js +393 -0
  14. package/dist/vue/formula-suggest-list.js +66 -0
  15. package/dist/vue/import-file.js +140 -0
  16. package/dist/vue/insert-count-menu-item.js +68 -0
  17. package/dist/vue/insert-image.js +79 -0
  18. package/dist/vue/popup-helpers.js +73 -0
  19. package/dist/vue/popups/border-popup.js +75 -0
  20. package/dist/vue/popups/border-preset-glyph.js +106 -0
  21. package/dist/vue/popups/export-popup.js +51 -0
  22. package/dist/vue/popups/fill-color-popup.js +37 -0
  23. package/dist/vue/popups/find-popup.js +113 -0
  24. package/dist/vue/popups/font-color-popup.js +37 -0
  25. package/dist/vue/popups/font-size-popup.js +63 -0
  26. package/dist/vue/popups/import.worker.d.ts +21 -0
  27. package/dist/vue/popups/import.worker.js +41 -0
  28. package/dist/vue/popups/insert-image-popup.js +38 -0
  29. package/dist/vue/sheet-context-menu.js +200 -0
  30. package/dist/vue/sheet-tabs.js +162 -0
  31. package/dist/vue/sheet-toolbar.js +106 -0
  32. package/dist/vue/sheet.js +144 -138
  33. package/dist/vue/style.d.ts +11 -1
  34. package/dist/vue/style.js +11 -0
  35. package/dist/vue/style2.css +564 -3
  36. package/dist/vue/use-find-replace.js +161 -0
  37. package/dist/vue/use-formula-ref-select.js +37 -0
  38. package/dist/vue/use-formula-suggest.js +126 -0
  39. package/dist/vue/use-sheet-grid.js +180 -0
  40. package/dist/vue/use-sheet-state.js +122 -0
  41. package/dist/vue/use-sheet-tabs-bar.js +90 -0
  42. package/dist/vue/use-tool-groups.js +42 -0
  43. package/dist/vue/use-tool-popup.js +123 -0
  44. package/dist/vue/use-toolbar-scroll.js +72 -0
  45. package/package.json +12 -6
  46. package/src/env.d.ts +14 -0
  47. package/src/index.ts +203 -13
  48. package/src/tools/__test__/builtin.test.ts +208 -66
  49. package/src/tools/__test__/context.test.ts +62 -2
  50. package/src/tools/builtin.ts +350 -6
  51. package/src/tools/context.ts +89 -11
  52. package/src/tools/download.ts +82 -0
  53. package/src/tools/export.worker.ts +61 -0
  54. package/src/tools/registry.ts +16 -1
  55. package/src/types/index.ts +6 -0
  56. package/src/types/sheet.ts +5 -3
  57. package/src/vue/__test__/formula-bar.test.ts +455 -0
  58. package/src/vue/__test__/import-file.test.ts +183 -0
  59. package/src/vue/__test__/insert-count-menu-item.test.ts +123 -0
  60. package/src/vue/__test__/insert-image-popup.test.ts +89 -0
  61. package/src/vue/__test__/insert-image.test.ts +100 -0
  62. package/src/vue/__test__/sheet-component.test.ts +716 -27
  63. package/src/vue/__test__/sheet-context-menu.test.ts +206 -0
  64. package/src/vue/__test__/use-formula-ref-select.test.ts +35 -0
  65. package/src/vue/__test__/use-formula-suggest.test.ts +83 -0
  66. package/src/vue/formula-bar.vue +473 -0
  67. package/src/vue/formula-suggest-list.vue +64 -0
  68. package/src/vue/import-file.ts +173 -0
  69. package/src/vue/insert-count-menu-item.vue +69 -0
  70. package/src/vue/insert-image.ts +90 -0
  71. package/src/vue/parsing.ts +11 -0
  72. package/src/vue/popup-helpers.ts +50 -0
  73. package/src/vue/popups/border-popup.vue +93 -0
  74. package/src/vue/popups/border-preset-glyph.vue +111 -0
  75. package/src/vue/popups/export-popup.vue +52 -0
  76. package/src/vue/popups/fill-color-popup.vue +39 -0
  77. package/src/vue/popups/find-popup.vue +111 -0
  78. package/src/vue/popups/font-color-popup.vue +39 -0
  79. package/src/vue/popups/font-size-popup.vue +52 -0
  80. package/src/vue/popups/import.worker.ts +66 -0
  81. package/src/vue/popups/insert-image-popup.vue +39 -0
  82. package/src/vue/sheet-context-menu.ts +229 -0
  83. package/src/vue/sheet-tabs.vue +162 -0
  84. package/src/vue/sheet-toolbar.vue +91 -0
  85. package/src/vue/sheet.vue +163 -148
  86. package/src/vue/style.scss +646 -3
  87. package/src/vue/style.ts +12 -0
  88. package/src/vue/use-find-replace.ts +200 -0
  89. package/src/vue/use-formula-ref-select.ts +34 -0
  90. package/src/vue/use-formula-suggest.ts +150 -0
  91. package/src/vue/use-sheet-grid.ts +243 -0
  92. package/src/vue/use-sheet-state.ts +161 -0
  93. package/src/vue/use-sheet-tabs-bar.ts +115 -0
  94. package/src/vue/use-tool-groups.ts +61 -0
  95. package/src/vue/use-tool-popup.ts +150 -0
  96. package/src/vue/use-toolbar-scroll.ts +95 -0
  97. package/dist/core/address.d.ts +0 -60
  98. package/dist/core/address.js +0 -142
  99. package/dist/core/address.js.map +0 -1
  100. package/dist/core/cell-store.d.ts +0 -61
  101. package/dist/core/cell-store.js +0 -135
  102. package/dist/core/cell-store.js.map +0 -1
  103. package/dist/core/command/default-registry.d.ts +0 -10
  104. package/dist/core/command/default-registry.js +0 -18
  105. package/dist/core/command/default-registry.js.map +0 -1
  106. package/dist/core/command/history.d.ts +0 -64
  107. package/dist/core/command/history.js +0 -127
  108. package/dist/core/command/history.js.map +0 -1
  109. package/dist/core/command/merge-cells.d.ts +0 -21
  110. package/dist/core/command/merge-cells.js +0 -74
  111. package/dist/core/command/merge-cells.js.map +0 -1
  112. package/dist/core/command/registry.d.ts +0 -17
  113. package/dist/core/command/registry.js +0 -26
  114. package/dist/core/command/registry.js.map +0 -1
  115. package/dist/core/command/set-cell-formula.d.ts +0 -17
  116. package/dist/core/command/set-cell-formula.js +0 -29
  117. package/dist/core/command/set-cell-formula.js.map +0 -1
  118. package/dist/core/command/set-cell-value.d.ts +0 -22
  119. package/dist/core/command/set-cell-value.js +0 -35
  120. package/dist/core/command/set-cell-value.js.map +0 -1
  121. package/dist/core/command/types.d.ts +0 -68
  122. package/dist/core/events.js +0 -29
  123. package/dist/core/events.js.map +0 -1
  124. package/dist/core/formula/ast.d.ts +0 -58
  125. package/dist/core/formula/ast.js +0 -38
  126. package/dist/core/formula/ast.js.map +0 -1
  127. package/dist/core/formula/dependency-graph.d.ts +0 -70
  128. package/dist/core/formula/dependency-graph.js +0 -269
  129. package/dist/core/formula/dependency-graph.js.map +0 -1
  130. package/dist/core/formula/errors.d.ts +0 -25
  131. package/dist/core/formula/errors.js +0 -36
  132. package/dist/core/formula/errors.js.map +0 -1
  133. package/dist/core/formula/evaluator.d.ts +0 -41
  134. package/dist/core/formula/evaluator.js +0 -154
  135. package/dist/core/formula/evaluator.js.map +0 -1
  136. package/dist/core/formula/functions.d.ts +0 -30
  137. package/dist/core/formula/functions.js +0 -209
  138. package/dist/core/formula/functions.js.map +0 -1
  139. package/dist/core/formula/parser.d.ts +0 -7
  140. package/dist/core/formula/parser.js +0 -208
  141. package/dist/core/formula/parser.js.map +0 -1
  142. package/dist/core/formula/tokenizer.d.ts +0 -37
  143. package/dist/core/formula/tokenizer.js +0 -146
  144. package/dist/core/formula/tokenizer.js.map +0 -1
  145. package/dist/core/merge-manager.d.ts +0 -64
  146. package/dist/core/merge-manager.js +0 -111
  147. package/dist/core/merge-manager.js.map +0 -1
  148. package/dist/core/selection.d.ts +0 -31
  149. package/dist/core/selection.js +0 -62
  150. package/dist/core/selection.js.map +0 -1
  151. package/dist/core/sheet.d.ts +0 -105
  152. package/dist/core/sheet.js +0 -202
  153. package/dist/core/sheet.js.map +0 -1
  154. package/dist/core/workbook.d.ts +0 -43
  155. package/dist/core/workbook.js +0 -77
  156. package/dist/core/workbook.js.map +0 -1
  157. package/dist/grid/sheet-grid.d.ts +0 -59
  158. package/dist/grid/sheet-grid.js +0 -230
  159. package/dist/grid/sheet-grid.js.map +0 -1
  160. package/dist/tools/builtin.js.map +0 -1
  161. package/dist/tools/context.js.map +0 -1
  162. package/dist/tools/registry.js.map +0 -1
  163. package/dist/vue/index.d.ts +0 -2
  164. package/dist/vue/sheet.js.map +0 -1
  165. package/dist/vue/sheet.vue.d.ts +0 -24
  166. package/src/core/__test__/address.test.ts +0 -113
  167. package/src/core/__test__/cell-store.test.ts +0 -97
  168. package/src/core/__test__/command.test.ts +0 -377
  169. package/src/core/__test__/formula-adversarial.test.ts +0 -265
  170. package/src/core/__test__/formula-engine.test.ts +0 -470
  171. package/src/core/__test__/formula-functions.test.ts +0 -178
  172. package/src/core/__test__/formula-parser.test.ts +0 -160
  173. package/src/core/__test__/history.test.ts +0 -225
  174. package/src/core/__test__/merge-manager.test.ts +0 -106
  175. package/src/core/__test__/sheet.test.ts +0 -142
  176. package/src/core/address.ts +0 -166
  177. package/src/core/cell-store.ts +0 -173
  178. package/src/core/command/default-registry.ts +0 -15
  179. package/src/core/command/history.ts +0 -167
  180. package/src/core/command/index.ts +0 -7
  181. package/src/core/command/merge-cells.ts +0 -74
  182. package/src/core/command/registry.ts +0 -30
  183. package/src/core/command/set-cell-formula.ts +0 -29
  184. package/src/core/command/set-cell-value.ts +0 -38
  185. package/src/core/command/types.ts +0 -73
  186. package/src/core/events.ts +0 -37
  187. package/src/core/formula/ast.ts +0 -66
  188. package/src/core/formula/dependency-graph.ts +0 -329
  189. package/src/core/formula/errors.ts +0 -41
  190. package/src/core/formula/evaluator.ts +0 -219
  191. package/src/core/formula/functions.ts +0 -266
  192. package/src/core/formula/index.ts +0 -7
  193. package/src/core/formula/parser.ts +0 -198
  194. package/src/core/formula/tokenizer.ts +0 -160
  195. package/src/core/merge-manager.ts +0 -158
  196. package/src/core/selection.ts +0 -66
  197. package/src/core/sheet.ts +0 -257
  198. package/src/core/workbook.ts +0 -99
  199. package/src/grid/__test__/canvas-mock.ts +0 -49
  200. package/src/grid/__test__/setup.ts +0 -3
  201. package/src/grid/__test__/sheet-grid-formula.test.ts +0 -140
  202. package/src/grid/__test__/sheet-grid.test.ts +0 -177
  203. package/src/grid/sheet-grid.ts +0 -283
@@ -1,74 +0,0 @@
1
- import { iterateRange, rangesIntersect } from "../address.js";
2
- import { cellDataEqual, isEmptyCellData } from "../cell-store.js";
3
- //#region src/core/command/merge-cells.ts
4
- /**
5
- * 合并命令。Patch 捕获完整 before 状态:
6
- * - 被解除的既有合并记录(undo 时逐一恢复)
7
- * - 包围盒内每一格的原数据(undo 时连被清空的值一起还原)
8
- * 值保留规则同 Excel/univer:行主序第一个有值格的值写入新锚点,其余清空。
9
- */
10
- const MergeCellsCommand = {
11
- id: "sheet.command.merge-cells",
12
- handler(ctx, params) {
13
- const { sheet } = ctx;
14
- const { range: finalRange, removed } = sheet.merges.computeMerge(params.range);
15
- const cellPatches = [];
16
- let retained;
17
- let anchorPatch;
18
- for (const addr of iterateRange(finalRange)) {
19
- const before = sheet.store.getCell(addr);
20
- if (before && !retained && !isEmptyCellData(before)) retained = before;
21
- const patch = {
22
- kind: "cell",
23
- addr,
24
- before,
25
- after: void 0
26
- };
27
- if (addr.row === finalRange.start.row && addr.col === finalRange.start.col) anchorPatch = patch;
28
- cellPatches.push(patch);
29
- }
30
- if (retained && anchorPatch) anchorPatch.after = { ...retained };
31
- const patches = [...[...removed.map((range) => ({
32
- kind: "merge",
33
- range,
34
- before: true,
35
- after: false
36
- })), {
37
- kind: "merge",
38
- range: finalRange,
39
- before: false,
40
- after: true
41
- }], ...cellPatches.filter((patch) => !cellDataEqual(patch.before, patch.after))];
42
- for (const patch of patches) ctx.applyPatch(patch, "redo");
43
- return {
44
- mutations: [{
45
- redo: patches,
46
- undo: [...patches].reverse()
47
- }],
48
- result: finalRange
49
- };
50
- }
51
- };
52
- /** 取消合并命令:解除与 range 相交的所有合并;undo 恢复合并记录 */
53
- const UnmergeCellsCommand = {
54
- id: "sheet.command.unmerge-cells",
55
- handler(ctx, params) {
56
- const removed = [];
57
- for (const range of ctx.sheet.merges.getMerges()) if (rangesIntersect(range, params.range)) removed.push({
58
- kind: "merge",
59
- range,
60
- before: true,
61
- after: false
62
- });
63
- if (removed.length === 0) return { mutations: [] };
64
- for (const patch of removed) ctx.applyPatch(patch, "redo");
65
- return { mutations: [{
66
- redo: removed,
67
- undo: [...removed].reverse()
68
- }] };
69
- }
70
- };
71
- //#endregion
72
- export { MergeCellsCommand, UnmergeCellsCommand };
73
-
74
- //# sourceMappingURL=merge-cells.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"merge-cells.js","names":[],"sources":["../../../src/core/command/merge-cells.ts"],"sourcesContent":["import { iterateRange, rangesIntersect, type CellRange } from '../address'\nimport { cellDataEqual, isEmptyCellData, type CellData } from '../cell-store'\nimport type { CellPatch, Command, CommandResult, MergePatch, Patch } from './types'\n\nexport interface MergeCellsParams {\n range: CellRange\n}\n\n/**\n * 合并命令。Patch 捕获完整 before 状态:\n * - 被解除的既有合并记录(undo 时逐一恢复)\n * - 包围盒内每一格的原数据(undo 时连被清空的值一起还原)\n * 值保留规则同 Excel/univer:行主序第一个有值格的值写入新锚点,其余清空。\n */\nexport const MergeCellsCommand: Command<MergeCellsParams, CellRange> = {\n id: 'sheet.command.merge-cells',\n\n handler(ctx, params): CommandResult<CellRange> {\n const { sheet } = ctx\n const { range: finalRange, removed } = sheet.merges.computeMerge(params.range)\n\n // 捕获包围盒内各格 before;同时按行主序找出第一个有值格\n const cellPatches: CellPatch[] = []\n let retained: CellData | undefined\n let anchorPatch: CellPatch | undefined\n for (const addr of iterateRange(finalRange)) {\n const before = sheet.store.getCell(addr)\n if (before && !retained && !isEmptyCellData(before)) retained = before\n const patch: CellPatch = { kind: 'cell', addr, before, after: undefined }\n if (addr.row === finalRange.start.row && addr.col === finalRange.start.col) {\n anchorPatch = patch\n }\n cellPatches.push(patch)\n }\n if (retained && anchorPatch) {\n anchorPatch.after = { ...retained }\n }\n\n const mergePatches: MergePatch[] = [\n ...removed.map((range): MergePatch => ({ kind: 'merge', range, before: true, after: false })),\n { kind: 'merge', range: finalRange, before: false, after: true }\n ]\n\n // 过滤无实际变化的 cell 补丁(如被覆盖格本就为空)\n const patches: Patch[] = [\n ...mergePatches,\n ...cellPatches.filter((patch) => !cellDataEqual(patch.before, patch.after))\n ]\n for (const patch of patches) ctx.applyPatch(patch, 'redo')\n\n return { mutations: [{ redo: patches, undo: [...patches].reverse() }], result: finalRange }\n }\n}\n\nexport interface UnmergeCellsParams {\n range: CellRange\n}\n\n/** 取消合并命令:解除与 range 相交的所有合并;undo 恢复合并记录 */\nexport const UnmergeCellsCommand: Command<UnmergeCellsParams> = {\n id: 'sheet.command.unmerge-cells',\n\n handler(ctx, params): CommandResult {\n const removed: MergePatch[] = []\n for (const range of ctx.sheet.merges.getMerges()) {\n if (rangesIntersect(range, params.range)) {\n removed.push({ kind: 'merge', range, before: true, after: false })\n }\n }\n if (removed.length === 0) return { mutations: [] }\n for (const patch of removed) ctx.applyPatch(patch, 'redo')\n return { mutations: [{ redo: removed, undo: [...removed].reverse() }] }\n }\n}\n"],"mappings":";;;;;;;;;AAcA,MAAa,oBAA0D;CACrE,IAAI;CAEJ,QAAQ,KAAK,QAAkC;EAC7C,MAAM,EAAE,UAAU;EAClB,MAAM,EAAE,OAAO,YAAY,YAAY,MAAM,OAAO,aAAa,OAAO,KAAK;EAG7E,MAAM,cAA2B,CAAC;EAClC,IAAI;EACJ,IAAI;EACJ,KAAK,MAAM,QAAQ,aAAa,UAAU,GAAG;GAC3C,MAAM,SAAS,MAAM,MAAM,QAAQ,IAAI;GACvC,IAAI,UAAU,CAAC,YAAY,CAAC,gBAAgB,MAAM,GAAG,WAAW;GAChE,MAAM,QAAmB;IAAE,MAAM;IAAQ;IAAM;IAAQ,OAAO,KAAA;GAAU;GACxE,IAAI,KAAK,QAAQ,WAAW,MAAM,OAAO,KAAK,QAAQ,WAAW,MAAM,KACrE,cAAc;GAEhB,YAAY,KAAK,KAAK;EACxB;EACA,IAAI,YAAY,aACd,YAAY,QAAQ,EAAE,GAAG,SAAS;EASpC,MAAM,UAAmB,CACvB,GAAG,CANH,GAAG,QAAQ,KAAK,WAAuB;GAAE,MAAM;GAAS;GAAO,QAAQ;GAAM,OAAO;EAAM,EAAE,GAC5F;GAAE,MAAM;GAAS,OAAO;GAAY,QAAQ;GAAO,OAAO;EAAK,CAKjD,GACd,GAAG,YAAY,QAAQ,UAAU,CAAC,cAAc,MAAM,QAAQ,MAAM,KAAK,CAAC,CAC5E;EACA,KAAK,MAAM,SAAS,SAAS,IAAI,WAAW,OAAO,MAAM;EAEzD,OAAO;GAAE,WAAW,CAAC;IAAE,MAAM;IAAS,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,QAAQ;GAAE,CAAC;GAAG,QAAQ;EAAW;CAC5F;AACF;;AAOA,MAAa,sBAAmD;CAC9D,IAAI;CAEJ,QAAQ,KAAK,QAAuB;EAClC,MAAM,UAAwB,CAAC;EAC/B,KAAK,MAAM,SAAS,IAAI,MAAM,OAAO,UAAU,GAC7C,IAAI,gBAAgB,OAAO,OAAO,KAAK,GACrC,QAAQ,KAAK;GAAE,MAAM;GAAS;GAAO,QAAQ;GAAM,OAAO;EAAM,CAAC;EAGrE,IAAI,QAAQ,WAAW,GAAG,OAAO,EAAE,WAAW,CAAC,EAAE;EACjD,KAAK,MAAM,SAAS,SAAS,IAAI,WAAW,OAAO,MAAM;EACzD,OAAO,EAAE,WAAW,CAAC;GAAE,MAAM;GAAS,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,QAAQ;EAAE,CAAC,EAAE;CACxE;AACF"}
@@ -1,17 +0,0 @@
1
- import { Command, CommandContext, CommandResult } from "./types.js";
2
- //#region src/core/command/registry.d.ts
3
- /**
4
- * 命令注册表:register / execute。
5
- * 命令无状态,可全局共享(见 default-registry);阶段 4 工具扩展可注册自定义命令。
6
- */
7
- declare class CommandRegistry {
8
- private commands;
9
- /** 注册命令;同 id 重复注册视为错误 */
10
- register(command: Command): void;
11
- get(id: string): Command | undefined;
12
- /** 执行命令;未注册的 id 抛错 */
13
- execute<R>(ctx: CommandContext, id: string, params: unknown): CommandResult<R> | undefined;
14
- }
15
- //#endregion
16
- export { CommandRegistry };
17
- //# sourceMappingURL=registry.d.ts.map
@@ -1,26 +0,0 @@
1
- //#region src/core/command/registry.ts
2
- /**
3
- * 命令注册表:register / execute。
4
- * 命令无状态,可全局共享(见 default-registry);阶段 4 工具扩展可注册自定义命令。
5
- */
6
- var CommandRegistry = class {
7
- commands = /* @__PURE__ */ new Map();
8
- /** 注册命令;同 id 重复注册视为错误 */
9
- register(command) {
10
- if (this.commands.has(command.id)) throw new Error(`命令重复注册: ${command.id}`);
11
- this.commands.set(command.id, command);
12
- }
13
- get(id) {
14
- return this.commands.get(id);
15
- }
16
- /** 执行命令;未注册的 id 抛错 */
17
- execute(ctx, id, params) {
18
- const command = this.commands.get(id);
19
- if (!command) throw new Error(`命令未注册: ${id}`);
20
- return command.handler(ctx, params);
21
- }
22
- };
23
- //#endregion
24
- export { CommandRegistry };
25
-
26
- //# sourceMappingURL=registry.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry.js","names":[],"sources":["../../../src/core/command/registry.ts"],"sourcesContent":["import type { Command, CommandContext, CommandResult } from './types'\n\n/**\n * 命令注册表:register / execute。\n * 命令无状态,可全局共享(见 default-registry);阶段 4 工具扩展可注册自定义命令。\n */\nexport class CommandRegistry {\n private commands = new Map<string, Command>()\n\n /** 注册命令;同 id 重复注册视为错误 */\n register(command: Command): void {\n if (this.commands.has(command.id)) {\n throw new Error(`命令重复注册: ${command.id}`)\n }\n this.commands.set(command.id, command)\n }\n\n get(id: string): Command | undefined {\n return this.commands.get(id)\n }\n\n /** 执行命令;未注册的 id 抛错 */\n execute<R>(ctx: CommandContext, id: string, params: unknown): CommandResult<R> | undefined {\n const command = this.commands.get(id)\n if (!command) {\n throw new Error(`命令未注册: ${id}`)\n }\n return command.handler(ctx, params) as CommandResult<R> | undefined\n }\n}\n"],"mappings":";;;;;AAMA,IAAa,kBAAb,MAA6B;CAC3B,2BAAmB,IAAI,IAAqB;;CAG5C,SAAS,SAAwB;EAC/B,IAAI,KAAK,SAAS,IAAI,QAAQ,EAAE,GAC9B,MAAM,IAAI,MAAM,WAAW,QAAQ,IAAI;EAEzC,KAAK,SAAS,IAAI,QAAQ,IAAI,OAAO;CACvC;CAEA,IAAI,IAAiC;EACnC,OAAO,KAAK,SAAS,IAAI,EAAE;CAC7B;;CAGA,QAAW,KAAqB,IAAY,QAA+C;EACzF,MAAM,UAAU,KAAK,SAAS,IAAI,EAAE;EACpC,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,UAAU,IAAI;EAEhC,OAAO,QAAQ,QAAQ,KAAK,MAAM;CACpC;AACF"}
@@ -1,17 +0,0 @@
1
- import { CellAddress } from "../address.js";
2
- import { Command } from "./types.js";
3
- //#region src/core/command/set-cell-formula.d.ts
4
- interface SetCellFormulaParams {
5
- addr: CellAddress;
6
- /** 公式文本(不含 '=') */
7
- formula: string;
8
- }
9
- /**
10
- * 公式写入命令:只登记公式原文(f);计算缓存(v/t)由命令执行后的
11
- * 增量重算以派生补丁填充(见 Sheet.executeCommand),重算波及的所有变更
12
- * 与源补丁并入同一 undo 单元。
13
- */
14
- declare const SetCellFormulaCommand: Command<SetCellFormulaParams>;
15
- //#endregion
16
- export { SetCellFormulaCommand, SetCellFormulaParams };
17
- //# sourceMappingURL=set-cell-formula.d.ts.map
@@ -1,29 +0,0 @@
1
- //#region src/core/command/set-cell-formula.ts
2
- /**
3
- * 公式写入命令:只登记公式原文(f);计算缓存(v/t)由命令执行后的
4
- * 增量重算以派生补丁填充(见 Sheet.executeCommand),重算波及的所有变更
5
- * 与源补丁并入同一 undo 单元。
6
- */
7
- const SetCellFormulaCommand = {
8
- id: "sheet.command.set-cell-formula",
9
- handler(ctx, params) {
10
- const anchor = ctx.sheet.merges.resolveAnchor(params.addr);
11
- const before = ctx.sheet.store.getCell(anchor);
12
- if (before?.f === params.formula) return { mutations: [] };
13
- const patch = {
14
- kind: "cell",
15
- addr: anchor,
16
- before,
17
- after: { f: params.formula }
18
- };
19
- ctx.applyPatch(patch, "redo");
20
- return { mutations: [{
21
- redo: [patch],
22
- undo: [patch]
23
- }] };
24
- }
25
- };
26
- //#endregion
27
- export { SetCellFormulaCommand };
28
-
29
- //# sourceMappingURL=set-cell-formula.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"set-cell-formula.js","names":[],"sources":["../../../src/core/command/set-cell-formula.ts"],"sourcesContent":["import type { CellAddress } from '../address'\nimport type { CellData } from '../cell-store'\nimport type { CellPatch, Command, CommandResult } from './types'\n\nexport interface SetCellFormulaParams {\n addr: CellAddress\n /** 公式文本(不含 '=') */\n formula: string\n}\n\n/**\n * 公式写入命令:只登记公式原文(f);计算缓存(v/t)由命令执行后的\n * 增量重算以派生补丁填充(见 Sheet.executeCommand),重算波及的所有变更\n * 与源补丁并入同一 undo 单元。\n */\nexport const SetCellFormulaCommand: Command<SetCellFormulaParams> = {\n id: 'sheet.command.set-cell-formula',\n\n handler(ctx, params): CommandResult {\n const anchor = ctx.sheet.merges.resolveAnchor(params.addr)\n const before = ctx.sheet.store.getCell(anchor)\n // 同公式重复输入 = 无实际变更,不入历史\n if (before?.f === params.formula) return { mutations: [] }\n const after: CellData = { f: params.formula }\n const patch: CellPatch = { kind: 'cell', addr: anchor, before, after }\n ctx.applyPatch(patch, 'redo')\n return { mutations: [{ redo: [patch], undo: [patch] }] }\n }\n}\n"],"mappings":";;;;;;AAeA,MAAa,wBAAuD;CAClE,IAAI;CAEJ,QAAQ,KAAK,QAAuB;EAClC,MAAM,SAAS,IAAI,MAAM,OAAO,cAAc,OAAO,IAAI;EACzD,MAAM,SAAS,IAAI,MAAM,MAAM,QAAQ,MAAM;EAE7C,IAAI,QAAQ,MAAM,OAAO,SAAS,OAAO,EAAE,WAAW,CAAC,EAAE;EAEzD,MAAM,QAAmB;GAAE,MAAM;GAAQ,MAAM;GAAQ;GAAQ,OAAA,EADrC,GAAG,OAAO,QAC+B;EAAE;EACrE,IAAI,WAAW,OAAO,MAAM;EAC5B,OAAO,EAAE,WAAW,CAAC;GAAE,MAAM,CAAC,KAAK;GAAG,MAAM,CAAC,KAAK;EAAE,CAAC,EAAE;CACzD;AACF"}
@@ -1,22 +0,0 @@
1
- import { CellAddress } from "../address.js";
2
- import { CellData } from "../cell-store.js";
3
- import { Command } from "./types.js";
4
- //#region src/core/command/set-cell-value.d.ts
5
- /** SetCellValueCommand 的批量写入项 */
6
- interface SetCellValueItem {
7
- addr: CellAddress;
8
- /** 目标数据;空数据(无公式且 v 为 null/undefined/'')= 清除 */
9
- data?: CellData;
10
- }
11
- interface SetCellValueParams {
12
- /** 批量写入(供粘贴/填充复用);一次调用 = 一个 undo 单元 */
13
- items: SetCellValueItem[];
14
- }
15
- /**
16
- * 单元格写入命令:逐项解析锚点、捕获 before/after 差量并立即应用。
17
- * 与 before 相等的项跳过(不产生补丁);全部无变化时不入历史。
18
- */
19
- declare const SetCellValueCommand: Command<SetCellValueParams>;
20
- //#endregion
21
- export { SetCellValueCommand, SetCellValueItem, SetCellValueParams };
22
- //# sourceMappingURL=set-cell-value.d.ts.map
@@ -1,35 +0,0 @@
1
- import { cellDataEqual, isEmptyCellData } from "../cell-store.js";
2
- //#region src/core/command/set-cell-value.ts
3
- /**
4
- * 单元格写入命令:逐项解析锚点、捕获 before/after 差量并立即应用。
5
- * 与 before 相等的项跳过(不产生补丁);全部无变化时不入历史。
6
- */
7
- const SetCellValueCommand = {
8
- id: "sheet.command.set-cell-value",
9
- handler(ctx, params) {
10
- const patches = [];
11
- for (const item of params.items) {
12
- const anchor = ctx.sheet.merges.resolveAnchor(item.addr);
13
- const before = ctx.sheet.store.getCell(anchor);
14
- const after = isEmptyCellData(item.data) ? void 0 : item.data;
15
- if (cellDataEqual(before, after)) continue;
16
- const patch = {
17
- kind: "cell",
18
- addr: anchor,
19
- before,
20
- after
21
- };
22
- ctx.applyPatch(patch, "redo");
23
- patches.push(patch);
24
- }
25
- if (patches.length === 0) return { mutations: [] };
26
- return { mutations: [{
27
- redo: patches,
28
- undo: [...patches].reverse()
29
- }] };
30
- }
31
- };
32
- //#endregion
33
- export { SetCellValueCommand };
34
-
35
- //# sourceMappingURL=set-cell-value.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"set-cell-value.js","names":[],"sources":["../../../src/core/command/set-cell-value.ts"],"sourcesContent":["import type { CellAddress } from '../address'\nimport { cellDataEqual, isEmptyCellData, type CellData } from '../cell-store'\nimport type { CellPatch, Command, CommandResult } from './types'\n\n/** SetCellValueCommand 的批量写入项 */\nexport interface SetCellValueItem {\n addr: CellAddress\n /** 目标数据;空数据(无公式且 v 为 null/undefined/'')= 清除 */\n data?: CellData\n}\n\nexport interface SetCellValueParams {\n /** 批量写入(供粘贴/填充复用);一次调用 = 一个 undo 单元 */\n items: SetCellValueItem[]\n}\n\n/**\n * 单元格写入命令:逐项解析锚点、捕获 before/after 差量并立即应用。\n * 与 before 相等的项跳过(不产生补丁);全部无变化时不入历史。\n */\nexport const SetCellValueCommand: Command<SetCellValueParams> = {\n id: 'sheet.command.set-cell-value',\n\n handler(ctx, params): CommandResult {\n const patches: CellPatch[] = []\n for (const item of params.items) {\n const anchor = ctx.sheet.merges.resolveAnchor(item.addr)\n const before = ctx.sheet.store.getCell(anchor)\n const after = isEmptyCellData(item.data) ? undefined : item.data\n if (cellDataEqual(before, after)) continue\n const patch: CellPatch = { kind: 'cell', addr: anchor, before, after }\n ctx.applyPatch(patch, 'redo')\n patches.push(patch)\n }\n if (patches.length === 0) return { mutations: [] }\n return { mutations: [{ redo: patches, undo: [...patches].reverse() }] }\n }\n}\n"],"mappings":";;;;;;AAoBA,MAAa,sBAAmD;CAC9D,IAAI;CAEJ,QAAQ,KAAK,QAAuB;EAClC,MAAM,UAAuB,CAAC;EAC9B,KAAK,MAAM,QAAQ,OAAO,OAAO;GAC/B,MAAM,SAAS,IAAI,MAAM,OAAO,cAAc,KAAK,IAAI;GACvD,MAAM,SAAS,IAAI,MAAM,MAAM,QAAQ,MAAM;GAC7C,MAAM,QAAQ,gBAAgB,KAAK,IAAI,IAAI,KAAA,IAAY,KAAK;GAC5D,IAAI,cAAc,QAAQ,KAAK,GAAG;GAClC,MAAM,QAAmB;IAAE,MAAM;IAAQ,MAAM;IAAQ;IAAQ;GAAM;GACrE,IAAI,WAAW,OAAO,MAAM;GAC5B,QAAQ,KAAK,KAAK;EACpB;EACA,IAAI,QAAQ,WAAW,GAAG,OAAO,EAAE,WAAW,CAAC,EAAE;EACjD,OAAO,EAAE,WAAW,CAAC;GAAE,MAAM;GAAS,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,QAAQ;EAAE,CAAC,EAAE;CACxE;AACF"}
@@ -1,68 +0,0 @@
1
- import { CellAddress, CellRange } from "../address.js";
2
- import { CellData } from "../cell-store.js";
3
- import { Sheet } from "../sheet.js";
4
- //#region src/core/command/types.d.ts
5
- /**
6
- * 命令系统类型定义(决策 5:命令 + 逆操作补丁)。
7
- *
8
- * - 一切模型变更都是 Command,执行时产出 Mutation
9
- * - Patch 是受影响单元格 / 合并记录的 before/after 差量,不是全量快照
10
- * - 同一批 Patch 双向回放:redo 方向应用 after,undo 方向应用 before
11
- */
12
- /** 补丁回放方向 */
13
- type PatchDirection = 'undo' | 'redo';
14
- /** 单元格数据差量补丁(原始存储语义;undefined = 该侧无此格) */
15
- interface CellPatch {
16
- kind: 'cell';
17
- addr: CellAddress;
18
- /**
19
- * 目标 sheet(跨表公式重算的派生补丁会落在其它 sheet 上);
20
- * 缺省 = 命令所在 sheet。回放时按此字段路由到目标 sheet 的变更通道。
21
- */
22
- sheet?: Sheet;
23
- /** 变更前的数据(undefined = 原本为空格) */
24
- before?: CellData;
25
- /** 变更后的数据(undefined = 变更后为空格) */
26
- after?: CellData;
27
- }
28
- /** 合并记录差量补丁(before/after = 该侧是否存在此合并) */
29
- interface MergePatch {
30
- kind: 'merge';
31
- range: CellRange;
32
- before: boolean;
33
- after: boolean;
34
- }
35
- type Patch = CellPatch | MergePatch;
36
- /**
37
- * 一次命令执行产生的变更单元。
38
- * `redo` 按列表顺序应用;`undo` 取同一批补丁的逆序(命令实现负责构造,
39
- * 保证 undo 先撤销后登记的副作用,例如先移除新合并再恢复旧合并)。
40
- */
41
- interface Mutation {
42
- redo: Patch[];
43
- undo: Patch[];
44
- }
45
- /** 命令执行结果 */
46
- interface CommandResult<R = unknown> {
47
- /** 产生的 mutation 列表(空数组 = 无实际变更,不入历史) */
48
- mutations: Mutation[];
49
- /** 命令附带返回值(如 MergeCellsCommand 返回最终生效区域) */
50
- result?: R;
51
- }
52
- /** 命令执行上下文 */
53
- interface CommandContext {
54
- sheet: Sheet;
55
- /**
56
- * 应用单个补丁。命令 handler 执行时对 redo 补丁逐项调用;
57
- * HistoryManager 回放 undo/redo 亦走此路径,保证只有一条变更通道。
58
- */
59
- applyPatch(patch: Patch, direction: PatchDirection): void;
60
- }
61
- /** 命令:id + handler */
62
- interface Command<P = unknown, R = unknown> {
63
- readonly id: string;
64
- handler(ctx: CommandContext, params: P): CommandResult<R> | undefined;
65
- }
66
- //#endregion
67
- export { CellPatch, Command, CommandContext, CommandResult, MergePatch, Mutation, Patch, PatchDirection };
68
- //# sourceMappingURL=types.d.ts.map
@@ -1,29 +0,0 @@
1
- //#region src/core/events.ts
2
- var TypedEventEmitter = class {
3
- handlers = /* @__PURE__ */ new Map();
4
- /** 订阅事件,返回取消订阅函数 */
5
- on(type, handler) {
6
- let set = this.handlers.get(type);
7
- if (!set) {
8
- set = /* @__PURE__ */ new Set();
9
- this.handlers.set(type, set);
10
- }
11
- set.add(handler);
12
- return () => this.off(type, handler);
13
- }
14
- off(type, handler) {
15
- this.handlers.get(type)?.delete(handler);
16
- }
17
- emit(type, payload) {
18
- const set = this.handlers.get(type);
19
- if (!set) return;
20
- for (const handler of set) handler(payload);
21
- }
22
- clear() {
23
- this.handlers.clear();
24
- }
25
- };
26
- //#endregion
27
- export { TypedEventEmitter };
28
-
29
- //# sourceMappingURL=events.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"events.js","names":[],"sources":["../../src/core/events.ts"],"sourcesContent":["/**\n * 包内轻量类型化事件发射器(core 内部基建,不对外导出实现细节)。\n */\n\nexport type EventHandler<T> = (payload: T) => void\n\nexport class TypedEventEmitter<EventMap extends Record<string, unknown>> {\n private handlers = new Map<keyof EventMap, Set<EventHandler<EventMap[keyof EventMap]>>>()\n\n /** 订阅事件,返回取消订阅函数 */\n on<K extends keyof EventMap>(type: K, handler: EventHandler<EventMap[K]>): () => void {\n let set = this.handlers.get(type)\n if (!set) {\n set = new Set()\n this.handlers.set(type, set)\n }\n set.add(handler as EventHandler<EventMap[keyof EventMap]>)\n return () => this.off(type, handler)\n }\n\n off<K extends keyof EventMap>(type: K, handler: EventHandler<EventMap[K]>): void {\n this.handlers.get(type)?.delete(handler as EventHandler<EventMap[keyof EventMap]>)\n }\n\n emit<K extends keyof EventMap>(type: K, payload: EventMap[K]): void {\n const set = this.handlers.get(type)\n if (!set) return\n // Set 迭代天然容忍遍历中取消订阅\n for (const handler of set) {\n ;(handler as EventHandler<EventMap[K]>)(payload)\n }\n }\n\n clear(): void {\n this.handlers.clear()\n }\n}\n"],"mappings":";AAMA,IAAa,oBAAb,MAAyE;CACvE,2BAAmB,IAAI,IAAiE;;CAGxF,GAA6B,MAAS,SAAgD;EACpF,IAAI,MAAM,KAAK,SAAS,IAAI,IAAI;EAChC,IAAI,CAAC,KAAK;GACR,sBAAM,IAAI,IAAI;GACd,KAAK,SAAS,IAAI,MAAM,GAAG;EAC7B;EACA,IAAI,IAAI,OAAiD;EACzD,aAAa,KAAK,IAAI,MAAM,OAAO;CACrC;CAEA,IAA8B,MAAS,SAA0C;EAC/E,KAAK,SAAS,IAAI,IAAI,CAAC,EAAE,OAAO,OAAiD;CACnF;CAEA,KAA+B,MAAS,SAA4B;EAClE,MAAM,MAAM,KAAK,SAAS,IAAI,IAAI;EAClC,IAAI,CAAC,KAAK;EAEV,KAAK,MAAM,WAAW,KACnB,QAAuC,OAAO;CAEnD;CAEA,QAAc;EACZ,KAAK,SAAS,MAAM;CACtB;AACF"}
@@ -1,58 +0,0 @@
1
- import { CellAddress, CellRange } from "../address.js";
2
- //#region src/core/formula/ast.d.ts
3
- /**
4
- * 公式 AST 节点。
5
- * 引用节点携带可选 sheet 名(跨表引用);缺省 = 公式所在 sheet。
6
- */
7
- type BinaryOperator = '+' | '-' | '*' | '/' | '^' | '&' | '=' | '<>' | '<' | '<=' | '>' | '>=';
8
- type AstNode = {
9
- kind: 'number';
10
- value: number;
11
- } | {
12
- kind: 'string';
13
- value: string;
14
- } | {
15
- kind: 'boolean';
16
- value: boolean;
17
- } |
18
- /** 未知名称(如裸写的 Sheet2 / 未定义命名);求值为 #NAME? */
19
- {
20
- kind: 'name';
21
- name: string;
22
- } | {
23
- kind: 'cell';
24
- sheet?: string;
25
- addr: CellAddress;
26
- } | {
27
- kind: 'range';
28
- sheet?: string;
29
- range: CellRange;
30
- } | {
31
- kind: 'unary';
32
- op: '-' | '+';
33
- operand: AstNode;
34
- } |
35
- /** 百分号后缀运算(除以 100) */
36
- {
37
- kind: 'percent';
38
- operand: AstNode;
39
- } | {
40
- kind: 'binary';
41
- op: BinaryOperator;
42
- left: AstNode;
43
- right: AstNode;
44
- } | {
45
- kind: 'call';
46
- name: string;
47
- args: AstNode[];
48
- };
49
- /** 公式中的引用(依赖图提取用):sheet 缺省由所属公式节点补齐 */
50
- interface AstReference {
51
- sheet?: string;
52
- range: CellRange;
53
- }
54
- /** 遍历 AST,收集全部引用(单格视为 1×1 区域) */
55
- declare function collectReferences(node: AstNode, out?: AstReference[]): AstReference[];
56
- //#endregion
57
- export { AstNode, AstReference, BinaryOperator, collectReferences };
58
- //# sourceMappingURL=ast.d.ts.map
@@ -1,38 +0,0 @@
1
- //#region src/core/formula/ast.ts
2
- /** 遍历 AST,收集全部引用(单格视为 1×1 区域) */
3
- function collectReferences(node, out = []) {
4
- switch (node.kind) {
5
- case "cell":
6
- out.push({
7
- sheet: node.sheet,
8
- range: {
9
- start: node.addr,
10
- end: node.addr
11
- }
12
- });
13
- break;
14
- case "range":
15
- out.push({
16
- sheet: node.sheet,
17
- range: node.range
18
- });
19
- break;
20
- case "unary":
21
- case "percent":
22
- collectReferences(node.operand, out);
23
- break;
24
- case "binary":
25
- collectReferences(node.left, out);
26
- collectReferences(node.right, out);
27
- break;
28
- case "call":
29
- for (const arg of node.args) collectReferences(arg, out);
30
- break;
31
- default: break;
32
- }
33
- return out;
34
- }
35
- //#endregion
36
- export { collectReferences };
37
-
38
- //# sourceMappingURL=ast.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ast.js","names":[],"sources":["../../../src/core/formula/ast.ts"],"sourcesContent":["import type { CellAddress, CellRange } from '../address'\n\n/**\n * 公式 AST 节点。\n * 引用节点携带可选 sheet 名(跨表引用);缺省 = 公式所在 sheet。\n */\n\nexport type BinaryOperator =\n | '+'\n | '-'\n | '*'\n | '/'\n | '^'\n | '&'\n | '='\n | '<>'\n | '<'\n | '<='\n | '>'\n | '>='\n\nexport type AstNode =\n | { kind: 'number'; value: number }\n | { kind: 'string'; value: string }\n | { kind: 'boolean'; value: boolean }\n /** 未知名称(如裸写的 Sheet2 / 未定义命名);求值为 #NAME? */\n | { kind: 'name'; name: string }\n | { kind: 'cell'; sheet?: string; addr: CellAddress }\n | { kind: 'range'; sheet?: string; range: CellRange }\n | { kind: 'unary'; op: '-' | '+'; operand: AstNode }\n /** 百分号后缀运算(除以 100) */\n | { kind: 'percent'; operand: AstNode }\n | { kind: 'binary'; op: BinaryOperator; left: AstNode; right: AstNode }\n | { kind: 'call'; name: string; args: AstNode[] }\n\n/** 公式中的引用(依赖图提取用):sheet 缺省由所属公式节点补齐 */\nexport interface AstReference {\n sheet?: string\n range: CellRange\n}\n\n/** 遍历 AST,收集全部引用(单格视为 1×1 区域) */\nexport function collectReferences(node: AstNode, out: AstReference[] = []): AstReference[] {\n switch (node.kind) {\n case 'cell':\n out.push({ sheet: node.sheet, range: { start: node.addr, end: node.addr } })\n break\n case 'range':\n out.push({ sheet: node.sheet, range: node.range })\n break\n case 'unary':\n case 'percent':\n collectReferences(node.operand, out)\n break\n case 'binary':\n collectReferences(node.left, out)\n collectReferences(node.right, out)\n break\n case 'call':\n for (const arg of node.args) collectReferences(arg, out)\n break\n default:\n break\n }\n return out\n}\n"],"mappings":";;AA0CA,SAAgB,kBAAkB,MAAe,MAAsB,CAAC,GAAmB;CACzF,QAAQ,KAAK,MAAb;EACE,KAAK;GACH,IAAI,KAAK;IAAE,OAAO,KAAK;IAAO,OAAO;KAAE,OAAO,KAAK;KAAM,KAAK,KAAK;IAAK;GAAE,CAAC;GAC3E;EACF,KAAK;GACH,IAAI,KAAK;IAAE,OAAO,KAAK;IAAO,OAAO,KAAK;GAAM,CAAC;GACjD;EACF,KAAK;EACL,KAAK;GACH,kBAAkB,KAAK,SAAS,GAAG;GACnC;EACF,KAAK;GACH,kBAAkB,KAAK,MAAM,GAAG;GAChC,kBAAkB,KAAK,OAAO,GAAG;GACjC;EACF,KAAK;GACH,KAAK,MAAM,OAAO,KAAK,MAAM,kBAAkB,KAAK,GAAG;GACvD;EACF,SACE;CACJ;CACA,OAAO;AACT"}
@@ -1,70 +0,0 @@
1
- import { CellAddress, CellRange } from "../address.js";
2
- import { CellData } from "../cell-store.js";
3
- import { CellPatch } from "../command/types.js";
4
- import { AstNode } from "./ast.js";
5
- import { Sheet } from "../sheet.js";
6
- //#region src/core/formula/dependency-graph.d.ts
7
- /**
8
- * 依赖图(工作簿级计算中枢):
9
- * - sheet 注册表:跨表引用按名解析(不存在 → #REF!)
10
- * - 正向索引:公式格 → 引用格集合(节点 deps);反向索引:引用格 → 依赖者
11
- * (单格引用走 cellKey 精确索引 O(1),区域引用走线性扫描)
12
- * - 变更时标脏(向上 BFS 收集全部依赖者)+ 拓扑序增量重算(递归向下,memo 去重)
13
- * - 循环引用检测:求值在途栈遇回边 → 环上所有格 #CYCLE!;依赖环外格只传播错误,
14
- * 打破循环(编辑环上格)后经标脏重算自动恢复
15
- *
16
- * 图状态与单元格存储严格同步:所有 f 变更(命令/undo/redo/rollback 回放)都经
17
- * Sheet.applyPatch → syncCell 维护节点;重算只发生在命令执行后(见 Sheet.executeCommand),
18
- * undo/redo 靠派生补丁精确回放缓存值,不重算。
19
- */
20
- /** 公式节点的一个依赖(sheet 名已补齐为具体值) */
21
- interface FormulaDependency {
22
- sheetName: string;
23
- range: CellRange;
24
- }
25
- /** 公式节点(依赖图管理的公式格状态;依赖图外部只读使用) */
26
- interface FormulaNode {
27
- readonly sheetName: string;
28
- readonly addr: CellAddress;
29
- readonly formula: string;
30
- /** null = 解析失败(求值 #ERROR!,无依赖) */
31
- readonly ast: AstNode | null;
32
- readonly deps: FormulaDependency[];
33
- /** 反向索引清理器(removeNode 时执行) */
34
- readonly cleanups: (() => void)[];
35
- }
36
- declare class DependencyGraph {
37
- private readonly sheets;
38
- /** 正向索引宿主:sheetName → cellKey → 公式节点 */
39
- private readonly nodes;
40
- /** 反向索引(单格引用):sheetName → cellKey → 依赖者集合 */
41
- private readonly exact;
42
- /** 反向索引(区域引用):sheetName → { 区域, 依赖者 } 集合(线性扫描) */
43
- private readonly ranged;
44
- registerSheet(sheet: Sheet): void;
45
- /** 注销 sheet 并移除其全部公式节点(引用它的公式在下次重算时得 #REF!) */
46
- unregisterSheet(sheet: Sheet): void;
47
- getSheet(name: string): Sheet | undefined;
48
- getNode(sheetName: string, addr: CellAddress): FormulaNode | undefined;
49
- /** 公式节点总数(测试/调试用) */
50
- get nodeCount(): number;
51
- /**
52
- * 单元格补丁后的图同步:f 增/删/改 → 节点增/删/重建。
53
- * 由 Sheet.applyPatch(唯一变更通道)调用,命令与 undo/redo 回放均覆盖。
54
- */
55
- syncCell(sheet: Sheet, addr: CellAddress, before?: CellData, after?: CellData): void;
56
- /**
57
- * 变更集 → 标脏 + 拓扑序重算 → 派生补丁(未应用)。
58
- * 调用方(Sheet.executeCommand)负责应用补丁并并入同一 undo 单元。
59
- */
60
- recalc(changed: readonly {
61
- sheet: Sheet;
62
- addr: CellAddress;
63
- }[]): CellPatch[];
64
- private addNode;
65
- private removeNode;
66
- private dependentsOf;
67
- }
68
- //#endregion
69
- export { DependencyGraph, FormulaDependency, FormulaNode };
70
- //# sourceMappingURL=dependency-graph.d.ts.map