@shbernal/ts-xlsx 3.0.0 → 3.2.0

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 (277) hide show
  1. package/README.md +34 -24
  2. package/dist/bytes.d.ts +10 -2
  3. package/dist/bytes.js +22 -0
  4. package/dist/core/address.d.ts +96 -2
  5. package/dist/core/address.js +87 -33
  6. package/dist/core/array-formula-ranges.d.ts +33 -0
  7. package/dist/core/array-formula-ranges.js +62 -0
  8. package/dist/core/autofilter.d.ts +4 -3
  9. package/dist/core/autofilter.js +31 -30
  10. package/dist/core/axis-handle.d.ts +2 -0
  11. package/dist/core/axis-handle.js +5 -2
  12. package/dist/core/cell.d.ts +4 -3
  13. package/dist/core/cell.js +4 -6
  14. package/dist/core/clone.d.ts +29 -0
  15. package/dist/core/clone.js +24 -0
  16. package/dist/core/color-resolution.js +4 -6
  17. package/dist/core/column.d.ts +1 -0
  18. package/dist/core/column.js +6 -2
  19. package/dist/core/comment-thread.d.ts +7 -3
  20. package/dist/core/comment-thread.js +2 -1
  21. package/dist/core/conditional-formatting-overlay.d.ts +11 -1
  22. package/dist/core/conditional-formatting-overlay.js +30 -3
  23. package/dist/core/conditional-formatting.d.ts +107 -11
  24. package/dist/core/conditional-formatting.js +76 -19
  25. package/dist/core/containers.d.ts +12 -0
  26. package/dist/core/containers.js +5 -0
  27. package/dist/core/data-validation-overlay.d.ts +7 -1
  28. package/dist/core/data-validation-overlay.js +19 -4
  29. package/dist/core/data-validation.d.ts +22 -0
  30. package/dist/core/data-validation.js +30 -4
  31. package/dist/core/date-format.d.ts +20 -0
  32. package/dist/core/date-format.js +170 -0
  33. package/dist/core/date.d.ts +43 -8
  34. package/dist/core/date.js +19 -3
  35. package/dist/core/formula-references.d.ts +26 -0
  36. package/dist/core/formula-references.js +173 -0
  37. package/dist/core/formula-scan.d.ts +2 -0
  38. package/dist/core/formula-scan.js +58 -0
  39. package/dist/core/formula.d.ts +76 -17
  40. package/dist/core/formula.js +87 -80
  41. package/dist/core/function-values.d.ts +4 -0
  42. package/dist/core/function-values.js +58 -0
  43. package/dist/core/future-functions.d.ts +3 -0
  44. package/dist/core/{modern-functions.js → future-functions.js} +119 -88
  45. package/dist/core/grid-edits.d.ts +30 -3
  46. package/dist/core/grid-edits.js +248 -81
  47. package/dist/core/grid-shift.d.ts +58 -9
  48. package/dist/core/grid-shift.js +26 -4
  49. package/dist/core/hyperlink.d.ts +39 -0
  50. package/dist/core/hyperlink.js +88 -0
  51. package/dist/core/image.d.ts +49 -14
  52. package/dist/core/image.js +16 -5
  53. package/dist/core/internal.d.ts +10 -2
  54. package/dist/core/limits.d.ts +25 -0
  55. package/dist/core/limits.js +4 -0
  56. package/dist/core/merge.d.ts +18 -4
  57. package/dist/core/merge.js +33 -20
  58. package/dist/core/page-setup.d.ts +26 -11
  59. package/dist/core/pivot-table.d.ts +49 -10
  60. package/dist/core/pivot-table.js +112 -60
  61. package/dist/core/protection.d.ts +66 -4
  62. package/dist/core/protection.js +6 -11
  63. package/dist/core/range.js +34 -30
  64. package/dist/core/row-input.js +2 -2
  65. package/dist/core/row.d.ts +1 -0
  66. package/dist/core/row.js +6 -2
  67. package/dist/core/structured-reference.d.ts +7 -0
  68. package/dist/core/structured-reference.js +7 -0
  69. package/dist/core/style.d.ts +85 -70
  70. package/dist/core/style.js +92 -28
  71. package/dist/core/table-style.d.ts +1 -1
  72. package/dist/core/table-style.js +4 -4
  73. package/dist/core/table.d.ts +64 -16
  74. package/dist/core/table.js +87 -40
  75. package/dist/core/theme.d.ts +2 -0
  76. package/dist/core/theme.js +9 -5
  77. package/dist/core/value.d.ts +60 -28
  78. package/dist/core/value.js +48 -43
  79. package/dist/core/workbook-media.d.ts +34 -0
  80. package/dist/core/workbook-media.js +44 -0
  81. package/dist/core/workbook-styles.d.ts +83 -1
  82. package/dist/core/workbook-styles.js +4 -0
  83. package/dist/core/workbook-theme.js +5 -3
  84. package/dist/core/workbook-vba.js +3 -2
  85. package/dist/core/workbook.d.ts +41 -3
  86. package/dist/core/workbook.js +46 -41
  87. package/dist/core/worksheet-comments.d.ts +2 -1
  88. package/dist/core/worksheet-comments.js +20 -13
  89. package/dist/core/worksheet-merges.d.ts +49 -0
  90. package/dist/core/worksheet-merges.js +65 -0
  91. package/dist/core/worksheet-model.d.ts +10 -2
  92. package/dist/core/worksheet-model.js +28 -9
  93. package/dist/core/worksheet-pictures.d.ts +3 -3
  94. package/dist/core/worksheet-pictures.js +7 -6
  95. package/dist/core/worksheet.d.ts +165 -27
  96. package/dist/core/worksheet.js +206 -89
  97. package/dist/customui/ribbon.js +2 -1
  98. package/dist/entries/core.d.ts +21 -14
  99. package/dist/entries/core.js +14 -7
  100. package/dist/entries/errors.d.ts +1 -0
  101. package/dist/entries/errors.js +1 -0
  102. package/dist/entries/xlsx.d.ts +1 -1
  103. package/dist/errors.d.ts +64 -0
  104. package/dist/errors.js +22 -0
  105. package/dist/hex.d.ts +8 -0
  106. package/dist/hex.js +3 -0
  107. package/dist/io/cell-metadata/metadata.d.ts +42 -0
  108. package/dist/io/cell-metadata/metadata.js +35 -0
  109. package/dist/io/cell-metadata/rich-values.d.ts +11 -0
  110. package/dist/io/cell-metadata/rich-values.js +80 -0
  111. package/dist/io/csv/delimiter.d.ts +21 -0
  112. package/dist/io/csv/delimiter.js +18 -0
  113. package/dist/io/csv/errors.d.ts +14 -0
  114. package/dist/io/csv/errors.js +5 -0
  115. package/dist/io/csv/read.d.ts +6 -1
  116. package/dist/io/csv/read.js +51 -22
  117. package/dist/io/csv/write.d.ts +19 -5
  118. package/dist/io/csv/write.js +24 -44
  119. package/dist/io/opc/inflate.js +14 -0
  120. package/dist/io/opc/namespaces.d.ts +16 -0
  121. package/dist/io/opc/namespaces.js +4 -0
  122. package/dist/io/opc/part-paths.d.ts +9 -0
  123. package/dist/io/opc/part-paths.js +5 -5
  124. package/dist/io/opc/read-opc.d.ts +58 -14
  125. package/dist/io/opc/read-opc.js +49 -21
  126. package/dist/io/opc/read-options.d.ts +5 -1
  127. package/dist/io/opc/sniff-format.d.ts +3 -3
  128. package/dist/io/opc/sniff-format.js +2 -2
  129. package/dist/io/opc/strict-relationships.d.ts +2 -0
  130. package/dist/io/opc/strict-relationships.js +12 -0
  131. package/dist/io/read-policy/column-budget.d.ts +26 -0
  132. package/dist/io/read-policy/column-budget.js +18 -0
  133. package/dist/io/read-policy/read-repair.d.ts +74 -0
  134. package/dist/io/read-policy/read-repair.js +119 -0
  135. package/dist/io/style/cell-style-resolution.d.ts +25 -0
  136. package/dist/io/style/cell-style-resolution.js +30 -0
  137. package/dist/io/style/xf-style.d.ts +23 -1
  138. package/dist/io/style/xf-style.js +8 -0
  139. package/dist/io/xlsb/formula.d.ts +2 -2
  140. package/dist/io/xlsb/formula.js +52 -35
  141. package/dist/io/xlsb/primitives.js +8 -14
  142. package/dist/io/xlsb/ptg-functions.d.ts +19 -10
  143. package/dist/io/xlsb/ptg-functions.js +495 -596
  144. package/dist/io/xlsb/read-metadata.d.ts +7 -0
  145. package/dist/io/xlsb/read-metadata.js +69 -0
  146. package/dist/io/xlsb/read-styles.js +45 -81
  147. package/dist/io/xlsb/read-worksheet.d.ts +26 -1
  148. package/dist/io/xlsb/read-worksheet.js +148 -106
  149. package/dist/io/xlsb/read.d.ts +6 -3
  150. package/dist/io/xlsb/read.js +70 -31
  151. package/dist/io/xlsb/record-stream.d.ts +30 -0
  152. package/dist/io/xlsb/record-stream.js +20 -0
  153. package/dist/io/xlsb/record-types.d.ts +14 -5
  154. package/dist/io/xlsb/record-types.js +14 -5
  155. package/dist/io/xlsb/sheet-protection.d.ts +20 -0
  156. package/dist/io/xlsb/sheet-protection.js +60 -0
  157. package/dist/io/xlsx/cell-accumulator.d.ts +24 -9
  158. package/dist/io/xlsx/cell-accumulator.js +74 -21
  159. package/dist/io/xlsx/cell-metadata.d.ts +39 -0
  160. package/dist/io/xlsx/cell-metadata.js +162 -0
  161. package/dist/io/xlsx/cell-value.d.ts +19 -5
  162. package/dist/io/xlsx/cell-value.js +45 -30
  163. package/dist/io/xlsx/color-xml.js +3 -2
  164. package/dist/io/xlsx/column-span.d.ts +11 -0
  165. package/dist/io/xlsx/column-span.js +9 -0
  166. package/dist/io/xlsx/comments.d.ts +9 -30
  167. package/dist/io/xlsx/comments.js +25 -83
  168. package/dist/io/xlsx/conditional-formatting.d.ts +43 -23
  169. package/dist/io/xlsx/conditional-formatting.js +437 -138
  170. package/dist/io/xlsx/data-validation.d.ts +12 -7
  171. package/dist/io/xlsx/data-validation.js +67 -53
  172. package/dist/io/xlsx/edit-vba.d.ts +7 -2
  173. package/dist/io/xlsx/edit-vba.js +52 -52
  174. package/dist/io/xlsx/font-xml.d.ts +7 -0
  175. package/dist/io/xlsx/font-xml.js +104 -0
  176. package/dist/io/xlsx/hyperlinks.d.ts +19 -21
  177. package/dist/io/xlsx/hyperlinks.js +12 -32
  178. package/dist/io/xlsx/images.d.ts +49 -16
  179. package/dist/io/xlsx/images.js +149 -50
  180. package/dist/io/xlsx/namespaces.d.ts +24 -0
  181. package/dist/io/xlsx/namespaces.js +11 -0
  182. package/dist/io/xlsx/package-plan.d.ts +60 -15
  183. package/dist/io/xlsx/package-plan.js +83 -18
  184. package/dist/io/xlsx/part-names.d.ts +6 -8
  185. package/dist/io/xlsx/part-names.js +3 -7
  186. package/dist/io/xlsx/pivot.d.ts +5 -5
  187. package/dist/io/xlsx/pivot.js +26 -24
  188. package/dist/io/xlsx/preserved-splices.d.ts +6 -0
  189. package/dist/io/xlsx/preserved-splices.js +74 -0
  190. package/dist/io/xlsx/read-comments.d.ts +29 -0
  191. package/dist/io/xlsx/read-comments.js +75 -0
  192. package/dist/io/xlsx/read-parts.d.ts +59 -0
  193. package/dist/io/xlsx/read-parts.js +259 -0
  194. package/dist/io/xlsx/read-pivot.js +11 -4
  195. package/dist/io/xlsx/{rich-runs.d.ts → read-rich-runs.d.ts} +8 -5
  196. package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +24 -4
  197. package/dist/io/xlsx/read-rows.d.ts +35 -11
  198. package/dist/io/xlsx/read-rows.js +73 -49
  199. package/dist/io/xlsx/read-shared-strings.js +3 -2
  200. package/dist/io/xlsx/read-styles.d.ts +0 -30
  201. package/dist/io/xlsx/read-styles.js +45 -105
  202. package/dist/io/xlsx/read-workbook-xml.d.ts +42 -0
  203. package/dist/io/xlsx/read-workbook-xml.js +175 -0
  204. package/dist/io/xlsx/read-worksheet.d.ts +9 -3
  205. package/dist/io/xlsx/read-worksheet.js +70 -177
  206. package/dist/io/xlsx/read.d.ts +3 -14
  207. package/dist/io/xlsx/read.js +74 -411
  208. package/dist/io/xlsx/relationships.d.ts +3 -0
  209. package/dist/io/xlsx/relationships.js +4 -0
  210. package/dist/io/xlsx/rich-text.js +1 -1
  211. package/dist/io/xlsx/row-position.d.ts +20 -0
  212. package/dist/io/xlsx/row-position.js +11 -0
  213. package/dist/io/xlsx/row-xml.d.ts +139 -0
  214. package/dist/io/xlsx/row-xml.js +222 -0
  215. package/dist/io/xlsx/shared-formulas.js +2 -2
  216. package/dist/io/xlsx/sheet-properties.d.ts +10 -1
  217. package/dist/io/xlsx/sheet-properties.js +182 -20
  218. package/dist/io/xlsx/strict-parts.d.ts +7 -0
  219. package/dist/io/xlsx/strict-parts.js +171 -0
  220. package/dist/io/xlsx/style-elements.d.ts +41 -0
  221. package/dist/io/xlsx/style-elements.js +136 -0
  222. package/dist/io/xlsx/styles.d.ts +17 -3
  223. package/dist/io/xlsx/styles.js +13 -209
  224. package/dist/io/xlsx/tables.d.ts +10 -2
  225. package/dist/io/xlsx/tables.js +55 -52
  226. package/dist/io/xlsx/theme-xml.d.ts +32 -4
  227. package/dist/io/xlsx/theme-xml.js +106 -71
  228. package/dist/io/xlsx/threaded-comments.d.ts +14 -11
  229. package/dist/io/xlsx/threaded-comments.js +16 -8
  230. package/dist/io/xlsx/workbook-xml.d.ts +45 -6
  231. package/dist/io/xlsx/workbook-xml.js +62 -54
  232. package/dist/io/xlsx/worksheet-xml.d.ts +26 -70
  233. package/dist/io/xlsx/worksheet-xml.js +69 -282
  234. package/dist/io/xlsx/write-stream.d.ts +90 -19
  235. package/dist/io/xlsx/write-stream.js +80 -25
  236. package/dist/io/xlsx/write.d.ts +12 -6
  237. package/dist/io/xlsx/write.js +226 -123
  238. package/dist/rel-type.d.ts +25 -0
  239. package/dist/rel-type.js +9 -0
  240. package/dist/token-set.d.ts +13 -0
  241. package/dist/token-set.js +4 -1
  242. package/dist/vba/bytes.d.ts +16 -5
  243. package/dist/vba/bytes.js +27 -6
  244. package/dist/vba/cfb-format.d.ts +55 -0
  245. package/dist/vba/cfb-format.js +35 -0
  246. package/dist/vba/cfb-writer.d.ts +8 -0
  247. package/dist/vba/cfb-writer.js +40 -40
  248. package/dist/vba/cfb.d.ts +21 -4
  249. package/dist/vba/cfb.js +124 -90
  250. package/dist/vba/codepage.js +2 -1
  251. package/dist/vba/dir-records.d.ts +6 -0
  252. package/dist/vba/dir-records.js +10 -2
  253. package/dist/vba/errors.d.ts +11 -4
  254. package/dist/vba/index.d.ts +0 -2
  255. package/dist/vba/index.js +0 -2
  256. package/dist/vba/ms-ovba.d.ts +6 -2
  257. package/dist/vba/ms-ovba.js +66 -22
  258. package/dist/vba/project-editor.js +129 -119
  259. package/dist/vba/project.d.ts +15 -1
  260. package/dist/vba/project.js +38 -13
  261. package/dist/vba/vba-encoding.d.ts +4 -10
  262. package/dist/vba/vba-encoding.js +3 -17
  263. package/dist/xml/xml-attrs.d.ts +37 -0
  264. package/dist/xml/xml-attrs.js +30 -0
  265. package/dist/xml/xml-chars.d.ts +40 -0
  266. package/dist/xml/xml-chars.js +12 -0
  267. package/dist/xml/xml-namespaces.d.ts +31 -0
  268. package/dist/xml/xml-namespaces.js +50 -0
  269. package/dist/xml/xml-read.d.ts +101 -11
  270. package/dist/xml/xml-read.js +150 -18
  271. package/dist/xml/xml-scan.d.ts +25 -34
  272. package/dist/xml/xml-scan.js +69 -46
  273. package/dist/xml/xml.d.ts +59 -26
  274. package/dist/xml/xml.js +45 -23
  275. package/package.json +15 -9
  276. package/skills/ts-xlsx-upstream/SKILL.md +21 -13
  277. package/dist/core/modern-functions.d.ts +0 -1
