@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
@@ -1,57 +1,26 @@
1
- import { decodeRange, encodeAddress } from '../../core/address.js';
2
- import { cellHasOwnStyle } from '../../core/cell.js';
3
- import { DEFAULT_DATE_NUMFMT, dateToSerial } from '../../core/date.js';
4
- import { mangleFormula } from '../../core/formula.js';
5
- import { NAMED_STYLE_ID } from '../../core/internal.js';
6
- import { CELL_STYLE_FACETS, pickStyleFacets } from '../../core/style.js';
7
- import { detectValueType, isDataTableFormulaValue, isErrorValue, isFormulaValue, isHyperlinkValue, isRichTextValue, isSharedFormulaValue, } from '../../core/value.js';
8
- import { AuthoringError, InternalError } from '../../errors.js';
9
- import { assertWritableNumber, escapeAttr, escapeSpreadsheetText, escapeText, numberText, textAttr, textElement, XML_DECLARATION, } from '../../xml/xml.js';
10
- import { relationship, relationshipsPart } from '../opc/rels.js';
11
- import { conditionalFormattingsExtXml, conditionalFormattingsXml } from './conditional-formatting.js';
1
+ import { encodeRect } from '../../core/address.js';
2
+ import { arrayRangeConflicts, formulaPlacement } from '../../core/array-formula-ranges.js';
3
+ import { mergesOverlappingTables } from '../../core/merge.js';
4
+ import { pickStyleFacets } from '../../core/style.js';
5
+ import { AuthoringError, InternalError, quoted } from '../../errors.js';
6
+ import { escapeAttr, numberText, XML_DECLARATION } from '../../xml/xml.js';
7
+ import { conditionalFormattingsExtXml, conditionalFormattingsXml, planConditionalFormatting, } from './conditional-formatting.js';
12
8
  import { dataValidationsExtXml, dataValidationsXml } from './data-validation.js';
13
9
  import { hyperlinksXml } from './hyperlinks.js';
14
10
  import { SLICER_LIST_EXT_URI } from './namespaces.js';
15
- import { commentsPart, drawingPart, mediaPart, pivotTablePart, printerSettingsPart, tablePart, targetFromWorksheet, threadedCommentsPart, vmlDrawingPart, } from './part-names.js';
16
- import { NS, REL } from './relationships.js';
17
- import { richTextRunsXml } from './rich-text.js';
11
+ import { NS } from './relationships.js';
12
+ import { assertWritableLevel, buildColumnDefaults, Extent, outlineAttr, renderRow, rowOpenTag, } from './row-xml.js';
18
13
  import { planSharedFormulas } from './shared-formulas.js';
19
14
  import { autoFilterXml, headerFooterXml, pageBreaksXml, pageMarginsXml, pageSetupXml, printOptionsXml, sheetProtectionXml, sheetPrXml, sheetViewsXml, } from './sheet-properties.js';
20
15
  import { x14Ext } from './x14-ext.js';
