@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,12 +3,17 @@ import { PassThrough } from 'node:stream';
3
3
  import { Zip, ZipDeflate } from 'fflate';
4
4
  import { concat } from '../../bytes.js';
5
5
  import { encodeAddress, tryDecodeCellRef } from '../../core/address.js';
6
+ import { formulaPlacement } from '../../core/array-formula-ranges.js';
7
+ import { formulaNamesInScope } from '../../core/formula.js';
6
8
  import { INTERNAL } from '../../core/internal.js';
7
9
  import { isSharedFormulaValue } from '../../core/value.js';
8
- import { Workbook } from '../../core/workbook.js';
9
- import { AuthoringError } from '../../errors.js';
10
+ import { Workbook, } from '../../core/workbook.js';
11
+ import { AuthoringError, quoted } from '../../errors.js';
10
12
  import { FIXED_ENTRY_MTIME } from '../opc/zip-mtime.js';
11
- import { buildColumnDefaults, buildPackageParts, createStyleRegistry, Extent, renderRow, } from './write.js';
13
+ import { WorkbookMetadataTable } from './cell-metadata.js';
14
+ import { collectNotes } from './comments.js';
15
+ import { buildColumnDefaults, Extent, renderRow, } from './row-xml.js';
16
+ import { buildPackageParts, createStyleRegistry } from './write.js';
12
17
  export class StreamedRow {
13
18
  #cells;
14
19
  #sheet;
@@ -19,6 +24,11 @@ export class StreamedRow {
19
24
  this.#sheet = sheet;
20
25
  this.#number = number;
21
26
  }
27
+ static [INTERNAL] = {
28
+ create(cells, sheet, number) {
29
+ return new StreamedRow(cells, sheet, number);
30
+ },
31
+ };
22
32
  get cells() {
23
33
  return this.#cells;
24
34
  }
@@ -26,7 +36,7 @@ export class StreamedRow {
26
36
  if (this.#committed)
27
37
  return;
28
38
  this.#committed = true;
29
- this.#sheet?.flushRow(this.#number, this.#cells);
39
+ this.#sheet?.[INTERNAL].flushRow(this.#number);
30
40
  }
31
41
  }
32
42
  export class WorksheetStreamWriter {
@@ -39,12 +49,25 @@ export class WorksheetStreamWriter {
39
49
  #flushedRows = [];
40
50
  #flushedNumbers = new Set();
41
51
  #extent = new Extent();
42
- #maxRowOutlineLevel = 0;
43
- constructor(sheet, eager, styles) {
52
+ #rowOutline = new Map();
53
+ #notes = [];
54
+ #formulas = [];
55
+ #dateEpoch;
56
+ #definedNames;
57
+ #cellMetadata;
58
+ constructor(sheet, eager, styles, cellMetadata, dateEpoch, definedNames) {
44
59
  this.#sheet = sheet;
45
60
  this.#eager = eager;
46
61
  this.#styles = styles;
62
+ this.#cellMetadata = cellMetadata;
63
+ this.#dateEpoch = dateEpoch;
64
+ this.#definedNames = definedNames;
47
65
  }
66
+ static [INTERNAL] = {
67
+ create(sheet, eager, styles, cellMetadata, dateEpoch, definedNames) {
68
+ return new WorksheetStreamWriter(sheet, eager, styles, cellMetadata, dateEpoch, definedNames);
69
+ },
70
+ };
48
71
  get name() {
49
72
  return this.#sheet.name;
50
73
  }
@@ -54,14 +77,14 @@ export class WorksheetStreamWriter {
54
77
  addRow(values) {
55
78
  this.#assertOpen();
56
79
  if (!this.#eager)
57
- return new StreamedRow(this.#sheet.addRow(values), null, 0);
80
+ return StreamedRow[INTERNAL].create(this.#sheet.addRow(values), null, 0);
58
81
  const number = this.#nextRowNumber();
59
- return new StreamedRow(this.#placeRow(number, values), this, number);
82
+ return StreamedRow[INTERNAL].create(this.#placeRow(number, values), this, number);
60
83
  }
61
84
  addRows(rows) {
62
85
  this.#assertOpen();
63
86
  if (!this.#eager)
64
- return this.#sheet.addRows(rows).map((cells) => new StreamedRow(cells, null, 0));
87
+ return this.#sheet.addRows(rows).map((cells) => StreamedRow[INTERNAL].create(cells, null, 0));
65
88
  return rows.map((values) => this.addRow(values));
66
89
  }
67
90
  #nextRowNumber() {
@@ -77,45 +100,61 @@ export class WorksheetStreamWriter {
77
100
  });
78
101
  return cells;
79
102
  }
80
- flushRow(number, cells) {
103
+ #flushRow(number) {
104
+ const row = this.#sheet.getRow(number);
105
+ const { cells } = row;
81
106
  for (const cell of cells) {
82
107
  if (isSharedFormulaValue(cell.value)) {
83
- throw new AuthoringError(`row ${number} of streamed sheet "${this.#sheet.name}" carries a shared-formula cell; a ` +
108
+ throw new AuthoringError(`row ${number} of streamed sheet ${quoted(this.#sheet.name)} carries a shared-formula cell; a ` +
84
109
  'committed row is finalised before the sheet is planned, so author shared formulas through ' +
85
110
  'getCell (leaving the row uncommitted) instead');
86
111
  }
87
112
  }
88
113
  this.#columnDefaults ??= buildColumnDefaults(this.#sheet);
89
- const properties = this.#sheet.getRow(number).properties;
90
- this.#maxRowOutlineLevel = Math.max(this.#maxRowOutlineLevel, properties?.outlineLevel ?? 0);
91
- const { xml, minCol, maxCol } = renderRow({ number, cells, properties }, {
114
+ const { properties } = row;
115
+ this.#rowOutline.set(number, {
116
+ outlineLevel: properties?.outlineLevel ?? 0,
117
+ hidden: properties?.hidden ?? false,
118
+ });
119
+ this.#notes.push(...collectNotes(cells));
120
+ for (const cell of cells) {
121
+ const placement = formulaPlacement(cell.address, cell.col, cell.row, cell.value);
122
+ if (placement !== undefined)
123
+ this.#formulas.push(placement);
124
+ }
125
+ const { xml, attrs, minCol, maxCol } = renderRow({ number, cells, properties }, {
92
126
  columnDefaults: this.#columnDefaults,
93
127
  styles: this.#styles,
94
128
  sharedStrings: null,
95
129
  sharedRoles: new Map(),
96
130
  collapsedSummaries: new Set(),
131
+ dateEpoch: this.#dateEpoch,
132
+ formulaNames: formulaNamesInScope(this.#definedNames, this.#sheet.name),
133
+ cellMetadata: this.#cellMetadata,
97
134
  });
98
135
  if (xml !== '') {
99
- this.#flushedRows.push({ number, xml });
136
+ this.#flushedRows.push({ number, xml, attrs });
100
137
  this.#extent.add(number, minCol, maxCol);
101
138
  }
102
139
  this.#flushedNumbers.add(number);
103
140
  this.#sheet[INTERNAL].evictRow(number);
104
141
  }
105
- flushedSheet() {
142
+ #flushedSheet() {
106
143
  if (this.#flushedRows.length === 0)
107
144
  return undefined;
108
145
  return {
109
146
  rows: this.#flushedRows,
110
147
  extent: this.#extent,
111
- maxRowOutlineLevel: this.#maxRowOutlineLevel,
148
+ rowOutline: this.#rowOutline,
149
+ notes: this.#notes,
150
+ formulas: this.#formulas,
112
151
  };
113
152
  }
114
153
  getCell(reference) {
115
154
  this.#assertOpen();
116
155
  const target = tryDecodeCellRef(reference);
117
156
  if (target !== undefined && this.#flushedNumbers.has(target.row)) {
118
- throw new AuthoringError(`cell ${reference} of streamed sheet "${this.#sheet.name}" is in row ${target.row}, which is ` +
157
+ throw new AuthoringError(`cell ${reference} of streamed sheet ${quoted(this.#sheet.name)} is in row ${target.row}, which is ` +
119
158
  'already committed: its bytes are written and its cells released, so this value could only ' +
120
159
  'be emitted as a second row with that number. Style a row before committing it.');
121
160
  }
@@ -125,6 +164,10 @@ export class WorksheetStreamWriter {
125
164
  this.#assertOpen();
126
165
  this.#sheet.addDataValidation(sqref, rule, options);
127
166
  }
167
+ addHyperlink(link) {
168
+ this.#assertOpen();
169
+ this.#sheet.addHyperlink(link);
170
+ }
128
171
  addConditionalFormatting(formatting) {
129
172
  this.#assertOpen();
130
173
  this.#sheet.addConditionalFormatting(formatting);
@@ -153,9 +196,15 @@ export class WorksheetStreamWriter {
153
196
  get model() {
154
197
  return this.#sheet;
155
198
  }
199
+ [INTERNAL] = {
200
+ flushRow: (number) => {
201
+ this.#flushRow(number);
202
+ },
203
+ flushedSheet: () => this.#flushedSheet(),
204
+ };
156
205
  #assertOpen() {
157
206
  if (this.#committed) {
158
- throw new AuthoringError(`worksheet "${this.#sheet.name}" is already committed: its rows are finalised and no more can be added`);
207
+ throw new AuthoringError(`worksheet ${quoted(this.#sheet.name)} is already committed: its rows are finalised and no more can be added`);
159
208
  }
160
209
  }
161
210
  }
@@ -165,6 +214,7 @@ export class WorkbookStreamWriter {
165
214
  #writeOptions;
166
215
  #sink;
167
216
  #styles;
217
+ #cellMetadata = new WorkbookMetadataTable();
168
218
  #eager;
169
219
  #stream;
170
220
  #committed = false;
@@ -172,6 +222,8 @@ export class WorkbookStreamWriter {
172
222
  constructor(options = {}) {
173
223
  this.#writeOptions = { useSharedStrings: options.useSharedStrings ?? false };
174
224
  this.#eager = !this.#writeOptions.useSharedStrings;
225
+ if (options.dateEpoch !== undefined)
226
+ this.#workbook.dateEpoch = options.dateEpoch;
175
227
  this.#styles = createStyleRegistry(this.#workbook);
176
228
  if (options.stream && options.filename) {
177
229
  throw new AuthoringError('provide either a stream or a filename to the streaming writer, not both');
@@ -192,7 +244,7 @@ export class WorkbookStreamWriter {
192
244
  }
193
245
  addWorksheet(name, options = {}) {
194
246
  this.#assertOpen('no more worksheets can be added');
195
- const sheet = new WorksheetStreamWriter(this.#workbook.addWorksheet(name, options), this.#eager, this.#styles);
247
+ const sheet = WorksheetStreamWriter[INTERNAL].create(this.#workbook.addWorksheet(name, options), this.#eager, this.#styles, this.#cellMetadata, this.#workbook.dateEpoch, this.#workbook.definedNames);
196
248
  this.#sheets.push(sheet);
197
249
  return sheet;
198
250
  }
@@ -205,23 +257,25 @@ export class WorkbookStreamWriter {
205
257
  this.#workbook.fullCalcOnLoad = true;
206
258
  const flushed = new Map();
207
259
  for (const sheet of this.#sheets) {
208
- const sheetFlushed = sheet.flushedSheet();
260
+ const sheetFlushed = sheet[INTERNAL].flushedSheet();
209
261
  if (sheetFlushed)
210
262
  flushed.set(sheet.model, sheetFlushed);
211
263
  }
212
264
  const owned = this.#stream;
213
265
  const sink = this.#sink;
266
+ const collect = sink === undefined || owned !== undefined;
214
267
  const sinkSettled = sink ? settleOnFinish(sink) : undefined;
215
268
  try {
216
269
  const parts = buildPackageParts(this.#workbook, {
217
270
  ...this.#writeOptions,
218
271
  styles: this.#styles,
272
+ cellMetadata: this.#cellMetadata,
219
273
  flushed,
220
274
  });
221
275
  const bytes = await streamZipPackage(parts, (chunk) => {
222
276
  owned?.write(chunk);
223
277
  sink?.write(chunk);
224
- });
278
+ }, collect);
225
279
  owned?.end();
226
280
  sink?.end();
227
281
  await sinkSettled;
@@ -247,7 +301,7 @@ function settleOnFinish(sink) {
247
301
  sink.once('error', reject);
248
302
  });
249
303
  }
250
- function streamZipPackage(parts, onChunk) {
304
+ function streamZipPackage(parts, onChunk, collect) {
251
305
  return new Promise((resolve, reject) => {
252
306
  const collected = [];
253
307
  const zip = new Zip((err, chunk, final) => {
@@ -255,10 +309,11 @@ function streamZipPackage(parts, onChunk) {
255
309
  reject(err);
256
310
  return;
257
311
  }
258
- collected.push(chunk);
312
+ if (collect)
313
+ collected.push(chunk);
259
314
  onChunk(chunk);
260
315
  if (final)
261
- resolve(concat(collected));
316
+ resolve(collect ? concat(collected) : undefined);
262
317
  });
263
318
  for (const [name, data] of Object.entries(parts)) {
264
319
  const entry = new ZipDeflate(name, { level: 6 });
@@ -1,15 +1,15 @@
1
1
  import type { Workbook } from '../../core/workbook.ts';
2
2
  import type { Worksheet } from '../../core/worksheet.ts';
3
+ import { WorkbookMetadataTable } from './cell-metadata.ts';
4
+ import type { FlushedSheet } from './row-xml.ts';
3
5
  import { StyleRegistry } from './styles.ts';
4
- import { type FlushedSheet } from './worksheet-xml.ts';
5
- export { buildColumnDefaults, Extent, type FlushedSheet, type RowRenderContext, renderRow, } from './worksheet-xml.ts';
6
6
  /** Options controlling how {@link writeXlsx} serialises a workbook. */
7
7
  export interface WriteOptions {
8
8
  /**
9
- * Pool plain string cell values into a shared-strings table (`xl/sharedStrings.xml`) that cells
10
- * reference by index, rather than storing each string inline in its cell. Deduplicates repeated
11
- * text and matches Excel's own storage; off by default, which keeps strings inline and omits the
12
- * part. Rich-text values stay inline regardless, so their run formatting is unaffected.
9
+ * Pool string and rich-text cell values into a shared-strings table (`xl/sharedStrings.xml`) that
10
+ * cells reference by index, rather than storing each inline in its cell. Deduplicates repeated text
11
+ * and matches Excel's own storage; a rich value is pooled as a `<si>` of its runs, so its formatting
12
+ * survives. Off by default, which keeps strings inline and omits the part.
13
13
  */
14
14
  readonly useSharedStrings?: boolean;
15
15
  }
@@ -28,6 +28,12 @@ export interface InternalWriteOptions extends WriteOptions {
28
28
  * so its output is unchanged.
29
29
  */
30
30
  readonly styles?: StyleRegistry;
31
+ /**
32
+ * The workbook metadata to record into, in place of a fresh table, for the reason {@link styles} is
33
+ * shared: a row the streaming writer rendered eagerly may already point a dynamic-array formula or a
34
+ * rich-value error at the parts this table decides whether to emit.
35
+ */
36
+ readonly cellMetadata?: WorkbookMetadataTable;
31
37
  /**
32
38
  * Per-sheet rows already serialised and evicted from the model by the streaming writer, keyed by
33
39
  * the model worksheet. Their XML is emitted ahead of the sheet's remaining live rows and their