@dou-ui/sheet 0.0.0-stage → 0.1.0-alpha.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 (262) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/dist/cell-types.js +20 -0
  4. package/dist/cell-types.js.map +1 -0
  5. package/dist/code/code-formula-bar.js +6 -0
  6. package/dist/code/code-formula-bar.js.map +1 -0
  7. package/dist/code/code-formula-bar.vue_vue_type_script_setup_true_lang.js +192 -0
  8. package/dist/code/code-formula-bar.vue_vue_type_script_setup_true_lang.js.map +1 -0
  9. package/dist/code/index.js +12 -0
  10. package/dist/code/index.js.map +1 -0
  11. package/dist/code/language.js +51 -0
  12. package/dist/code/language.js.map +1 -0
  13. package/dist/code/style.d.ts +1 -0
  14. package/dist/code/style.js +2 -0
  15. package/dist/collaboration/anchor.js +143 -0
  16. package/dist/collaboration/anchor.js.map +1 -0
  17. package/dist/collaboration/index.js +770 -0
  18. package/dist/collaboration/index.js.map +1 -0
  19. package/dist/collaboration/peers.js +87 -0
  20. package/dist/collaboration/peers.js.map +1 -0
  21. package/dist/collaboration/shared.js +450 -0
  22. package/dist/collaboration/shared.js.map +1 -0
  23. package/dist/components/cell-panel.js +6 -0
  24. package/dist/components/cell-panel.js.map +1 -0
  25. package/dist/components/cell-panel.vue_vue_type_script_setup_true_lang.js +70 -0
  26. package/dist/components/cell-panel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  27. package/dist/components/cell-renders.js +40 -0
  28. package/dist/components/cell-renders.js.map +1 -0
  29. package/dist/components/date-panel.js +6 -0
  30. package/dist/components/date-panel.js.map +1 -0
  31. package/dist/components/date-panel.vue_vue_type_script_setup_true_lang.js +48 -0
  32. package/dist/components/date-panel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  33. package/dist/components/filter-panel.js +6 -0
  34. package/dist/components/filter-panel.js.map +1 -0
  35. package/dist/components/filter-panel.vue_vue_type_script_setup_true_lang.js +259 -0
  36. package/dist/components/filter-panel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  37. package/dist/components/format-dialog.js +6 -0
  38. package/dist/components/format-dialog.js.map +1 -0
  39. package/dist/components/format-dialog.vue_vue_type_script_setup_true_lang.js +432 -0
  40. package/dist/components/format-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
  41. package/dist/components/format-list.js +6 -0
  42. package/dist/components/format-list.js.map +1 -0
  43. package/dist/components/format-list.vue_vue_type_script_setup_true_lang.js +187 -0
  44. package/dist/components/format-list.vue_vue_type_script_setup_true_lang.js.map +1 -0
  45. package/dist/components/format-presets.js +97 -0
  46. package/dist/components/format-presets.js.map +1 -0
  47. package/dist/components/option-panel.js +6 -0
  48. package/dist/components/option-panel.js.map +1 -0
  49. package/dist/components/option-panel.vue_vue_type_script_setup_true_lang.js +117 -0
  50. package/dist/components/option-panel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  51. package/dist/components/sheet-comment.js +6 -0
  52. package/dist/components/sheet-comment.js.map +1 -0
  53. package/dist/components/sheet-comment.vue_vue_type_script_setup_true_lang.js +104 -0
  54. package/dist/components/sheet-comment.vue_vue_type_script_setup_true_lang.js.map +1 -0
  55. package/dist/components/sheet-formula-bar.js +6 -0
  56. package/dist/components/sheet-formula-bar.js.map +1 -0
  57. package/dist/components/sheet-formula-bar.vue_vue_type_script_setup_true_lang.js +124 -0
  58. package/dist/components/sheet-formula-bar.vue_vue_type_script_setup_true_lang.js.map +1 -0
  59. package/dist/components/sheet-link.js +6 -0
  60. package/dist/components/sheet-link.js.map +1 -0
  61. package/dist/components/sheet-link.vue_vue_type_script_setup_true_lang.js +249 -0
  62. package/dist/components/sheet-link.vue_vue_type_script_setup_true_lang.js.map +1 -0
  63. package/dist/components/sheet-menu.js +6 -0
  64. package/dist/components/sheet-menu.js.map +1 -0
  65. package/dist/components/sheet-menu.vue_vue_type_script_setup_true_lang.js +115 -0
  66. package/dist/components/sheet-menu.vue_vue_type_script_setup_true_lang.js.map +1 -0
  67. package/dist/components/sheet-name-box.js +6 -0
  68. package/dist/components/sheet-name-box.js.map +1 -0
  69. package/dist/components/sheet-name-box.vue_vue_type_script_setup_true_lang.js +91 -0
  70. package/dist/components/sheet-name-box.vue_vue_type_script_setup_true_lang.js.map +1 -0
  71. package/dist/components/sheet-note.js +6 -0
  72. package/dist/components/sheet-note.js.map +1 -0
  73. package/dist/components/sheet-note.vue_vue_type_script_setup_true_lang.js +146 -0
  74. package/dist/components/sheet-note.vue_vue_type_script_setup_true_lang.js.map +1 -0
  75. package/dist/components/sheet-outline.js +6 -0
  76. package/dist/components/sheet-outline.js.map +1 -0
  77. package/dist/components/sheet-outline.vue_vue_type_script_setup_true_lang.js +237 -0
  78. package/dist/components/sheet-outline.vue_vue_type_script_setup_true_lang.js.map +1 -0
  79. package/dist/components/sheet-tabs.js +6 -0
  80. package/dist/components/sheet-tabs.js.map +1 -0
  81. package/dist/components/sheet-tabs.vue_vue_type_script_setup_true_lang.js +487 -0
  82. package/dist/components/sheet-tabs.vue_vue_type_script_setup_true_lang.js.map +1 -0
  83. package/dist/components/sheet-toolbar.js +6 -0
  84. package/dist/components/sheet-toolbar.js.map +1 -0
  85. package/dist/components/sheet-toolbar.vue_vue_type_script_setup_true_lang.js +1562 -0
  86. package/dist/components/sheet-toolbar.vue_vue_type_script_setup_true_lang.js.map +1 -0
  87. package/dist/components/validation-dialog.js +6 -0
  88. package/dist/components/validation-dialog.js.map +1 -0
  89. package/dist/components/validation-dialog.vue_vue_type_script_setup_true_lang.js +370 -0
  90. package/dist/components/validation-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
  91. package/dist/context.js +12 -0
  92. package/dist/context.js.map +1 -0
  93. package/dist/core/address.js +256 -0
  94. package/dist/core/address.js.map +1 -0
  95. package/dist/core/axis.js +72 -0
  96. package/dist/core/axis.js.map +1 -0
  97. package/dist/core/cell-type.js +30 -0
  98. package/dist/core/cell-type.js.map +1 -0
  99. package/dist/core/clipboard.js +141 -0
  100. package/dist/core/clipboard.js.map +1 -0
  101. package/dist/core/commands.js +63 -0
  102. package/dist/core/commands.js.map +1 -0
  103. package/dist/core/comments.js +74 -0
  104. package/dist/core/comments.js.map +1 -0
  105. package/dist/core/conditional.js +362 -0
  106. package/dist/core/conditional.js.map +1 -0
  107. package/dist/core/csv.js +191 -0
  108. package/dist/core/csv.js.map +1 -0
  109. package/dist/core/data.js +118 -0
  110. package/dist/core/data.js.map +1 -0
  111. package/dist/core/document.js +187 -0
  112. package/dist/core/document.js.map +1 -0
  113. package/dist/core/extension.js +60 -0
  114. package/dist/core/extension.js.map +1 -0
  115. package/dist/core/file.js +336 -0
  116. package/dist/core/file.js.map +1 -0
  117. package/dist/core/fill.js +153 -0
  118. package/dist/core/fill.js.map +1 -0
  119. package/dist/core/find.js +42 -0
  120. package/dist/core/find.js.map +1 -0
  121. package/dist/core/format.js +404 -0
  122. package/dist/core/format.js.map +1 -0
  123. package/dist/core/group.js +134 -0
  124. package/dist/core/group.js.map +1 -0
  125. package/dist/core/history.js +68 -0
  126. package/dist/core/history.js.map +1 -0
  127. package/dist/core/index.js +17 -0
  128. package/dist/core/link.js +34 -0
  129. package/dist/core/link.js.map +1 -0
  130. package/dist/core/merge.js +105 -0
  131. package/dist/core/merge.js.map +1 -0
  132. package/dist/core/model.js +48 -0
  133. package/dist/core/model.js.map +1 -0
  134. package/dist/core/nav.js +44 -0
  135. package/dist/core/nav.js.map +1 -0
  136. package/dist/core/paint.js +106 -0
  137. package/dist/core/paint.js.map +1 -0
  138. package/dist/core/plain-cell-types.js +54 -0
  139. package/dist/core/plain-cell-types.js.map +1 -0
  140. package/dist/core/protect.js +246 -0
  141. package/dist/core/protect.js.map +1 -0
  142. package/dist/core/selection.js +37 -0
  143. package/dist/core/selection.js.map +1 -0
  144. package/dist/core/transaction.js +1582 -0
  145. package/dist/core/transaction.js.map +1 -0
  146. package/dist/core/validation.js +135 -0
  147. package/dist/core/validation.js.map +1 -0
  148. package/dist/core/versions.js +161 -0
  149. package/dist/core/versions.js.map +1 -0
  150. package/dist/export/color.js +36 -0
  151. package/dist/export/color.js.map +1 -0
  152. package/dist/export/draw.js +316 -0
  153. package/dist/export/draw.js.map +1 -0
  154. package/dist/export/index.js +390 -0
  155. package/dist/export/index.js.map +1 -0
  156. package/dist/formula/edit.js +210 -0
  157. package/dist/formula/edit.js.map +1 -0
  158. package/dist/formula/engine.js +526 -0
  159. package/dist/formula/engine.js.map +1 -0
  160. package/dist/formula/error.js +39 -0
  161. package/dist/formula/error.js.map +1 -0
  162. package/dist/formula/functions.js +1493 -0
  163. package/dist/formula/functions.js.map +1 -0
  164. package/dist/formula/help.js +408 -0
  165. package/dist/formula/help.js.map +1 -0
  166. package/dist/formula/index.js +7 -0
  167. package/dist/formula/parse.js +369 -0
  168. package/dist/formula/parse.js.map +1 -0
  169. package/dist/formula/values.js +123 -0
  170. package/dist/formula/values.js.map +1 -0
  171. package/dist/formulas.js +30 -0
  172. package/dist/formulas.js.map +1 -0
  173. package/dist/index.js +39 -0
  174. package/dist/index.js.map +1 -0
  175. package/dist/locale.js +1312 -0
  176. package/dist/locale.js.map +1 -0
  177. package/dist/sheet.js +6 -0
  178. package/dist/sheet.js.map +1 -0
  179. package/dist/sheet.vue_vue_type_script_setup_true_lang.js +7166 -0
  180. package/dist/sheet.vue_vue_type_script_setup_true_lang.js.map +1 -0
  181. package/dist/style.css +1 -0
  182. package/dist/style.d.ts +1 -0
  183. package/dist/style.js +17 -0
  184. package/dist/types/cell-types.d.ts +2 -0
  185. package/dist/types/code/code-formula-bar.vue.d.ts +3 -0
  186. package/dist/types/code/index.d.ts +12 -0
  187. package/dist/types/code/language.d.ts +13 -0
  188. package/dist/types/collaboration/anchor.d.ts +65 -0
  189. package/dist/types/collaboration/index.d.ts +59 -0
  190. package/dist/types/collaboration/peers.d.ts +21 -0
  191. package/dist/types/collaboration/shared.d.ts +75 -0
  192. package/dist/types/components/cell-panel.vue.d.ts +20 -0
  193. package/dist/types/components/cell-renders.d.ts +9 -0
  194. package/dist/types/components/date-panel.vue.d.ts +9 -0
  195. package/dist/types/components/filter-panel.vue.d.ts +21 -0
  196. package/dist/types/components/format-dialog.vue.d.ts +24 -0
  197. package/dist/types/components/format-list.vue.d.ts +25 -0
  198. package/dist/types/components/format-presets.d.ts +30 -0
  199. package/dist/types/components/option-panel.vue.d.ts +13 -0
  200. package/dist/types/components/sheet-comment.vue.d.ts +29 -0
  201. package/dist/types/components/sheet-formula-bar.vue.d.ts +3 -0
  202. package/dist/types/components/sheet-link.vue.d.ts +32 -0
  203. package/dist/types/components/sheet-menu.vue.d.ts +20 -0
  204. package/dist/types/components/sheet-name-box.vue.d.ts +3 -0
  205. package/dist/types/components/sheet-note.vue.d.ts +22 -0
  206. package/dist/types/components/sheet-outline.vue.d.ts +36 -0
  207. package/dist/types/components/sheet-tabs.vue.d.ts +9 -0
  208. package/dist/types/components/sheet-toolbar.vue.d.ts +11 -0
  209. package/dist/types/components/validation-dialog.vue.d.ts +25 -0
  210. package/dist/types/context.d.ts +189 -0
  211. package/dist/types/core/address.d.ts +109 -0
  212. package/dist/types/core/axis.d.ts +23 -0
  213. package/dist/types/core/cell-type.d.ts +157 -0
  214. package/dist/types/core/clipboard.d.ts +48 -0
  215. package/dist/types/core/commands.d.ts +76 -0
  216. package/dist/types/core/comments.d.ts +22 -0
  217. package/dist/types/core/conditional.d.ts +114 -0
  218. package/dist/types/core/csv.d.ts +93 -0
  219. package/dist/types/core/data.d.ts +26 -0
  220. package/dist/types/core/document.d.ts +49 -0
  221. package/dist/types/core/extension.d.ts +177 -0
  222. package/dist/types/core/file.d.ts +301 -0
  223. package/dist/types/core/fill.d.ts +23 -0
  224. package/dist/types/core/find.d.ts +39 -0
  225. package/dist/types/core/format.d.ts +47 -0
  226. package/dist/types/core/group.d.ts +76 -0
  227. package/dist/types/core/history.d.ts +27 -0
  228. package/dist/types/core/index.d.ts +33 -0
  229. package/dist/types/core/link.d.ts +14 -0
  230. package/dist/types/core/merge.d.ts +26 -0
  231. package/dist/types/core/model.d.ts +363 -0
  232. package/dist/types/core/nav.d.ts +15 -0
  233. package/dist/types/core/paint.d.ts +19 -0
  234. package/dist/types/core/plain-cell-types.d.ts +6 -0
  235. package/dist/types/core/protect.d.ts +34 -0
  236. package/dist/types/core/selection.d.ts +25 -0
  237. package/dist/types/core/transaction.d.ts +470 -0
  238. package/dist/types/core/validation.d.ts +55 -0
  239. package/dist/types/core/versions.d.ts +38 -0
  240. package/dist/types/export/color.d.ts +7 -0
  241. package/dist/types/export/draw.d.ts +98 -0
  242. package/dist/types/export/index.d.ts +47 -0
  243. package/dist/types/formula/edit.d.ts +62 -0
  244. package/dist/types/formula/engine.d.ts +99 -0
  245. package/dist/types/formula/error.d.ts +30 -0
  246. package/dist/types/formula/functions.d.ts +62 -0
  247. package/dist/types/formula/help.d.ts +12 -0
  248. package/dist/types/formula/index.d.ts +13 -0
  249. package/dist/types/formula/parse.d.ts +92 -0
  250. package/dist/types/formula/values.d.ts +65 -0
  251. package/dist/types/formulas.d.ts +32 -0
  252. package/dist/types/index.d.ts +225 -0
  253. package/dist/types/locale.d.ts +531 -0
  254. package/dist/types/sheet.vue.d.ts +60 -0
  255. package/dist/types/types.d.ts +498 -0
  256. package/dist/types/use-comments.d.ts +47 -0
  257. package/dist/types/use-messages.d.ts +7 -0
  258. package/dist/use-comments.js +130 -0
  259. package/dist/use-comments.js.map +1 -0
  260. package/dist/use-messages.js +29 -0
  261. package/dist/use-messages.js.map +1 -0
  262. package/package.json +93 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction.js","names":[],"sources":["../../src/core/transaction.ts"],"sourcesContent":["import {\n boundsOf,\n columnIndex,\n formatRange,\n moveReferences,\n parseCell,\n shiftFormula,\n parseRange,\n dropReferences,\n renameReferences,\n splitSheet,\n type SheetBounds,\n type SheetRefMap,\n type SheetPoint,\n type SheetRange,\n} from './address'\nimport {\n cellOf,\n colCountOf,\n compactCell,\n rowCountOf,\n type SheetCell,\n type SheetCellInput,\n type SheetConditionalFormat,\n type SheetData,\n type SheetFilter,\n type SheetFilterRule,\n type SheetGroup,\n type SheetProtection,\n type SheetRow,\n type SheetRuleRange,\n type SheetStyle,\n type SheetTypeSetup,\n type SheetValidation,\n type SheetValue,\n type SheetWorkbook,\n valueOf,\n} from './model'\nimport { continueValues, type SheetFillMode } from './fill'\nimport { mergesOf, overlaps } from './merge'\nimport { groupRange, groupsOf, groupSpan } from './group'\nimport { rangesOf } from './conditional'\nimport { sortRows, textCollator, type SheetSortKey } from './data'\n\n/** The lists of rules a sheet keeps, each rule with a `range`. */\n/** Throws when a rule's ranges aren't all ranges. */\nfunction checkRuleRange(range: SheetRuleRange) {\n const texts = rangesOf(range)\n if (!texts.length) throw new RangeError('[@dou-ui/sheet] a rule needs a range')\n for (const text of texts)\n if (!parseRange(text)) throw new RangeError(`[@dou-ui/sheet] \"${text}\" isn't a range`)\n}\n\ntype RuleKey = 'conditionalFormats' | 'validations'\ntype RuleOf<K extends RuleKey> = K extends 'conditionalFormats'\n ? SheetConditionalFormat\n : SheetValidation\n\n/*\n * Every change to a workbook is a list of steps. Applying a step also gives\n * the step that undoes it, so history, collaboration and the `transaction`\n * event all work on the same small vocabulary.\n *\n * Changes copy only what they touch: the workbook, the sheet, its list of\n * rows and the rows that change. Every other row stays the same array, so\n * the grid knows which rows to draw again by comparing them.\n */\n\ntype Patch<T> = { [K in keyof T]?: T[K] | undefined }\n\n/** The parts of a sheet set with `updateSheet`. */\nexport type SheetPatch = Patch<Omit<SheetData, 'cells' | 'rowSizes' | 'colSizes'>>\n\n/** Changes to the workbook's own settings: those besides its sheets, styles and types. */\nexport type SheetBookPatch = Patch<Omit<SheetWorkbook, 'sheets' | 'styles' | 'types'>>\n\n/** Changes to a style: fields to set, and fields set to `undefined` to take off. */\nexport type SheetStylePatch = Patch<SheetStyle>\n\n/** A style written the same way whatever order its fields came in. */\n// oxlint-disable-next-line unicorn/no-array-sort -- sorts a fresh array\nconst styleKey = (style: SheetStyle) => JSON.stringify(style, Object.keys(style).sort())\n\n/** A sheet: its index in the workbook, or its `id` or `name`. */\nexport type SheetRef = number | string\n\n/**\n * A cell: `'B3'`, `'表 2'!B3` for another sheet, or a point with an\n * optional `sheet`. Without a sheet it is on the transaction's sheet.\n */\nexport type SheetCellAt = string | (SheetPoint & { sheet?: SheetRef })\n\n/**\n * A range, written like a cell: `'A1:C4'`, `'表 2'!B:B`, or a range or its\n * bounds with an optional `sheet`.\n */\nexport type SheetRangeAt = string | ((SheetRange | SheetBounds) & { sheet?: SheetRef })\n\n/** Rows or columns. */\nexport type SheetAxisName = 'row' | 'col'\n\n/**\n * Rows or columns: a zero-based number, or as people write them, `'5'` or\n * `'5:7'` for rows and `'C'` or `'B:C'` for columns.\n */\nexport type SheetLinesAt = number | string | { from: number; count: number }\n\n/** What made a change, as the `change` and `transaction` events tell it. */\nexport type SheetAction =\n | 'input'\n | 'paste'\n | 'cut'\n | 'fill'\n | 'clear'\n | 'resize'\n | 'move'\n | 'insert'\n | 'delete'\n | 'hide'\n | 'merge'\n | 'group'\n | 'note'\n | 'comment'\n | 'sort'\n | 'filter'\n | 'format'\n | 'validation'\n | 'protect'\n | 'link'\n | 'style'\n | 'freeze'\n | 'sheet'\n | 'import'\n | 'restore'\n | 'replace'\n | 'undo'\n | 'redo'\n | 'api'\n\n/** What a step calls a sheet: its `id`, or its name when it has none. */\nexport const sheetKey = (sheet: SheetData) => sheet.id ?? sheet.name\n\n/*\n * Steps name sheets by key rather than index, so they still apply after\n * sheets are reordered, and on another client in collaboration.\n */\nexport type SheetStep =\n /** Writes a cell; `cell` left out empties it. */\n | { type: 'setCell'; sheet: string; row: number; col: number; cell?: SheetCellInput }\n /** Sets a row's height or a column's width; `size` left out goes back to the default. */\n | { type: 'setSize'; sheet: string; axis: 'row' | 'col'; index: number; size?: number }\n | { type: 'updateSheet'; sheet: string; patch: SheetPatch }\n /** Changes the workbook's own settings, such as `protect`. */\n | { type: 'updateBook'; patch: SheetBookPatch }\n /** Adds, replaces or (with `style` left out) removes a named style. */\n | { type: 'setStyle'; name: string; style?: SheetStyle }\n /** Adds, replaces or (with `setup` left out) removes a named cell type. */\n | { type: 'setType'; name: string; setup?: SheetTypeSetup }\n /**\n * Adds `count` rows (or columns) before `index`, moving the rest down (or\n * right). They are empty unless `cells` and `sizes` fill them: for rows,\n * `cells` holds the rows; for columns, each row's cells in them.\n */\n | {\n type: 'insertLines'\n sheet: string\n axis: SheetAxisName\n index: number\n count: number\n cells?: (SheetRow | null)[]\n sizes?: (number | null)[]\n }\n /** Removes `count` rows (or columns) from `index`, moving the rest up (or left). */\n | { type: 'removeLines'; sheet: string; axis: SheetAxisName; index: number; count: number }\n /**\n * Moves `count` rows (or columns) from `from` to before `to`, both\n * numbered as before the move.\n */\n | {\n type: 'moveLines'\n sheet: string\n axis: SheetAxisName\n from: number\n count: number\n to: number\n }\n /** Adds a sheet at `index`, moving the ones from there on along. */\n | { type: 'insertSheet'; index: number; data: SheetData }\n | { type: 'removeSheet'; sheet: string }\n /** Moves a sheet to `index`, counted after it is taken out. */\n | { type: 'moveSheet'; sheet: string; index: number }\n\nexport interface SheetTransactionMeta {\n /** Keep out of the undo history, e.g. a change from another client. */\n history?: boolean\n /** Consecutive transactions in the same group within a second undo as one. */\n group?: string\n /** Who made the change, passed on to the `transaction` event. */\n origin?: string\n /** What the change was; the grid sets it, a change made in code is `api`. */\n action?: SheetAction\n /**\n * With `false`, the grid doesn't hold the change to the protection of\n * sheets and the workbook, e.g. for code that fills in a protected form.\n * A change with `history: false`, such as undo, redo or another person's,\n * isn't held either: it can't be cancelled.\n */\n protection?: boolean\n}\n\n/**\n * A batch of changes. Steps apply as they are added, so later calls see\n * earlier ones; `doc` is the result. Cells and ranges without a sheet are\n * on `sheet` (in the grid, the one shown).\n */\nexport class SheetTransaction {\n readonly steps: SheetStep[] = []\n /** What undoes each step, in the order the steps were made. */\n private undoing: SheetStep[] = []\n private reversed: SheetStep[] | null = null\n\n /** The steps that undo this transaction, in the order to apply them. */\n get inverse(): readonly SheetStep[] {\n // put in order when asked, as adding each to the front would take long for many steps\n // oxlint-disable-next-line unicorn/no-array-reverse -- reverses a fresh copy\n this.reversed ??= this.undoing.slice().reverse()\n return this.reversed\n }\n meta: SheetTransactionMeta = {}\n private book: SheetWorkbook\n /** What this transaction has copied, so it copies each thing once. */\n private own = { book: false, sheets: false, styles: false, types: false }\n /** The sheets this transaction copied, and the rows it copied of each. */\n private ownSheets = new WeakSet<SheetData>()\n private ownRows = new WeakMap<SheetData, Set<number>>()\n\n constructor(\n readonly before: SheetWorkbook,\n /** The sheet cells and ranges are on when they don't name one. */\n readonly sheet: SheetRef = 0,\n ) {\n this.book = before\n }\n\n get doc(): SheetWorkbook {\n return this.book\n }\n\n /** Whether the change makes any change: it has steps and wasn't cancelled. */\n get changed() {\n return this.steps.length > 0 && !this.stopped\n }\n\n private stopped: { reason?: string } | null = null\n\n /**\n * Stops the change: none of it is applied or kept for undo, and the\n * editor fires `transactionCancel` and says why. For an extension's `transaction`\n * hook, e.g. to keep people from changing what they may not; hooks after\n * it don't run. A change kept out of the history (`meta.history: false`),\n * such as undo, redo or another person's, can't be cancelled and goes ahead.\n */\n cancel(reason?: string) {\n if (this.meta.history !== false) this.stopped = { reason }\n else warnUncancellable()\n return this\n }\n\n /** Whether `cancel` stopped it. */\n get cancelled() {\n return this.stopped !== null\n }\n\n /** What `cancel` was given, to tell people why. */\n get cancelReason() {\n return this.stopped?.reason\n }\n\n setMeta(meta: SheetTransactionMeta) {\n Object.assign(this.meta, meta)\n return this\n }\n\n /** The index of a sheet, by index, `id` or name; `-1` when there is none. */\n indexOf(ref: SheetRef = this.sheet) {\n const { sheets } = this.book\n if (typeof ref === 'number') return ref >= 0 && ref < sheets.length ? ref : -1\n const byId = sheets.findIndex((sheet) => sheet.id === ref)\n return byId === -1 ? sheets.findIndex((sheet) => sheet.id == null && sheet.name === ref) : byId\n }\n\n /** A sheet as it is now in this transaction. */\n getSheet(ref: SheetRef = this.sheet): SheetData {\n const index = this.indexOf(ref)\n if (index === -1) throw new RangeError(`[@dou-ui/sheet] there is no sheet \"${ref}\"`)\n return this.book.sheets[index]!\n }\n\n getCell(at: SheetCellAt): SheetCellInput {\n const { index, row, col } = this.cellAt(at)\n return this.book.sheets[index]!.cells[row]?.[col] ?? undefined\n }\n\n step(step: SheetStep) {\n const inverse = this.apply(step)\n if (inverse) {\n this.steps.push(step)\n this.undoing.push(inverse)\n this.reversed = null\n }\n return this\n }\n\n /** Replaces a cell; `undefined` empties it. */\n setCell(at: SheetCellAt, cell: SheetCellInput) {\n const { index, row, col } = this.cellAt(at)\n return this.step({ type: 'setCell', sheet: this.keyOf(index), row, col, cell })\n }\n\n /** Changes some of a cell's fields and keeps the rest. */\n updateCell(at: SheetCellAt, patch: Patch<SheetCell>) {\n const target = this.cellAt(at)\n const point = { sheet: target.index, row: target.row, col: target.col }\n return this.setCell(point, compactCell({ ...cellOf(this.getCell(point)), ...patch }))\n }\n\n /** Writes a cell's value and keeps its style and format. */\n setValue(at: SheetCellAt, value: SheetValue | undefined) {\n return this.updateCell(at, { value: value ?? undefined })\n }\n\n /** Empties the values in a range, keeping styles and formats. */\n clearValues(at: SheetRangeAt) {\n const { index, bounds } = this.rangeAt(at)\n const { cells } = this.book.sheets[index]!\n const last = Math.min(bounds.bottom, cells.length - 1)\n for (let row = bounds.top; row <= last; row++) {\n const line = cells[row]\n if (!line) continue\n const end = Math.min(bounds.right, line.length - 1)\n for (let col = bounds.left; col <= end; col++) {\n const cell = line[col]\n if (cell != null && cell !== '' && (typeof cell !== 'object' || cell.value != null))\n this.setValue({ sheet: index, row, col }, undefined)\n }\n }\n return this\n }\n\n /** Writes a cell's note; empty text or `undefined` takes it off. */\n setNote(at: SheetCellAt, note: string | undefined) {\n return this.updateCell(at, { note: note?.trim() ? note : undefined })\n }\n\n /**\n * Puts a comment thread on a cell, or takes it off with `undefined`. Use\n * it with `{ history: false }`: a thread stays when the change before it\n * is undone.\n */\n setComment(at: SheetCellAt, id: string | undefined) {\n return this.updateCell(at, { comment: id || undefined })\n }\n\n /** Takes the notes off the cells in a range, keeping what they hold. */\n clearNotes(at: SheetRangeAt) {\n const { index, bounds } = this.rangeAt(at)\n const { cells } = this.book.sheets[index]!\n const last = Math.min(bounds.bottom, cells.length - 1)\n for (let row = bounds.top; row <= last; row++) {\n const line = cells[row]\n if (!line) continue\n const end = Math.min(bounds.right, line.length - 1)\n for (let col = bounds.left; col <= end; col++) {\n const cell = line[col]\n if (cell && typeof cell === 'object' && cell.note != null)\n this.setNote({ sheet: index, row, col }, undefined)\n }\n }\n return this\n }\n\n /** Sets a row's height or a column's width in px; `undefined` for the default, `0` hides it. */\n setSize(axis: 'row' | 'col', index: number, size: number | undefined, sheet?: SheetRef) {\n const key = this.keyOf(this.mustIndex(sheet))\n return this.step({ type: 'setSize', sheet: key, axis, index, size })\n }\n\n /** Changes a sheet's name, freeze, row or column count. */\n updateSheet(patch: SheetPatch, sheet?: SheetRef) {\n return this.step({ type: 'updateSheet', sheet: this.keyOf(this.mustIndex(sheet)), patch })\n }\n\n /** Changes the workbook's own settings, such as `protect`. */\n updateBook(patch: SheetBookPatch) {\n return this.step({ type: 'updateBook', patch })\n }\n\n /**\n * Protects a sheet, or with `false` stops protecting it: its locked cells\n * (all but those whose style has `locked: false`) can't be changed, nor\n * can the sheet's rows, columns and rules, except what `options` allows.\n */\n protectSheet(protect: boolean | SheetProtection, sheet?: SheetRef) {\n return this.updateSheet({ protect: protect === false ? undefined : protect }, sheet)\n }\n\n setStyle(name: string, style: SheetStyle | undefined) {\n return this.step({ type: 'setStyle', name, style })\n }\n\n /** Adds, replaces or (with `undefined`) removes a named cell type, such as a list to pick from. */\n setType(name: string, setup: SheetTypeSetup | undefined) {\n return this.step({ type: 'setType', name, setup })\n }\n\n /**\n * Writes a block of cells with its top left corner at `at`, row by row.\n * `undefined` in the block empties a cell; a shorter row leaves the cells\n * past it as they are.\n */\n setCells(at: SheetCellAt, block: readonly (readonly SheetCellInput[])[]) {\n const { index, row, col } = this.cellAt(at)\n block.forEach((line, r) =>\n line.forEach((cell, c) => this.setCell({ sheet: index, row: row + r, col: col + c }, cell)),\n )\n return this\n }\n\n /**\n * Fills `to` from `from`, the cells it extends down, up, right or left:\n * each line of cells continues as the fill handle does (see\n * `continueValues`), with the styles and formats of the cells it repeats.\n * Formulas are copied with their references moved along. `mode` is\n * `auto` as dragging does, `series` to count a single number up too, or\n * `copy` to only repeat, as Ctrl+D does. With `keepStyle`, the filled\n * cells keep their own styles and formats, as on a protected sheet.\n */\n fill(\n from: SheetRangeAt,\n to: SheetRangeAt,\n options: { mode?: SheetFillMode; keepStyle?: boolean } = {},\n ) {\n const { index, bounds: s } = this.rangeAt(from)\n const t = this.rangeAt(to).bounds\n const vertical = t.left === s.left && t.right === s.right\n const horizontal = t.top === s.top && t.bottom === s.bottom\n if (vertical && horizontal) return this\n let direction: 'down' | 'up' | 'right' | 'left'\n if (vertical && t.top === s.top && t.bottom > s.bottom) direction = 'down'\n else if (vertical && t.bottom === s.bottom && t.top < s.top) direction = 'up'\n else if (horizontal && t.left === s.left && t.right > s.right) direction = 'right'\n else if (horizontal && t.right === s.right && t.left < s.left) direction = 'left'\n else\n throw new RangeError(\n '[@dou-ui/sheet] the range to fill must extend the cells it is filled from',\n )\n const down = direction === 'down' || direction === 'up'\n const forward = direction === 'down' || direction === 'right'\n const count = down\n ? t.bottom - t.top - (s.bottom - s.top)\n : t.right - t.left - (s.right - s.left)\n const length = down ? s.bottom - s.top + 1 : s.right - s.left + 1\n const lines = down ? [s.left, s.right] : [s.top, s.bottom]\n const cells = this.book.sheets[index]!.cells\n for (let line = lines[0]!; line <= lines[1]!; line++) {\n // the cells of the line in the order the fill continues them\n const points = Array.from({ length }, (_, i) => {\n const along = forward ? i : length - 1 - i\n return down ? { row: s.top + along, col: line } : { row: line, col: s.left + along }\n })\n const sources = points.map((p) => cells[p.row]?.[p.col] ?? undefined)\n const values = continueValues(sources.map(valueOf), count, {\n mode: options.mode,\n back: !forward,\n })\n for (let i = 0; i < count; i++) {\n const k = i % length\n const origin = points[k]!\n const step = (forward ? 1 : -1) * (length + i - k)\n const point = down\n ? { row: origin.row + step, col: line }\n : { row: line, col: origin.col + step }\n const source = cellOf(sources[k])\n const value = source?.value\n const next =\n typeof value === 'string' && value.startsWith('=')\n ? shiftFormula(value, point.row - origin.row, point.col - origin.col)\n : values[i]\n const look = options.keepStyle ? cellOf(cells[point.row]?.[point.col]) : source\n // a cell's thread stays on it, and isn't copied along\n const target = { sheet: index, ...point }\n this.setCell(\n target,\n compactCell({\n ...source,\n value: next ?? undefined,\n style: look?.style,\n format: look?.format,\n comment: cellOf(this.getCell(target))?.comment,\n }),\n )\n }\n }\n return this\n }\n\n /**\n * Sorts the rows of a range by the values in `keys`' columns; the cells\n * outside the range stay. `header` keeps the first row in place. Equal rows\n * keep their order, and empty values go last either way. Formulas move\n * with their rows and their references move along, as when copied.\n * `valueAt` gives what a cell comes to, e.g. a formula's result; the value\n * as written is used without it. Ranges with merged cells are not sorted.\n */\n sortRange(\n at: SheetRangeAt,\n keys: readonly SheetSortKey[],\n options: {\n header?: boolean\n valueAt?: (row: number, col: number) => unknown\n lang?: string\n } = {},\n ) {\n const { index, bounds } = this.rangeIn(at)\n const sheet = this.book.sheets[index]!\n const top = bounds.top + (options.header ? 1 : 0)\n if (top >= bounds.bottom || !keys.length) return this\n const body = { ...bounds, top }\n if (mergesOf(sheet).touching(body).length)\n throw new RangeError('[@dou-ui/sheet] a range with merged cells cannot be sorted')\n const rows = Array.from({ length: bounds.bottom - top + 1 }, (_, i) => top + i)\n const cells = sheet.cells\n const valueAt =\n options.valueAt ?? ((row: number, col: number) => valueOf(cells[row]?.[col] ?? undefined))\n const order = sortRows(rows, keys, valueAt, textCollator(options.lang))\n // read the moved cells before writing any\n const moved = order.map((from) =>\n Array.from({ length: bounds.right - bounds.left + 1 }, (_, c) =>\n cellOf(cells[from]?.[bounds.left + c] ?? undefined),\n ),\n )\n order.forEach((from, i) => {\n const to = top + i\n if (from === to) return\n moved[i]!.forEach((cell, c) => {\n const value = cell?.value\n const next =\n typeof value === 'string' && value.startsWith('=')\n ? compactCell({ ...cell, value: shiftFormula(value, to - from, 0) })\n : compactCell(cell)\n this.setCell({ sheet: index, row: to, col: bounds.left + c }, next)\n })\n })\n return this\n }\n\n /**\n * Puts a filter on a range, headings in its first row; `null` takes the\n * filter off, showing the rows it hid. A new range drops the old rules.\n */\n setFilter(at: SheetRangeAt | null) {\n if (at == null) {\n const index = this.mustIndex()\n if (!this.book.sheets[index]!.filter) return this\n return this.updateSheet({ filter: undefined }, index)\n }\n const { index, bounds } = this.rangeIn(at)\n const old = this.book.sheets[index]!.filter\n const range = rangeText(bounds)\n if (old?.range === range) return this\n return this.updateSheet({ filter: { range } }, index)\n }\n\n /**\n * Sets which rows a column of the filter keeps; `undefined` keeps all.\n * `sorted` marks the column the rows were sorted by, for its button.\n */\n filterColumn(col: number, rule: SheetFilterRule | undefined, sheet: SheetRef = this.sheet) {\n const index = this.mustIndex(sheet)\n const filter = this.book.sheets[index]!.filter\n if (!filter) throw new RangeError('[@dou-ui/sheet] the sheet has no filter')\n const columns = { ...filter.columns }\n if (rule) columns[col] = rule\n else delete columns[col]\n const next: SheetFilter = {\n ...filter,\n columns: Object.keys(columns).length ? columns : undefined,\n }\n if (!next.columns) delete next.columns\n return this.updateSheet({ filter: next }, index)\n }\n\n /** Remembers the filter column the rows were sorted by, or forgets it with `undefined`. */\n markSorted(sorted: SheetFilter['sorted'], sheet: SheetRef = this.sheet) {\n const index = this.mustIndex(sheet)\n const filter = this.book.sheets[index]!.filter\n if (!filter) return this\n const next: SheetFilter = { ...filter, sorted }\n if (!sorted) delete next.sorted\n return this.updateSheet({ filter: next }, index)\n }\n\n /**\n * Adds a conditional format after the sheet's others; where two give the\n * same part of a cell's look, the earlier one wins. The format's `range`\n * names cells of `sheet`.\n */\n addConditionalFormat(format: SheetConditionalFormat, sheet: SheetRef = this.sheet) {\n return this.addRule('conditionalFormats', format, sheet)\n }\n\n /** Sets a sheet's conditional formats, in order, e.g. after moving one up; `[]` removes them all. */\n setConditionalFormats(formats: readonly SheetConditionalFormat[], sheet: SheetRef = this.sheet) {\n return this.setRules('conditionalFormats', formats, sheet)\n }\n\n /**\n * Removes the conditional formats whose cells overlap a range, such as\n * the selection; without a range, all of the sheet's.\n */\n clearConditionalFormats(at?: SheetRangeAt) {\n return this.clearRules('conditionalFormats', at)\n }\n\n /**\n * Adds a validation rule after the sheet's others; where two cover a\n * cell, the earlier one applies. The rule's `range` names cells of `sheet`.\n */\n addValidation(rule: SheetValidation, sheet: SheetRef = this.sheet) {\n return this.addRule('validations', rule, sheet)\n }\n\n /** Sets a sheet's validation rules, in order; `[]` removes them all. */\n setValidations(rules: readonly SheetValidation[], sheet: SheetRef = this.sheet) {\n return this.setRules('validations', rules, sheet)\n }\n\n /**\n * Removes the validation rules whose cells overlap a range, such as the\n * selection; without a range, all of the sheet's.\n */\n clearValidations(at?: SheetRangeAt) {\n return this.clearRules('validations', at)\n }\n\n private addRule<K extends RuleKey>(key: K, rule: RuleOf<K>, sheet: SheetRef) {\n const index = this.mustIndex(sheet)\n checkRuleRange(rule.range)\n const rules = (this.book.sheets[index]![key] ?? []) as RuleOf<K>[]\n return this.updateSheet({ [key]: [...rules, rule] }, index)\n }\n\n private setRules<K extends RuleKey>(key: K, rules: readonly RuleOf<K>[], sheet: SheetRef) {\n const index = this.mustIndex(sheet)\n for (const rule of rules) checkRuleRange(rule.range)\n return this.updateSheet({ [key]: rules.length ? [...rules] : undefined }, index)\n }\n\n private clearRules(key: RuleKey, at?: SheetRangeAt) {\n const { index, bounds } =\n at == null ? { index: this.mustIndex(), bounds: null } : this.rangeAt(at)\n const rules = this.book.sheets[index]![key]\n if (!rules?.length) return this\n const kept = bounds\n ? (rules as { range: SheetRuleRange }[]).filter((rule) =>\n rangesOf(rule.range).every((text) => {\n const range = parseRange(text)\n return range && !overlaps(boundsOf(range), bounds)\n }),\n )\n : []\n if (kept.length === rules.length) return this\n return this.updateSheet({ [key]: kept.length ? kept : undefined }, index)\n }\n\n /**\n * Groups rows so they can be folded away: `groupRows('3:8')` or\n * `groupRows(2, 6)`. A group may hold other groups, at most eight deep;\n * one beside a group of the same level joins it, and one that would cross\n * a group, or nest too deep, throws a `RangeError`.\n */\n groupRows(at: SheetLinesAt, count?: number, sheet?: SheetRef) {\n const lines = linesOf('row', at, count)\n return this.groupLines('row', lines.from, lines.count, sheet)\n }\n\n /** Groups columns so they can be folded away: `groupCols('B:D')`. */\n groupCols(at: SheetLinesAt, count?: number, sheet?: SheetRef) {\n const lines = linesOf('col', at, count)\n return this.groupLines('col', lines.from, lines.count, sheet)\n }\n\n /**\n * Takes rows out of their groups: the groups that lie within them go (the\n * outer ones, when groups nest); without any, the rows leave the innermost\n * group they are in, which may split it in two.\n */\n ungroupRows(at: SheetLinesAt, count?: number, sheet?: SheetRef) {\n const lines = linesOf('row', at, count)\n return this.ungroupLines('row', lines.from, lines.count, sheet)\n }\n\n /** Takes columns out of their groups, as `ungroupRows` does rows. */\n ungroupCols(at: SheetLinesAt, count?: number, sheet?: SheetRef) {\n const lines = linesOf('col', at, count)\n return this.ungroupLines('col', lines.from, lines.count, sheet)\n }\n\n /** Folds a group away: `collapseGroup('3:8')`, `range` being the group's rows or columns. */\n collapseGroup(range: string, sheet?: SheetRef) {\n return this.foldGroup(range, true, sheet)\n }\n\n /** Shows a folded group again: `expandGroup('3:8')`. */\n expandGroup(range: string, sheet?: SheetRef) {\n return this.foldGroup(range, false, sheet)\n }\n\n private foldGroup(range: string, collapsed: boolean, sheet: SheetRef = this.sheet) {\n const index = this.mustIndex(sheet)\n const data = this.book.sheets[index]!\n const span = groupSpan(range)\n const group = span && groupsOf(data).axis(span.axis).find(span.start, span.end)\n if (!group) throw new RangeError(`[@dou-ui/sheet] there is no group \"${range}\"`)\n if (group.collapsed === collapsed) return this\n return this.setGroups(index, (g, i) => (i === group.index ? { ...g, collapsed } : g))\n }\n\n /**\n * Shows the groups of an axis down to a level, as the outline's level\n * buttons do: level 1 folds every group, level 2 shows the outer groups\n * with theirs folded, and one past the deepest shows them all.\n */\n showGroupLevel(axis: SheetAxisName, level: number, sheet: SheetRef = this.sheet) {\n const index = this.mustIndex(sheet)\n const laid = groupsOf(this.book.sheets[index]!).axis(axis)\n const fold = new Map<number, boolean>()\n for (const g of laid.list) if (g.collapsed !== g.depth >= level) fold.set(g.index, !g.collapsed)\n if (!fold.size) return this\n return this.setGroups(index, (g, i) => (fold.has(i) ? { ...g, collapsed: fold.get(i) } : g))\n }\n\n private groupLines(axis: SheetAxisName, from: number, count: number, ref?: SheetRef) {\n if (count <= 0) return this\n const index = this.mustIndex(ref)\n const data = this.book.sheets[index]!\n let start = from\n let end = from + count - 1\n const laid = groupsOf(data).axis(axis)\n if (laid.find(start, end)) return this\n const problem = laid.problem(start, end)\n if (problem === 'deep')\n throw new RangeError(\n `[@dou-ui/sheet] \"${groupRange(axis, start, end)}\" would nest more than eight deep`,\n )\n if (problem) {\n const other = groupRange(axis, problem.cross.start, problem.cross.end)\n throw new RangeError(\n `[@dou-ui/sheet] \"${groupRange(axis, start, end)}\" would cross the group \"${other}\"`,\n )\n }\n // groups of the same level right beside it join it, as one group\n const joined = new Set<number>()\n for (const g of laid.beside(start, end)) {\n joined.add(g.index)\n start = Math.min(start, g.start)\n end = Math.max(end, g.end)\n }\n const kept = (data.groups ?? []).filter((_, i) => !joined.has(i))\n return this.updateSheet({ groups: [...kept, { range: groupRange(axis, start, end) }] }, index)\n }\n\n private ungroupLines(axis: SheetAxisName, from: number, count: number, ref?: SheetRef) {\n if (count <= 0) return this\n const index = this.mustIndex(ref)\n const data = this.book.sheets[index]!\n const laid = groupsOf(data).axis(axis)\n const end = from + count - 1\n const within = laid.list.filter((g) => g.start >= from && g.end <= end)\n if (within.length) {\n // the outer ones: those not inside another that goes\n const gone = new Set<number>()\n for (const g of within)\n if (\n !within.some((o) => o !== g && o.depth < g.depth && o.start <= g.start && o.end >= g.end)\n )\n gone.add(g.index)\n return this.setGroups(index, (g, i) => (gone.has(i) ? null : g))\n }\n // the lines leave the deepest groups they touch\n const touching = laid.list.filter((g) => g.start <= end && g.end >= from)\n if (!touching.length) return this\n const deepest = Math.max(...touching.map((g) => g.depth))\n const parts = new Map<number, SheetGroup[]>()\n for (const g of touching) {\n if (g.depth !== deepest) continue\n const group = data.groups![g.index]!\n const split: SheetGroup[] = []\n const keep = (a: number, b: number) => split.push({ ...group, range: groupRange(axis, a, b) })\n if (g.start < from) keep(g.start, from - 1)\n if (g.end > end) keep(end + 1, g.end)\n parts.set(g.index, split)\n }\n return this.setGroups(index, (g, i) => parts.get(i) ?? g)\n }\n\n /** Rewrites a sheet's groups: each to itself, another, several or none. */\n private setGroups(\n index: number,\n map: (group: SheetGroup, index: number) => SheetGroup | SheetGroup[] | null,\n ) {\n const next: SheetGroup[] = []\n this.book.sheets[index]!.groups?.forEach((g, i) => {\n const out = map(g, i)\n if (Array.isArray(out)) next.push(...out)\n else if (out) next.push(out)\n })\n return this.updateSheet({ groups: next.length ? next : undefined }, index)\n }\n\n /**\n * Adds empty rows before `at`: `insertRows(4, 2)` or `insertRows('5:6')`\n * both add two rows where row 5 was. Frozen rows and the row count grow\n * with them, and formulas pointing below follow their cells.\n */\n insertRows(at: SheetLinesAt, count?: number, sheet?: SheetRef) {\n const lines = linesOf('row', at, count)\n return this.insertLines('row', lines.from, lines.count, sheet)\n }\n\n /** Adds empty columns before `at`, `insertCols('C')` or `insertCols(2)`. */\n insertCols(at: SheetLinesAt, count?: number, sheet?: SheetRef) {\n const lines = linesOf('col', at, count)\n return this.insertLines('col', lines.from, lines.count, sheet)\n }\n\n /**\n * Removes rows with their cells and heights: `deleteRows('5:7')` or\n * `deleteRows(4, 3)`. Formulas pointing at them read `#REF!`.\n */\n deleteRows(at: SheetLinesAt, count?: number, sheet?: SheetRef) {\n const lines = linesOf('row', at, count)\n return this.deleteLines('row', lines.from, lines.count, sheet)\n }\n\n /** Removes columns with their cells and widths: `deleteCols('B:C')`. */\n deleteCols(at: SheetLinesAt, count?: number, sheet?: SheetRef) {\n const lines = linesOf('col', at, count)\n return this.deleteLines('col', lines.from, lines.count, sheet)\n }\n\n /**\n * Moves rows to before row `to`, numbered as before the move:\n * `moveRows('2:3', '6')` puts rows 2 and 3 above what was row 6.\n * Formulas pointing at them follow.\n */\n moveRows(lines: SheetLinesAt, to: number | string, sheet?: SheetRef) {\n const { from, count } = linesOf('row', lines)\n return this.moveLines('row', from, count, linesOf('row', to).from, sheet)\n }\n\n /** Moves columns to before column `to`: `moveCols('C', 'A')`. */\n moveCols(lines: SheetLinesAt, to: number | string, sheet?: SheetRef) {\n const { from, count } = linesOf('col', lines)\n return this.moveLines('col', from, count, linesOf('col', to).from, sheet)\n }\n\n /**\n * Moves a block of cells so its top left corner is at `to`, as cutting\n * and pasting does: the cells at `from` empty, those at `to` are\n * replaced, and formulas pointing at the block follow it.\n */\n moveCells(from: SheetRangeAt, to: SheetCellAt) {\n const source = this.rangeAt(from)\n const target = this.cellAt(to)\n const b = source.bounds\n const rows = target.row - b.top\n const cols = target.col - b.left\n if (rows === 0 && cols === 0 && source.index === target.index) return this\n const cells = this.book.sheets[source.index]!.cells\n const block = Array.from({ length: b.bottom - b.top + 1 }, (_, r) =>\n Array.from({ length: b.right - b.left + 1 }, (_cell, c) => cells[b.top + r]?.[b.left + c]),\n )\n for (let r = b.top; r <= b.bottom; r++)\n for (let c = b.left; c <= b.right; c++)\n this.setCell({ sheet: source.index, row: r, col: c }, undefined)\n this.setCells(target, block)\n const dest: SheetBounds = {\n top: target.row,\n left: target.col,\n bottom: b.bottom + rows,\n right: b.right + cols,\n }\n const sourceName = this.book.sheets[source.index]!.name\n const destName = this.book.sheets[target.index]!.name\n const same = sourceName === destName\n // references to the cells the block replaced lose them\n this.rewriteReferences(destName, (r) => (inside(r, dest) && !(same && inside(r, b)) ? null : r))\n // references to the block follow it\n this.rewriteReferences(sourceName, (r) => {\n if (!inside(r, b)) return r\n const moved = {\n top: r.top + rows,\n left: r.left + cols,\n bottom: r.bottom + rows,\n right: r.right + cols,\n }\n return same ? moved : { sheet: destName, bounds: moved }\n })\n return this\n }\n\n private insertLines(axis: SheetAxisName, index: number, count: number, ref?: SheetRef) {\n if (count <= 0) return this\n const at = this.mustIndex(ref)\n const sheet = this.book.sheets[at]!\n this.step({ type: 'insertLines', sheet: this.keyOf(at), axis, index, count })\n this.updateSheet(\n linesPatch(sheet, axis, (n) => (n > index ? n + count : n), count),\n at,\n )\n const add = (n: number) => (n >= index ? n + count : n)\n return this.moveRanges(\n at,\n lineMap(axis, (a, b) => [add(a), add(b)]),\n )\n }\n\n private deleteLines(axis: SheetAxisName, index: number, count: number, ref?: SheetRef) {\n if (count <= 0) return this\n const at = this.mustIndex(ref)\n const sheet = this.book.sheets[at]!\n this.step({ type: 'removeLines', sheet: this.keyOf(at), axis, index, count })\n // frozen lines that were removed are no longer frozen\n const left = (n: number) => n - Math.max(0, Math.min(n, index + count) - index)\n this.updateSheet(linesPatch(sheet, axis, left, -count), at)\n const end = index + count\n return this.moveRanges(\n at,\n lineMap(axis, (a, b) => {\n if (a >= index && b < end) return null\n const first = a < index ? a : a >= end ? a - count : index\n const last = b < index ? b : b >= end ? b - count : index - 1\n return [first, last]\n }),\n )\n }\n\n private moveLines(axis: SheetAxisName, from: number, count: number, to: number, ref?: SheetRef) {\n if (count <= 0 || (to >= from && to <= from + count)) return this\n const at = this.mustIndex(ref)\n this.step({ type: 'moveLines', sheet: this.keyOf(at), axis, from, count, to })\n const place = movedIndex(from, count, to)\n return this.moveRanges(\n at,\n lineMap(axis, (a, b) => {\n const x = place(a)\n const y = place(b)\n return [Math.min(x, y), Math.max(x, y)]\n }),\n )\n }\n\n /**\n * After rows or columns of a sheet change: rewrites formulas pointing at\n * it, and moves its merged cells, dropping those that are gone or now\n * one cell.\n */\n private moveRanges(index: number, map: SheetRefMap) {\n const sheet = this.book.sheets[index]!\n this.rewriteReferences(sheet.name, map)\n this.moveFilter(index, map)\n this.moveRules('conditionalFormats', index, map)\n this.moveRules('validations', index, map)\n this.moveGroups(index, map)\n const merges = sheet.merges\n if (!merges?.length) return this\n const next: string[] = []\n for (const text of merges) {\n const range = parseRange(text)\n if (!range) continue\n const moved = map(boundsOf(range))\n if (!moved) continue\n const b = 'bounds' in moved ? moved.bounds : moved\n if (b.top === b.bottom && b.left === b.right) continue\n next.push(rangeText(b))\n }\n const same = next.length === merges.length && next.every((m, i) => m === merges[i])\n return same ? this : this.updateSheet({ merges: next.length ? next : undefined }, index)\n }\n\n /** Moves a sheet's rules with their cells; a rule goes when its cells do. */\n private moveRules(key: RuleKey, index: number, map: SheetRefMap) {\n const rules = this.book.sheets[index]![key] as { range: SheetRuleRange }[] | undefined\n if (!rules?.length) return\n const next: { range: SheetRuleRange }[] = []\n for (const rule of rules) {\n // each range moves on its own; the rule goes when all of them do\n const texts: string[] = []\n for (const text of rangesOf(rule.range)) {\n const range = parseRange(text)\n const moved = range && map(boundsOf(range))\n if (moved) texts.push(rangeText('bounds' in moved ? moved.bounds : moved))\n }\n if (!texts.length) continue\n const range = Array.isArray(rule.range) ? texts : texts[0]!\n const same = Array.isArray(rule.range)\n ? texts.length === rule.range.length && texts.every((t, i) => t === rule.range[i])\n : range === rule.range\n next.push(same ? rule : { ...rule, range })\n }\n if (next.length !== rules.length || next.some((rule, i) => rule !== rules[i]))\n this.updateSheet({ [key]: next.length ? next : undefined }, index)\n }\n\n /** Moves a sheet's groups with their lines; a group goes when its lines do. */\n private moveGroups(index: number, map: SheetRefMap) {\n const groups = this.book.sheets[index]!.groups\n if (!groups?.length) return\n const next: SheetGroup[] = []\n for (const group of groups) {\n const range = parseRange(group.range)\n const moved = range && map(boundsOf(range))\n if (!moved) continue\n const text = rangeText('bounds' in moved ? moved.bounds : moved)\n next.push(text === group.range ? group : { ...group, range: text })\n }\n if (next.length !== groups.length || next.some((g, i) => g !== groups[i]))\n this.updateSheet({ groups: next.length ? next : undefined }, index)\n }\n\n /** Moves a sheet's filter with its rows and columns; it goes when its range does. */\n private moveFilter(index: number, map: SheetRefMap) {\n const filter = this.book.sheets[index]!.filter\n if (!filter) return\n const range = parseRange(filter.range)\n const moved = range && map(boundsOf(range))\n if (!moved) {\n this.updateSheet({ filter: undefined }, index)\n return\n }\n const b = 'bounds' in moved ? moved.bounds : moved\n const columns: Record<number, SheetFilterRule> = {}\n for (const [key, rule] of Object.entries(filter.columns ?? {})) {\n const col = Number(key)\n const to = map({ top: b.top, bottom: b.top, left: col, right: col })\n if (!to) continue\n const at = 'bounds' in to ? to.bounds : to\n if (at.left === at.right) columns[at.left] = rule\n }\n const next: SheetFilter = { range: rangeText(b) }\n if (Object.keys(columns).length) next.columns = columns\n if (filter.sorted) {\n const col = filter.sorted.col\n const to = map({ top: b.top, bottom: b.top, left: col, right: col })\n const at = to && ('bounds' in to ? to.bounds : to)\n if (at && at.left === at.right) next.sorted = { ...filter.sorted, col: at.left }\n }\n if (JSON.stringify(next) !== JSON.stringify(filter)) this.updateSheet({ filter: next }, index)\n }\n\n /**\n * Merges a range into one cell. Merges it touches are taken into it. The\n * top left cell keeps its content; the values of the other cells are\n * cleared, keeping their styles, unless `keep` leaves them hidden under the\n * merge, to show again when it is split.\n */\n mergeCells(at: SheetRangeAt, options: { keep?: boolean } = {}) {\n const { index, bounds } = this.rangeAt(at)\n const sheet = this.book.sheets[index]!\n const b = mergesOf(sheet).expand(bounds)\n if (b.top === b.bottom && b.left === b.right) return this\n if (!options.keep)\n for (let row = b.top; row <= b.bottom; row++)\n for (let col = b.left; col <= b.right; col++)\n if ((row !== b.top || col !== b.left) && valueOf(sheet.cells[row]?.[col]) != null)\n this.setValue({ sheet: index, row, col }, undefined)\n const kept = (sheet.merges ?? []).filter((text) => {\n const range = parseRange(text)\n return !range || !overlaps(boundsOf(range), b)\n })\n return this.updateSheet({ merges: [...kept, rangeText(b)] }, index)\n }\n\n /** Splits the merged cells a range touches back into single cells. */\n unmergeCells(at: SheetRangeAt) {\n const { index, bounds } = this.rangeAt(at)\n const sheet = this.book.sheets[index]!\n if (!sheet.merges?.length) return this\n const kept = sheet.merges.filter((text) => {\n const range = parseRange(text)\n return !range || !overlaps(boundsOf(range), bounds)\n })\n if (kept.length === sheet.merges.length) return this\n return this.updateSheet({ merges: kept.length ? kept : undefined }, index)\n }\n\n /**\n * Changes how the cells in a range look: each cell's style with `patch`\n * laid over it, where a field set to `undefined` (or `false`, but for\n * `locked`) is taken off; `null` takes the whole style off. Cells that end up looking the\n * same share one style: one in `styles` that matches, or a new one named\n * `s1`, `s2`…. Whole columns and rows stop at the sheet's edge.\n */\n styleCells(at: SheetRangeAt, patch: SheetStylePatch | null) {\n const { index, bounds } = this.rangeIn(at)\n // a cell's style name → the name it changes to, worked out once per name\n const next = new Map<string | undefined, string | undefined>()\n for (let row = bounds.top; row <= bounds.bottom; row++)\n for (let col = bounds.left; col <= bounds.right; col++) {\n const point = { sheet: index, row, col }\n const style = cellOf(this.getCell(point))?.style\n if (!next.has(style)) next.set(style, this.styleFor(style, patch))\n const name = next.get(style)\n if (name !== style) this.updateCell(point, { style: name })\n }\n return this\n }\n\n /**\n * Sets the number or date format of the cells in a range (`undefined`\n * for none), or changes each with a function of its format and value,\n * such as `(format, value) => changeDecimals(format, value, 1)`.\n */\n formatCells(\n at: SheetRangeAt,\n format:\n string | undefined | ((format: string | undefined, value: SheetValue) => string | undefined),\n ) {\n const { index, bounds } = this.rangeIn(at)\n for (let row = bounds.top; row <= bounds.bottom; row++)\n for (let col = bounds.left; col <= bounds.right; col++) {\n const point = { sheet: index, row, col }\n const input = this.getCell(point)\n const old = cellOf(input)?.format\n const value = typeof format === 'function' ? format(old, valueOf(input)) : format\n if ((value || undefined) !== old) this.updateCell(point, { format: value || undefined })\n }\n return this\n }\n\n /** The name of a style that looks like `name`'s with `patch` laid over it. */\n private styleFor(name: string | undefined, patch: SheetStylePatch | null) {\n const styles = this.book.styles ?? {}\n const style: SheetStyle = {}\n if (patch)\n for (const [key, value] of Object.entries({ ...(name ? styles[name] : undefined), ...patch }))\n // `false` takes a field off, but `locked: false` is what unlocks a cell\n if (value !== undefined && (value !== false || key === 'locked') && value !== '')\n (style as Record<string, unknown>)[key] = value\n const key = styleKey(style)\n if (key === '{}') return undefined\n if (name && styles[name] && styleKey(styles[name]) === key) return name\n for (const [other, look] of Object.entries(styles)) if (styleKey(look) === key) return other\n let n = 1\n while (styles[`s${n}`]) n++\n this.setStyle(`s${n}`, style)\n return `s${n}`\n }\n\n /**\n * Adds a sheet, at the end or at `index`. Its name must not be taken\n * (`uniqueName` gives one that isn't); it is `Sheet1`, `Sheet2`… when\n * left out, whatever the language. Returns the transaction; the new sheet\n * is `tr.getSheet(name)`.\n */\n addSheet(sheet: Partial<SheetData> = {}, index = this.book.sheets.length) {\n const name = sheet.name ?? this.freeName('Sheet')\n this.checkName(name, sheet.id)\n const data: SheetData = { ...sheet, name, cells: sheet.cells ?? [] }\n return this.step({ type: 'insertSheet', index, data })\n }\n\n /**\n * Removes a sheet. The last one stays: a workbook always has a sheet.\n * Formulas on other sheets pointing at it read `#REF!`.\n */\n removeSheet(sheet: SheetRef = this.sheet) {\n const index = this.mustIndex(sheet)\n if (this.book.sheets.length < 2) return this\n const { name } = this.book.sheets[index]!\n this.step({ type: 'removeSheet', sheet: this.keyOf(index) })\n return this.rewriteFormulas((formula) => dropReferences(formula, name))\n }\n\n /** Moves a sheet to `index`, counted among the sheets without it. */\n moveSheet(sheet: SheetRef, index: number) {\n return this.step({ type: 'moveSheet', sheet: this.keyOf(this.mustIndex(sheet)), index })\n }\n\n /** Renames a sheet; formulas naming it follow. The name must not be taken. */\n renameSheet(sheet: SheetRef, name: string) {\n const index = this.mustIndex(sheet)\n const old = this.book.sheets[index]!\n if (old.name === name) return this\n this.checkName(name, old.id, index)\n this.updateSheet({ name }, index)\n return this.rewriteFormulas((formula) => renameReferences(formula, old.name, name))\n }\n\n /**\n * Adds a copy of a sheet right after it, named `name` or the sheet's name\n * with a number, such as `数据 (2)`. Formulas on the copy that name the\n * sheet keep pointing at the original.\n */\n duplicateSheet(sheet: SheetRef = this.sheet, name?: string) {\n const index = this.mustIndex(sheet)\n const original = this.book.sheets[index]!\n const { id: _id, ...source } = original\n // the copy shares the rows: changing either from here on copies them first\n this.ownSheets.delete(original)\n this.ownRows.delete(original)\n const next = name ?? this.uniqueName(source.name)\n this.checkName(next)\n return this.step({ type: 'insertSheet', index: index + 1, data: { ...source, name: next } })\n }\n\n /**\n * `name` if no sheet has it, otherwise the name with the first free\n * number: `门店 (2)`, `门店 (3)`…\n */\n uniqueName(name: string) {\n const taken = new Set(this.book.sheets.map((sheet) => sheet.name))\n if (!taken.has(name)) return name\n let n = 2\n while (taken.has(`${name} (${n})`)) n++\n return `${name} (${n})`\n }\n\n /** Passes every formula of the workbook through `rewrite`. */\n private rewriteFormulas(rewrite: (formula: string) => string) {\n this.book.sheets.forEach((sheet, index) =>\n sheet.cells.forEach((line, row) =>\n line?.forEach((cell, col) => {\n const value = typeof cell === 'object' ? cell?.value : cell\n if (typeof value !== 'string' || !value.startsWith('=')) return\n const next = rewrite(value)\n if (next !== value) this.setValue({ sheet: index, row, col }, next)\n }),\n ),\n )\n return this.rewriteRuleFormulas((formula) => rewrite(formula))\n }\n\n /**\n * Rewrites the formulas of every sheet's rules: conditional formats' and\n * validations' formulas, and the references of validation lists.\n */\n private rewriteRuleFormulas(rewrite: (formula: string, sheet: SheetData) => string) {\n this.book.sheets.forEach((sheet, index) => {\n for (const key of ['conditionalFormats', 'validations'] as const) {\n const rules = sheet[key] as RuleOf<RuleKey>[] | undefined\n if (!rules?.length) continue\n let changed = false\n const next = rules.map((rule) => {\n if ('formula' in rule) {\n const formula = rewrite(rule.formula, sheet)\n if (formula === rule.formula) return rule\n changed = true\n return { ...rule, formula }\n }\n if ('list' in rule && typeof rule.list === 'string') {\n const list = rewrite(rule.list, sheet)\n if (list === rule.list) return rule\n changed = true\n return { ...rule, list }\n }\n return rule\n })\n if (changed) this.updateSheet({ [key]: next }, index)\n }\n })\n return this\n }\n\n /** The first name `prefix` + a number, from the count of sheets on, that no sheet has. */\n private freeName(prefix: string) {\n const taken = new Set(this.book.sheets.map((sheet) => sheet.name))\n let n = this.book.sheets.length + 1\n while (taken.has(`${prefix}${n}`)) n++\n return `${prefix}${n}`\n }\n\n private checkName(name: string, id?: string, self = -1) {\n if (!name.trim()) throw new RangeError('[@dou-ui/sheet] a sheet needs a name')\n this.book.sheets.forEach((sheet, i) => {\n if (i === self) return\n if (sheet.name === name)\n throw new RangeError(`[@dou-ui/sheet] there is a sheet \"${name}\" already`)\n if (id != null && sheet.id === id)\n throw new RangeError(`[@dou-ui/sheet] there is a sheet \"${id}\" already`)\n })\n }\n\n /** Rewrites the references to cells on sheet `name` in every formula of the workbook. */\n private rewriteReferences(name: string, map: SheetRefMap) {\n this.book.sheets.forEach((sheet, index) => {\n sheet.cells.forEach((line, row) =>\n line?.forEach((cell, col) => {\n const value = typeof cell === 'object' ? cell?.value : cell\n if (typeof value !== 'string' || !value.startsWith('=')) return\n const next = moveReferences(value, sheet.name, name, map)\n if (next !== value) this.setValue({ sheet: index, row, col }, next)\n }),\n )\n })\n return this.rewriteRuleFormulas((formula, sheet) =>\n moveReferences(formula, sheet.name, name, map),\n )\n }\n\n private mustIndex(ref: SheetRef = this.sheet) {\n const index = this.indexOf(ref)\n if (index === -1) throw new RangeError(`[@dou-ui/sheet] there is no sheet \"${ref}\"`)\n return index\n }\n\n private keyOf(index: number) {\n return sheetKey(this.book.sheets[index]!)\n }\n\n private cellAt(at: SheetCellAt) {\n if (typeof at === 'string') {\n const { sheet, ref } = splitSheet(at)\n const point = parseCell(ref)\n if (!point) throw new RangeError(`[@dou-ui/sheet] \"${at}\" isn't a cell`)\n return { index: this.mustIndex(sheet), ...point }\n }\n return { index: this.mustIndex(at.sheet), row: at.row, col: at.col }\n }\n\n private rangeAt(at: SheetRangeAt) {\n let sheet: SheetRef | undefined\n let bounds: SheetBounds\n if (typeof at === 'string') {\n const split = splitSheet(at)\n sheet = split.sheet\n const range = parseRange(split.ref)\n if (!range) throw new RangeError(`[@dou-ui/sheet] \"${at}\" isn't a range`)\n bounds = boundsOf(range)\n } else {\n sheet = at.sheet\n bounds =\n 'start' in at\n ? boundsOf(at)\n : { top: at.top, left: at.left, bottom: at.bottom, right: at.right }\n }\n return { index: this.mustIndex(sheet), bounds }\n }\n\n /** A range kept inside its sheet, so whole columns and rows end at its edge. */\n private rangeIn(at: SheetRangeAt) {\n const { index, bounds } = this.rangeAt(at)\n const sheet = this.book.sheets[index]!\n return {\n index,\n bounds: {\n top: Math.max(0, bounds.top),\n left: Math.max(0, bounds.left),\n bottom: Math.min(rowCountOf(sheet) - 1, bounds.bottom),\n right: Math.min(colCountOf(sheet) - 1, bounds.right),\n },\n }\n }\n\n /** Applies a step, returning the step that undoes it, or `null` when nothing changes. */\n private apply(step: SheetStep): SheetStep | null {\n if (step.type === 'setStyle') {\n const old = this.book.styles?.[step.name]\n if (old === step.style) return null\n const book = this.ownBook()\n const styles = this.own.styles ? book.styles! : { ...book.styles }\n this.own.styles = true\n if (step.style) styles[step.name] = step.style\n else delete styles[step.name]\n book.styles = styles\n return { type: 'setStyle', name: step.name, style: old }\n }\n if (step.type === 'setType') {\n const old = this.book.types?.[step.name]\n if (old === step.setup) return null\n const book = this.ownBook()\n const types = this.own.types ? book.types! : { ...book.types }\n this.own.types = true\n if (step.setup) types[step.name] = step.setup\n else delete types[step.name]\n book.types = types\n return { type: 'setType', name: step.name, setup: old }\n }\n if (step.type === 'updateBook') {\n const book = this.book as unknown as Record<string, unknown>\n const old: Record<string, unknown> = {}\n let changed = false\n for (const [key, value] of Object.entries(step.patch)) {\n old[key] = book[key]\n if (book[key] !== value) changed = true\n }\n if (!changed) return null\n const own = this.ownBook() as unknown as Record<string, unknown>\n for (const [key, value] of Object.entries(step.patch)) {\n if (value === undefined) delete own[key]\n else own[key] = value\n }\n return { type: 'updateBook', patch: old as SheetBookPatch }\n }\n if (step.type === 'insertSheet') {\n const sheets = this.ownList()\n const index = Math.max(0, Math.min(sheets.length, step.index))\n sheets.splice(index, 0, step.data)\n return { type: 'removeSheet', sheet: sheetKey(step.data) }\n }\n const index = this.mustIndex(step.sheet)\n const sheet = this.book.sheets[index]!\n switch (step.type) {\n case 'removeSheet': {\n this.ownList().splice(index, 1)\n // what the undo step keeps must not change, even if the sheet comes back\n this.ownSheets.delete(sheet)\n this.ownRows.delete(sheet)\n return { type: 'insertSheet', index, data: sheet }\n }\n case 'moveSheet': {\n const sheets = this.book.sheets\n const to = Math.max(0, Math.min(sheets.length - 1, step.index))\n if (to === index) return null\n const list = this.ownList()\n list.splice(index, 1)\n list.splice(to, 0, sheet)\n return { type: 'moveSheet', sheet: step.sheet, index }\n }\n case 'setCell': {\n const { row, col } = step\n const cell = step.cell ?? undefined\n const old = sheet.cells[row]?.[col] ?? undefined\n if (old === cell || (old == null && cell == null)) return null\n this.row(index, row)[col] = cell\n return { ...step, cell: old }\n }\n case 'setSize': {\n const key = step.axis === 'row' ? 'rowSizes' : 'colSizes'\n const sizes = sheet[key]\n const old = sizes?.[step.index]\n if (old === step.size) return null\n const next = { ...sizes }\n if (step.size == null) delete next[step.index]\n else next[step.index] = step.size\n this.ownSheet(index)[key] = next\n return { ...step, size: old }\n }\n case 'updateSheet': {\n const old: Record<string, unknown> = {}\n let changed = false\n for (const key of Object.keys(step.patch) as (keyof SheetPatch)[]) {\n old[key] = sheet[key]\n if (sheet[key] !== step.patch[key]) changed = true\n }\n if (!changed) return null\n const own = this.ownSheet(index) as unknown as Record<string, unknown>\n for (const [key, value] of Object.entries(step.patch)) {\n if (value === undefined) delete own[key]\n else own[key] = value\n }\n // a rename changes the key of a sheet without an id\n return { type: 'updateSheet', sheet: this.keyOf(index), patch: old as SheetPatch }\n }\n case 'insertLines':\n return this.insertAt(index, step)\n case 'removeLines':\n return this.removeAt(index, step)\n case 'moveLines':\n return this.moveAt(index, step)\n }\n }\n\n private insertAt(index: number, step: Extract<SheetStep, { type: 'insertLines' }>): SheetStep {\n const { axis, count } = step\n const at = step.index\n const own = this.ownSheet(index)\n const fill = step.cells\n if (axis === 'row') {\n if (at < own.cells.length || fill?.some((line) => line?.length)) {\n while (own.cells.length < at) own.cells.push(null)\n own.cells.splice(at, 0, ...Array.from({ length: count }, (_, i) => fill?.[i] ?? null))\n }\n // rows moved: what was copied is now at other numbers\n this.ownRows.delete(own)\n } else {\n const length = Math.max(own.cells.length, fill?.length ?? 0)\n for (let r = 0; r < length; r++) {\n const line = own.cells[r]\n const part = fill?.[r]\n if (!part?.length && (!line || line.length <= at)) continue\n const next = this.row(index, r)\n while (next.length < at) next.push(undefined)\n next.splice(at, 0, ...Array.from({ length: count }, (_, i) => part?.[i] ?? undefined))\n }\n }\n shiftSizes(own, axis, (n) => (n >= at ? n + count : n), at, step.sizes)\n return { type: 'removeLines', sheet: step.sheet, axis, index: at, count }\n }\n\n private removeAt(index: number, step: Extract<SheetStep, { type: 'removeLines' }>): SheetStep {\n const { axis, count } = step\n const at = step.index\n const own = this.ownSheet(index)\n let cells: (SheetRow | null)[] | undefined\n if (axis === 'row') {\n if (at < own.cells.length) cells = own.cells.splice(at, count).map((line) => line ?? null)\n this.ownRows.delete(own)\n } else {\n for (let r = 0; r < own.cells.length; r++) {\n const line = own.cells[r]\n if (!line || line.length <= at) continue\n const removed = this.row(index, r).splice(at, count)\n if (removed.some((cell) => cell != null)) (cells ??= [])[r] = removed\n }\n if (cells) for (let r = 0; r < cells.length; r++) cells[r] ??= null\n }\n const sizeKey = axis === 'row' ? 'rowSizes' : 'colSizes'\n const old = own[sizeKey]\n let sizes: (number | null)[] | undefined\n if (old)\n for (let i = 0; i < count; i++)\n if (old[at + i] != null)\n (sizes ??= Array<number | null>(count).fill(null))[i] = old[at + i]!\n shiftSizes(own, axis, (n) => (n < at ? n : n >= at + count ? n - count : -1))\n const inverse: SheetStep = { type: 'insertLines', sheet: step.sheet, axis, index: at, count }\n if (cells) inverse.cells = cells\n if (sizes) inverse.sizes = sizes\n return inverse\n }\n\n private moveAt(index: number, step: Extract<SheetStep, { type: 'moveLines' }>): SheetStep {\n const { axis, from, count, to } = step\n const own = this.ownSheet(index)\n const place = movedIndex(from, count, to)\n const reorder = <T>(list: T[], empty: T) => {\n const end = Math.max(from + count, to)\n if (list.length <= Math.min(from, to)) return list\n const out = list.slice()\n while (out.length < end) out.push(empty)\n for (let i = Math.min(from, to); i < end; i++) out[place(i)] = list[i] ?? empty\n while (out.length && out[out.length - 1] == null) out.pop()\n return out\n }\n if (axis === 'row') {\n own.cells = reorder(own.cells, null)\n this.ownRows.delete(own)\n } else\n for (let r = 0; r < own.cells.length; r++) {\n const line = own.cells[r]\n if (!line || line.length <= Math.min(from, to)) continue\n const next = reorder(line, undefined)\n if (next !== line) own.cells[r] = next\n }\n shiftSizes(own, axis, place)\n const back = to > from ? to - count : to\n return {\n type: 'moveLines',\n sheet: step.sheet,\n axis,\n from: back,\n count,\n to: to > from ? from : from + count,\n }\n }\n\n private ownBook() {\n if (!this.own.book) {\n this.book = { ...this.book }\n this.own.book = true\n }\n return this.book\n }\n\n /** The list of sheets as an array this transaction may change. */\n private ownList() {\n const book = this.ownBook()\n if (!this.own.sheets) {\n book.sheets = book.sheets.slice()\n this.own.sheets = true\n }\n return book.sheets\n }\n\n private ownSheet(index: number) {\n const book = this.ownBook()\n this.ownList()\n let sheet = book.sheets[index]!\n if (!this.ownSheets.has(sheet)) {\n sheet = book.sheets[index] = { ...sheet, cells: sheet.cells.slice() }\n this.ownSheets.add(sheet)\n }\n return sheet\n }\n\n /** The row as an array this transaction may change. */\n private row(sheet: number, row: number): SheetRow {\n const own = this.ownSheet(sheet)\n let rows = this.ownRows.get(own)\n if (!rows) this.ownRows.set(own, (rows = new Set()))\n if (!rows.has(row)) {\n own.cells[row] = own.cells[row]?.slice() ?? []\n rows.add(row)\n }\n return own.cells[row]!\n }\n}\n\nconst rangeText = (b: SheetBounds) =>\n formatRange({ start: { row: b.top, col: b.left }, end: { row: b.bottom, col: b.right } })\n\n/** Whether `x` lies inside `y`. */\nconst inside = (x: SheetBounds, y: SheetBounds) =>\n x.top >= y.top && x.bottom <= y.bottom && x.left >= y.left && x.right <= y.right\n\n/** Rows or columns written as a number, `'5:7'` or `'B:C'`, as a first line and a count. */\nfunction linesOf(axis: SheetAxisName, at: SheetLinesAt, count?: number) {\n if (typeof at === 'number') return { from: at, count: count ?? 1 }\n if (typeof at === 'object') return at\n const [a = '', b = a, extra] = at.replaceAll('$', '').trim().split(':')\n const line = (text: string) =>\n axis === 'row' ? (/^[1-9]\\d*$/.test(text) ? Number(text) - 1 : -1) : columnIndex(text)\n const first = line(a!)\n const last = line(b)\n if (extra != null || first < 0 || last < 0)\n throw new RangeError(`[@dou-ui/sheet] \"${at}\" isn't ${axis === 'row' ? 'rows' : 'columns'}`)\n return { from: Math.min(first, last), count: count ?? Math.abs(last - first) + 1 }\n}\n\n/**\n * A reference map for a change to rows or columns: `span` gives a range's\n * new first and last line on that axis, or `null` when they are gone.\n * Whole rows are not touched by a change to columns, and so on.\n */\nfunction lineMap(\n axis: SheetAxisName,\n span: (a: number, b: number) => [number, number] | null,\n): SheetRefMap {\n return (b) => {\n const [a, z] = axis === 'row' ? [b.top, b.bottom] : [b.left, b.right]\n // whole columns for rows, whole rows for columns\n if (a === 0 && z === Infinity) return b\n const next = span(a, z === Infinity ? a : z)\n if (!next) return null\n const last = z === Infinity ? Infinity : next[1]\n return axis === 'row'\n ? { ...b, top: next[0], bottom: last }\n : { ...b, left: next[0], right: last }\n }\n}\n\n/** Where line `i` ends up when `count` lines from `from` move to before `to`. */\nexport function movedIndex(from: number, count: number, to: number) {\n return (i: number) => {\n if (i >= from && i < from + count) return to > from ? i - from + to - count : i - from + to\n if (to > from && i >= from + count && i < to) return i - count\n if (to < from && i >= to && i < from) return i + count\n return i\n }\n}\n\n/** Renumbers a sheet's changed sizes; a number below 0 drops the size. */\nfunction shiftSizes(\n sheet: SheetData,\n axis: SheetAxisName,\n to: (n: number) => number,\n insertAt?: number,\n inserted?: (number | null)[],\n) {\n const key = axis === 'row' ? 'rowSizes' : 'colSizes'\n const old = sheet[key]\n if (!old && !inserted?.some((size) => size != null)) return\n const next: Record<number, number> = {}\n for (const [n, size] of Object.entries(old ?? {})) {\n const moved = to(Number(n))\n if (moved >= 0) next[moved] = size\n }\n inserted?.forEach((size, i) => {\n if (size != null) next[insertAt! + i] = size\n })\n sheet[key] = next\n}\n\n/** The frozen count and line count after lines are added or removed. */\nfunction linesPatch(\n sheet: SheetData,\n axis: SheetAxisName,\n frozen: (n: number) => number,\n change: number,\n): SheetPatch {\n const patch: SheetPatch = {}\n const countKey = axis === 'row' ? 'rowCount' : 'colCount'\n const freezeKey = axis === 'row' ? 'rows' : 'cols'\n const count = sheet[countKey]\n if (count != null) patch[countKey] = Math.max(1, count + change)\n const freeze = sheet.freeze?.[freezeKey]\n if (freeze) {\n const next = frozen(freeze)\n if (next !== freeze) patch.freeze = { ...sheet.freeze, [freezeKey]: next }\n }\n return patch\n}\n\n/** Applies steps to a workbook, as one transaction. */\nexport function applySheetSteps(doc: SheetWorkbook, steps: readonly SheetStep[]) {\n const tr = new SheetTransaction(doc)\n for (const step of steps) tr.step(step)\n return tr\n}\n\nconst keyOf = (step: SheetStep) => {\n switch (step.type) {\n case 'setCell':\n return `c${step.sheet}:${step.row}:${step.col}`\n case 'setSize':\n return `s${step.sheet}:${step.axis}:${step.index}`\n case 'setStyle':\n return `y${step.name}`\n case 'setType':\n return `t${step.name}`\n default:\n return null\n }\n}\n\n/**\n * The same changes in fewer steps: of several steps writing the same cell,\n * size or style, keeps only the last, which is the one that counts.\n */\nexport function compactSheetSteps(steps: readonly SheetStep[]) {\n const out: SheetStep[] = []\n const at = new Map<string, number>()\n for (const step of steps) {\n const key = keyOf(step)\n if (key == null) {\n // a step without a key may depend on what came before; keep everything up to it\n at.clear()\n out.push(step)\n continue\n }\n const index = at.get(key)\n if (index == null) {\n at.set(key, out.length)\n out.push(step)\n } else out[index] = step\n }\n return out\n}\n\nlet warnedUncancellable = false\n/** Says once that cancelling a change kept out of the history does nothing. */\nfunction warnUncancellable() {\n // the app's bundler replaces this, as for Vue's own warnings\n if (process.env.NODE_ENV === 'production' || warnedUncancellable) return\n warnedUncancellable = true\n console.warn(\n \"[@dou-ui/sheet] a change kept out of the history (undo, redo or another person's) can't be cancelled; it goes ahead\",\n )\n}\n"],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ import { shiftFormula } from "./address.js";