@@ -3,7 +3,15 @@ import type { Worksheet, WorksheetModel } from './worksheet.ts';
3
3
  /** One field of a {@link WorksheetModel}, with both directions of its round-trip declared together. */
4
4
  interface ModelFacet<K extends keyof WorksheetModel = keyof WorksheetModel> {
5
5
  readonly key: K;
6
- /** Produce the field's value, copied deeply enough that mutating it cannot reach back into the sheet. */
6
+ /**
7
+ * Produce the field's value, in a form a caller cannot mutate the sheet through.
8
+ *
9
+ * Copying is one way to get there and the type is the other. `tabColor`, `autoFilter` and
10
+ * `protection` are handed back by reference precisely because their types are readonly all the way
11
+ * down, so there is nothing to defend against and a clone would only be one more shape to keep in
12
+ * step with its declaration. Every other field is a mutable record or array and is copied, which is
13
+ * where the spreads below come from.
14
+ */
7
15
  readonly read: (sheet: Worksheet) => WorksheetModel[K];
8
16
  /**
9
17
  * Apply the field to a sheet whose content has already been reset. Takes the whole model rather
@@ -23,7 +31,7 @@ interface ModelFacet<K extends keyof WorksheetModel = keyof WorksheetModel> {
23
31
  * load-bearing: cells are placed at their exact positions before any merge exists, so a covered
24
32
  * cell's value lands where the model says instead of being routed to a region master mid-load.
25
33
  */
26
- export declare const WORKSHEET_MODEL_FACETS: (ModelFacet<"autoFilter"> | ModelFacet<"cells"> | ModelFacet<"columnBreaks"> | ModelFacet<"columns"> | ModelFacet<"conditionalFormattings"> | ModelFacet<"dataValidations"> | ModelFacet<"headerFooter"> | ModelFacet<"merges"> | ModelFacet<"outline"> | ModelFacet<"pageMargins"> | ModelFacet<"pageSetup"> | ModelFacet<"printOptions"> | ModelFacet<"properties"> | ModelFacet<"protection"> | ModelFacet<"rowBreaks"> | ModelFacet<"rows"> | ModelFacet<"state"> | ModelFacet<"tabColor"> | ModelFacet<"tables"> | ModelFacet<"view">)[];
34
+ export declare const WORKSHEET_MODEL_FACETS: (ModelFacet<"autoFilter"> | ModelFacet<"cells"> | ModelFacet<"columnBreaks"> | ModelFacet<"columns"> | ModelFacet<"conditionalFormattings"> | ModelFacet<"dataValidations"> | ModelFacet<"headerFooter"> | ModelFacet<"hyperlinks"> | ModelFacet<"merges"> | ModelFacet<"outline"> | ModelFacet<"pageMargins"> | ModelFacet<"pageSetup"> | ModelFacet<"printOptions"> | ModelFacet<"properties"> | ModelFacet<"protection"> | ModelFacet<"rowBreaks"> | ModelFacet<"rows"> | ModelFacet<"state"> | ModelFacet<"tabColor"> | ModelFacet<"tables"> | ModelFacet<"view">)[];
27
35
  /**
28
36
  * Compile-time proof that {@link WORKSHEET_MODEL_FACETS} covers every {@link WorksheetModel} field.
29
37
  * A field added without a facet resolves this to that field's name, which does not satisfy `never`,
@@ -6,6 +6,21 @@ import { INTERNAL } from './internal.js';
6
6
  function facet(key, read, write) {
7
7
  return { key, read, write: (sheet, model) => write(sheet, model[key]) };
8
8
  }
9
+ function recordFacet(key) {
10
+ return {
11
+ key,
12
+ read: (sheet) => ({ ...sheet[key] }),
13
+ write: (sheet, model) => overwrite(sheet[key], model[key]),
14
+ };
15
+ }
16
+ function recordsFacet(key) {
17
+ const copy = (breaks) => breaks.map((brk) => ({ ...brk }));
18
+ return {
19
+ key,
20
+ read: (sheet) => copy(sheet[key]),
21
+ write: (sheet, model) => replaceContents(sheet[key], copy(model[key])),
22
+ };
23
+ }
9
24
  export const WORKSHEET_MODEL_FACETS = [
10
25
  facet('state', (sheet) => sheet.state, (sheet, value) => {
11
26
  sheet.state = value;
@@ -13,15 +28,15 @@ export const WORKSHEET_MODEL_FACETS = [
13
28
  facet('tabColor', (sheet) => sheet.tabColor, (sheet, value) => {
14
29
  sheet.tabColor = value;
15
30
  }),
16
- facet('properties', (sheet) => ({ ...sheet.properties }), (sheet, value) => overwrite(sheet.properties, value)),
17
- facet('outline', (sheet) => ({ ...sheet.outline }), (sheet, value) => overwrite(sheet.outline, value)),
18
- facet('view', (sheet) => ({ ...sheet.view }), (sheet, value) => overwrite(sheet.view, value)),
19
- facet('pageSetup', (sheet) => ({ ...sheet.pageSetup }), (sheet, value) => overwrite(sheet.pageSetup, value)),
20
- facet('printOptions', (sheet) => ({ ...sheet.printOptions }), (sheet, value) => overwrite(sheet.printOptions, value)),
21
- facet('pageMargins', (sheet) => ({ ...sheet.pageMargins }), (sheet, value) => overwrite(sheet.pageMargins, value)),
22
- facet('headerFooter', (sheet) => ({ ...sheet.headerFooter }), (sheet, value) => overwrite(sheet.headerFooter, value)),
23
- facet('rowBreaks', (sheet) => sheet.rowBreaks.map((brk) => ({ ...brk })), (sheet, value) => replaceContents(sheet.rowBreaks, value.map((brk) => ({ ...brk })))),
24
- facet('columnBreaks', (sheet) => sheet.columnBreaks.map((brk) => ({ ...brk })), (sheet, value) => replaceContents(sheet.columnBreaks, value.map((brk) => ({ ...brk })))),
31
+ recordFacet('properties'),
32
+ recordFacet('outline'),
33
+ recordFacet('view'),
34
+ recordFacet('pageSetup'),
35
+ recordFacet('printOptions'),
36
+ recordFacet('pageMargins'),
37
+ recordFacet('headerFooter'),
38
+ recordsFacet('rowBreaks'),
39
+ recordsFacet('columnBreaks'),
25
40
  facet('columns', (sheet) => [...sheet.columns()].map(({ index, properties }) => ({ index, properties: { ...properties } })), (sheet, value) => {
26
41
  for (const { index, properties } of value)
27
42
  Object.assign(sheet.getColumn(index), properties);
@@ -51,6 +66,10 @@ export const WORKSHEET_MODEL_FACETS = [
51
66
  for (const range of value)
52
67
  sheet.mergeCells(range);
53
68
  }),
69
+ facet('hyperlinks', (sheet) => sheet.hyperlinks.map((link) => ({ ...link })), (sheet, value) => {
70
+ for (const link of value)
71
+ sheet.addHyperlink(link);
72
+ }),
54
73
  facet('dataValidations', (sheet) => sheet.dataValidations.map(({ sqref, rule, extended }) => ({
55
74
  sqref,
56
75
  rule: cloneDataValidation(rule),
@@ -1,4 +1,4 @@
1
- import { type AnchoredImage, type AnchorPoint, type ImageAnchor, type ImageEditAs } from './image.ts';
1
+ import { type AnchoredImage, type AnchorPoint, type ImageAnchor, type ImageEditAs, type PictureProperties } from './image.ts';
2
2
  /** The two shapes {@link WorksheetPictures.add} accepts, in caller-facing pixel units. */
3
3
  export type PixelAnchor = {
4
4
  readonly tl: AnchorPoint;
@@ -22,8 +22,8 @@ export declare class WorksheetPictures {
22
22
  /** The anchored images, in the order they were added. */
23
23
  get anchors(): AnchoredImage[];
24
24
  get backgroundImageId(): number | undefined;
25
- add(imageId: number, anchor: PixelAnchor): void;
26
- addAnchor(imageId: number, anchor: ImageAnchor): void;
25
+ add(imageId: number, anchor: PixelAnchor, properties?: PictureProperties): void;
26
+ addAnchor(imageId: number, anchor: ImageAnchor, properties?: PictureProperties): void;
27
27
  remove(imageId: number): void;
28
28
  setBackground(imageId: number | undefined): void;
29
29
  }
@@ -1,5 +1,5 @@
1
1
  import { replaceContents } from './containers.js';
2
- import { PX_TO_EMU, resolveAnchorPoint, } from './image.js';
2
+ import { pictureProperties, PX_TO_EMU, resolveAnchorPoint, } from './image.js';
3
3
  export class WorksheetPictures {
4
4
  #metrics;
5
5
  #anchors = [];
@@ -13,7 +13,8 @@ export class WorksheetPictures {
13
13
  get backgroundImageId() {
14
14
  return this.#backgroundImageId;
15
15
  }
16
- add(imageId, anchor) {
16
+ add(imageId, anchor, properties = {}) {
17
+ const picture = pictureProperties(properties);
17
18
  const columnWidth = (col) => this.#metrics.columnWidth(col);
18
19
  const rowHeight = (row) => this.#metrics.rowHeight(row);
19
20
  if ('ext' in anchor) {
@@ -22,16 +23,16 @@ export class WorksheetPictures {
22
23
  cy: Math.round(anchor.ext.height * PX_TO_EMU),
23
24
  };
24
25
  const from = resolveAnchorPoint(anchor.tl, columnWidth, rowHeight);
25
- this.#anchors.push({ imageId, anchor: { from, ext } });
26
+ this.#anchors.push({ imageId, anchor: { from, ext }, ...picture });
26
27
  return;
27
28
  }
28
29
  const from = resolveAnchorPoint(anchor.tl, columnWidth, rowHeight);
29
30
  const to = resolveAnchorPoint(anchor.br, columnWidth, rowHeight);
30
31
  const twoCell = anchor.editAs !== undefined ? { from, to, editAs: anchor.editAs } : { from, to };
31
- this.#anchors.push({ imageId, anchor: twoCell });
32
+ this.#anchors.push({ imageId, anchor: twoCell, ...picture });
32
33
  }
33
- addAnchor(imageId, anchor) {
34
- this.#anchors.push({ imageId, anchor });
34
+ addAnchor(imageId, anchor, properties = {}) {
35
+ this.#anchors.push({ imageId, anchor, ...pictureProperties(properties) });
35
36
  }
36
37
  remove(imageId) {
37
38
  replaceContents(this.#anchors, this.#anchors.filter((image) => image.imageId !== imageId));
@@ -4,7 +4,9 @@ import { Column } from './column.ts';
4
4
  import type { CommentThread } from './comment-thread.ts';
5
5
  import type { ConditionalFormatting } from './conditional-formatting.ts';
6
6
  import type { DataValidation, DataValidationEntry } from './data-validation.ts';
7
- import type { AnchoredImage, AnchorPoint, ImageAnchor, ImageEditAs } from './image.ts';
7
+ import { type SheetSplice } from './formula-references.ts';
8
+ import { type Hyperlink } from './hyperlink.ts';
9
+ import type { AnchoredImage, AnchorPoint, ImageAnchor, ImageEditAs, PictureProperties } from './image.ts';
8
10
  import { INTERNAL } from './internal.ts';
9
11
  import type { HeaderFooter, PageBreak, PageMargins, PageSetup, PrintOptions } from './page-setup.ts';
10
12
  import { type ParsedPivotTable, PivotTable, type PivotTableOptions } from './pivot-table.ts';
@@ -12,9 +14,9 @@ import type { PreservedWorksheetReference } from './preserved.ts';
12
14
  import { type SheetProtection, type SheetProtectionOptions } from './protection.ts';
13
15
  import { Range } from './range.ts';
14
16
  import { Row } from './row.ts';
15
- import type { CellStyle, Color, Fill } from './style.ts';
17
+ import type { CellContent, CellStyle, Color, Fill } from './style.ts';
16
18
  import { Table, type TableOptions } from './table.ts';
17
- import type { CellValue } from './value.ts';
19
+ import { type CellValue } from './value.ts';
18
20
  /**
19
21
  * Whether a thing Excel can hide is showing: a sheet's tab, or the document window itself.
20
22
  *
@@ -107,8 +109,13 @@ export interface RowProperties {
107
109
  /** Background fill applied to the row's cells that carry no fill of their own. */
108
110
  fill?: Fill;
109
111
  }
110
- /** One materialised cell in a {@link WorksheetModel}: its position, value, and per-cell style facets. */
111
- export interface CellModel extends CellStyle {
112
+ /**
113
+ * One materialised cell in a {@link WorksheetModel}: its position, value, note, and every facet of its
114
+ * formatting. Extends {@link CellContent} rather than {@link CellStyle} so the quote-prefix flag and
115
+ * the named-style link travel with a model round-trip: they are written and read back like any other
116
+ * facet, and leaving them off the tuple is what made a `dst.model = src.model` drop them.
117
+ */
118
+ export interface CellModel extends CellContent {
112
119
  readonly row: number;
113
120
  readonly col: number;
114
121
  value: CellValue;
@@ -159,6 +166,7 @@ export interface WorksheetModel {
159
166
  }[];
160
167
  cells: CellModel[];
161
168
  merges: string[];
169
+ hyperlinks: Hyperlink[];
162
170
  dataValidations: DataValidationEntry[];
163
171
  conditionalFormattings: ConditionalFormatting[];
164
172
  tables: TableOptions[];
@@ -177,6 +185,17 @@ export declare class Worksheet {
177
185
  * never fabricates one.
178
186
  */
179
187
  tabColor: Color | undefined;
188
+ /**
189
+ * The sheet's VBA identity (`<sheetPr codeName>`), the name a macro means by `Sheet1`. Undefined
190
+ * for a sheet in a workbook with no VBA project, which is what Excel writes for one.
191
+ *
192
+ * Preserved rather than modeled: nothing here reads it, but a `.xlsm` whose sheet code names are
193
+ * dropped on a round trip has had the binding between its macros and its sheets cut. Deliberately
194
+ * absent from {@link WorksheetModel}, which is the copy shape: a code name identifies *this* sheet
195
+ * to the workbook's VBA project, so copying it onto a second sheet would give the project two
196
+ * sheets answering to one name.
197
+ */
198
+ codeName?: string;
180
199
  /** Sheet-level format defaults. Mutate in place: `sheet.properties.defaultRowHeight = 20`. */
181
200
  readonly properties: WorksheetProperties;
182
201
  /**
@@ -206,15 +225,17 @@ export declare class Worksheet {
206
225
  /** Page header/footer text. Mutate in place: `sheet.headerFooter.oddHeader = '&C&"..."'`. */
207
226
  readonly headerFooter: HeaderFooter;
208
227
  /**
209
- * Manual horizontal page breaks (`<rowBreaks>`): each break's `id` is a row the print layout splits
210
- * before. Mutate in place: `sheet.rowBreaks.push({id: 3})`. Empty means no manual row breaks and the
211
- * writer emits no `<rowBreaks>` element.
228
+ * Horizontal page breaks (`<rowBreaks>`): each break's `id` is the last row before it, so
229
+ * `sheet.rowBreaks.push({id: 3})` starts a new printed page at row 4. Mutate in place. A row splice
230
+ * moves a break with the row after it. Empty means no row breaks and the writer emits no
231
+ * `<rowBreaks>` element.
212
232
  */
213
233
  readonly rowBreaks: PageBreak[];
214
234
  /**
215
- * Manual vertical page breaks (`<colBreaks>`): each break's `id` is a column the print layout splits
216
- * before. Mutate in place: `sheet.columnBreaks.push({id: 3})`. Empty means no manual column breaks and
217
- * the writer emits no `<colBreaks>` element.
235
+ * Vertical page breaks (`<colBreaks>`): each break's `id` is the last column before it, so
236
+ * `sheet.columnBreaks.push({id: 3})` starts a new printed page at column D. Mutate in place. A column
237
+ * splice moves a break with the column after it. Empty means no column breaks and the writer emits
238
+ * no `<colBreaks>` element.
218
239
  */
219
240
  readonly columnBreaks: PageBreak[];
220
241
  constructor(name: string, id: number, state?: WorksheetState['state']);
@@ -267,6 +288,7 @@ export declare class Worksheet {
267
288
  *
268
289
  * @throws {SyntaxError} if the reference is unparseable, names another worksheet, or leaves an
269
290
  * axis unbounded.
291
+ * @throws {AuthoringError} if the numeric form is called with fewer than four corners.
270
292
  * @throws {RangeError} if a numeric corner is not a positive integer within the sheet's bounds.
271
293
  */
272
294
  getRange(reference: string): Range;
@@ -341,7 +363,8 @@ export declare class Worksheet {
341
363
  getTable(name: string): Table | undefined;
342
364
  /**
343
365
  * Add a pivot table to this (destination) sheet, summarising a source sheet's data. The source is
344
- * read once, now, so the pivot is a snapshot: later edits to the source do not change it. The
366
+ * read once, now, so the pivot is a snapshot: later edits to the source's values do not change it,
367
+ * while a row or column splice of the source sheet moves its {@link PivotTable.sourceRef}. The
345
368
  * supported shape (one summed value field, at least one row and column field) is enforced here.
346
369
  *
347
370
  * @throws {AuthoringError} if the metric, fields, or source shape are unsupported.
@@ -354,7 +377,9 @@ export declare class Worksheet {
354
377
  * read-only inspection view (source range, field roles, value field, aggregation). A pivot
355
378
  * authored on this sheet via {@link addPivotTable} does not appear here; a pivot loaded from a
356
379
  * file does not appear in {@link pivotTables}. The loaded pivots re-emit verbatim through
357
- * byte-preservation, so this collection is never itself serialised.
380
+ * byte-preservation, so this collection is never itself serialised. A row or column splice of a
381
+ * pivot's source sheet moves its {@link ParsedPivotSource.ref} here and in the cache the writer
382
+ * emits, by one rule, so the view says what is written.
358
383
  */
359
384
  get loadedPivotTables(): readonly ParsedPivotTable[];
360
385
  /**
@@ -366,7 +391,8 @@ export declare class Worksheet {
366
391
  * Every message supplies its own {@link Comment.id} and {@link Comment.date}, and names its author by
367
392
  * {@link Comment.personId} into the workbook registry ({@link Workbook.addPerson}): the writer has no
368
393
  * clock and no id generator, so nothing here is invented and the same workbook always serialises to the
369
- * same bytes. Every id is normalised to the brace-wrapped upper-case GUID form the format requires, so a
394
+ * same bytes. An author id nobody registered is refused when the workbook is written, where the
395
+ * registry is complete; a message with no `personId` is written as Excel writes an unknown author. Every id is normalised to the brace-wrapped upper-case GUID form the format requires, so a
370
396
  * `crypto.randomUUID()` is accepted as-is.
371
397
  *
372
398
  * Message ids must be unique **within this sheet**, because that is the scope in which they mean
@@ -404,25 +430,33 @@ export declare class Worksheet {
404
430
  *
405
431
  * Grid points are 0-based (`{col: 0, row: 0}` is cell A1). A later row/column splice re-pins the
406
432
  * anchor to the same logical position.
433
+ *
434
+ * `properties` gives the picture alternative text and a title, crops it, or makes it a link; see
435
+ * {@link PictureProperties}.
436
+ *
437
+ * A sheet read from a file keeps its drawing whole when the drawing holds a chart, a shape or other
438
+ * content the library does not model. A picture added to such a sheet is written into that drawing,
439
+ * beside what it holds, and read back it is part of the kept drawing rather than one of
440
+ * {@link images}.
407
441
  */
408
442
  addImage(imageId: number, anchor: {
409
443
  readonly tl: AnchorPoint;
410
444
  readonly br: AnchorPoint;
411
445
  readonly editAs?: ImageEditAs;
412
- }): void;
446
+ }, properties?: PictureProperties): void;
413
447
  addImage(imageId: number, anchor: {
414
448
  readonly tl: AnchorPoint;
415
449
  readonly ext: {
416
450
  readonly width: number;
417
451
  readonly height: number;
418
452
  };
419
- }): void;
453
+ }, properties?: PictureProperties): void;
420
454
  /**
421
455
  * Anchor an image with a pre-built model anchor in the model's own units (EMUs). This is the
422
456
  * low-level primitive {@link addImage} builds on and the reader uses to re-pin an image parsed from
423
457
  * a drawing part without a lossy pixel round-trip.
424
458
  */
425
- addImageAnchor(imageId: number, anchor: ImageAnchor): void;
459
+ addImageAnchor(imageId: number, anchor: ImageAnchor, properties?: PictureProperties): void;
426
460
  /** Drop every anchor of the given workbook image from this sheet. The image stays registered on the
427
461
  * workbook (another sheet may still show it), so only this sheet's anchors are removed; the writer
428
462
  * then omits any media no sheet anchors any longer. */
@@ -448,9 +482,16 @@ export declare class Worksheet {
448
482
  * anchor's, exactly how Excel collapses a range on merge. Leaving it would emit a populated `<c>`
449
483
  * under the `<mergeCell>` ref, the geometry Excel opens with a repair prompt. Covered-cell styles
450
484
  * survive (a border spanning the merge is legal), so only the conflicting value is cleared.
485
+ *
486
+ * The range is stored in canonical form, `$` anchors dropped and the top-left corner first, so
487
+ * merging `$B$2:$A$1` reports `A1:B2` through {@link merges}.
488
+ *
489
+ * @throws {SyntaxError} if the range is unparseable or names a worksheet: a merge belongs to the
490
+ * sheet it is made on, and a prefix naming another one used to be ignored.
491
+ * @throws {AuthoringError} if the range overlaps an already-merged region.
451
492
  */
452
493
  mergeCells(range: string): void;
453
- /** The merged ranges on this sheet, in the order they were added. */
494
+ /** The merged ranges on this sheet, in canonical form (`A1:B2`), in the order they were added. */
454
495
  get merges(): readonly string[];
455
496
  /**
456
497
  * The sheet's autofilter (its range plus any per-column criteria), or `undefined` when the sheet
@@ -467,9 +508,12 @@ export declare class Worksheet {
467
508
  get autoFilter(): AutoFilter | undefined;
468
509
  set autoFilter(filter: string | AutoFilter | undefined);
469
510
  /**
470
- * Remove a merged range previously added with {@link mergeCells}, returning whether a merge with
471
- * that exact range string existed. The covering rectangle is dropped alongside it, so a cell the
472
- * merge had masked addresses independently again. The inverse of {@link mergeCells}.
511
+ * Remove a merged range previously added with {@link mergeCells}, returning whether such a merge
512
+ * existed. The range matches however it is spelled (`$` anchors, corner order), since merges are
513
+ * stored and compared in canonical form. The covering rectangle is dropped alongside it, so a cell
514
+ * the merge had masked addresses independently again. The inverse of {@link mergeCells}.
515
+ *
516
+ * @throws {SyntaxError} if the range is unparseable or names a worksheet.
473
517
  */
474
518
  unmergeCells(range: string): boolean;
475
519
  /**
@@ -493,6 +537,8 @@ export declare class Worksheet {
493
537
  * range (`"A1:A10"`), a whole column, or several space-separated areas (`"A1:C1 A3:C3"`) sharing one
494
538
  * rule set. The block is stored once against the range, defensively copied so the getter never hands
495
539
  * back a reference into the caller's object.
540
+ *
541
+ * @throws {AuthoringError} when `formatting.ref` names no cells: empty, or no area of it decodes.
496
542
  */
497
543
  addConditionalFormatting(formatting: ConditionalFormatting): void;
498
544
  /** The conditional formattings on this sheet, each bound to its target range, in insertion order. */
@@ -502,6 +548,35 @@ export declare class Worksheet {
502
548
  * contains the cell wins, mirroring how a spreadsheet resolves overlapping validations.
503
549
  */
504
550
  dataValidationAt(reference: string): DataValidation | undefined;
551
+ /**
552
+ * Put a hyperlink on a cell or a rectangle of cells: `{ref: 'B2', target: 'https://example.com'}`,
553
+ * or `{ref: 'D1:H1', target: '#Summary!A1', tooltip: 'Back to the summary'}`. A `#`-prefixed target
554
+ * is a place in this workbook; any other is a URL or a path, written as given.
555
+ *
556
+ * A link is not part of a cell's value, so it goes on a number, a date, a formula or an empty cell as
557
+ * readily as on text, and the value stays whatever it is. A link over the same `ref` as one already
558
+ * on the sheet replaces it. One over a different range is added beside it: where two cover a cell,
559
+ * {@link hyperlinkAt} reports the later, and Excel keeps both.
560
+ *
561
+ * A row or column splice moves a link with the cells it covers, growing it when lines are inserted
562
+ * inside it and shrinking it when some of its lines are deleted, as Excel does.
563
+ *
564
+ * @throws {SyntaxError} if `ref` is not a reference.
565
+ * @throws {AuthoringError} if `ref` names a whole row or column rather than cells.
566
+ */
567
+ addHyperlink(link: Hyperlink): void;
568
+ /**
569
+ * Remove the hyperlink whose `ref` is `ref`, and report whether there was one. A link over a wider
570
+ * range that merely covers `ref` stays.
571
+ */
572
+ removeHyperlink(ref: string): boolean;
573
+ /** The hyperlinks on this sheet, in the order they were added. */
574
+ get hyperlinks(): readonly Hyperlink[];
575
+ /**
576
+ * The hyperlink a cell opens, or `undefined` when none covers it. Of two links covering the cell, the
577
+ * one added later.
578
+ */
579
+ hyperlinkAt(reference: string): Hyperlink | undefined;
505
580
  /**
506
581
  * Remove `count` rows starting at the 1-based `start`, then insert the given rows in their place.
507
582
  * Rows below the edit shift by `inserts.length - count`: a delete pulls the tail up, an insert
@@ -511,7 +586,21 @@ export declare class Worksheet {
511
586
  * silently becomes a no-op. Cells carry their full style to the shifted position, and merged ranges
512
587
  * shift with the rows they cover.
513
588
  *
589
+ * Formulas move with the rows as Excel moves them: a reference to this sheet, in any sheet's formula,
590
+ * a defined name, a data validation, a conditional format or a table's column formulas, follows the
591
+ * row it names, and one to a deleted row becomes `#REF!`. An authored pivot drawing from this sheet
592
+ * has its source range moved the same way. What the inserted rows carry is written against the sheet after the
593
+ * edit and is not moved. A dynamic array whose range the edit leaves holding another formula has its
594
+ * spill blocked, as Excel blocks it: the array formula keeps its own cell alone and caches `#SPILL!`.
595
+ *
514
596
  * @throws {RangeError} if `start` is not a positive integer or `count` is negative.
597
+ * @throws {RangeError} if an inserted row would land past the last row of the grid. The sheet is
598
+ * left untouched, so this is a refused edit rather than half of one: a region pushed off the edge
599
+ * clamps and absorbs the loss, but content pushed off it is what Excel refuses outright.
600
+ * @throws {AuthoringError} if the edit would cut through a Ctrl+Shift+Enter array formula's range: an
601
+ * insert strictly inside it, or a delete taking part of it. Excel refuses the same edit, as a change
602
+ * to part of an array, and the sheet is left untouched. An edit moving or deleting the whole range,
603
+ * and any edit through a dynamic array's range, goes ahead.
515
604
  */
516
605
  spliceRows(start: number, count: number, ...inserts: RowInput[]): void;
517
606
  /**
@@ -547,7 +636,8 @@ export declare class Worksheet {
547
636
  * beneath them. `freeze(1)` pins a header row; `freeze(0, 1)` pins the first column. Passing both
548
637
  * zero clears the freeze (equivalent to {@link unfreeze}).
549
638
  *
550
- * @throws {RangeError} if either split is a negative or non-integer count.
639
+ * @throws {RangeError} if either split is a negative or non-integer count, or leaves no row or
640
+ * column of the grid to scroll. The view is left as it was.
551
641
  */
552
642
  freeze(ySplit?: number, xSplit?: number): void;
553
643
  /** Clear any frozen split, returning the sheet to a normal (fully scrolling) view. */
@@ -561,9 +651,16 @@ export declare class Worksheet {
561
651
  *
562
652
  * Each copy is a faithful duplicate of the source: its cell values, its per-cell styles, and its
563
653
  * row properties (height, hidden, outline level, row fill). It carries no merge of its own, so a
564
- * range can be merged onto a duplicated row afterwards.
654
+ * range can be merged onto a duplicated row afterwards. A formula is copied as Excel copies a row,
655
+ * its relative references moved down with it and its cached result dropped, since that was computed
656
+ * over the source's cells; an inserted copy is taken from the source as the insert left it. A copy
657
+ * landing in a dynamic array's range blocks its spill, as {@link spliceRows} says.
565
658
  *
566
- * @throws {RangeError} if `start` is not a positive integer or `count` is negative.
659
+ * @throws {RangeError} if `start` is not a positive integer or `count` is negative, or if a copy
660
+ * would land past the last row. The sheet is left untouched.
661
+ * @throws {AuthoringError} if a copy would land inside a Ctrl+Shift+Enter array formula's range, or
662
+ * replace part of one, which Excel refuses as a change to part of an array. The sheet is left
663
+ * untouched.
567
664
  */
568
665
  duplicateRow(start: number, options?: {
569
666
  count?: number;
@@ -576,7 +673,15 @@ export declare class Worksheet {
576
673
  * the right of the edit re-anchors to its new columns. Each inserted column is an array of values
577
674
  * indexed by row (index 0 → row 1); an empty array inserts a blank column.
578
675
  *
676
+ * Formulas move with the columns, by the rules {@link spliceRows} gives for rows.
677
+ *
579
678
  * @throws {RangeError} if `start` is not a positive integer or `count` is negative.
679
+ * @throws {RangeError} if an inserted column would land past the last column, or one of its values
680
+ * past the last row. The sheet is left untouched, so this is a refused edit rather than half of
681
+ * one: a region pushed off the edge clamps and absorbs the loss, but content pushed off it is
682
+ * what Excel refuses outright, and {@link addColumn} refuses the same argument identically.
683
+ * @throws {AuthoringError} if the edit would cut through a Ctrl+Shift+Enter array formula's range, by
684
+ * the rule {@link spliceRows} gives for rows. The sheet is left untouched.
580
685
  */
581
686
  spliceColumns(start: number, count: number, ...inserts: CellValue[][]): void;
582
687
  /**
@@ -584,7 +689,8 @@ export declare class Worksheet {
584
689
  * by one. `values` is an array of values indexed by row (index 0 → row 1), like
585
690
  * {@link addColumn}. Shorthand for {@link spliceColumns}`(pos, 0, values)`.
586
691
  *
587
- * @throws {RangeError} if `pos` is not a positive integer.
692
+ * @throws {RangeError} if `pos` is not a positive integer, or if the column would land past the
693
+ * last column or one of its values past the last row; see {@link spliceColumns}.
588
694
  */
589
695
  insertColumn(pos: number, values: CellValue[]): void;
590
696
  /**
@@ -684,6 +790,14 @@ export interface WorksheetInternals {
684
790
  * restores that credential verbatim rather than re-hashing.
685
791
  */
686
792
  restoreProtection(protection: SheetProtection): void;
793
+ /**
794
+ * Hand the sheet what moves the formulas beyond it, every other sheet's and the workbook's defined
795
+ * names, when a splice of this sheet moves the lines they refer to. The workbook sets it on each sheet
796
+ * it creates.
797
+ */
798
+ setFormulaHost(host: (edit: SheetSplice) => void): void;
799
+ /** Move the references this sheet's formulas make to a spliced sheet, which here is another one. */
800
+ spliceFormulas(edit: SheetSplice): void;
687
801
  /**
688
802
  * Materialise the cell at an exact 1-based position, creating it on first access. Unlike
689
803
  * {@link Worksheet.getCell} this performs no merge resolution: the cell returned is the one at
@@ -693,18 +807,42 @@ export interface WorksheetInternals {
693
807
  */
694
808
  cellAt(row: number, col: number): Cell;
695
809
  /**
696
- * The store behind a {@link Row} or {@link Column} handle. These six exist because the handles are
810
+ * The cell materialised at a position, or `undefined` when nothing has been written there.
811
+ *
812
+ * Merge-blind and non-materialising, which is what separates it from `Worksheet.getCell`: that
813
+ * resolves a covered address to its merge master, so `hasCell(row, col)` followed by a `getCell` of
814
+ * the same position can hand back a *different* cell. A caller walking a rectangle got the master
815
+ * once per covered position and never saw the covered cells at all, which made a `clearStyle` over a
816
+ * merge clear the master repeatedly and the covered cells not once. A caller that wants merge
817
+ * resolution keeps `getCell`; a caller enumerating what is actually stored wants this.
818
+ */
819
+ peekCell(row: number, col: number): Cell | undefined;
820
+ /**
821
+ * {@link cellAt} with merge resolution: the cell a write to this position lands on, materialised.
822
+ *
823
+ * What {@link Worksheet.getCell} does, minus the address. `getCell` is the public spelling and takes
824
+ * an A1 reference, so a caller already holding a row and a column had to encode one and have it
825
+ * decoded straight back. That round-trip costs about three times a positional read, and a
826
+ * {@link Range} write performs one per cell: styling a 100x100 block spent 10,000 encodes and 10,000
827
+ * regex decodes on positions it already had.
828
+ */
829
+ masterAt(row: number, col: number): Cell;
830
+ /**
831
+ * The store behind a {@link Row} or {@link Column} handle. These exist because the handles are
697
832
  * views rather than records: they hold a sheet and a position, and every read and write goes
698
833
  * through here to the one authoritative map. `…PropertiesOf` never fabricates, so reading a row
699
834
  * cannot extend the used range; `ensure…` is what a write calls, so the record appears exactly
700
- * when a value is set.
835
+ * when a value is set; `drop…` is what clearing the last field calls, so the record disappears
836
+ * exactly when the line stops being formatted, which is what keeps the used range honest.
701
837
  */
702
838
  rowPropertiesOf(number: number): RowProperties | undefined;
703
839
  ensureRowProperties(number: number): RowProperties;
840
+ dropRowProperties(number: number): void;
704
841
  /** The row's materialised cells in ascending column order. */
705
842
  rowCells(number: number): Cell[];
706
843
  columnPropertiesOf(index: number): ColumnProperties | undefined;
707
844
  ensureColumnProperties(index: number): ColumnProperties;
845
+ dropColumnProperties(index: number): void;
708
846
  /** The column's materialised cells in ascending row order. */
709
847
  columnCells(index: number): Cell[];
710
848
  }