@rowsncolumns/spreadsheet-state 28.0.74 → 28.0.76

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 (253) hide show
  1. package/dist/cjs/api/anchored-objects.d.ts +66 -0
  2. package/dist/cjs/api/anchored-objects.d.ts.map +1 -0
  3. package/dist/cjs/api/anchored-objects.js +259 -0
  4. package/dist/cjs/api/datatype.d.ts.map +1 -1
  5. package/dist/cjs/api/datatype.js +8 -1
  6. package/dist/cjs/api/dependency.d.ts +13 -2
  7. package/dist/cjs/api/dependency.d.ts.map +1 -1
  8. package/dist/cjs/api/dependency.js +11 -5
  9. package/dist/cjs/api/fill-series-spec.d.ts +35 -0
  10. package/dist/cjs/api/fill-series-spec.d.ts.map +1 -0
  11. package/dist/cjs/api/fill-series-spec.js +164 -0
  12. package/dist/cjs/api/fill.d.ts +95 -3
  13. package/dist/cjs/api/fill.d.ts.map +1 -1
  14. package/dist/cjs/api/fill.js +1186 -418
  15. package/dist/cjs/api/formula.d.ts +61 -4
  16. package/dist/cjs/api/formula.d.ts.map +1 -1
  17. package/dist/cjs/api/formula.js +250 -61
  18. package/dist/cjs/api/immer-utils.d.ts.map +1 -1
  19. package/dist/cjs/api/immer-utils.js +20 -15
  20. package/dist/cjs/api/intl.d.ts.map +1 -1
  21. package/dist/cjs/api/merges.d.ts +8 -0
  22. package/dist/cjs/api/merges.d.ts.map +1 -1
  23. package/dist/cjs/api/merges.js +64 -1
  24. package/dist/cjs/api/named-range-structural.d.ts +62 -0
  25. package/dist/cjs/api/named-range-structural.d.ts.map +1 -0
  26. package/dist/cjs/api/named-range-structural.js +197 -0
  27. package/dist/cjs/api/paint-format.d.ts +15 -1
  28. package/dist/cjs/api/paint-format.d.ts.map +1 -1
  29. package/dist/cjs/api/paint-format.js +69 -10
  30. package/dist/cjs/api/range-rule-helpers.d.ts +45 -1
  31. package/dist/cjs/api/range-rule-helpers.d.ts.map +1 -1
  32. package/dist/cjs/api/range-rule-helpers.js +159 -6
  33. package/dist/cjs/api/structural-formula-update.d.ts.map +1 -1
  34. package/dist/cjs/api/structural-formula-update.js +24 -6
  35. package/dist/cjs/api/structural-guards.d.ts +78 -0
  36. package/dist/cjs/api/structural-guards.d.ts.map +1 -0
  37. package/dist/cjs/api/structural-guards.js +202 -0
  38. package/dist/cjs/api/structural-table-refs.d.ts +94 -0
  39. package/dist/cjs/api/structural-table-refs.d.ts.map +1 -0
  40. package/dist/cjs/api/structural-table-refs.js +313 -0
  41. package/dist/cjs/commands.d.ts +11 -1
  42. package/dist/cjs/commands.d.ts.map +1 -1
  43. package/dist/cjs/constants.d.ts +25 -0
  44. package/dist/cjs/constants.d.ts.map +1 -0
  45. package/dist/cjs/constants.js +26 -0
  46. package/dist/cjs/hooks/use-calculation-worker.d.ts.map +1 -1
  47. package/dist/cjs/hooks/use-calculation-worker.js +64 -6
  48. package/dist/cjs/hooks/use-calculation.d.ts +8 -1
  49. package/dist/cjs/hooks/use-calculation.d.ts.map +1 -1
  50. package/dist/cjs/hooks/use-calculation.js +15 -0
  51. package/dist/cjs/hooks/use-on-calculation-success.d.ts +7 -0
  52. package/dist/cjs/hooks/use-on-calculation-success.d.ts.map +1 -1
  53. package/dist/cjs/hooks/use-on-calculation-success.js +7 -1
  54. package/dist/cjs/hooks/use-on-delete-cells-shift-left.d.ts +13 -3
  55. package/dist/cjs/hooks/use-on-delete-cells-shift-left.d.ts.map +1 -1
  56. package/dist/cjs/hooks/use-on-delete-cells-shift-left.js +27 -2
  57. package/dist/cjs/hooks/use-on-delete-cells-shift-up.d.ts +13 -3
  58. package/dist/cjs/hooks/use-on-delete-cells-shift-up.d.ts.map +1 -1
  59. package/dist/cjs/hooks/use-on-delete-cells-shift-up.js +27 -2
  60. package/dist/cjs/hooks/use-on-delete-column.d.ts +13 -4
  61. package/dist/cjs/hooks/use-on-delete-column.d.ts.map +1 -1
  62. package/dist/cjs/hooks/use-on-delete-column.js +14 -2
  63. package/dist/cjs/hooks/use-on-delete-row.d.ts +13 -4
  64. package/dist/cjs/hooks/use-on-delete-row.d.ts.map +1 -1
  65. package/dist/cjs/hooks/use-on-delete-row.js +14 -2
  66. package/dist/cjs/hooks/use-on-fill.d.ts +13 -4
  67. package/dist/cjs/hooks/use-on-fill.d.ts.map +1 -1
  68. package/dist/cjs/hooks/use-on-fill.js +28 -7
  69. package/dist/cjs/hooks/use-on-insert-cells-shift-down.d.ts +13 -3
  70. package/dist/cjs/hooks/use-on-insert-cells-shift-down.d.ts.map +1 -1
  71. package/dist/cjs/hooks/use-on-insert-cells-shift-down.js +27 -2
  72. package/dist/cjs/hooks/use-on-insert-cells-shift-right.d.ts +13 -3
  73. package/dist/cjs/hooks/use-on-insert-cells-shift-right.d.ts.map +1 -1
  74. package/dist/cjs/hooks/use-on-insert-cells-shift-right.js +27 -2
  75. package/dist/cjs/hooks/use-on-insert-column.d.ts +10 -3
  76. package/dist/cjs/hooks/use-on-insert-column.d.ts.map +1 -1
  77. package/dist/cjs/hooks/use-on-insert-column.js +33 -7
  78. package/dist/cjs/hooks/use-on-insert-row.d.ts +10 -3
  79. package/dist/cjs/hooks/use-on-insert-row.d.ts.map +1 -1
  80. package/dist/cjs/hooks/use-on-insert-row.js +32 -7
  81. package/dist/cjs/hooks/use-paint-format.d.ts.map +1 -1
  82. package/dist/cjs/hooks/use-paint-format.js +10 -7
  83. package/dist/cjs/hooks/use-spreadsheet-state.d.ts +3 -3
  84. package/dist/cjs/hooks/use-spreadsheet-state.d.ts.map +1 -1
  85. package/dist/cjs/hooks/use-spreadsheet-state.js +73 -16
  86. package/dist/cjs/hooks/use-structured-reference.d.ts.map +1 -1
  87. package/dist/cjs/hooks/use-structured-reference.js +10 -6
  88. package/dist/cjs/index.d.ts +3 -0
  89. package/dist/cjs/index.d.ts.map +1 -1
  90. package/dist/cjs/index.js +3 -0
  91. package/dist/cjs/interface/apply-fill.d.ts +3 -3
  92. package/dist/cjs/interface/apply-fill.d.ts.map +1 -1
  93. package/dist/cjs/interface/apply-fill.js +100 -53
  94. package/dist/cjs/interface/calculation-interface.d.ts +9 -0
  95. package/dist/cjs/interface/calculation-interface.d.ts.map +1 -1
  96. package/dist/cjs/interface/calculation-interface.js +31 -2
  97. package/dist/cjs/interface/delete-cells-shift-left.d.ts +8 -1
  98. package/dist/cjs/interface/delete-cells-shift-left.d.ts.map +1 -1
  99. package/dist/cjs/interface/delete-cells-shift-left.js +158 -80
  100. package/dist/cjs/interface/delete-cells-shift-up.d.ts +9 -1
  101. package/dist/cjs/interface/delete-cells-shift-up.d.ts.map +1 -1
  102. package/dist/cjs/interface/delete-cells-shift-up.js +155 -73
  103. package/dist/cjs/interface/delete-column.d.ts +1 -1
  104. package/dist/cjs/interface/delete-column.d.ts.map +1 -1
  105. package/dist/cjs/interface/delete-column.js +90 -31
  106. package/dist/cjs/interface/delete-row.d.ts +1 -1
  107. package/dist/cjs/interface/delete-row.d.ts.map +1 -1
  108. package/dist/cjs/interface/delete-row.js +85 -26
  109. package/dist/cjs/interface/insert-cells-shift-down.d.ts +10 -1
  110. package/dist/cjs/interface/insert-cells-shift-down.d.ts.map +1 -1
  111. package/dist/cjs/interface/insert-cells-shift-down.js +147 -52
  112. package/dist/cjs/interface/insert-cells-shift-right.d.ts +10 -1
  113. package/dist/cjs/interface/insert-cells-shift-right.d.ts.map +1 -1
  114. package/dist/cjs/interface/insert-cells-shift-right.js +154 -58
  115. package/dist/cjs/interface/insert-column.d.ts +1 -1
  116. package/dist/cjs/interface/insert-column.d.ts.map +1 -1
  117. package/dist/cjs/interface/insert-column.js +46 -8
  118. package/dist/cjs/interface/insert-row.d.ts +1 -1
  119. package/dist/cjs/interface/insert-row.d.ts.map +1 -1
  120. package/dist/cjs/interface/insert-row.js +47 -10
  121. package/dist/cjs/interface/spreadsheet-interface.d.ts +1 -1
  122. package/dist/cjs/interface/spreadsheet-interface.d.ts.map +1 -1
  123. package/dist/cjs/interface/spreadsheet-interface.js +33 -0
  124. package/dist/cjs/sheet-cell.d.ts.map +1 -1
  125. package/dist/cjs/sheet-cell.js +30 -6
  126. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  127. package/dist/esm/api/anchored-objects.d.ts +66 -0
  128. package/dist/esm/api/anchored-objects.d.ts.map +1 -0
  129. package/dist/esm/api/anchored-objects.js +212 -0
  130. package/dist/esm/api/datatype.d.ts.map +1 -1
  131. package/dist/esm/api/datatype.js +8 -1
  132. package/dist/esm/api/dependency.d.ts +13 -2
  133. package/dist/esm/api/dependency.d.ts.map +1 -1
  134. package/dist/esm/api/dependency.js +10 -4
  135. package/dist/esm/api/fill-series-spec.d.ts +35 -0
  136. package/dist/esm/api/fill-series-spec.d.ts.map +1 -0
  137. package/dist/esm/api/fill-series-spec.js +160 -0
  138. package/dist/esm/api/fill.d.ts +95 -3
  139. package/dist/esm/api/fill.d.ts.map +1 -1
  140. package/dist/esm/api/fill.js +1158 -418
  141. package/dist/esm/api/formula.d.ts +61 -4
  142. package/dist/esm/api/formula.d.ts.map +1 -1
  143. package/dist/esm/api/formula.js +238 -60
  144. package/dist/esm/api/immer-utils.d.ts.map +1 -1
  145. package/dist/esm/api/immer-utils.js +20 -15
  146. package/dist/esm/api/intl.d.ts.map +1 -1
  147. package/dist/esm/api/merges.d.ts +8 -0
  148. package/dist/esm/api/merges.d.ts.map +1 -1
  149. package/dist/esm/api/merges.js +51 -0
  150. package/dist/esm/api/named-range-structural.d.ts +62 -0
  151. package/dist/esm/api/named-range-structural.d.ts.map +1 -0
  152. package/dist/esm/api/named-range-structural.js +176 -0
  153. package/dist/esm/api/paint-format.d.ts +15 -1
  154. package/dist/esm/api/paint-format.d.ts.map +1 -1
  155. package/dist/esm/api/paint-format.js +46 -1
  156. package/dist/esm/api/range-rule-helpers.d.ts +45 -1
  157. package/dist/esm/api/range-rule-helpers.d.ts.map +1 -1
  158. package/dist/esm/api/range-rule-helpers.js +153 -1
  159. package/dist/esm/api/structural-formula-update.d.ts.map +1 -1
  160. package/dist/esm/api/structural-formula-update.js +24 -6
  161. package/dist/esm/api/structural-guards.d.ts +78 -0
  162. package/dist/esm/api/structural-guards.d.ts.map +1 -0
  163. package/dist/esm/api/structural-guards.js +186 -0
  164. package/dist/esm/api/structural-table-refs.d.ts +94 -0
  165. package/dist/esm/api/structural-table-refs.d.ts.map +1 -0
  166. package/dist/esm/api/structural-table-refs.js +219 -0
  167. package/dist/esm/commands.d.ts +11 -1
  168. package/dist/esm/commands.d.ts.map +1 -1
  169. package/dist/esm/constants.d.ts +25 -0
  170. package/dist/esm/constants.d.ts.map +1 -0
  171. package/dist/esm/constants.js +26 -0
  172. package/dist/esm/hooks/use-calculation-worker.d.ts.map +1 -1
  173. package/dist/esm/hooks/use-calculation-worker.js +45 -0
  174. package/dist/esm/hooks/use-calculation.d.ts +8 -1
  175. package/dist/esm/hooks/use-calculation.d.ts.map +1 -1
  176. package/dist/esm/hooks/use-calculation.js +15 -0
  177. package/dist/esm/hooks/use-on-calculation-success.d.ts +7 -0
  178. package/dist/esm/hooks/use-on-calculation-success.d.ts.map +1 -1
  179. package/dist/esm/hooks/use-on-calculation-success.js +7 -1
  180. package/dist/esm/hooks/use-on-delete-cells-shift-left.d.ts +13 -3
  181. package/dist/esm/hooks/use-on-delete-cells-shift-left.d.ts.map +1 -1
  182. package/dist/esm/hooks/use-on-delete-cells-shift-left.js +26 -2
  183. package/dist/esm/hooks/use-on-delete-cells-shift-up.d.ts +13 -3
  184. package/dist/esm/hooks/use-on-delete-cells-shift-up.d.ts.map +1 -1
  185. package/dist/esm/hooks/use-on-delete-cells-shift-up.js +26 -2
  186. package/dist/esm/hooks/use-on-delete-column.d.ts +13 -4
  187. package/dist/esm/hooks/use-on-delete-column.d.ts.map +1 -1
  188. package/dist/esm/hooks/use-on-delete-column.js +14 -2
  189. package/dist/esm/hooks/use-on-delete-row.d.ts +13 -4
  190. package/dist/esm/hooks/use-on-delete-row.d.ts.map +1 -1
  191. package/dist/esm/hooks/use-on-delete-row.js +14 -2
  192. package/dist/esm/hooks/use-on-fill.d.ts +13 -4
  193. package/dist/esm/hooks/use-on-fill.d.ts.map +1 -1
  194. package/dist/esm/hooks/use-on-fill.js +24 -4
  195. package/dist/esm/hooks/use-on-insert-cells-shift-down.d.ts +13 -3
  196. package/dist/esm/hooks/use-on-insert-cells-shift-down.d.ts.map +1 -1
  197. package/dist/esm/hooks/use-on-insert-cells-shift-down.js +26 -2
  198. package/dist/esm/hooks/use-on-insert-cells-shift-right.d.ts +13 -3
  199. package/dist/esm/hooks/use-on-insert-cells-shift-right.d.ts.map +1 -1
  200. package/dist/esm/hooks/use-on-insert-cells-shift-right.js +26 -2
  201. package/dist/esm/hooks/use-on-insert-column.d.ts +10 -3
  202. package/dist/esm/hooks/use-on-insert-column.d.ts.map +1 -1
  203. package/dist/esm/hooks/use-on-insert-column.js +33 -7
  204. package/dist/esm/hooks/use-on-insert-row.d.ts +10 -3
  205. package/dist/esm/hooks/use-on-insert-row.d.ts.map +1 -1
  206. package/dist/esm/hooks/use-on-insert-row.js +32 -7
  207. package/dist/esm/hooks/use-paint-format.d.ts.map +1 -1
  208. package/dist/esm/hooks/use-paint-format.js +10 -7
  209. package/dist/esm/hooks/use-spreadsheet-state.d.ts +3 -3
  210. package/dist/esm/hooks/use-spreadsheet-state.d.ts.map +1 -1
  211. package/dist/esm/hooks/use-spreadsheet-state.js +73 -16
  212. package/dist/esm/hooks/use-structured-reference.d.ts.map +1 -1
  213. package/dist/esm/hooks/use-structured-reference.js +10 -6
  214. package/dist/esm/index.d.ts +3 -0
  215. package/dist/esm/index.d.ts.map +1 -1
  216. package/dist/esm/index.js +3 -0
  217. package/dist/esm/interface/apply-fill.d.ts +3 -3
  218. package/dist/esm/interface/apply-fill.d.ts.map +1 -1
  219. package/dist/esm/interface/apply-fill.js +93 -48
  220. package/dist/esm/interface/calculation-interface.d.ts +9 -0
  221. package/dist/esm/interface/calculation-interface.d.ts.map +1 -1
  222. package/dist/esm/interface/calculation-interface.js +33 -2
  223. package/dist/esm/interface/delete-cells-shift-left.d.ts +8 -1
  224. package/dist/esm/interface/delete-cells-shift-left.d.ts.map +1 -1
  225. package/dist/esm/interface/delete-cells-shift-left.js +135 -59
  226. package/dist/esm/interface/delete-cells-shift-up.d.ts +9 -1
  227. package/dist/esm/interface/delete-cells-shift-up.d.ts.map +1 -1
  228. package/dist/esm/interface/delete-cells-shift-up.js +133 -53
  229. package/dist/esm/interface/delete-column.d.ts +1 -1
  230. package/dist/esm/interface/delete-column.d.ts.map +1 -1
  231. package/dist/esm/interface/delete-column.js +80 -11
  232. package/dist/esm/interface/delete-row.d.ts +1 -1
  233. package/dist/esm/interface/delete-row.d.ts.map +1 -1
  234. package/dist/esm/interface/delete-row.js +81 -11
  235. package/dist/esm/interface/insert-cells-shift-down.d.ts +10 -1
  236. package/dist/esm/interface/insert-cells-shift-down.d.ts.map +1 -1
  237. package/dist/esm/interface/insert-cells-shift-down.js +116 -47
  238. package/dist/esm/interface/insert-cells-shift-right.d.ts +10 -1
  239. package/dist/esm/interface/insert-cells-shift-right.d.ts.map +1 -1
  240. package/dist/esm/interface/insert-cells-shift-right.js +120 -51
  241. package/dist/esm/interface/insert-column.d.ts +1 -1
  242. package/dist/esm/interface/insert-column.d.ts.map +1 -1
  243. package/dist/esm/interface/insert-column.js +46 -8
  244. package/dist/esm/interface/insert-row.d.ts +1 -1
  245. package/dist/esm/interface/insert-row.d.ts.map +1 -1
  246. package/dist/esm/interface/insert-row.js +47 -10
  247. package/dist/esm/interface/spreadsheet-interface.d.ts +1 -1
  248. package/dist/esm/interface/spreadsheet-interface.d.ts.map +1 -1
  249. package/dist/esm/interface/spreadsheet-interface.js +29 -0
  250. package/dist/esm/sheet-cell.d.ts.map +1 -1
  251. package/dist/esm/sheet-cell.js +30 -6
  252. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  253. package/package.json +17 -17