2
+ import { optionOf } from "./cell-type.js";
3
+ import { isEmptyValue, meetsCondition, textCollator } from "./data.js";
4
+ import { areasIn } from "./conditional.js";
5
+ import { format } from "../locale.js";
6
+ // src/core/validation.ts
7
+ /** Whether a rule reads other cells, so a cell's mark can change when they do. */
8
+ var readsOthers = (rule) => "formula" in rule || "list" in rule && typeof rule.list === "string";
9
+ /** Two values are the same option: equal, or the same text without case. */
10
+ function sameOption(a, b) {
11
+ if (a === b) return true;
12
+ return typeof a === "string" && typeof b === "string" && a.toLowerCase() === b.toLowerCase();
13
+ }
14
+ /**
15
+ * The validation rules of a sheet. Make a new one when the workbook
16
+ * changes; it reads a list's cells once.
17
+ */
18
+ var SheetChecks = class {
19
+ source;
20
+ rules = [];
21
+ collator;
22
+ constructor(validations, source) {
23
+ this.source = source;
24
+ this.collator = textCollator(source.lang);
25
+ for (const rule of validations ?? []) {
26
+ const { areas, anchor } = areasIn(rule.range, source.size);
27
+ const list = {};
28
+ for (const bounds of areas) this.rules.push({
29
+ rule,
30
+ bounds,
31
+ anchor,
32
+ list
33
+ });
34
+ }
35
+ }
36
+ /** Whether there are any rules. */
37
+ get empty() {
38
+ return !this.rules.length;
39
+ }
40
+ /** Whether a rule covering the row reads other cells. */
41
+ readsOthersIn(row) {
42
+ return this.rules.some((r) => row >= r.bounds.top && row <= r.bounds.bottom && readsOthers(r.rule));
43
+ }
44
+ entryAt(row, col) {
45
+ for (const r of this.rules) {
46
+ const b = r.bounds;
47
+ if (row >= b.top && row <= b.bottom && col >= b.left && col <= b.right) return r;
48
+ }
49
+ }
50
+ /** The rule a cell must keep, or `undefined`. */
51
+ ruleAt(row, col) {
52
+ return this.entryAt(row, col)?.rule;
53
+ }
54
+ /** The options of the list rule a cell must keep, or `undefined` when it has none. */
55
+ optionsAt(row, col) {
56
+ const entry = this.entryAt(row, col);
57
+ return entry && "list" in entry.rule ? this.optionsOf(entry) : void 0;
58
+ }
59
+ optionsOf(entry) {
60
+ const { list } = entry.rule;
61
+ const cache = entry.list;
62
+ if (!cache.options) {
63
+ if (typeof list !== "string") cache.options = list;
64
+ else {
65
+ const seen = [];
66
+ for (const value of this.source.listAt(list)) if (!isEmptyValue(value) && !seen.some((v) => sameOption(v, value))) seen.push(value);
67
+ cache.options = seen;
68
+ }
69
+ }
70
+ return cache.options;
71
+ }
72
+ /**
73
+ * Whether a value fits the rule of the cell at `row`, `col`; `text` is how
74
+ * it shows. Without a rule, anything fits.
75
+ */
76
+ fits(row, col, value, text) {
77
+ const entry = this.entryAt(row, col);
78
+ if (!entry || isEmptyValue(value)) return true;
79
+ const { rule } = entry;
80
+ if ("list" in rule) return this.optionsOf(entry).some((option) => sameOption(optionOf(option).value, value));
81
+ if ("when" in rule) {
82
+ const { when } = rule;
83
+ if (rule.integer || typeof when.value === "number" || typeof when.to === "number") {
84
+ if (typeof value !== "number") return false;
85
+ if (rule.integer && !Number.isInteger(value)) return false;
86
+ }
87
+ return meetsCondition(when, value, text, this.collator);
88
+ }
89
+ const formula = shiftFormula(rule.formula, row - entry.anchor.row, col - entry.anchor.col);
90
+ const result = this.source.evaluate(formula);
91
+ return result === true || typeof result === "number" && result !== 0;
92
+ }
93
+ /** The rule a cell breaks as it is now, or `undefined`. */
94
+ brokenAt(row, col) {
95
+ const rule = this.ruleAt(row, col);
96
+ if (!rule) return void 0;
97
+ const s = this.source;
98
+ return this.fits(row, col, s.valueAt(row, col), s.textAt(row, col)) ? void 0 : rule;
99
+ }
100
+ /** Every cell that breaks its rule, rule by rule. */
101
+ *broken() {
102
+ const seen = /* @__PURE__ */ new Set();
103
+ for (const { bounds: b } of this.rules) for (let row = b.top; row <= b.bottom; row++) for (let col = b.left; col <= b.right; col++) {
104
+ const pos = row * 16384 + col;
105
+ if (seen.has(pos)) continue;
106
+ seen.add(pos);
107
+ const rule = this.brokenAt(row, col);
108
+ if (rule) yield {
109
+ row,
110
+ col,
111
+ rule
112
+ };
113
+ }
114
+ }
115
+ };
116
+ var shown = (value) => value == null ? "" : String(value);
117
+ /** A rule in words: its `message`, or what it asks for. */
118
+ function ruleMessage(rule, messages) {
119
+ if (rule.message) return rule.message;
120
+ const m = messages.validation;
121
+ if ("list" in rule) return m.list;
122
+ if ("formula" in rule) return format(m.formulaFailed, { formula: rule.formula });
123
+ const { op, value, to } = rule.when;
124
+ const number = rule.integer || typeof value === "number" || typeof to === "number";
125
+ if (op === "notBlank" && number) return rule.integer ? m.integerOnly : m.numberOnly;
126
+ const cond = format(op === "between" || op === "notBetween" ? m.condBetween : m.cond, {
127
+ op: messages.ops[op],
128
+ value: shown(value),
129
+ to: shown(to)
130
+ }).trim();
131
+ return format(rule.integer ? m.integer : number ? m.number : m.text, { cond });
132
+ }
133
+ export { SheetChecks, readsOthers, ruleMessage };
134
+
135
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","names":[],"sources":["../../src/core/validation.ts"],"sourcesContent":["import { shiftFormula, type SheetBounds } from './address'\nimport { optionOf } from './cell-type'\nimport { areasIn } from './conditional'\nimport { isEmptyValue, meetsCondition, textCollator } from './data'\nimport type { SheetSelectOption, SheetValidation, SheetValue } from './model'\nimport { format, type SheetMessages } from '../locale'\n\n/*\n * Data validation: what the cells of a range may hold. A rule is checked\n * when a value is typed (a strict rule refuses it) and when cells are\n * drawn, where a value that doesn't fit gets a mark.\n */\n\n/** Where the rules read cells and work out formulas, for the sheet they belong to. */\nexport interface SheetCheckSource {\n /** What a cell holds, its formula's result for a formula. */\n valueAt: (row: number, col: number) => unknown\n /** How a cell shows. */\n textAt: (row: number, col: number) => string\n /** Works out a formula on the sheet. */\n evaluate: (formula: string) => unknown\n /** The values of the cells a list refers to, such as `'=$H$2:$H$9'`. */\n listAt: (reference: string) => SheetValue[]\n size: { rows: number; cols: number }\n lang?: string\n}\n\n/** A rule over one of its ranges; the ranges of a rule share its `list`. */\ninterface Rule {\n rule: SheetValidation\n bounds: SheetBounds\n /** The cell its formula is written for. */\n anchor: { row: number; col: number }\n list: { options?: SheetSelectOption[] }\n}\n\n/** Whether a rule reads other cells, so a cell's mark can change when they do. */\nexport const readsOthers = (rule: SheetValidation) =>\n 'formula' in rule || ('list' in rule && typeof rule.list === 'string')\n\n/** Two values are the same option: equal, or the same text without case. */\nfunction sameOption(a: unknown, b: unknown) {\n if (a === b) return true\n return typeof a === 'string' && typeof b === 'string' && a.toLowerCase() === b.toLowerCase()\n}\n\n/**\n * The validation rules of a sheet. Make a new one when the workbook\n * changes; it reads a list's cells once.\n */\nexport class SheetChecks {\n private rules: Rule[] = []\n private collator: Intl.Collator\n\n constructor(\n validations: readonly SheetValidation[] | undefined,\n private source: SheetCheckSource,\n ) {\n this.collator = textCollator(source.lang)\n for (const rule of validations ?? []) {\n const { areas, anchor } = areasIn(rule.range, source.size)\n const list = {}\n for (const bounds of areas) this.rules.push({ rule, bounds, anchor, list })\n }\n }\n\n /** Whether there are any rules. */\n get empty() {\n return !this.rules.length\n }\n\n /** Whether a rule covering the row reads other cells. */\n readsOthersIn(row: number) {\n return this.rules.some(\n (r) => row >= r.bounds.top && row <= r.bounds.bottom && readsOthers(r.rule),\n )\n }\n\n private entryAt(row: number, col: number) {\n for (const r of this.rules) {\n const b = r.bounds\n if (row >= b.top && row <= b.bottom && col >= b.left && col <= b.right) return r\n }\n return undefined\n }\n\n /** The rule a cell must keep, or `undefined`. */\n ruleAt(row: number, col: number): SheetValidation | undefined {\n return this.entryAt(row, col)?.rule\n }\n\n /** The options of the list rule a cell must keep, or `undefined` when it has none. */\n optionsAt(row: number, col: number): SheetSelectOption[] | undefined {\n const entry = this.entryAt(row, col)\n return entry && 'list' in entry.rule ? this.optionsOf(entry) : undefined\n }\n\n private optionsOf(entry: Rule) {\n const { list } = entry.rule as Extract<SheetValidation, { list: unknown }>\n const cache = entry.list\n if (!cache.options) {\n if (typeof list !== 'string') cache.options = list\n else {\n // a list's cells, without blanks or values given twice\n const seen: SheetValue[] = []\n for (const value of this.source.listAt(list))\n if (!isEmptyValue(value) && !seen.some((v) => sameOption(v, value))) seen.push(value)\n cache.options = seen\n }\n }\n return cache.options\n }\n\n /**\n * Whether a value fits the rule of the cell at `row`, `col`; `text` is how\n * it shows. Without a rule, anything fits.\n */\n fits(row: number, col: number, value: unknown, text: string) {\n const entry = this.entryAt(row, col)\n if (!entry || isEmptyValue(value)) return true\n const { rule } = entry\n if ('list' in rule)\n return this.optionsOf(entry).some((option) => sameOption(optionOf(option).value, value))\n if ('when' in rule) {\n const { when } = rule\n if (rule.integer || typeof when.value === 'number' || typeof when.to === 'number') {\n if (typeof value !== 'number') return false\n if (rule.integer && !Number.isInteger(value)) return false\n }\n return meetsCondition(when, value, text, this.collator)\n }\n const formula = shiftFormula(rule.formula, row - entry.anchor.row, col - entry.anchor.col)\n const result = this.source.evaluate(formula)\n return result === true || (typeof result === 'number' && result !== 0)\n }\n\n /** The rule a cell breaks as it is now, or `undefined`. */\n brokenAt(row: number, col: number): SheetValidation | undefined {\n const rule = this.ruleAt(row, col)\n if (!rule) return undefined\n const s = this.source\n return this.fits(row, col, s.valueAt(row, col), s.textAt(row, col)) ? undefined : rule\n }\n\n /** Every cell that breaks its rule, rule by rule. */\n *broken(): Generator<{ row: number; col: number; rule: SheetValidation }> {\n const seen = new Set<number>()\n for (const { bounds: b } of this.rules)\n for (let row = b.top; row <= b.bottom; row++)\n for (let col = b.left; col <= b.right; col++) {\n const pos = row * 16384 + col\n if (seen.has(pos)) continue\n seen.add(pos)\n const rule = this.brokenAt(row, col)\n if (rule) yield { row, col, rule }\n }\n }\n}\n\nconst shown = (value: SheetValue | undefined) => (value == null ? '' : String(value))\n\n/** A rule in words: its `message`, or what it asks for. */\nexport function ruleMessage(rule: SheetValidation, messages: SheetMessages) {\n if (rule.message) return rule.message\n const m = messages.validation\n if ('list' in rule) return m.list\n if ('formula' in rule) return format(m.formulaFailed, { formula: rule.formula })\n const { op, value, to } = rule.when\n const number = rule.integer || typeof value === 'number' || typeof to === 'number'\n if (op === 'notBlank' && number) return rule.integer ? m.integerOnly : m.numberOnly\n const between = op === 'between' || op === 'notBetween'\n const cond = format(between ? m.condBetween : m.cond, {\n op: messages.ops[op],\n value: shown(value),\n to: shown(to),\n }).trim()\n return format(rule.integer ? m.integer : number ? m.number : m.text, { cond })\n}\n"],"mappings":"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"}
@@ -0,0 +1,161 @@
1
+ import { formatCell } from "./address.js";
2
+ import { cellOf, colCountOf, compactCell, rowCountOf } from "./model.js";
3
+ import { sheetKey } from "./transaction.js";
4
+ // src/core/versions.ts
5
+ /**
6
+ * A cell as versions compare it: without its thread, fields left
7
+ * `undefined` dropped, and an empty value (`''` or `null`) taken for none,
8
+ * so `{ value: 1 }` and `1` are the same cell.
9
+ */
10
+ var bare = (cell) => {
11
+ const own = cellOf(cell);
12
+ if (!own) return void 0;
13
+ const { comment: _comment, ...rest } = own;
14
+ if (rest.value === "" || rest.value === null) rest.value = void 0;
15
+ return compactCell(rest) ?? void 0;
16
+ };
17
+ /** JSON with the keys of objects in order, so the order they were written in doesn't count. */
18
+ var stable = (value) => JSON.stringify(value ?? null, (_key, item) => item && typeof item === "object" && !Array.isArray(item) ? Object.fromEntries(Object.entries(item).filter(([, v]) => v !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) : item);
19
+ var same = (a, b) => a === b || stable(a) === stable(b);
20
+ var sameCell = (a, b) => same(bare(a), bare(b));
21
+ /** The fields of a sheet other than its cells and sizes. */
22
+ function settingsOf(sheet) {
23
+ const { cells: _cells, rowSizes: _rows, colSizes: _cols, id: _id, ...rest } = sheet;
24
+ return {
25
+ ...rest,
26
+ rowCount: rowCountOf(sheet),
27
+ colCount: colCountOf(sheet)
28
+ };
29
+ }
30
+ /** The cells that differ between two sheets, as `[row, col]`. */
31
+ function changedCells(before, after) {
32
+ const out = [];
33
+ const rows = Math.max(before.cells.length, after.cells.length);
34
+ for (let row = 0; row < rows; row++) {
35
+ const a = before.cells[row];
36
+ const b = after.cells[row];
37
+ if (a === b) continue;
38
+ const cols = Math.max(a?.length ?? 0, b?.length ?? 0);
39
+ for (let col = 0; col < cols; col++) if (!sameCell(a?.[col], b?.[col])) out.push([row, col]);
40
+ }
41
+ return out;
42
+ }
43
+ /** The workbook's own settings, such as `protect`. */
44
+ function bookSettings(book) {
45
+ const { sheets: _sheets, styles: _styles, types: _types, ...rest } = book;
46
+ return rest;
47
+ }
48
+ /** The names whose entries differ between two records of named things. */
49
+ function changedNames(a = {}, b = {}) {
50
+ return [.../* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)])].filter((name) => !same(a[name], b[name]));
51
+ }
52
+ /** What changed from `before` to `after`. */
53
+ function diffWorkbooks(before, after) {
54
+ const old = new Map(before.sheets.map((sheet) => [sheetKey(sheet), sheet]));
55
+ const now = new Set(after.sheets.map(sheetKey));
56
+ const diff = {
57
+ cells: [],
58
+ addedSheets: [],
59
+ removedSheets: [],
60
+ changedSheets: [],
61
+ changedStyles: [],
62
+ changedTypes: [],
63
+ bookChanged: !same(bookSettings(before), bookSettings(after))
64
+ };
65
+ for (const sheet of after.sheets) {
66
+ const key = sheetKey(sheet);
67
+ const was = old.get(key);
68
+ if (!was) {
69
+ diff.addedSheets.push(key);
70
+ continue;
71
+ }
72
+ for (const [row, col] of changedCells(was, sheet)) diff.cells.push({
73
+ sheet: key,
74
+ row,
75
+ col,
76
+ address: formatCell({
77
+ row,
78
+ col
79
+ }),
80
+ before: was.cells[row]?.[col] ?? void 0,
81
+ after: sheet.cells[row]?.[col] ?? void 0
82
+ });
83
+ if (!same(settingsOf(was), settingsOf(sheet)) || !same(was.rowSizes, sheet.rowSizes) || !same(was.colSizes, sheet.colSizes)) diff.changedSheets.push(key);
84
+ }
85
+ for (const key of old.keys()) if (!now.has(key)) diff.removedSheets.push(key);
86
+ diff.changedStyles = changedNames(before.styles, after.styles);
87
+ diff.changedTypes = changedNames(before.types, after.types);
88
+ return diff;
89
+ }
90
+ /** A version's sheet without the threads it had then. */
91
+ function withoutThreads(sheet) {
92
+ return {
93
+ ...sheet,
94
+ cells: sheet.cells.map((line) => line?.map((cell) => bare(cell)) ?? line)
95
+ };
96
+ }
97
+ /**
98
+ * Adds the steps that bring the workbook to `book`, writing only what
99
+ * differs: cells, sizes and settings of the sheets in both (protection
100
+ * too), sheets added and removed, their order, the workbook's settings,
101
+ * and the named styles and types.
102
+ */
103
+ function restoreWorkbook(tr, book) {
104
+ const wanted = book.sheets.map(sheetKey);
105
+ book.sheets.forEach((sheet, index) => {
106
+ if (tr.indexOf(sheetKey(sheet)) === -1) tr.step({
107
+ type: "insertSheet",
108
+ index: Math.min(index, tr.doc.sheets.length),
109
+ data: withoutThreads(sheet)
110
+ });
111
+ });
112
+ for (const sheet of tr.doc.sheets.slice()) if (!wanted.includes(sheetKey(sheet))) tr.step({
113
+ type: "removeSheet",
114
+ sheet: sheetKey(sheet)
115
+ });
116
+ wanted.forEach((key, index) => {
117
+ if (tr.indexOf(key) !== index) tr.step({
118
+ type: "moveSheet",
119
+ sheet: key,
120
+ index
121
+ });
122
+ });
123
+ for (const sheet of book.sheets) {
124
+ const key = sheetKey(sheet);
125
+ const now = tr.getSheet(key);
126
+ const was = settingsOf(now);
127
+ const next = settingsOf(sheet);
128
+ const patch = {};
129
+ for (const name of /* @__PURE__ */ new Set([...Object.keys(was), ...Object.keys(next)])) if (!same(was[name], next[name])) patch[name] = next[name];
130
+ if (Object.keys(patch).length) tr.updateSheet(patch, key);
131
+ for (const axis of ["row", "col"]) {
132
+ const field = axis === "row" ? "rowSizes" : "colSizes";
133
+ const a = now[field] ?? {};
134
+ const b = sheet[field] ?? {};
135
+ for (const index of /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)])) if (a[Number(index)] !== b[Number(index)]) tr.setSize(axis, Number(index), b[Number(index)], key);
136
+ }
137
+ for (const [row, col] of changedCells(tr.getSheet(key), sheet)) {
138
+ const at = {
139
+ sheet: key,
140
+ row,
141
+ col
142
+ };
143
+ const thread = cellOf(tr.getCell(at))?.comment;
144
+ tr.setCell(at, compactCell({
145
+ ...cellOf(bare(sheet.cells[row]?.[col])),
146
+ comment: thread
147
+ }));
148
+ }
149
+ }
150
+ const was = bookSettings(tr.doc);
151
+ const next = bookSettings(book);
152
+ const patch = {};
153
+ for (const name of changedNames(was, next)) patch[name] = next[name];
154
+ if (Object.keys(patch).length) tr.updateBook(patch);
155
+ for (const name of changedNames(tr.doc.styles, book.styles)) tr.setStyle(name, book.styles?.[name]);
156
+ for (const name of changedNames(tr.doc.types, book.types)) tr.setType(name, book.types?.[name]);
157
+ return tr;
158
+ }
159
+ export { diffWorkbooks, restoreWorkbook };
160
+
161
+ //# sourceMappingURL=versions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versions.js","names":[],"sources":["../../src/core/versions.ts"],"sourcesContent":["import { formatCell } from './address'\nimport {\n cellOf,\n colCountOf,\n compactCell,\n rowCountOf,\n type SheetCellInput,\n type SheetData,\n type SheetWorkbook,\n} from './model'\nimport {\n sheetKey,\n type SheetBookPatch,\n type SheetPatch,\n type SheetTransaction,\n} from './transaction'\n\n/*\n * Versions of a workbook: what changed between two, and going back to one.\n * Sheets are matched by `id` (or name); cells by where they are, as rows\n * and columns have no ids of their own. A cell's comment thread is not\n * part of a version: it doesn't count as a change, and going back to a\n * version keeps the threads where they are.\n */\n\n/** A cell that differs between two versions. */\nexport interface SheetCellChange {\n /** The sheet's key: its `id`, or its name. */\n sheet: string\n row: number\n col: number\n /** The cell as people write it, e.g. `B3`. */\n address: string\n before: SheetCellInput\n after: SheetCellInput\n}\n\nexport interface WorkbookDiff {\n /** The cells that differ on the sheets in both versions, sheet by sheet, row by row. */\n cells: SheetCellChange[]\n /** The keys of the sheets only the newer version has. */\n addedSheets: string[]\n /** The keys of the sheets only the older version has. */\n removedSheets: string[]\n /** The keys of the sheets whose other settings (name, sizes, merges, rules, protection…) differ. */\n changedSheets: string[]\n /** The named styles (in `styles`) that differ, such as one now unlocking its cells. */\n changedStyles: string[]\n /** The named cell types (in `types`) that differ. */\n changedTypes: string[]\n /** Whether the workbook's own settings, such as `protect`, differ. */\n bookChanged: boolean\n}\n\n/**\n * A cell as versions compare it: without its thread, fields left\n * `undefined` dropped, and an empty value (`''` or `null`) taken for none,\n * so `{ value: 1 }` and `1` are the same cell.\n */\nconst bare = (cell: SheetCellInput): SheetCellInput => {\n const own = cellOf(cell)\n if (!own) return undefined\n const { comment: _comment, ...rest } = own\n if (rest.value === '' || rest.value === null) rest.value = undefined\n return compactCell(rest) ?? undefined\n}\n\n/** JSON with the keys of objects in order, so the order they were written in doesn't count. */\nconst stable = (value: unknown): string =>\n JSON.stringify(value ?? null, (_key, item: unknown) =>\n item && typeof item === 'object' && !Array.isArray(item)\n ? Object.fromEntries(\n Object.entries(item as Record<string, unknown>)\n .filter(([, v]) => v !== undefined)\n // oxlint-disable-next-line unicorn/no-array-sort -- sorts a fresh array\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)),\n )\n : item,\n )\n\nconst same = (a: unknown, b: unknown) => a === b || stable(a) === stable(b)\n\nconst sameCell = (a: SheetCellInput, b: SheetCellInput) => same(bare(a), bare(b))\n\n/** The fields of a sheet other than its cells and sizes. */\nfunction settingsOf(sheet: SheetData) {\n const { cells: _cells, rowSizes: _rows, colSizes: _cols, id: _id, ...rest } = sheet\n return { ...rest, rowCount: rowCountOf(sheet), colCount: colCountOf(sheet) }\n}\n\n/** The cells that differ between two sheets, as `[row, col]`. */\nfunction changedCells(before: SheetData, after: SheetData) {\n const out: [number, number][] = []\n const rows = Math.max(before.cells.length, after.cells.length)\n for (let row = 0; row < rows; row++) {\n const a = before.cells[row]\n const b = after.cells[row]\n if (a === b) continue\n const cols = Math.max(a?.length ?? 0, b?.length ?? 0)\n for (let col = 0; col < cols; col++) if (!sameCell(a?.[col], b?.[col])) out.push([row, col])\n }\n return out\n}\n\n/** The workbook's own settings, such as `protect`. */\nfunction bookSettings(book: SheetWorkbook) {\n const { sheets: _sheets, styles: _styles, types: _types, ...rest } = book\n return rest\n}\n\n/** The names whose entries differ between two records of named things. */\nfunction changedNames(a: Record<string, unknown> = {}, b: Record<string, unknown> = {}) {\n return [...new Set([...Object.keys(a), ...Object.keys(b)])].filter(\n (name) => !same(a[name], b[name]),\n )\n}\n\n/** What changed from `before` to `after`. */\nexport function diffWorkbooks(before: SheetWorkbook, after: SheetWorkbook): WorkbookDiff {\n const old = new Map(before.sheets.map((sheet) => [sheetKey(sheet), sheet]))\n const now = new Set(after.sheets.map(sheetKey))\n const diff: WorkbookDiff = {\n cells: [],\n addedSheets: [],\n removedSheets: [],\n changedSheets: [],\n changedStyles: [],\n changedTypes: [],\n bookChanged: !same(bookSettings(before), bookSettings(after)),\n }\n for (const sheet of after.sheets) {\n const key = sheetKey(sheet)\n const was = old.get(key)\n if (!was) {\n diff.addedSheets.push(key)\n continue\n }\n for (const [row, col] of changedCells(was, sheet))\n diff.cells.push({\n sheet: key,\n row,\n col,\n address: formatCell({ row, col }),\n before: was.cells[row]?.[col] ?? undefined,\n after: sheet.cells[row]?.[col] ?? undefined,\n })\n if (\n !same(settingsOf(was), settingsOf(sheet)) ||\n !same(was.rowSizes, sheet.rowSizes) ||\n !same(was.colSizes, sheet.colSizes)\n )\n diff.changedSheets.push(key)\n }\n for (const key of old.keys()) if (!now.has(key)) diff.removedSheets.push(key)\n diff.changedStyles = changedNames(before.styles, after.styles)\n diff.changedTypes = changedNames(before.types, after.types)\n return diff\n}\n\n/** A version's sheet without the threads it had then. */\nfunction withoutThreads(sheet: SheetData): SheetData {\n return {\n ...sheet,\n cells: sheet.cells.map((line) => line?.map((cell) => bare(cell)) ?? line),\n }\n}\n\n/**\n * Adds the steps that bring the workbook to `book`, writing only what\n * differs: cells, sizes and settings of the sheets in both (protection\n * too), sheets added and removed, their order, the workbook's settings,\n * and the named styles and types.\n */\nexport function restoreWorkbook(tr: SheetTransaction, book: SheetWorkbook) {\n const wanted = book.sheets.map(sheetKey)\n // sheets the version has and the workbook doesn't, where they go\n book.sheets.forEach((sheet, index) => {\n if (tr.indexOf(sheetKey(sheet)) === -1)\n tr.step({\n type: 'insertSheet',\n index: Math.min(index, tr.doc.sheets.length),\n data: withoutThreads(sheet),\n })\n })\n for (const sheet of tr.doc.sheets.slice())\n if (!wanted.includes(sheetKey(sheet))) tr.step({ type: 'removeSheet', sheet: sheetKey(sheet) })\n wanted.forEach((key, index) => {\n if (tr.indexOf(key) !== index) tr.step({ type: 'moveSheet', sheet: key, index })\n })\n\n for (const sheet of book.sheets) {\n const key = sheetKey(sheet)\n const now = tr.getSheet(key)\n // settings first: the size, so cells past the old one have room\n const was = settingsOf(now) as Record<string, unknown>\n const next = settingsOf(sheet) as Record<string, unknown>\n const patch: Record<string, unknown> = {}\n for (const name of new Set([...Object.keys(was), ...Object.keys(next)]))\n if (!same(was[name], next[name])) patch[name] = next[name]\n if (Object.keys(patch).length) tr.updateSheet(patch as SheetPatch, key)\n for (const axis of ['row', 'col'] as const) {\n const field = axis === 'row' ? 'rowSizes' : 'colSizes'\n const a = now[field] ?? {}\n const b = sheet[field] ?? {}\n for (const index of new Set([...Object.keys(a), ...Object.keys(b)]))\n if (a[Number(index)] !== b[Number(index)])\n tr.setSize(axis, Number(index), b[Number(index)], key)\n }\n for (const [row, col] of changedCells(tr.getSheet(key), sheet)) {\n const at = { sheet: key, row, col }\n // the thread on the cell stays\n const thread = cellOf(tr.getCell(at))?.comment\n tr.setCell(at, compactCell({ ...cellOf(bare(sheet.cells[row]?.[col])), comment: thread }))\n }\n }\n\n const was = bookSettings(tr.doc) as Record<string, unknown>\n const next = bookSettings(book) as Record<string, unknown>\n const patch: Record<string, unknown> = {}\n for (const name of changedNames(was, next)) patch[name] = next[name]\n if (Object.keys(patch).length) tr.updateBook(patch as SheetBookPatch)\n for (const name of changedNames(tr.doc.styles, book.styles))\n tr.setStyle(name, book.styles?.[name])\n for (const name of changedNames(tr.doc.types, book.types)) tr.setType(name, book.types?.[name])\n return tr\n}\n"],"mappings":"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"}