21
- export class Extent {
22
- top = Infinity;
23
- left = Infinity;
24
- bottom = -Infinity;
25
- right = -Infinity;
26
- constructor(seed) {
27
- if (seed) {
28
- this.top = seed.top;
29
- this.left = seed.left;
30
- this.bottom = seed.bottom;
31
- this.right = seed.right;
32
- }
33
- }
34
- get isEmpty() {
35
- return this.bottom === -Infinity;
36
- }
37
- add(row, minCol, maxCol) {
38
- if (minCol === Infinity)
39
- return;
40
- if (row < this.top)
41
- this.top = row;
42
- if (row > this.bottom)
43
- this.bottom = row;
44
- if (minCol < this.left)
45
- this.left = minCol;
46
- if (maxCol > this.right)
47
- this.right = maxCol;
48
- }
49
- }
50
- export function worksheetXml(sheet, tables, styles, references, hyperlinks, sharedStrings, active, flushed) {
16
+ export function worksheetXml(inputs) {
17
+ const { sheet, tables, styles, references, hyperlinks, sharedStrings, cellMetadata, dateEpoch, formulaNames, active, flushed, } = inputs;
51
18
  validateMerges(sheet);
19
+ validateArrayRanges(sheet, flushed);
52
20
  const columnDefaults = buildColumnDefaults(sheet);
53
21
  const sharedRoles = planSharedFormulas(sheet);
54
- const rowOutline = scanRowOutline(sheet);
22
+ const formattingPlan = planConditionalFormatting(sheet.conditionalFormattings);
23
+ const rowOutline = scanRowOutline(sheet, flushed);
55
24
  const collapsedSummaries = rowOutline.collapsedSummaries;
56
25
  const context = {
57
26
  columnDefaults,
@@ -59,6 +28,9 @@ export function worksheetXml(sheet, tables, styles, references, hyperlinks, shar
59
28
  sharedStrings,
60
29
  sharedRoles,
61
30
  collapsedSummaries,
31
+ dateEpoch,
32
+ formulaNames,
33
+ cellMetadata,
62
34
  };
63
35
  const liveRows = [];
64
36
  const extent = new Extent(flushed?.extent);
@@ -69,11 +41,9 @@ export function worksheetXml(sheet, tables, styles, references, hyperlinks, shar
69
41
  liveRows.push({ number: entry.number, xml });
70
42
  extent.add(entry.number, minCol, maxCol);
71
43
  }
72
- const dimensionRef = extent.isEmpty
73
- ? 'A1'
74
- : `${encodeAddress(extent.left, extent.top)}:${encodeAddress(extent.right, extent.bottom)}`;
44
+ const dimensionRef = extent.isEmpty ? 'A1' : encodeRect(extent);
75
45
  const orderedRows = flushed
76
- ? [...flushed.rows, ...liveRows].sort((a, b) => a.number - b.number)
46
+ ? [...flushed.rows.map((row) => completeCollapsed(row, collapsedSummaries)), ...liveRows].sort((a, b) => a.number - b.number)
77
47
  : liveRows;
78
48
  const bodyXml = orderedRows.map((row) => row.xml).join('');
79
49
  const sheetData = bodyXml === '' ? '<sheetData/>' : `<sheetData>${bodyXml}</sheetData>`;
@@ -84,15 +54,15 @@ export function worksheetXml(sheet, tables, styles, references, hyperlinks, shar
84
54
  sheetViewsXml(sheet.view, active) +
85
55
  sheetFormatPr(sheet.properties, {
86
56
  col: maxColumnOutlineLevel(sheet),
87
- row: Math.max(rowOutline.maxLevel, flushed?.maxRowOutlineLevel ?? 0),
57
+ row: rowOutline.maxLevel,
88
58
  }) +
89
59
  colsXml(sheet, styles) +
90
60
  sheetData +
91
61
  sheetProtectionXml(sheet.protection) +
92
62
  autoFilterXml(sheet.autoFilter) +
93
63
  mergeCellsXml(sheet.merges) +
94
- conditionalFormattingsXml(sheet.conditionalFormattings, styles) +
95
- dataValidationsXml(sheet.dataValidations) +
64
+ conditionalFormattingsXml(sheet.conditionalFormattings, styles, formattingPlan, formulaNames) +
65
+ dataValidationsXml(sheet.dataValidations, formulaNames) +
96
66
  hyperlinksXml(hyperlinks) +
97
67
  printOptionsXml(sheet.printOptions) +
98
68
  pageMarginsXml(sheet.pageMargins) +
@@ -105,58 +75,13 @@ export function worksheetXml(sheet, tables, styles, references, hyperlinks, shar
105
75
  refElement('legacyDrawingHF', references.legacyDrawingHFRelId) +
106
76
  refElement('picture', references.backgroundRelId) +
107
77
  tablePartsXml(tables) +
108
- worksheetExtLstXml(sheet, references.slicerRelIds) +
78
+ worksheetExtLstXml(sheet, styles, references.slicerRelIds, formattingPlan, formulaNames) +
109
79
  '</worksheet>');
110
80
  }
111
- export function buildColumnDefaults(sheet) {
112
- const columnDefaults = new Map();
113
- for (const { index, properties } of sheet.columns())
114
- columnDefaults.set(index, properties ?? {});
115
- return columnDefaults;
116
- }
117
- export function renderRow(entry, ctx) {
118
- const { number, cells, properties } = entry;
119
- const rendered = cells.filter((cell) => cell.value !== null || cellHasOwnStyle(cell));
120
- const attrs = rowAttrs(properties, ctx.styles, ctx.collapsedSummaries.has(number));
121
- if (rendered.length === 0 && attrs === '')
122
- return { xml: '', minCol: Infinity, maxCol: -Infinity };
123
- const rowFill = properties?.fill;
124
- const cellsXml = rendered
125
- .map((cell) => {
126
- const style = ctx.styles.styleId(composeCellStyle(cell, rowFill, ctx.columnDefaults.get(cell.col)));
127
- return cellXml(cell, style, ctx.sharedRoles.get(cell.address), ctx.sharedStrings);
128
- })
129
- .join('');
130
- let minCol = Infinity;
131
- let maxCol = -Infinity;
132
- for (const cell of rendered) {
133
- if (cell.col < minCol)
134
- minCol = cell.col;
135
- if (cell.col > maxCol)
136
- maxCol = cell.col;
137
- }
138
- return { xml: `<row r="${number}"${attrs}>${cellsXml}</row>`, minCol, maxCol };
139
- }
140
- function composeCellStyle(cell, rowFill, colDef) {
141
- const style = {};
142
- for (const facet of CELL_STYLE_FACETS)
143
- inheritFacet(style, facet, cell, colDef);
144
- style.fill = cell.fill ?? rowFill ?? colDef?.fill;
145
- style.numFmt = cell.numFmt ?? colDef?.numFmt ?? dateDefaultNumFmt(cell.value);
146
- if (cell.quotePrefix !== undefined)
147
- style.quotePrefix = cell.quotePrefix;
148
- const xfId = cell[NAMED_STYLE_ID];
149
- if (xfId !== undefined)
150
- style.xfId = xfId;
151
- return style;
152
- }
153
- function inheritFacet(target, key, cell, colDef) {
154
- target[key] = cell[key] ?? colDef?.[key];
155
- }
156
- function worksheetExtLstXml(sheet, slicerRelIds) {
81
+ function worksheetExtLstXml(sheet, styles, slicerRelIds, formattingPlan, formulaNames) {
157
82
  const exts = [
158
- conditionalFormattingsExtXml(sheet.conditionalFormattings),
159
- dataValidationsExtXml(sheet.dataValidations),
83
+ conditionalFormattingsExtXml(sheet.conditionalFormattings, styles, formattingPlan, formulaNames),
84
+ dataValidationsExtXml(sheet.dataValidations, formulaNames),
160
85
  slicerListExtXml(slicerRelIds),
161
86
  ].filter((ext) => ext !== '');
162
87
  return exts.length === 0 ? '' : `<extLst>${exts.join('')}</extLst>`;
@@ -168,30 +93,33 @@ function slicerListExtXml(slicerRelIds) {
168
93
  return x14Ext(SLICER_LIST_EXT_URI, `<x14:slicerList>${slicers}</x14:slicerList>`);
169
94
  }
170
95
  function validateMerges(sheet) {
171
- if (sheet.merges.length === 0 || sheet.tables.length === 0)
96
+ const [conflict] = mergesOverlappingTables(sheet.merges, sheet.tables);
97
+ if (conflict === undefined)
172
98
  return;
173
- for (const merge of sheet.merges) {
174
- const { left, right, top, bottom } = decodeRange(merge);
175
- if (left === undefined || right === undefined || top === undefined || bottom === undefined)
176
- continue;
177
- for (const table of sheet.tables) {
178
- const region = table.region;
179
- const overlaps = left <= region.right &&
180
- right >= region.left &&
181
- top <= region.bottom &&
182
- bottom >= region.top;
183
- if (overlaps) {
184
- throw new AuthoringError(`merged range ${merge} overlaps table "${table.name}" (${table.range}): Excel forbids a merge inside a table`);
185
- }
99
+ const { merge, table } = conflict;
100
+ throw new AuthoringError(`merged range ${merge} overlaps table ${quoted(table.name)} (${table.range}): Excel forbids a merge inside a table`);
101
+ }
102
+ function validateArrayRanges(sheet, flushed) {
103
+ const placements = [...(flushed?.formulas ?? [])];
104
+ for (const { cells } of sheet.rows()) {
105
+ for (const cell of cells) {
106
+ const placement = formulaPlacement(cell.address, cell.col, cell.row, cell.value);
107
+ if (placement !== undefined)
108
+ placements.push(placement);
186
109
  }
187
110
  }
111
+ const [conflict] = arrayRangeConflicts(placements);
112
+ if (conflict === undefined)
113
+ return;
114
+ const { array, other, kind } = conflict;
115
+ throw new AuthoringError(kind === 'formula-inside'
116
+ ? `the array formula in ${array.address} fills ${quoted(array.arrayRef ?? '')}, which holds the formula in ${other}: Excel repairs a package with a formula inside another array formula's range`
117
+ : `the array formula in ${array.address} fills ${quoted(array.arrayRef ?? '')}, which shares cells with the range of the array formula in ${other}: Excel repairs a package whose array formula ranges overlap`);
188
118
  }
189
119
  function mergeCellsXml(merges) {
190
120
  if (merges.length === 0)
191
121
  return '';
192
- const cells = merges
193
- .map((range) => `<mergeCell ref="${escapeAttr(decodeRange(range).dimensions)}"/>`)
194
- .join('');
122
+ const cells = merges.map((range) => `<mergeCell ref="${escapeAttr(range)}"/>`).join('');
195
123
  return `<mergeCells count="${merges.length}">${cells}</mergeCells>`;
196
124
  }
197
125
  function refElement(tag, relId) {
@@ -203,45 +131,6 @@ function tablePartsXml(tables) {
203
131
  const parts = tables.map(({ relId }) => `<tablePart r:id="${relId}"/>`).join('');
204
132
  return `<tableParts count="${tables.length}">${parts}</tableParts>`;
205
133
  }
206
- export function worksheetRelsXml(tables, drawing, comments, threadedComments, printerSettings, background, hyperlinks, preservedReferences, pivots) {
207
- const rels = [
208
- ...tables.map(({ relId, number }) => relationship(relId, REL.table, targetFromWorksheet(tablePart(number)))),
209
- ...pivots.map((pivot) => relationship(pivot.sheetRelId, REL.pivotTable, targetFromWorksheet(pivotTablePart(pivot.number)))),
210
- ...(drawing === null
211
- ? []
212
- : [
213
- relationship(drawing.relId, REL.drawing, targetFromWorksheet(drawingPart(drawing.number))),
214
- ]),
215
- ...(comments === null
216
- ? []
217
- : [
218
- relationship(comments.vmlRelId, REL.vmlDrawing, targetFromWorksheet(vmlDrawingPart(comments.number))),
219
- relationship(comments.commentsRelId, REL.comments, targetFromWorksheet(commentsPart(comments.number))),
220
- ]),
221
- ...(threadedComments === null
222
- ? []
223
- : [
224
- relationship(threadedComments.relId, REL.threadedComment, targetFromWorksheet(threadedCommentsPart(threadedComments.number))),
225
- ]),
226
- ...(printerSettings === null
227
- ? []
228
- : [
229
- relationship(printerSettings.relId, REL.printerSettings, targetFromWorksheet(printerSettingsPart(printerSettings.number))),
230
- ]),
231
- ...(background === null
232
- ? []
233
- : [
234
- relationship(background.relId, REL.image, targetFromWorksheet(mediaPart(background.mediaNumber, background.extension))),
235
- ]),
236
- ...preservedReferences.map((reference) => relationship(reference.relId, reference.relType, escapeAttr(targetFromWorksheet(reference.entryPath)))),
237
- ...hyperlinks
238
- .filter((link) => link.relId !== undefined && link.target !== undefined)
239
- .map((link) => relationship(link.relId, REL.hyperlink, link.target, {
240
- external: true,
241
- })),
242
- ];
243
- return relationshipsPart(rels);
244
- }
245
134
  const DEFAULT_ROW_HEIGHT = 15;
246
135
  function sheetFormatPr(properties, outlineLevel) {
247
136
  const rowHeight = properties.defaultRowHeight ?? DEFAULT_ROW_HEIGHT;
@@ -255,12 +144,6 @@ function sheetFormatPr(properties, outlineLevel) {
255
144
  attrs += outlineAttr('outlineLevelRow', outlineLevel.row);
256
145
  return `<sheetFormatPr${attrs}/>`;
257
146
  }
258
- function outlineAttr(name, level) {
259
- if (level === undefined)
260
- return '';
261
- const text = numberText(level);
262
- return level > 0 ? ` ${name}="${text}"` : '';
263
- }
264
147
  function maxColumnOutlineLevel(sheet) {
265
148
  let max = 0;
266
149
  for (const column of sheet.columns())
@@ -313,33 +196,35 @@ function colBody(properties, styles) {
313
196
  }
314
197
  return meaningful ? attrs : null;
315
198
  }
316
- function rowAttrs(properties, styles, collapsedSummary) {
317
- if (properties === undefined)
318
- return collapsedSummary ? ' collapsed="1"' : '';
319
- let attrs = '';
320
- if (properties.height !== undefined)
321
- attrs += ` ht="${numberText(properties.height)}" customHeight="1"`;
322
- if (properties.hidden)
323
- attrs += ' hidden="1"';
324
- attrs += outlineAttr('outlineLevel', properties.outlineLevel);
325
- if (properties.collapsed || collapsedSummary)
326
- attrs += ' collapsed="1"';
327
- const style = styles.styleId({ fill: properties.fill });
328
- if (style !== 0)
329
- attrs += ` s="${style}" customFormat="1"`;
330
- return attrs;
199
+ function completeCollapsed(row, collapsedSummaries) {
200
+ if (!collapsedSummaries.has(row.number) || row.attrs.includes(' collapsed="1"')) {
201
+ return { number: row.number, xml: row.xml };
202
+ }
203
+ const open = rowOpenTag(row.number);
204
+ if (!row.xml.startsWith(open)) {
205
+ throw new InternalError(`flushed row ${row.number} does not open with ${quoted(open)}`);
206
+ }
207
+ return {
208
+ number: row.number,
209
+ xml: `${open} collapsed="1"${row.xml.slice(open.length)}`,
210
+ };
331
211
  }
332
- function scanRowOutline(sheet) {
212
+ function scanRowOutline(sheet, flushed) {
333
213
  const level = new Map();
334
214
  const hidden = new Map();
335
215
  let maxLevel = 0;
336
- for (const { number, properties } of sheet.rows()) {
337
- const rowLevel = properties?.outlineLevel ?? 0;
338
- assertWritableNumber(rowLevel);
216
+ const note = (number, rowLevel, rowHidden) => {
217
+ assertWritableLevel(`row ${number} outlineLevel`, rowLevel);
339
218
  level.set(number, rowLevel);
340
- hidden.set(number, properties?.hidden ?? false);
219
+ hidden.set(number, rowHidden);
341
220
  if (rowLevel > maxLevel)
342
221
  maxLevel = rowLevel;
222
+ };
223
+ for (const [number, entry] of flushed?.rowOutline ?? []) {
224
+ note(number, entry.outlineLevel, entry.hidden);
225
+ }
226
+ for (const { number, properties } of sheet.rows()) {
227
+ note(number, properties?.outlineLevel ?? 0, properties?.hidden ?? false);
343
228
  }
344
229
  const levelOf = (row) => level.get(row) ?? 0;
345
230
  const step = sheet.outline.summaryBelow === false ? 1 : -1;
@@ -348,7 +233,7 @@ function scanRowOutline(sheet) {
348
233
  let detail = summary + step;
349
234
  let sawDetail = false;
350
235
  let allHidden = true;
351
- while (levelOf(detail) > summaryLevel) {
236
+ while (level.get(detail) !== undefined && levelOf(detail) > summaryLevel) {
352
237
  sawDetail = true;
353
238
  if (!hidden.get(detail))
354
239
  allHidden = false;
@@ -359,101 +244,3 @@ function scanRowOutline(sheet) {
359
244
  }
360
245
  return { collapsedSummaries, maxLevel };
361
246
  }
362
- function dateDefaultNumFmt(value) {
363
- const date = value instanceof Date
364
- ? value
365
- : (isFormulaValue(value) || isSharedFormulaValue(value)) && value.result instanceof Date
366
- ? value.result
367
- : undefined;
368
- return date !== undefined && !Number.isNaN(date.getTime()) ? DEFAULT_DATE_NUMFMT : undefined;
369
- }
370
- function cellXml(cell, style, shared, sharedStrings) {
371
- const ref = cell.address;
372
- const value = cell.value;
373
- const s = style !== 0 ? ` s="${style}"` : '';
374
- const formula = cellFormulaXml(ref, s, value, shared);
375
- if (formula !== undefined)
376
- return formula;
377
- if (value instanceof Date) {
378
- if (Number.isNaN(value.getTime()))
379
- return `<c r="${ref}"${s}/>`;
380
- return `<c r="${ref}"${s}><v>${numberText(dateToSerial(value))}</v></c>`;
381
- }
382
- if (typeof value === 'number') {
383
- if (!Number.isFinite(value))
384
- return `<c r="${ref}"${s}/>`;
385
- return `<c r="${ref}"${s}><v>${numberText(value)}</v></c>`;
386
- }
387
- if (typeof value === 'boolean') {
388
- return `<c r="${ref}"${s} t="b"><v>${value ? 1 : 0}</v></c>`;
389
- }
390
- if (typeof value === 'string') {
391
- if (sharedStrings !== null) {
392
- return `<c r="${ref}"${s} t="s"><v>${sharedStrings.intern(value)}</v></c>`;
393
- }
394
- return `<c r="${ref}"${s} t="inlineStr"><is>${textElement(value)}</is></c>`;
395
- }
396
- if (isRichTextValue(value)) {
397
- if (sharedStrings !== null) {
398
- return `<c r="${ref}"${s} t="s"><v>${sharedStrings.intern(value)}</v></c>`;
399
- }
400
- return `<c r="${ref}"${s} t="inlineStr"><is>${richTextRunsXml(value.richText)}</is></c>`;
401
- }
402
- if (isHyperlinkValue(value)) {
403
- const label = typeof value.text === 'string'
404
- ? textElement(value.text)
405
- : richTextRunsXml(value.text.richText);
406
- return `<c r="${ref}"${s} t="inlineStr"><is>${label}</is></c>`;
407
- }
408
- if (isErrorValue(value)) {
409
- return `<c r="${ref}"${s} t="e"><v>${value.error}</v></c>`;
410
- }
411
- if (value === null)
412
- return `<c r="${ref}"${s}/>`;
413
- throw new InternalError(`writing a ${detectValueType(value)} cell value has no arm: every CellValue kind is handled above`);
414
- }
415
- function cellFormulaXml(ref, s, value, shared) {
416
- if (shared !== undefined) {
417
- if (shared.ref !== undefined && isFormulaValue(value)) {
418
- const f = `<f t="shared" ref="${shared.ref}" si="${shared.si}">${escapeText(mangleFormula(value.formula))}</f>`;
419
- return formulaBodyXml(ref, s, f, value.result);
420
- }
421
- const result = isSharedFormulaValue(value) ? value.result : undefined;
422
- return formulaBodyXml(ref, s, `<f t="shared" si="${shared.si}"/>`, result);
423
- }
424
- if (isDataTableFormulaValue(value)) {
425
- const attrs = `ref="${escapeAttr(value.ref)}"` +
426
- ` dt2D="${value.dataTable2D ? 1 : 0}"` +
427
- ` dtr="${value.dataTableRow ? 1 : 0}"` +
428
- textAttr('r1', value.r1) +
429
- textAttr('r2', value.r2);
430
- return formulaBodyXml(ref, s, `<f t="dataTable" ${attrs}/>`, value.result);
431
- }
432
- if (isFormulaValue(value)) {
433
- return formulaBodyXml(ref, s, `<f>${escapeText(mangleFormula(value.formula))}</f>`, value.result);
434
- }
435
- return undefined;
436
- }
437
- function formulaBodyXml(ref, s, f, result) {
438
- if (result === undefined || (typeof result === 'number' && !Number.isFinite(result))) {
439
- return `<c r="${ref}"${s}>${f}</c>`;
440
- }
441
- if (typeof result === 'number') {
442
- return `<c r="${ref}"${s}>${f}<v>${numberText(result)}</v></c>`;
443
- }
444
- if (typeof result === 'boolean') {
445
- return `<c r="${ref}"${s} t="b">${f}<v>${result ? 1 : 0}</v></c>`;
446
- }
447
- if (typeof result === 'string') {
448
- return `<c r="${ref}"${s} t="str">${f}<v>${escapeSpreadsheetText(result)}</v></c>`;
449
- }
450
- if (isErrorValue(result)) {
451
- return `<c r="${ref}"${s} t="e">${f}<v>${result.error}</v></c>`;
452
- }
453
- if (result instanceof Date) {
454
- if (Number.isNaN(result.getTime()))
455
- return `<c r="${ref}"${s}>${f}</c>`;
456
- return `<c r="${ref}"${s}>${f}<v>${numberText(dateToSerial(result))}</v></c>`;
457
- }
458
- throw new InternalError('writing a non-primitive formula result has no arm: every FormulaResult kind is handled above');
459
- }
@@ -3,13 +3,17 @@ import type { AutoFilter } from '../../core/autofilter.ts';
3
3
  import type { Cell } from '../../core/cell.ts';
4
4
  import type { ConditionalFormatting } from '../../core/conditional-formatting.ts';
5
5
  import type { DataValidation } from '../../core/data-validation.ts';
6
+ import type { DateEpoch } from '../../core/date.ts';
7
+ import type { Hyperlink } from '../../core/hyperlink.ts';
6
8
  import type { AnchorPoint } from '../../core/image.ts';
9
+ import { INTERNAL } from '../../core/internal.ts';
7
10
  import type { SheetProtectionOptions } from '../../core/protection.ts';
8
11
  import { type CellValue } from '../../core/value.ts';
9
- import { type AddImageOptions, type AddWorksheetOptions, Workbook } from '../../core/workbook.ts';
12
+ import { type AddImageOptions, type AddWorksheetOptions, type DefinedName, Workbook } from '../../core/workbook.ts';
10
13
  import type { Worksheet } from '../../core/worksheet.ts';
14
+ import { WorkbookMetadataTable } from './cell-metadata.ts';
15
+ import { type FlushedSheet } from './row-xml.ts';
11
16
  import type { StyleRegistry } from './styles.ts';
12
- import { type FlushedSheet } from './write.ts';
13
17
  /** Calculation settings applied to the streamed workbook. Mirrors the {@link Workbook} flags. */
14
18
  export interface CalcProperties {
15
19
  /** Ask the consumer to recalculate every formula on open: the OOXML `fullCalcOnLoad` flag. */
@@ -45,6 +49,13 @@ export type WorkbookStreamWriterOptions = SinkOptions & {
45
49
  * same {@link WriteOptions.useSharedStrings} the buffered writer exposes. Off by default.
46
50
  */
47
51
  readonly useSharedStrings?: boolean;
52
+ /**
53
+ * Which date system this workbook's serials count in ({@link Workbook.dateEpoch}). A construction
54
+ * option rather than a settable property, unlike on the buffered writer: an eager writer serialises
55
+ * each row as it is committed, so a system changed part-way through would leave the rows before the
56
+ * change counting from a different day than the rows after it.
57
+ */
58
+ readonly dateEpoch?: DateEpoch;
48
59
  };
49
60
  /**
50
61
  * A row appended to a {@link WorksheetStreamWriter}. Style its cells through {@link cells}, then call
@@ -54,13 +65,25 @@ export type WorkbookStreamWriterOptions = SinkOptions & {
54
65
  */
55
66
  export declare class StreamedRow {
56
67
  #private;
57
- constructor(cells: readonly Cell[], sheet: WorksheetStreamWriter | null, number: number);
58
- /** The cells this row materialised, for styling before it is committed. */
68
+ private constructor();
69
+ /** The sheet writer's construction channel, keyed like its own; see `core/internal.ts`. */
70
+ static readonly [INTERNAL]: StreamedRowFactory;
71
+ /** The cells `addRow` materialised, for styling before it is committed. A cell added to the row
72
+ * through {@link WorksheetStreamWriter.getCell} is not among them, and is committed all the same. */
59
73
  get cells(): readonly Cell[];
60
74
  /** Finalise the row: an eager writer serialises it now and releases its cells; otherwise a no-op.
61
75
  * Committing twice is harmless: the second call does nothing rather than re-emitting the row. */
62
76
  commit(): void;
63
77
  }
78
+ /**
79
+ * How a {@link StreamedRow} comes into being. A row belongs to the sheet writer that numbered it, and
80
+ * only that writer knows which number is still open. `sheet` is `null` for a writer that keeps every
81
+ * row live until the workbook commits, where committing a row has nothing to do. Reached as
82
+ * `StreamedRow[INTERNAL]`.
83
+ */
84
+ export interface StreamedRowFactory {
85
+ create(cells: readonly Cell[], sheet: WorksheetStreamWriter | null, number: number): StreamedRow;
86
+ }
64
87
  /**
65
88
  * A worksheet being written incrementally. Append rows with {@link addRow}/{@link addRows}, style
66
89
  * cells through {@link getCell}, then {@link commit} to freeze it, after which any further mutation
@@ -68,7 +91,13 @@ export declare class StreamedRow {
68
91
  */
69
92
  export declare class WorksheetStreamWriter {
70
93
  #private;
71
- constructor(sheet: Worksheet, eager: boolean, styles: StyleRegistry);
94
+ private constructor();
95
+ /**
96
+ * The workbook writer's construction channel. A static member keyed by the same symbol as the
97
+ * instance one below, so both halves of this class's internal wiring are reached the one way; see
98
+ * `core/internal.ts`.
99
+ */
100
+ static readonly [INTERNAL]: WorksheetStreamWriterFactory;
72
101
  /** The sheet's name. */
73
102
  get name(): string;
74
103
  /** The number of rows written so far. Spans gaps and formatted-only rows, like the model, and
@@ -78,16 +107,6 @@ export declare class WorksheetStreamWriter {
78
107
  addRow(values: CellValue[]): StreamedRow;
79
108
  /** Append a batch of rows in one call, each landing directly below the previous. */
80
109
  addRows(rows: CellValue[][]): StreamedRow[];
81
- /**
82
- * Serialise an eagerly-committed row and release its cells from the model. Called by
83
- * {@link StreamedRow.commit}; the row's `<row>` XML is retained (interned into the workbook's live
84
- * style registry so its ids stay valid) and the cell graph is dropped, bounding peak memory.
85
- *
86
- * @throws {AuthoringError} if the row carries a shared-formula cell: a finished row cannot join the
87
- * whole-sheet formula planning, so shared formulas must be authored through {@link getCell}.
88
- */
89
- flushRow(number: number, cells: readonly Cell[]): void;
90
- flushedSheet(): FlushedSheet | undefined;
91
110
  /**
92
111
  * Address a cell by its A1 reference to read or style it before the sheet is committed. The row it
93
112
  * names must still be live: a row whose {@link StreamedRow.commit} has run is finished.
@@ -105,6 +124,12 @@ export declare class WorksheetStreamWriter {
105
124
  addDataValidation(sqref: string, rule: DataValidation, options?: {
106
125
  extended?: boolean;
107
126
  }): void;
127
+ /**
128
+ * Put a hyperlink on a cell or a rectangle of cells before the sheet is committed; mirrors
129
+ * {@link Worksheet.addHyperlink}. A link lives beside the grid rather than in a row, so it may cover
130
+ * cells of a row that is already committed.
131
+ */
132
+ addHyperlink(link: Hyperlink): void;
108
133
  /**
109
134
  * Attach a conditional formatting to a range before the sheet is committed. Like every other block,
110
135
  * it lands in its schema-mandated slot, after `<mergeCells>` and before `<dataValidations>` and
@@ -139,6 +164,43 @@ export declare class WorksheetStreamWriter {
139
164
  /** Whether the sheet has been committed. */
140
165
  get committed(): boolean;
141
166
  get model(): Worksheet;
167
+ readonly [INTERNAL]: WorksheetStreamWriterInternals;
168
+ }
169
+ /**
170
+ * How a {@link WorksheetStreamWriter} comes into being. Its parameters are the writer's own plumbing
171
+ * -- the interning table its rows' style ids are assigned from, the epoch its dates are serialised
172
+ * against -- and a consumer supplies neither, because a consumer receives the sheet writer from
173
+ * {@link WorkbookStreamWriter.addWorksheet}. Reached as `WorksheetStreamWriter[INTERNAL]`.
174
+ */
175
+ export interface WorksheetStreamWriterFactory {
176
+ create(sheet: Worksheet, eager: boolean, styles: StyleRegistry, cellMetadata: WorkbookMetadataTable, dateEpoch: DateEpoch, definedNames: readonly DefinedName[]): WorksheetStreamWriter;
177
+ }
178
+ /**
179
+ * What the streaming writer's own machinery may do to a sheet writer that a caller may not, the same
180
+ * boundary `sheet[INTERNAL]` draws around the model. Reached as `writer[INTERNAL]`; see
181
+ * `core/internal.ts`.
182
+ *
183
+ * Both members were public until they were not. Neither is callable by anyone but this module, and
184
+ * between them they named seven writer-internal types -- `StyleRegistry`, `FlushedSheet` and the
185
+ * shapes those reach -- on a published class's signature, so a consumer could hold values whose types
186
+ * the package would not export. They carried `@unpublished` to record that, which is a note rather
187
+ * than a boundary; this is the boundary.
188
+ */
189
+ export interface WorksheetStreamWriterInternals {
190
+ /**
191
+ * Serialise an eagerly-committed row and release its cells from the model. Called by
192
+ * {@link StreamedRow.commit}; the row's `<row>` XML is retained (interned into the workbook's live
193
+ * style registry so its ids stay valid) and the cell graph is dropped, bounding peak memory. The
194
+ * row is rendered from every cell the model holds for it, including any `getCell` added after
195
+ * `addRow` returned.
196
+ *
197
+ * @throws {AuthoringError} if the row carries a shared-formula cell: a finished row cannot join the
198
+ * whole-sheet formula planning, so shared formulas must be authored through
199
+ * {@link WorksheetStreamWriter.getCell}.
200
+ */
201
+ flushRow(number: number): void;
202
+ /** The rows this writer flushed, or undefined if none. Handed to `buildPackageParts` at commit. */
203
+ flushedSheet(): FlushedSheet | undefined;
142
204
  }
143
205
  /**
144
206
  * A workbook written incrementally to a Node stream. Add worksheets, append their rows, commit each
@@ -169,9 +231,18 @@ export declare class WorkbookStreamWriter {
169
231
  /** Create a worksheet and append it to the workbook. */
170
232
  addWorksheet(name: string, options?: AddWorksheetOptions): WorksheetStreamWriter;
171
233
  /**
172
- * Assemble the workbook into its package, stream the bytes through {@link stream}, and resolve with
173
- * the same bytes. Every sheet is frozen first, so a row added after this rejects legibly. Idempotent
174
- * only in that a second call throws rather than re-emitting.
234
+ * Assemble the workbook into its package and stream the bytes out. Every sheet is frozen first, so
235
+ * a row added after this rejects legibly. Idempotent only in that a second call throws rather than
236
+ * re-emitting.
237
+ *
238
+ * **What it resolves with, and why it can be `undefined`.** The archive is handed back only when
239
+ * somebody asked for it: when no sink was supplied, or when {@link stream} was touched, since a
240
+ * `PassThrough` nobody drained would otherwise be the only copy. A caller who passed `{filename}`
241
+ * or their own `stream` and never reached for {@link stream} gets `undefined`, and the package is
242
+ * never materialised as a whole: retaining every chunk to concatenate them at the end costs a
243
+ * second full-size buffer on top of the part map and the archive itself, which is exactly the
244
+ * memory the caller passed a sink to avoid. The type says so rather than the prose alone, because
245
+ * a promise that resolves with a value the caller was told to ignore is a promise they will use.
175
246
  *
176
247
  * If assembling or zipping the package fails, the returned promise rejects *and* every stream this
177
248
  * writer was given or handed out is destroyed with that error. A caller piping {@link stream}, or
@@ -179,6 +250,6 @@ export declare class WorkbookStreamWriter {
179
250
  * end; and it is an `error` rather than a clean `end` because the bytes written so far are a
180
251
  * truncated package that must not be read as a whole one.
181
252
  */
182
- commit(): Promise<Uint8Array>;
253
+ commit(): Promise<Uint8Array | undefined>;
183
254
  }
184
255
  export {};