@@ -22,6 +22,23 @@ export declare const updateNamedRangeName: (formulaValue: string, newName: strin
22
22
  * @param newName
23
23
  */
24
24
  export declare const updateColumnName: (formulaValue: string, newName: string, oldName: string) => string;
25
+ /** The column specifier Excel writes for a deleted table column (`Table1[@#REF!]`). */
26
+ export declare const REF_ERROR_COLUMN = "#REF!";
27
+ /**
28
+ * Rewrite every structured reference into `tableName` to the `#REF!` token —
29
+ * Excel's text for a formula whose table was deleted (`=SUM(Table1[Price])`
30
+ * → `=SUM(#REF!)`), so the cell evaluates to `#REF!` rather than `#NAME?`.
31
+ * Returns the input unchanged when the formula never names the table.
32
+ */
33
+ export declare const breakTableReferencesInFormula: (formulaValue: string, tableName: string) => string;
34
+ /**
35
+ * Rewrite the column specifiers of `columnNames` inside structured references
36
+ * to `tableName` (or, when `tableName` is undefined, the bare this-row form
37
+ * `[@Col]` whose table is implied by the formula's own cell) to `#REF!` —
38
+ * Excel's text for a deleted table column (`=Table1[@Qty]*2` →
39
+ * `=Table1[@#REF!]*2`). Keeps every other character of the reference as typed.
40
+ */
41
+ export declare const breakTableColumnsInFormula: (formulaValue: string, tableName: string | undefined, columnNames: string[]) => string;
25
42
  /**
26
43
  * Converts tokens to string
27
44
  * @param tokens
@@ -46,24 +63,64 @@ export declare const isAbsoluteColumnReference: (formula: string | undefined) =>
46
63
  * @param formula
47
64
  */
48
65
  export declare const isAbsoluteRowReference: (formula: string | undefined) => boolean;
66
+ export type StructuralRangeRewriteOptions = {
67
+ /**
68
+ * Whether references WITHOUT a sheet qualifier resolve to the edited sheet.
69
+ * True for a formula that lives on the edited sheet; false for a formula on
70
+ * another sheet, whose bare `A1:A3` is its own sheet's range and must not
71
+ * move when the edited sheet changes shape.
72
+ */
73
+ includeUnqualifiedReferences?: boolean;
74
+ /**
75
+ * Restrict the rewrite to ranges whose PERPENDICULAR span lies inside this
76
+ * band — an insert/delete-cells shift of columns `B:C` only touches ranges
77
+ * that live entirely inside columns B..C (SHF-08); a wider range keeps its
78
+ * address (SHF-07). Whole-column and whole-row references span the entire
79
+ * sheet, so they never fall inside a band.
80
+ */
81
+ bandSpan?: RangeBandSpan;
82
+ };
83
+ /** Alias kept for callers that import the scope options under this name. */
84
+ export type StructuralFormulaScopeOptions = StructuralRangeRewriteOptions;
85
+ /**
86
+ * Restricts `expandRangesInFormula` / `contractRangesInFormula` to ranges whose PERPENDICULAR span
87
+ * lies within a band — an insert/delete-cells shift of columns `B:C` only expands ranges that live
88
+ * entirely inside columns B..C (SHF-08); a wider range keeps its address (SHF-07). Whole-column and
89
+ * whole-row references span the entire sheet, so they never fall inside a band.
90
+ */
91
+ export type RangeBandSpan = {
92
+ startIndex: number;
93
+ endIndex: number;
94
+ };
49
95
  /**
50
96
  * Expands ranges in a formula when rows or columns are inserted within the range
51
97
  * @param formula The formula to process
52
98
  * @param insertionIndex The row or column index where insertion happens
53
99
  * @param count Number of rows or columns being inserted
54
100
  * @param dimension Whether inserting 'row' or 'column'
55
- * @param activeSheetName Active sheet name to scope range updates
101
+ * @param activeSheetName Name of the EDITED sheet: only references that resolve
102
+ * to it are touched
103
+ * @param options `includeUnqualifiedReferences` — whether references without a
104
+ * sheet qualifier resolve to the edited sheet (true when the formula lives on
105
+ * it; false for a formula on another sheet, whose bare `A1:A3` is its own)
56
106
  * @returns The formula with expanded ranges, or undefined if no changes
57
107
  */
58
- export declare const expandRangesInFormula: (formula: string | undefined, insertionIndex: number, count: number, dimension: "row" | "column", activeSheetName: string) => string | undefined;
108
+ export declare const expandRangesInFormula: (formula: string | undefined, insertionIndex: number, count: number, dimension: "row" | "column", activeSheetName: string, options?: StructuralRangeRewriteOptions) => string | undefined;
59
109
  /**
60
110
  * Contracts ranges in a formula when rows or columns are deleted within the range
61
111
  * @param formula The formula to process
62
112
  * @param deletionIndex The row or column index where deletion starts
63
113
  * @param count Number of rows or columns being deleted
64
114
  * @param dimension Whether deleting 'row' or 'column'
65
- * @param activeSheetName Active sheet name to scope range updates
115
+ * @param activeSheetName Name of the EDITED sheet: only references that resolve
116
+ * to it are touched
117
+ * @param options `includeUnqualifiedReferences` — see `expandRangesInFormula`
66
118
  * @returns The formula with contracted ranges, or undefined if no changes
119
+ *
120
+ * Excel semantics for the deleted band: a range whose rows/columns are ALL
121
+ * deleted becomes the `#REF!` token (`=SUM(A2:A3)` → `=SUM(#REF!)`); a single
122
+ * cell reference into the band becomes `#REF!` (`=A3+1` → `=#REF!+1`, a spill
123
+ * reference `=C1#` → `=#REF!#`); a partially covered range shrinks.
67
124
  */
68
- export declare const contractRangesInFormula: (formula: string | undefined, deletionIndex: number, count: number, dimension: "row" | "column", activeSheetName: string) => string | undefined;
125
+ export declare const contractRangesInFormula: (formula: string | undefined, deletionIndex: number, count: number, dimension: "row" | "column", activeSheetName: string, options?: StructuralRangeRewriteOptions) => string | undefined;
69
126
  //# sourceMappingURL=formula.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"formula.d.ts","sourceRoot":"","sources":["../../../api/formula.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAS,MAAM,2BAA2B,CAAC;AAUpE,OAAO,EACL,yBAAyB,EACzB,eAAe,EACf,0BAA0B,GAC3B,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,iCAAiC,EAAE,MAAM,0BAA0B,CAAC;AAElF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAC1B,cAAc,MAAM,EACpB,SAAS,MAAM,EACf,SAAS,MAAM,WA4BhB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,cAAc,MAAM,EACpB,SAAS,MAAM,EACf,SAAS,MAAM,WAehB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAC3B,cAAc,MAAM,EACpB,SAAS,MAAM,EACf,SAAS,MAAM,WAYhB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,UAAU,GAAI,QAAQ,WAAW,EAAE,WAU/C,CAAC;AAiBF;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,GACpC,SAAS,MAAM,EACf,UAAU,MAAM,EAChB,aAAa,MAAM,WAGpB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GAAI,SAAS,MAAM,GAAG,SAAS,YAGpE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,SAAS,MAAM,GAAG,SAAS,YAGjE,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAChC,SAAS,MAAM,GAAG,SAAS,EAC3B,gBAAgB,MAAM,EACtB,OAAO,MAAM,EACb,WAAW,KAAK,GAAG,QAAQ,EAC3B,iBAAiB,MAAM,KACtB,MAAM,GAAG,SAmKX,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,GAClC,SAAS,MAAM,GAAG,SAAS,EAC3B,eAAe,MAAM,EACrB,OAAO,MAAM,EACb,WAAW,KAAK,GAAG,QAAQ,EAC3B,iBAAiB,MAAM,KACtB,MAAM,GAAG,SA6NX,CAAC"}
1
+ {"version":3,"file":"formula.d.ts","sourceRoot":"","sources":["../../../api/formula.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAS,MAAM,2BAA2B,CAAC;AAUpE,OAAO,EACL,yBAAyB,EACzB,eAAe,EACf,0BAA0B,GAC3B,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,iCAAiC,EAAE,MAAM,0BAA0B,CAAC;AAElF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAC1B,cAAc,MAAM,EACpB,SAAS,MAAM,EACf,SAAS,MAAM,WA4BhB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,cAAc,MAAM,EACpB,SAAS,MAAM,EACf,SAAS,MAAM,WAehB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAC3B,cAAc,MAAM,EACpB,SAAS,MAAM,EACf,SAAS,MAAM,WAYhB,CAAC;AAEF,uFAAuF;AACvF,eAAO,MAAM,gBAAgB,UAAU,CAAC;AAgDxC;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,GACxC,cAAc,MAAM,EACpB,WAAW,MAAM,KAChB,MA4BF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,GACrC,cAAc,MAAM,EACpB,WAAW,MAAM,GAAG,SAAS,EAC7B,aAAa,MAAM,EAAE,KACpB,MA+BF,CAAC;AAaF;;;GAGG;AACH,eAAO,MAAM,UAAU,GAAI,QAAQ,WAAW,EAAE,WAU/C,CAAC;AAiBF;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,GACpC,SAAS,MAAM,EACf,UAAU,MAAM,EAChB,aAAa,MAAM,WAGpB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,GAAI,SAAS,MAAM,GAAG,SAAS,YAGpE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,SAAS,MAAM,GAAG,SAAS,YAGjE,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C;;;;;OAKG;IACH,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,6BAA6B,GAAG,6BAA6B,CAAC;AAE1E;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAmBrE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,GAChC,SAAS,MAAM,GAAG,SAAS,EAC3B,gBAAgB,MAAM,EACtB,OAAO,MAAM,EACb,WAAW,KAAK,GAAG,QAAQ,EAC3B,iBAAiB,MAAM,EACvB,UAAS,6BAAkC,KAC1C,MAAM,GAAG,SAyKX,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,uBAAuB,GAClC,SAAS,MAAM,GAAG,SAAS,EAC3B,eAAe,MAAM,EACrB,OAAO,MAAM,EACb,WAAW,KAAK,GAAG,QAAQ,EAC3B,iBAAiB,MAAM,EACvB,UAAS,6BAAkC,KAC1C,MAAM,GAAG,SAkPX,CAAC"}
@@ -1,4 +1,4 @@
1
- import { isRangeToken, lexify, stripPropertyFromCellRef, tokenVocabulary, } from "@rowsncolumns/calculator";
1
+ import { cleanupColumnName, cleanupTableName, isRangeToken, lexify, stripPropertyFromCellRef, tokenVocabulary, } from "@rowsncolumns/calculator";
2
2
  import { addressToCell, alpha2number, cellToAddress, desanitizeSheetName, number2Alpha, sanitizeSheetName, } from "@rowsncolumns/utils";
3
3
  export { ERROR_CIRCULAR_DEPENDENCY, ERROR_REFERENCE, formulaToRelativeReference, } from "@rowsncolumns/calculator";
4
4
  /**
@@ -65,6 +65,138 @@ export const updateColumnName = (formulaValue, newName, oldName) => {
65
65
  }
66
66
  return detokenize(newTokens);
67
67
  };
68
+ /** The column specifier Excel writes for a deleted table column (`Table1[@#REF!]`). */
69
+ export const REF_ERROR_COLUMN = "#REF!";
70
+ const REF_ERROR_TOKEN = "#REF!";
71
+ /**
72
+ * One `#REF!` token standing in for the run `start … end` (a range's start,
73
+ * colon and end): it keeps `start`'s position and stretches to `end` so
74
+ * `detokenize` (which re-inserts a space wherever adjacent tokens' offsets
75
+ * disagree) prints `SUM(#REF!)`, not `SUM(#REF! )`.
76
+ */
77
+ const collapseToRefError = (start, end) => ({
78
+ ...start,
79
+ image: REF_ERROR_TOKEN,
80
+ tokenType: tokenVocabulary.RefError,
81
+ endOffset: end?.endOffset ?? start.endOffset,
82
+ endColumn: end?.endColumn ?? start.endColumn,
83
+ });
84
+ const isTableNameToken = (token) => token?.tokenType.name === tokenVocabulary.TableName.name;
85
+ const isTableColumnToken = (token) => token?.tokenType.name === tokenVocabulary.TableColumnName.name;
86
+ /** Bracket depth change contributed by one token's image (`Table1[` opens, `Qty]` closes). */
87
+ const bracketDelta = (image) => {
88
+ let depth = 0;
89
+ for (const ch of image) {
90
+ if (ch === "[")
91
+ depth++;
92
+ else if (ch === "]")
93
+ depth--;
94
+ }
95
+ return depth;
96
+ };
97
+ /**
98
+ * Index just past the last token of the structured reference that starts at
99
+ * `start` (a TableName token): consume tokens until the bracket the table name
100
+ * opened is closed again.
101
+ */
102
+ const structuredReferenceEnd = (tokens, start) => {
103
+ let depth = 0;
104
+ let i = start;
105
+ while (i < tokens.length) {
106
+ depth += bracketDelta(tokens[i].image);
107
+ i++;
108
+ if (depth <= 0)
109
+ break;
110
+ }
111
+ return i;
112
+ };
113
+ /**
114
+ * Rewrite every structured reference into `tableName` to the `#REF!` token —
115
+ * Excel's text for a formula whose table was deleted (`=SUM(Table1[Price])`
116
+ * → `=SUM(#REF!)`), so the cell evaluates to `#REF!` rather than `#NAME?`.
117
+ * Returns the input unchanged when the formula never names the table.
118
+ */
119
+ export const breakTableReferencesInFormula = (formulaValue, tableName) => {
120
+ if (!formulaValue.includes("["))
121
+ return formulaValue;
122
+ const tokens = cloneTokens(lexify(formulaValue).tokens);
123
+ const newTokens = [];
124
+ const target = tableName.toLowerCase();
125
+ let hasChanges = false;
126
+ for (let i = 0; i < tokens.length; i++) {
127
+ const token = tokens[i];
128
+ if (isTableNameToken(token) &&
129
+ cleanupTableName(token.image).trim().toLowerCase() === target) {
130
+ const end = structuredReferenceEnd(tokens, i);
131
+ const last = tokens[end - 1] ?? token;
132
+ newTokens.push({
133
+ ...token,
134
+ image: REF_ERROR_TOKEN,
135
+ endOffset: last.endOffset,
136
+ endColumn: last.endColumn,
137
+ tokenType: tokenVocabulary.RefError,
138
+ });
139
+ i = end - 1;
140
+ hasChanges = true;
141
+ continue;
142
+ }
143
+ newTokens.push(token);
144
+ }
145
+ return hasChanges ? detokenize(newTokens) : formulaValue;
146
+ };
147
+ /**
148
+ * Rewrite the column specifiers of `columnNames` inside structured references
149
+ * to `tableName` (or, when `tableName` is undefined, the bare this-row form
150
+ * `[@Col]` whose table is implied by the formula's own cell) to `#REF!` —
151
+ * Excel's text for a deleted table column (`=Table1[@Qty]*2` →
152
+ * `=Table1[@#REF!]*2`). Keeps every other character of the reference as typed.
153
+ */
154
+ export const breakTableColumnsInFormula = (formulaValue, tableName, columnNames) => {
155
+ if (!formulaValue.includes("[") || columnNames.length === 0) {
156
+ return formulaValue;
157
+ }
158
+ const targets = new Set(columnNames.map((name) => name.toLowerCase()));
159
+ const target = tableName?.toLowerCase();
160
+ const tokens = cloneTokens(lexify(formulaValue).tokens);
161
+ let hasChanges = false;
162
+ let i = 0;
163
+ while (i < tokens.length) {
164
+ const token = tokens[i];
165
+ if (isTableNameToken(token)) {
166
+ const end = structuredReferenceEnd(tokens, i);
167
+ const matches = target !== undefined &&
168
+ cleanupTableName(token.image).trim().toLowerCase() === target;
169
+ if (matches) {
170
+ for (let j = i + 1; j < end; j++) {
171
+ if (breakColumnToken(tokens[j], targets))
172
+ hasChanges = true;
173
+ }
174
+ }
175
+ i = end;
176
+ continue;
177
+ }
178
+ // A bare `[@Col]` / `[Col]` names the table the formula cell sits in.
179
+ if (target === undefined && isTableColumnToken(token)) {
180
+ if (breakColumnToken(token, targets))
181
+ hasChanges = true;
182
+ }
183
+ i++;
184
+ }
185
+ return hasChanges ? detokenize(tokens) : formulaValue;
186
+ };
187
+ const breakColumnToken = (token, targets) => {
188
+ if (!token || !isTableColumnToken(token))
189
+ return false;
190
+ const name = cleanupColumnName(token.image);
191
+ if (!name || !targets.has(name.toLowerCase()))
192
+ return false;
193
+ const at = token.image.indexOf(name);
194
+ if (at === -1)
195
+ return false;
196
+ token.image =
197
+ token.image.slice(0, at) + REF_ERROR_COLUMN + token.image.slice(at + name.length);
198
+ return true;
199
+ };
68
200
  /**
69
201
  * Converts tokens to string
70
202
  * @param tokens
@@ -122,19 +254,33 @@ export const isAbsoluteRowReference = (formula) => {
122
254
  return false;
123
255
  return /\$\d+/gi.test(formula);
124
256
  };
257
+ const isRangeWithinBandSpan = (startCell, endCell, dimension, bandSpan) => {
258
+ if (!bandSpan)
259
+ return true;
260
+ const [start, end] = dimension === "row"
261
+ ? [startCell.columnIndex, endCell.columnIndex]
262
+ : [startCell.rowIndex, endCell.rowIndex];
263
+ return (Math.min(start, end) >= bandSpan.startIndex &&
264
+ Math.max(start, end) <= bandSpan.endIndex);
265
+ };
125
266
  /**
126
267
  * Expands ranges in a formula when rows or columns are inserted within the range
127
268
  * @param formula The formula to process
128
269
  * @param insertionIndex The row or column index where insertion happens
129
270
  * @param count Number of rows or columns being inserted
130
271
  * @param dimension Whether inserting 'row' or 'column'
131
- * @param activeSheetName Active sheet name to scope range updates
272
+ * @param activeSheetName Name of the EDITED sheet: only references that resolve
273
+ * to it are touched
274
+ * @param options `includeUnqualifiedReferences` — whether references without a
275
+ * sheet qualifier resolve to the edited sheet (true when the formula lives on
276
+ * it; false for a formula on another sheet, whose bare `A1:A3` is its own)
132
277
  * @returns The formula with expanded ranges, or undefined if no changes
133
278
  */
134
- export const expandRangesInFormula = (formula, insertionIndex, count, dimension, activeSheetName) => {
279
+ export const expandRangesInFormula = (formula, insertionIndex, count, dimension, activeSheetName, options = {}) => {
135
280
  if (!formula || count <= 0) {
136
281
  return formula;
137
282
  }
283
+ const { includeUnqualifiedReferences = true, bandSpan } = options;
138
284
  const normalizedActiveSheetName = activeSheetName.toLowerCase();
139
285
  const tokens = cloneTokens(lexify(formula).tokens);
140
286
  const newTokens = [];
@@ -142,7 +288,9 @@ export const expandRangesInFormula = (formula, insertionIndex, count, dimension,
142
288
  for (let i = 0; i < tokens.length; i++) {
143
289
  const token = tokens[i];
144
290
  const sheetName = getSheetNameFromToken(tokens[i - 1]);
145
- const skipSheet = sheetName && sheetName.toLowerCase() !== normalizedActiveSheetName;
291
+ const skipSheet = sheetName
292
+ ? sheetName.toLowerCase() !== normalizedActiveSheetName
293
+ : !includeUnqualifiedReferences;
146
294
  // Handle cell ranges (e.g., A1:A10)
147
295
  if (token.tokenType.name === tokenVocabulary.Cell.name) {
148
296
  const isRange = isRangeToken(tokens[i + 1]);
@@ -157,7 +305,9 @@ export const expandRangesInFormula = (formula, insertionIndex, count, dimension,
157
305
  if (isRange && tokens[i + 2]) {
158
306
  const startCell = addressToCell(stripPropertyFromCellRef(token.image));
159
307
  const endCell = addressToCell(stripPropertyFromCellRef(tokens[i + 2].image));
160
- if (startCell && endCell) {
308
+ if (startCell &&
309
+ endCell &&
310
+ isRangeWithinBandSpan(startCell, endCell, dimension, bandSpan)) {
161
311
  const isAbsoluteEndRow = isAbsoluteRowReference(tokens[i + 2].image);
162
312
  const isAbsoluteEndCol = isAbsoluteColumnReference(tokens[i + 2].image);
163
313
  if (dimension === "row") {
@@ -197,7 +347,7 @@ export const expandRangesInFormula = (formula, insertionIndex, count, dimension,
197
347
  if (dimension === "column" &&
198
348
  token.tokenType.name === tokenVocabulary.Column.name) {
199
349
  const isRange = isRangeToken(tokens[i + 1]);
200
- if (skipSheet) {
350
+ if (skipSheet || bandSpan) {
201
351
  if (isRange) {
202
352
  newTokens.push(token, tokens[i + 1], tokens[i + 2]);
203
353
  i += 2;
@@ -224,7 +374,7 @@ export const expandRangesInFormula = (formula, insertionIndex, count, dimension,
224
374
  if (dimension === "row" &&
225
375
  token.tokenType.name === tokenVocabulary.Number.name) {
226
376
  const isRange = isRangeToken(tokens[i + 1]);
227
- if (skipSheet) {
377
+ if (skipSheet || bandSpan) {
228
378
  if (isRange) {
229
379
  newTokens.push(token, tokens[i + 1], tokens[i + 2]);
230
380
  i += 2;
@@ -257,22 +407,45 @@ export const expandRangesInFormula = (formula, insertionIndex, count, dimension,
257
407
  * @param deletionIndex The row or column index where deletion starts
258
408
  * @param count Number of rows or columns being deleted
259
409
  * @param dimension Whether deleting 'row' or 'column'
260
- * @param activeSheetName Active sheet name to scope range updates
410
+ * @param activeSheetName Name of the EDITED sheet: only references that resolve
411
+ * to it are touched
412
+ * @param options `includeUnqualifiedReferences` — see `expandRangesInFormula`
261
413
  * @returns The formula with contracted ranges, or undefined if no changes
414
+ *
415
+ * Excel semantics for the deleted band: a range whose rows/columns are ALL
416
+ * deleted becomes the `#REF!` token (`=SUM(A2:A3)` → `=SUM(#REF!)`); a single
417
+ * cell reference into the band becomes `#REF!` (`=A3+1` → `=#REF!+1`, a spill
418
+ * reference `=C1#` → `=#REF!#`); a partially covered range shrinks.
262
419
  */
263
- export const contractRangesInFormula = (formula, deletionIndex, count, dimension, activeSheetName) => {
420
+ export const contractRangesInFormula = (formula, deletionIndex, count, dimension, activeSheetName, options = {}) => {
264
421
  if (!formula || count <= 0) {
265
422
  return formula;
266
423
  }
424
+ const { includeUnqualifiedReferences = true, bandSpan } = options;
267
425
  const normalizedActiveSheetName = activeSheetName.toLowerCase();
268
426
  const tokens = cloneTokens(lexify(formula).tokens);
269
427
  const newTokens = [];
270
428
  let hasChanges = false;
271
429
  const deletionEnd = deletionIndex + count - 1;
430
+ const inDeletedBand = (cell) => {
431
+ const index = dimension === "row" ? cell.rowIndex : cell.columnIndex;
432
+ return index >= deletionIndex && index <= deletionEnd;
433
+ };
434
+ const overlapsBand = (start, end) => deletionIndex <= end && deletionEnd >= start;
435
+ // The survivors of a span that overlaps (but is not swallowed by) the band:
436
+ // whatever lay before the band keeps its start, whatever lay inside starts at
437
+ // the deletion point; an end past the band moves up by the full count, an
438
+ // end inside the band stops just before it.
439
+ const contractSpan = (start, end) => ({
440
+ start: Math.min(start, deletionIndex),
441
+ end: end > deletionEnd ? end - count : deletionIndex - 1,
442
+ });
272
443
  for (let i = 0; i < tokens.length; i++) {
273
444
  const token = tokens[i];
274
445
  const sheetName = getSheetNameFromToken(tokens[i - 1]);
275
- const skipSheet = sheetName && sheetName.toLowerCase() !== normalizedActiveSheetName;
446
+ const skipSheet = sheetName
447
+ ? sheetName.toLowerCase() !== normalizedActiveSheetName
448
+ : !includeUnqualifiedReferences;
276
449
  // Handle cell ranges (e.g., A1:A10)
277
450
  if (token.tokenType.name === tokenVocabulary.Cell.name) {
278
451
  const isRange = isRangeToken(tokens[i + 1]);
@@ -284,10 +457,33 @@ export const contractRangesInFormula = (formula, deletionIndex, count, dimension
284
457
  }
285
458
  continue;
286
459
  }
460
+ if (!isRange) {
461
+ // Single cell: broken when it sits in the deleted band. The trailing
462
+ // spilled-range operator (`C1#`) stays on the token (`#REF!#`).
463
+ const spill = token.image.endsWith("#") ? "#" : "";
464
+ const cell = addressToCell(stripPropertyFromCellRef(spill ? token.image.slice(0, -1) : token.image));
465
+ if (cell &&
466
+ inDeletedBand(cell) &&
467
+ isRangeWithinBandSpan(cell, cell, dimension, bandSpan)) {
468
+ token.image = `${REF_ERROR_TOKEN}${spill}`;
469
+ hasChanges = true;
470
+ }
471
+ newTokens.push(token);
472
+ continue;
473
+ }
287
474
  if (isRange && tokens[i + 2]) {
288
475
  const startCell = addressToCell(stripPropertyFromCellRef(token.image));
289
476
  const endCell = addressToCell(stripPropertyFromCellRef(tokens[i + 2].image));
290
- if (startCell && endCell) {
477
+ if (startCell &&
478
+ endCell &&
479
+ isRangeWithinBandSpan(startCell, endCell, dimension, bandSpan)) {
480
+ // Every row/column of the range deleted → the whole range is #REF!.
481
+ if (inDeletedBand(startCell) && inDeletedBand(endCell)) {
482
+ newTokens.push(collapseToRefError(token, tokens[i + 2]));
483
+ i += 2;
484
+ hasChanges = true;
485
+ continue;
486
+ }
291
487
  const isAbsoluteStartRow = isAbsoluteRowReference(token.image);
292
488
  const isAbsoluteEndRow = isAbsoluteRowReference(tokens[i + 2].image);
293
489
  const isAbsoluteStartCol = isAbsoluteColumnReference(token.image);
@@ -295,18 +491,10 @@ export const contractRangesInFormula = (formula, deletionIndex, count, dimension
295
491
  if (dimension === "row") {
296
492
  const rangeStart = startCell.rowIndex;
297
493
  const rangeEnd = endCell.rowIndex;
298
- // Check if deletion overlaps with range
299
- if (deletionIndex <= rangeEnd && deletionEnd >= rangeStart) {
300
- // Calculate how many deleted rows are within the range
301
- const overlapStart = Math.max(deletionIndex, rangeStart);
302
- const overlapEnd = Math.min(deletionEnd, rangeEnd);
303
- const rowsDeletedInRange = overlapEnd - overlapStart + 1;
304
- // Contract the end of the range
305
- endCell.rowIndex -= rowsDeletedInRange;
306
- // If entire range is deleted, result in #REF! (but we'll just contract to minimum)
307
- if (endCell.rowIndex < startCell.rowIndex) {
308
- endCell.rowIndex = startCell.rowIndex;
309
- }
494
+ if (overlapsBand(rangeStart, rangeEnd)) {
495
+ const survivors = contractSpan(rangeStart, rangeEnd);
496
+ startCell.rowIndex = survivors.start;
497
+ endCell.rowIndex = survivors.end;
310
498
  const newStartAddress = cellToAddress(startCell, isAbsoluteStartCol, isAbsoluteStartRow);
311
499
  const newEndAddress = cellToAddress(endCell, isAbsoluteEndCol, isAbsoluteEndRow);
312
500
  if (newStartAddress && newEndAddress) {
@@ -320,18 +508,10 @@ export const contractRangesInFormula = (formula, deletionIndex, count, dimension
320
508
  // dimension === 'column'
321
509
  const rangeStart = startCell.columnIndex;
322
510
  const rangeEnd = endCell.columnIndex;
323
- // Check if deletion overlaps with range
324
- if (deletionIndex <= rangeEnd && deletionEnd >= rangeStart) {
325
- // Calculate how many deleted columns are within the range
326
- const overlapStart = Math.max(deletionIndex, rangeStart);
327
- const overlapEnd = Math.min(deletionEnd, rangeEnd);
328
- const colsDeletedInRange = overlapEnd - overlapStart + 1;
329
- // Contract the end of the range
330
- endCell.columnIndex -= colsDeletedInRange;
331
- // If entire range is deleted, result in #REF! (but we'll just contract to minimum)
332
- if (endCell.columnIndex < startCell.columnIndex) {
333
- endCell.columnIndex = startCell.columnIndex;
334
- }
511
+ if (overlapsBand(rangeStart, rangeEnd)) {
512
+ const survivors = contractSpan(rangeStart, rangeEnd);
513
+ startCell.columnIndex = survivors.start;
514
+ endCell.columnIndex = survivors.end;
335
515
  const newStartAddress = cellToAddress(startCell, isAbsoluteStartCol, isAbsoluteStartRow);
336
516
  const newEndAddress = cellToAddress(endCell, isAbsoluteEndCol, isAbsoluteEndRow);
337
517
  if (newStartAddress && newEndAddress) {
@@ -351,7 +531,7 @@ export const contractRangesInFormula = (formula, deletionIndex, count, dimension
351
531
  if (dimension === "column" &&
352
532
  token.tokenType.name === tokenVocabulary.Column.name) {
353
533
  const isRange = isRangeToken(tokens[i + 1]);
354
- if (skipSheet) {
534
+ if (skipSheet || bandSpan) {
355
535
  if (isRange) {
356
536
  newTokens.push(token, tokens[i + 1], tokens[i + 2]);
357
537
  i += 2;
@@ -361,20 +541,19 @@ export const contractRangesInFormula = (formula, deletionIndex, count, dimension
361
541
  if (isRange && tokens[i + 2]) {
362
542
  const startColumnIndex = alpha2number(token.image);
363
543
  const endColumnIndex = alpha2number(tokens[i + 2].image);
364
- // Check if deletion overlaps with range
365
- if (deletionIndex <= endColumnIndex &&
366
- deletionEnd >= startColumnIndex) {
367
- // Calculate how many deleted columns are within the range
368
- const overlapStart = Math.max(deletionIndex, startColumnIndex);
369
- const overlapEnd = Math.min(deletionEnd, endColumnIndex);
370
- const colsDeletedInRange = overlapEnd - overlapStart + 1;
371
- // Contract the end column
372
- const newEndColumnIndex = endColumnIndex - colsDeletedInRange;
373
- // If entire range is deleted, keep at minimum
374
- if (newEndColumnIndex >= startColumnIndex) {
375
- tokens[i + 2].image = number2Alpha(newEndColumnIndex - 1);
544
+ if (overlapsBand(startColumnIndex, endColumnIndex)) {
545
+ // Every column deleted → #REF!; otherwise the survivors close up.
546
+ if (startColumnIndex >= deletionIndex &&
547
+ endColumnIndex <= deletionEnd) {
548
+ newTokens.push(collapseToRefError(token, tokens[i + 2]));
549
+ i += 2;
376
550
  hasChanges = true;
551
+ continue;
377
552
  }
553
+ const survivors = contractSpan(startColumnIndex, endColumnIndex);
554
+ token.image = number2Alpha(survivors.start - 1);
555
+ tokens[i + 2].image = number2Alpha(survivors.end - 1);
556
+ hasChanges = true;
378
557
  }
379
558
  newTokens.push(token, tokens[i + 1], tokens[i + 2]);
380
559
  i += 2;
@@ -385,7 +564,7 @@ export const contractRangesInFormula = (formula, deletionIndex, count, dimension
385
564
  if (dimension === "row" &&
386
565
  token.tokenType.name === tokenVocabulary.Number.name) {
387
566
  const isRange = isRangeToken(tokens[i + 1]);
388
- if (skipSheet) {
567
+ if (skipSheet || bandSpan) {
389
568
  if (isRange) {
390
569
  newTokens.push(token, tokens[i + 1], tokens[i + 2]);
391
570
  i += 2;
@@ -397,19 +576,18 @@ export const contractRangesInFormula = (formula, deletionIndex, count, dimension
397
576
  tokens[i + 2].tokenType.name === tokenVocabulary.Number.name) {
398
577
  const startRowIndex = Number(token.image);
399
578
  const endRowIndex = Number(tokens[i + 2].image);
400
- // Check if deletion overlaps with range
401
- if (deletionIndex <= endRowIndex && deletionEnd >= startRowIndex) {
402
- // Calculate how many deleted rows are within the range
403
- const overlapStart = Math.max(deletionIndex, startRowIndex);
404
- const overlapEnd = Math.min(deletionEnd, endRowIndex);
405
- const rowsDeletedInRange = overlapEnd - overlapStart + 1;
406
- // Contract the end row
407
- const newEndRowIndex = endRowIndex - rowsDeletedInRange;
408
- // If entire range is deleted, keep at minimum
409
- if (newEndRowIndex >= startRowIndex) {
410
- tokens[i + 2].image = String(newEndRowIndex);
579
+ if (overlapsBand(startRowIndex, endRowIndex)) {
580
+ // Every row deleted → #REF!; otherwise the survivors close up.
581
+ if (startRowIndex >= deletionIndex && endRowIndex <= deletionEnd) {
582
+ newTokens.push(collapseToRefError(token, tokens[i + 2]));
583
+ i += 2;
411
584
  hasChanges = true;
585
+ continue;
412
586
  }
587
+ const survivors = contractSpan(startRowIndex, endRowIndex);
588
+ token.image = String(survivors.start);
589
+ tokens[i + 2].image = String(survivors.end);
590
+ hasChanges = true;
413
591
  }
414
592
  newTokens.push(token, tokens[i + 1], tokens[i + 2]);
415
593
  i += 2;
@@ -1 +1 @@
1
- {"version":3,"file":"immer-utils.d.ts","sourceRoot":"","sources":["../../../api/immer-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"immer-utils.d.ts","sourceRoot":"","sources":["../../../api/immer-utils.ts"],"names":[],"mappings":"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"}
@@ -47,8 +47,7 @@ const isGenericNumberFormatType = (type) => !type || type === "NUMBER" || type =
47
47
  * Date-family types — when the derived (resolved) type is one of these
48
48
  * and the precedent's type is also in this set, we preserve the
49
49
  * precedent's exact custom pattern instead of synthesizing a locale
50
- * default. Mirrors Excel's behaviour for date-arithmetic functions
51
- * (EDATE, EOMONTH, …) where `=EDATE(A1, 1)` keeps A1's custom pattern.
50
+ * default (`=DATE(YEAR(A1), MONTH(A1), 1)` keeps A1's custom pattern).
52
51
  */
53
52
  const isDateFamilyType = (type) => type === "DATE" || type === "TIME" || type === "DATE_TIME";
54
53
  const customNumberFormatMap = {
@@ -161,18 +160,21 @@ const functionReturnTypes = {
161
160
  NETWORKDAYS: "NUMBER",
162
161
  "NETWORKDAYS.INTL": "NUMBER",
163
162
  DAYS360: "NUMBER",
163
+ // The date-arithmetic functions return date serials, but Excel does
164
+ // NOT auto-format them: `=EDATE(DATE(2026,1,31),1)` shows 46081 in a
165
+ // General cell until the user formats it (rowsncolumns/spreadsheet#642
166
+ // B-09). NUMBER — like DATEVALUE — rather than absent, so a nested
167
+ // DATE()/TODAY() argument cannot promote the result to a date (the
168
+ // outermost function decides, as in `=YEAR(TODAY())`).
169
+ EDATE: "NUMBER",
170
+ EOMONTH: "NUMBER",
171
+ WORKDAY: "NUMBER",
172
+ "WORKDAY.INTL": "NUMBER",
164
173
  // ─── Date/time — date producers (must render as DATE/TIME/DATE_TIME) ─
165
174
  NOW: "DATE_TIME",
166
175
  TODAY: "DATE",
167
176
  DATE: "DATE",
168
177
  TIME: "TIME",
169
- EDATE: "DATE",
170
- EOMONTH: "DATE",
171
- // WORKDAY returns a date serial number — must render as DATE, not
172
- // raw NUMBER (was a bug: cells showed e.g. "45292" instead of the
173
- // calendar date).
174
- WORKDAY: "DATE",
175
- "WORKDAY.INTL": "DATE",
176
178
  // ─── Aggregation / rounding (return NUMBER; CURRENCY precedent
177
179
  // preserved via the "expectedOutputType === NUMBER + numFormat
178
180
  // CURRENCY → keep numFormat" branch) ──────────────────────────
@@ -319,7 +321,10 @@ const currencyDecimalAdjustmentFunctions = new Set([
319
321
  "QUOTIENT",
320
322
  ]);
321
323
  // Get all function names from formula
322
- const functionRegex = /([A-Za-z0-9_]+)\s*\(/g;
324
+ // Function names may be dotted (`WORKDAY.INTL`, `PERCENTILE.INC`, `FORECAST.ETS`); without the
325
+ // `.` the match stopped at the suffix (`INTL(`) and the dotted keys of `functionReturnTypes` /
326
+ // `formatDerivationRules` never applied.
327
+ const functionRegex = /([A-Za-z0-9_.]+)\s*\(/g;
323
328
  export const getFunctionNamesFromFormula = (formula) => {
324
329
  let match;
325
330
  const matches = [];
@@ -500,7 +505,7 @@ resolvePrecedentNumberFormat) => {
500
505
  effectivePrecedents = filterPrecedentsByBounds(effectivePrecedents, directBounds);
501
506
  const upperFormula = formula?.trim().toUpperCase();
502
507
  if (upperFormula) {
503
- const functionNameMatch = upperFormula.match(/^=([A-Z0-9_]+)\(/);
508
+ const functionNameMatch = upperFormula.match(/^=([A-Z0-9_.]+)\(/);
504
509
  topLevelFunctionName = functionNameMatch ? functionNameMatch[1] : undefined;
505
510
  const rule = topLevelFunctionName
506
511
  ? formatDerivationRules[topLevelFunctionName]
@@ -673,10 +678,10 @@ resolvePrecedentNumberFormat) => {
673
678
  // Date/time types need a concrete pattern — without one the renderer
674
679
  // falls back to "General" and shows the serial number (the
675
680
  // =TODAY() bug). When the precedent itself is a date-family format
676
- // with a pattern, inherit that pattern (e.g. `=EDATE(A1, 1)` keeps
677
- // A1's custom `yyyy-mm-dd` instead of falling back to the locale
678
- // default). Otherwise mirror the format toolbar's default for the
679
- // type.
681
+ // with a pattern, inherit that pattern (e.g. `=DATE(YEAR(A1),
682
+ // MONTH(A1), 1)` keeps A1's custom `yyyy-mm-dd` instead of falling
683
+ // back to the locale default). Otherwise mirror the format toolbar's
684
+ // default for the type.
680
685
  if (isDateFamilyType(resolvedNumberFormat.type) &&
681
686
  isDateFamilyType(numFormat?.type) &&
682
687
  numFormat?.pattern) {
@@ -1 +1 @@
1
- {"version":3,"file":"intl.d.ts","sourceRoot":"","sources":["../../../api/intl.ts"],"names":[],"mappings":"AA0BA;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,EAAE,gBAAc,WAK5D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,MAAM;;;;;CA2ClD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,SAAS,MAAM;eA1E5B,MAAM;YAAU,OAAO;YAAU,OAAO;iBAAe,OAAO;CAqH5E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM;UAtHxC,MAAM;YAAU,OAAO;YAAU,OAAO;CAkJjD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,SAAS,MAAM;aA/JlC,MAAM;eAAa,MAAM;WAAS,MAAM;aAgMpD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM,wBAkBhD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAAI,MAAM,MAAM,YAuBnD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAAI,aAAa,MAAM,gBA0BtD,CAAC"}
1
+ {"version":3,"file":"intl.d.ts","sourceRoot":"","sources":["../../../api/intl.ts"],"names":[],"mappings":"AA0BA;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,EAAE,gBAAc,WAK5D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,MAAM;WAlCxC,MAAM;aAAW,MAAM;eAAa,MAAM;iBAAe,MAAM;CA6EzE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,SAAS,MAAM;eA1E5B,MAAM;YAAU,OAAO;YAAU,OAAO;iBAAe,OAAO;CAqH5E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM;UAtHxC,MAAM;YAAU,OAAO;YAAU,OAAO;CAkJjD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,SAAS,MAAM;aA/JlC,MAAM;eAAa,MAAM;WAAS,MAAM;aAgMpD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM,wBAkBhD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAAI,MAAM,MAAM,YAuBnD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAAI,aAAa,MAAM,gBA0BtD,CAAC"}
@@ -4,4 +4,12 @@ export declare const shrinkMergesOnRowDelete: (merges: GridRange[], deleteStart:
4
4
  export declare const shrinkMergesOnColumnDelete: (merges: GridRange[], deleteStart: number, deleteCount: number) => GridRange[];
5
5
  export declare const expandMergesOnRowInsert: (merges: GridRange[], insertIndex: number, count: number) => GridRange[];
6
6
  export declare const expandMergesOnColumnInsert: (merges: GridRange[], insertIndex: number, count: number) => GridRange[];
7
+ /**
8
+ * Merges that travel with an insert/delete-cells shift: a merge wholly inside the shifted band
9
+ * (rows `>= start` in the band's columns for a vertical shift; columns `>= start` in its rows for a
10
+ * horizontal one) moves by `count`; on a delete, a merge wholly inside the deleted block is dropped
11
+ * with it. Merges the band only partially covers are refused upstream (`findTornMerge`) — this
12
+ * helper never tears one, it leaves anything outside the band untouched.
13
+ */
14
+ export declare const shiftMergesInBand: (merges: GridRange[] | undefined | null, axis: "row" | "column", start: number, count: number, insert: boolean, spanStart: number, spanEnd: number) => GridRange[] | null | undefined;
7
15
  //# sourceMappingURL=merges.d.ts.map