@shbernal/ts-xlsx 3.1.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 (214) hide show
  1. package/README.md +30 -23
  2. package/dist/bytes.d.ts +3 -2
  3. package/dist/core/address.d.ts +36 -0
  4. package/dist/core/address.js +47 -9
  5. package/dist/core/array-formula-ranges.d.ts +33 -0
  6. package/dist/core/array-formula-ranges.js +62 -0
  7. package/dist/core/color-resolution.js +2 -2
  8. package/dist/core/column.js +3 -2
  9. package/dist/core/comment-thread.d.ts +7 -3
  10. package/dist/core/conditional-formatting-overlay.d.ts +9 -0
  11. package/dist/core/conditional-formatting-overlay.js +28 -1
  12. package/dist/core/conditional-formatting.d.ts +98 -10
  13. package/dist/core/conditional-formatting.js +42 -1
  14. package/dist/core/data-validation-overlay.d.ts +5 -0
  15. package/dist/core/data-validation-overlay.js +15 -0
  16. package/dist/core/data-validation.d.ts +16 -0
  17. package/dist/core/data-validation.js +15 -0
  18. package/dist/core/date-format.js +14 -4
  19. package/dist/core/date.js +1 -1
  20. package/dist/core/formula-references.d.ts +26 -0
  21. package/dist/core/formula-references.js +173 -0
  22. package/dist/core/formula-scan.d.ts +2 -0
  23. package/dist/core/formula-scan.js +58 -0
  24. package/dist/core/formula.d.ts +51 -18
  25. package/dist/core/formula.js +77 -86
  26. package/dist/core/function-values.d.ts +4 -0
  27. package/dist/core/function-values.js +58 -0
  28. package/dist/core/future-functions.d.ts +3 -0
  29. package/dist/core/{modern-functions.js → future-functions.js} +119 -88
  30. package/dist/core/grid-edits.d.ts +28 -0
  31. package/dist/core/grid-edits.js +193 -25
  32. package/dist/core/hyperlink.d.ts +39 -0
  33. package/dist/core/hyperlink.js +88 -0
  34. package/dist/core/image.d.ts +36 -5
  35. package/dist/core/image.js +9 -0
  36. package/dist/core/internal.d.ts +3 -1
  37. package/dist/core/limits.d.ts +5 -3
  38. package/dist/core/merge.d.ts +13 -0
  39. package/dist/core/merge.js +15 -1
  40. package/dist/core/page-setup.d.ts +26 -11
  41. package/dist/core/pivot-table.d.ts +49 -10
  42. package/dist/core/pivot-table.js +55 -21
  43. package/dist/core/protection.d.ts +66 -4
  44. package/dist/core/protection.js +4 -0
  45. package/dist/core/row.js +3 -2
  46. package/dist/core/structured-reference.d.ts +7 -0
  47. package/dist/core/structured-reference.js +7 -0
  48. package/dist/core/table.d.ts +38 -8
  49. package/dist/core/table.js +37 -7
  50. package/dist/core/theme.d.ts +2 -0
  51. package/dist/core/theme.js +4 -1
  52. package/dist/core/value.d.ts +51 -28
  53. package/dist/core/value.js +15 -12
  54. package/dist/core/workbook-styles.d.ts +17 -1
  55. package/dist/core/workbook-styles.js +4 -0
  56. package/dist/core/workbook-theme.js +5 -3
  57. package/dist/core/workbook.d.ts +20 -3
  58. package/dist/core/workbook.js +26 -5
  59. package/dist/core/worksheet-merges.d.ts +9 -4
  60. package/dist/core/worksheet-merges.js +17 -11
  61. package/dist/core/worksheet-model.d.ts +1 -1
  62. package/dist/core/worksheet-model.js +4 -0
  63. package/dist/core/worksheet-pictures.d.ts +3 -3
  64. package/dist/core/worksheet-pictures.js +7 -6
  65. package/dist/core/worksheet.d.ts +110 -21
  66. package/dist/core/worksheet.js +174 -49
  67. package/dist/entries/core.d.ts +7 -5
  68. package/dist/entries/core.js +4 -3
  69. package/dist/entries/errors.d.ts +1 -0
  70. package/dist/entries/errors.js +1 -0
  71. package/dist/errors.js +1 -1
  72. package/dist/io/cell-metadata/metadata.d.ts +42 -0
  73. package/dist/io/cell-metadata/metadata.js +35 -0
  74. package/dist/io/cell-metadata/rich-values.d.ts +11 -0
  75. package/dist/io/cell-metadata/rich-values.js +80 -0
  76. package/dist/io/csv/delimiter.d.ts +14 -2
  77. package/dist/io/csv/delimiter.js +12 -0
  78. package/dist/io/csv/errors.d.ts +14 -0
  79. package/dist/io/csv/errors.js +5 -0
  80. package/dist/io/csv/read.d.ts +6 -1
  81. package/dist/io/csv/read.js +46 -24
  82. package/dist/io/csv/write.d.ts +10 -3
  83. package/dist/io/csv/write.js +16 -7
  84. package/dist/io/opc/part-paths.js +4 -4
  85. package/dist/io/opc/read-opc.d.ts +4 -0
  86. package/dist/io/opc/read-opc.js +10 -4
  87. package/dist/io/opc/strict-relationships.d.ts +2 -0
  88. package/dist/io/opc/strict-relationships.js +12 -0
  89. package/dist/io/read-policy/column-budget.d.ts +26 -0
  90. package/dist/io/{xlsx → read-policy}/column-budget.js +4 -8
  91. package/dist/io/read-policy/read-repair.d.ts +74 -0
  92. package/dist/io/read-policy/read-repair.js +119 -0
  93. package/dist/io/style/cell-style-resolution.d.ts +25 -0
  94. package/dist/io/style/cell-style-resolution.js +30 -0
  95. package/dist/io/xlsb/formula.js +4 -2
  96. package/dist/io/xlsb/ptg-functions.js +110 -0
  97. package/dist/io/xlsb/read-metadata.d.ts +7 -0
  98. package/dist/io/xlsb/read-metadata.js +69 -0
  99. package/dist/io/xlsb/read-worksheet.d.ts +6 -0
  100. package/dist/io/xlsb/read-worksheet.js +95 -37
  101. package/dist/io/xlsb/read.js +26 -8
  102. package/dist/io/xlsb/record-types.d.ts +13 -0
  103. package/dist/io/xlsb/record-types.js +13 -0
  104. package/dist/io/xlsb/sheet-protection.d.ts +20 -0
  105. package/dist/io/xlsb/sheet-protection.js +60 -0
  106. package/dist/io/xlsx/cell-accumulator.d.ts +20 -12
  107. package/dist/io/xlsx/cell-accumulator.js +49 -19
  108. package/dist/io/xlsx/cell-metadata.d.ts +39 -0
  109. package/dist/io/xlsx/cell-metadata.js +162 -0
  110. package/dist/io/xlsx/cell-value.d.ts +16 -4
  111. package/dist/io/xlsx/cell-value.js +38 -21
  112. package/dist/io/xlsx/color-xml.js +1 -1
  113. package/dist/io/xlsx/column-span.d.ts +11 -0
  114. package/dist/io/xlsx/column-span.js +9 -0
  115. package/dist/io/xlsx/comments.d.ts +3 -28
  116. package/dist/io/xlsx/comments.js +3 -65
  117. package/dist/io/xlsx/conditional-formatting.d.ts +42 -25
  118. package/dist/io/xlsx/conditional-formatting.js +424 -129
  119. package/dist/io/xlsx/data-validation.d.ts +12 -7
  120. package/dist/io/xlsx/data-validation.js +41 -29
  121. package/dist/io/xlsx/edit-vba.js +43 -36
  122. package/dist/io/xlsx/hyperlinks.d.ts +16 -50
  123. package/dist/io/xlsx/hyperlinks.js +8 -37
  124. package/dist/io/xlsx/images.d.ts +49 -16
  125. package/dist/io/xlsx/images.js +145 -44
  126. package/dist/io/xlsx/namespaces.d.ts +8 -0
  127. package/dist/io/xlsx/namespaces.js +4 -0
  128. package/dist/io/xlsx/package-plan.d.ts +48 -15
  129. package/dist/io/xlsx/package-plan.js +46 -9
  130. package/dist/io/xlsx/part-names.d.ts +6 -8
  131. package/dist/io/xlsx/part-names.js +3 -7
  132. package/dist/io/xlsx/pivot.d.ts +5 -5
  133. package/dist/io/xlsx/pivot.js +23 -22
  134. package/dist/io/xlsx/preserved-splices.d.ts +6 -0
  135. package/dist/io/xlsx/preserved-splices.js +74 -0
  136. package/dist/io/xlsx/read-comments.d.ts +29 -0
  137. package/dist/io/xlsx/read-comments.js +75 -0
  138. package/dist/io/xlsx/read-parts.d.ts +2 -2
  139. package/dist/io/xlsx/read-parts.js +44 -37
  140. package/dist/io/xlsx/read-pivot.js +9 -3
  141. package/dist/io/xlsx/read-rich-runs.d.ts +8 -5
  142. package/dist/io/xlsx/read-rich-runs.js +18 -1
  143. package/dist/io/xlsx/read-rows.d.ts +18 -7
  144. package/dist/io/xlsx/read-rows.js +47 -37
  145. package/dist/io/xlsx/read-styles.d.ts +0 -25
  146. package/dist/io/xlsx/read-styles.js +39 -34
  147. package/dist/io/xlsx/read-workbook-xml.d.ts +6 -0
  148. package/dist/io/xlsx/read-workbook-xml.js +9 -4
  149. package/dist/io/xlsx/read-worksheet.d.ts +8 -3
  150. package/dist/io/xlsx/read-worksheet.js +45 -23
  151. package/dist/io/xlsx/read.d.ts +0 -4
  152. package/dist/io/xlsx/read.js +17 -21
  153. package/dist/io/xlsx/relationships.d.ts +3 -0
  154. package/dist/io/xlsx/relationships.js +4 -0
  155. package/dist/io/xlsx/row-position.d.ts +3 -1
  156. package/dist/io/xlsx/row-xml.d.ts +18 -7
  157. package/dist/io/xlsx/row-xml.js +54 -35
  158. package/dist/io/xlsx/sheet-properties.js +68 -42
  159. package/dist/io/xlsx/strict-parts.d.ts +7 -0
  160. package/dist/io/xlsx/strict-parts.js +171 -0
  161. package/dist/io/xlsx/style-elements.d.ts +0 -2
  162. package/dist/io/xlsx/style-elements.js +9 -29
  163. package/dist/io/xlsx/styles.d.ts +5 -0
  164. package/dist/io/xlsx/styles.js +11 -5
  165. package/dist/io/xlsx/tables.d.ts +10 -2
  166. package/dist/io/xlsx/tables.js +49 -42
  167. package/dist/io/xlsx/theme-xml.d.ts +6 -0
  168. package/dist/io/xlsx/theme-xml.js +16 -19
  169. package/dist/io/xlsx/threaded-comments.d.ts +6 -1
  170. package/dist/io/xlsx/threaded-comments.js +14 -7
  171. package/dist/io/xlsx/workbook-xml.d.ts +13 -24
  172. package/dist/io/xlsx/workbook-xml.js +15 -33
  173. package/dist/io/xlsx/worksheet-xml.d.ts +5 -2
  174. package/dist/io/xlsx/worksheet-xml.js +37 -69
  175. package/dist/io/xlsx/write-stream.d.ts +28 -6
  176. package/dist/io/xlsx/write-stream.js +42 -17
  177. package/dist/io/xlsx/write.d.ts +11 -4
  178. package/dist/io/xlsx/write.js +153 -90
  179. package/dist/rel-type.d.ts +9 -0
  180. package/dist/rel-type.js +3 -0
  181. package/dist/vba/bytes.d.ts +2 -0
  182. package/dist/vba/bytes.js +11 -0
  183. package/dist/vba/cfb-format.d.ts +47 -0
  184. package/dist/vba/cfb-format.js +34 -0
  185. package/dist/vba/cfb-writer.d.ts +1 -2
  186. package/dist/vba/cfb-writer.js +33 -36
  187. package/dist/vba/cfb.d.ts +9 -4
  188. package/dist/vba/cfb.js +55 -43
  189. package/dist/vba/dir-records.d.ts +6 -0
  190. package/dist/vba/dir-records.js +10 -2
  191. package/dist/vba/errors.d.ts +4 -4
  192. package/dist/vba/index.d.ts +0 -2
  193. package/dist/vba/index.js +0 -2
  194. package/dist/vba/ms-ovba.d.ts +6 -2
  195. package/dist/vba/ms-ovba.js +15 -6
  196. package/dist/vba/project-editor.js +102 -87
  197. package/dist/vba/project.d.ts +4 -0
  198. package/dist/vba/project.js +12 -6
  199. package/dist/vba/vba-encoding.d.ts +4 -10
  200. package/dist/vba/vba-encoding.js +2 -15
  201. package/dist/xml/xml-read.d.ts +29 -1
  202. package/dist/xml/xml-read.js +56 -0
  203. package/dist/xml/xml-scan.d.ts +13 -0
  204. package/dist/xml/xml-scan.js +58 -7
  205. package/dist/xml/xml.d.ts +33 -1
  206. package/dist/xml/xml.js +22 -0
  207. package/package.json +5 -4
  208. package/skills/ts-xlsx-upstream/SKILL.md +21 -13
  209. package/dist/core/modern-functions.d.ts +0 -1
  210. package/dist/io/xlsx/cell-style-resolution.d.ts +0 -25
  211. package/dist/io/xlsx/cell-style-resolution.js +0 -29
  212. package/dist/io/xlsx/column-budget.d.ts +0 -26
  213. package/dist/io/xlsx/read-repair.d.ts +0 -26
  214. package/dist/io/xlsx/read-repair.js +0 -39
@@ -1,12 +1,15 @@
1
1
  import { AuthoringError } from '../errors.js';
2
2
  import { tokenSet } from '../token-set.js';
3
- import { assertAxisInBounds, decodeCellRef, encodeAddress, tryDecodeCellRef } from './address.js';
3
+ import { assertAxisInBounds, boundedRect, decodeCellRef, encodeAddress, encodeRange, MAX_ROW, tryDecodeAnchoredRange, tryDecodeCellRef, tryDecodeRange, } from './address.js';
4
+ import { arrayRangeConflicts, formulaPlacement, } from './array-formula-ranges.js';
4
5
  import { canonicalizeAutoFilter } from './autofilter.js';
5
6
  import { applyCellStyle, Cell, copyCellContent } from './cell.js';
6
7
  import { Column } from './column.js';
7
8
  import { ConditionalFormattingOverlay } from './conditional-formatting-overlay.js';
8
9
  import { DataValidationOverlay } from './data-validation-overlay.js';
10
+ import { translateFormula } from './formula-references.js';
9
11
  import { GridEdits } from './grid-edits.js';
12
+ import { HyperlinkOverlay } from './hyperlink.js';
10
13
  import { INTERNAL } from './internal.js';
11
14
  import { clearCoveredValues } from './merge.js';
12
15
  import { PivotTable } from './pivot-table.js';
@@ -16,6 +19,7 @@ import { buildRowCells, positionalPlacements, rowPlacements } from './row-input.
16
19
  import { Row } from './row.js';
17
20
  import { Table } from './table.js';
18
21
  import { UsedExtent } from './used-extent.js';
22
+ import { isArrayFormulaValue, isFormulaValue, isSharedFormulaValue, } from './value.js';
19
23
  import { WorksheetComments } from './worksheet-comments.js';
20
24
  import { WorksheetMerges } from './worksheet-merges.js';
21
25
  import { WORKSHEET_MODEL_FACETS } from './worksheet-model.js';
@@ -51,7 +55,9 @@ export class Worksheet {
51
55
  #preservedReferences = [];
52
56
  #dataValidations = new DataValidationOverlay();
53
57
  #conditionalFormattings = new ConditionalFormattingOverlay();
58
+ #hyperlinks = new HyperlinkOverlay();
54
59
  #protection;
60
+ #formulaHost;
55
61
  #autoFilter;
56
62
  #edits;
57
63
  #extent;
@@ -71,10 +77,17 @@ export class Worksheet {
71
77
  columns: this.#columns,
72
78
  merges: this.#merges,
73
79
  tables: this.#tables,
80
+ pivotTables: this.#pivotTables,
81
+ loadedPivotTables: this.#loadedPivotTables,
74
82
  images: this.#images.anchors,
75
83
  dataValidations: this.#dataValidations,
76
84
  conditionalFormattings: this.#conditionalFormattings,
85
+ hyperlinks: this.#hyperlinks,
77
86
  comments: this.#comments,
87
+ rowBreaks: this.rowBreaks,
88
+ columnBreaks: this.columnBreaks,
89
+ sheetName: () => this.name,
90
+ formulaHost: () => this.#formulaHost,
78
91
  autoFilter: {
79
92
  get: () => this.#autoFilter,
80
93
  set: (next) => {
@@ -146,7 +159,7 @@ export class Worksheet {
146
159
  }
147
160
  addTable(options) {
148
161
  const table = new Table(options, {
149
- holdsValue: (row, col) => this.hasCell(row, col) && this.#cellAt(row, col).value != null,
162
+ holdsValue: (row, col) => this.#rows.get(row)?.get(col)?.value != null,
150
163
  writeCell: (row, col, value, style) => {
151
164
  const cell = this.#cellAt(row, col);
152
165
  cell.value = value;
@@ -184,11 +197,11 @@ export class Worksheet {
184
197
  commentThreadAt(reference) {
185
198
  return this.#comments.at(reference);
186
199
  }
187
- addImage(imageId, anchor) {
188
- this.#images.add(imageId, anchor);
200
+ addImage(imageId, anchor, properties) {
201
+ this.#images.add(imageId, anchor, properties);
189
202
  }
190
- addImageAnchor(imageId, anchor) {
191
- this.#images.addAnchor(imageId, anchor);
203
+ addImageAnchor(imageId, anchor, properties) {
204
+ this.#images.addAnchor(imageId, anchor, properties);
192
205
  }
193
206
  removeImage(imageId) {
194
207
  this.#images.remove(imageId);
@@ -246,12 +259,26 @@ export class Worksheet {
246
259
  const cell = tryDecodeCellRef(reference);
247
260
  return cell === undefined ? undefined : this.#dataValidations.at(cell.col, cell.row);
248
261
  }
262
+ addHyperlink(link) {
263
+ this.#hyperlinks.add(link);
264
+ }
265
+ removeHyperlink(ref) {
266
+ return this.#hyperlinks.remove(ref);
267
+ }
268
+ get hyperlinks() {
269
+ return this.#hyperlinks.entries;
270
+ }
271
+ hyperlinkAt(reference) {
272
+ const cell = tryDecodeCellRef(reference);
273
+ return cell === undefined ? undefined : this.#hyperlinks.at(cell.col, cell.row);
274
+ }
249
275
  spliceRows(start, count, ...inserts) {
250
276
  assertStartAndCount('splice', 'row', start, count);
277
+ assertSpliceFits('row', start, inserts.length);
278
+ this.#assertArraysSurvive('row', start, count, inserts.length);
251
279
  const inserted = inserts.map((values, i) => buildRowCells(start + i, values, this.#columns));
252
280
  this.#edits.spliceRows(start, count, inserted);
253
- this.#merges.invalidate();
254
- this.#extent.invalidate();
281
+ this.#afterStructuralEdit();
255
282
  }
256
283
  insertRow(pos, values) {
257
284
  this.spliceRows(pos, 0, values);
@@ -260,15 +287,21 @@ export class Worksheet {
260
287
  return this.addRows([values])[0] ?? [];
261
288
  }
262
289
  addRows(rows) {
263
- let number = this.rowCount;
264
- return rows.map((values) => {
265
- number += 1;
266
- return rowPlacements(values, this.#columns).map(([col, value]) => {
267
- const cell = this.#cellAt(number, col);
268
- cell.value = value;
269
- return cell;
270
- });
290
+ const first = this.rowCount + 1;
291
+ const planned = rows.map((values, i) => {
292
+ const row = first + i;
293
+ const placements = rowPlacements(values, this.#columns);
294
+ for (const [col] of placements) {
295
+ assertAxisInBounds('row', row);
296
+ assertAxisInBounds('column', col);
297
+ }
298
+ return { row, placements };
271
299
  });
300
+ return planned.map(({ row, placements }) => placements.map(([col, value]) => {
301
+ const cell = this.#cellAt(row, col);
302
+ cell.value = value;
303
+ return cell;
304
+ }));
272
305
  }
273
306
  freeze(ySplit = 1, xSplit = 0) {
274
307
  if (!Number.isInteger(ySplit) || ySplit < 0 || !Number.isInteger(xSplit) || xSplit < 0) {
@@ -278,10 +311,11 @@ export class Worksheet {
278
311
  this.unfreeze();
279
312
  return;
280
313
  }
314
+ const topLeftCell = encodeAddress(xSplit + 1, ySplit + 1);
281
315
  this.view.state = 'frozen';
282
316
  this.view.xSplit = xSplit;
283
317
  this.view.ySplit = ySplit;
284
- this.view.topLeftCell = encodeAddress(xSplit + 1, ySplit + 1);
318
+ this.view.topLeftCell = topLeftCell;
285
319
  }
286
320
  unfreeze() {
287
321
  this.view.state = 'normal';
@@ -292,16 +326,19 @@ export class Worksheet {
292
326
  duplicateRow(start, options = {}) {
293
327
  const { count = 1, insert = true } = options;
294
328
  assertStartAndCount('duplicate', 'row', start, count);
295
- const source = this.#rows.get(start);
329
+ assertSpliceFits('row', start + 1, count);
330
+ if (insert)
331
+ this.#assertArraysSurvive('row', start + 1, 0, count);
332
+ else
333
+ this.#assertArraysSurvive('row', start + 1, count, count);
296
334
  const sourceProperties = this.#rowProperties.get(start);
297
335
  const snapshot = (destRow) => {
298
336
  const row = new Map();
299
- if (source) {
300
- for (const [col, cell] of source) {
301
- const copy = new Cell(destRow, col);
302
- copyCellContent(cell, copy);
303
- row.set(col, copy);
304
- }
337
+ for (const [col, cell] of this.#rows.get(start) ?? []) {
338
+ const copy = new Cell(destRow, col);
339
+ copyCellContent(cell, copy);
340
+ copy.value = filledDown(cell.value, destRow - start);
341
+ row.set(col, copy);
305
342
  }
306
343
  return row;
307
344
  };
@@ -312,23 +349,23 @@ export class Worksheet {
312
349
  this.#rowProperties.set(destRow, { ...sourceProperties });
313
350
  };
314
351
  if (insert) {
315
- const copies = Array.from({ length: count }, () => snapshot(start));
316
- this.#edits.spliceRows(start + 1, 0, copies);
317
- this.#merges.invalidate();
318
- }
319
- else {
320
- for (let i = 1; i <= count; i++)
321
- this.#rows.set(start + i, snapshot(start + i));
352
+ const blanks = Array.from({ length: count }, () => new Map());
353
+ this.#edits.spliceRows(start + 1, 0, blanks);
322
354
  }
355
+ for (let i = 1; i <= count; i++)
356
+ this.#rows.set(start + i, snapshot(start + i));
323
357
  for (let i = 1; i <= count; i++)
324
358
  copyProperties(start + i);
325
- this.#extent.invalidate();
359
+ for (let i = 1; i <= count; i++)
360
+ this.#hyperlinks.copyRow(start, start + i);
361
+ this.#afterStructuralEdit();
326
362
  }
327
363
  spliceColumns(start, count, ...inserts) {
328
364
  assertStartAndCount('splice', 'column', start, count);
365
+ assertSpliceFits('column', start, inserts.length);
366
+ this.#assertArraysSurvive('column', start, count, inserts.length);
329
367
  this.#edits.spliceColumns(start, count, inserts);
330
- this.#merges.invalidate();
331
- this.#extent.invalidate();
368
+ this.#afterStructuralEdit();
332
369
  }
333
370
  insertColumn(pos, values) {
334
371
  this.spliceColumns(pos, 0, values);
@@ -337,15 +374,21 @@ export class Worksheet {
337
374
  return this.addColumns([values])[0] ?? [];
338
375
  }
339
376
  addColumns(columns) {
340
- let index = this.columnCount;
341
- return columns.map((values) => {
342
- index += 1;
343
- return positionalPlacements(values).map(([row, value]) => {
344
- const cell = this.#cellAt(row, index);
345
- cell.value = value;
346
- return cell;
347
- });
377
+ const first = this.columnCount + 1;
378
+ const planned = columns.map((values, i) => {
379
+ const col = first + i;
380
+ const placements = positionalPlacements(values);
381
+ for (const [row] of placements) {
382
+ assertAxisInBounds('column', col);
383
+ assertAxisInBounds('row', row);
384
+ }
385
+ return { col, placements };
348
386
  });
387
+ return planned.map(({ col, placements }) => placements.map(([row, value]) => {
388
+ const cell = this.#cellAt(row, col);
389
+ cell.value = value;
390
+ return cell;
391
+ }));
349
392
  }
350
393
  get model() {
351
394
  const model = {};
@@ -353,6 +396,56 @@ export class Worksheet {
353
396
  model[facet.key] = facet.read(this);
354
397
  return model;
355
398
  }
399
+ #afterStructuralEdit() {
400
+ this.#extent.invalidate();
401
+ this.#blockObstructedSpills();
402
+ }
403
+ #blockObstructedSpills() {
404
+ const cells = [...this.#rows.values()].flatMap((cols) => [...cols.values()]);
405
+ if (!cells.some(({ value }) => isArrayFormulaValue(value) && value.dynamic === true))
406
+ return;
407
+ const placements = [];
408
+ for (const cell of cells) {
409
+ if (typeof cell.value !== 'object' || cell.value === null)
410
+ continue;
411
+ const placement = formulaPlacement(cell.address, cell.col, cell.row, cell.value);
412
+ if (placement !== undefined)
413
+ placements.push(placement);
414
+ }
415
+ for (const { array } of arrayRangeConflicts(placements)) {
416
+ const cell = this.#rows.get(array.row)?.get(array.col);
417
+ if (cell === undefined)
418
+ continue;
419
+ const value = cell.value;
420
+ if (!isArrayFormulaValue(value) || value.dynamic !== true)
421
+ continue;
422
+ cell.value = { ...value, ref: cell.address, result: { error: '#SPILL!' } };
423
+ }
424
+ }
425
+ #assertArraysSurvive(axis, start, count, insertCount) {
426
+ if (count === 0 && insertCount === 0)
427
+ return;
428
+ const end = start + count - 1;
429
+ for (const cols of this.#rows.values()) {
430
+ for (const cell of cols.values()) {
431
+ const value = cell.value;
432
+ if (!isArrayFormulaValue(value) || value.dynamic === true)
433
+ continue;
434
+ const range = tryDecodeAnchoredRange(value.ref, cell.col, cell.row);
435
+ if (range === undefined)
436
+ continue;
437
+ const lo = axis === 'row' ? range.top : range.left;
438
+ const hi = axis === 'row' ? range.bottom : range.right;
439
+ const cuts = count > 0
440
+ ? start <= hi && end >= lo && !(start <= lo && end >= hi)
441
+ : lo < start && start <= hi;
442
+ if (cuts) {
443
+ const verb = count > 0 ? 'deleting' : 'inserting';
444
+ throw new AuthoringError(`${verb} at ${axis} ${start} would cut through the array formula in ${cell.address}, which fills ${value.ref}: Excel refuses to change part of an array, so move or delete the whole range`);
445
+ }
446
+ }
447
+ }
448
+ }
356
449
  #resetContent() {
357
450
  this.#rows.clear();
358
451
  this.#columns.clear();
@@ -360,10 +453,14 @@ export class Worksheet {
360
453
  this.#merges.clear();
361
454
  this.#dataValidations.clear();
362
455
  this.#conditionalFormattings.clear();
456
+ this.#hyperlinks.clear();
363
457
  this.#tables.length = 0;
364
458
  this.#extent.reset();
365
459
  }
366
460
  set model(model) {
461
+ const rehearsal = new Worksheet(this.name, this.id);
462
+ for (const facet of WORKSHEET_MODEL_FACETS)
463
+ facet.write(rehearsal, model);
367
464
  this.#resetContent();
368
465
  for (const facet of WORKSHEET_MODEL_FACETS)
369
466
  facet.write(this, model);
@@ -385,15 +482,14 @@ export class Worksheet {
385
482
  return this.#protection;
386
483
  }
387
484
  #cellAt(row, col) {
388
- let cols = this.#rows.get(row);
389
- if (cols === undefined) {
390
- cols = new Map();
391
- this.#rows.set(row, cols);
392
- }
393
- let cell = cols.get(col);
485
+ const cols = this.#rows.get(row);
486
+ let cell = cols?.get(col);
394
487
  if (cell === undefined) {
395
488
  cell = new Cell(row, col);
396
- cols.set(col, cell);
489
+ if (cols === undefined)
490
+ this.#rows.set(row, new Map([[col, cell]]));
491
+ else
492
+ cols.set(col, cell);
397
493
  }
398
494
  this.#extent.noteCell(row, col);
399
495
  return cell;
@@ -413,6 +509,12 @@ export class Worksheet {
413
509
  addPreservedReference: (reference) => {
414
510
  this.#preservedReferences.push(reference);
415
511
  },
512
+ setFormulaHost: (host) => {
513
+ this.#formulaHost = host;
514
+ },
515
+ spliceFormulas: (edit) => {
516
+ this.#edits.spliceFormulas(edit);
517
+ },
416
518
  restoreProtection: (protection) => {
417
519
  this.#protection = protection;
418
520
  },
@@ -465,9 +567,32 @@ export class Worksheet {
465
567
  },
466
568
  };
467
569
  }
570
+ function filledDown(value, offset) {
571
+ if (isFormulaValue(value))
572
+ return { formula: translateFormula(value.formula, 0, offset) };
573
+ if (isArrayFormulaValue(value)) {
574
+ const formula = translateFormula(value.formula, 0, offset);
575
+ const decoded = tryDecodeRange(value.ref);
576
+ const range = decoded === undefined ? undefined : boundedRect(decoded);
577
+ if (range === undefined || range.bottom + offset > MAX_ROW)
578
+ return { formula };
579
+ const ref = encodeRange({ ...range, top: range.top + offset, bottom: range.bottom + offset });
580
+ return { shareType: 'array', formula, ref, ...(value.dynamic === true ? { dynamic: true } : {}) };
581
+ }
582
+ if (isSharedFormulaValue(value)) {
583
+ return value.formula === undefined
584
+ ? { sharedFormula: value.sharedFormula }
585
+ : { sharedFormula: value.sharedFormula, formula: translateFormula(value.formula, 0, offset) };
586
+ }
587
+ return value;
588
+ }
468
589
  function assertStartAndCount(verb, axis, start, count) {
469
590
  assertAxisInBounds(axis, start);
470
591
  if (!Number.isInteger(count) || count < 0) {
471
592
  throw new RangeError(`${verb} count ${count} is invalid: it must be a non-negative integer`);
472
593
  }
473
594
  }
595
+ function assertSpliceFits(axis, start, insertCount) {
596
+ if (insertCount > 0)
597
+ assertAxisInBounds(axis, start + insertCount - 1);
598
+ }
@@ -6,11 +6,13 @@ export { AxisHandle } from '../core/axis-handle.ts';
6
6
  export { Column } from '../core/column.ts';
7
7
  export type { DateEpoch } from '../core/date.ts';
8
8
  export type { Comment, CommentThread, Mention, MentionRef, Person } from '../core/comment-thread.ts';
9
- export { type CfTimePeriod, type CfValueObject, type CfValueObjectType, type ConditionalFormatting, type ConditionalFormattingOperator, type ConditionalFormattingRule, type ConditionalFormattingType, type IconSetType, isCfTimePeriod, isCfValueObjectType, isConditionalFormattingOperator, isConditionalFormattingType, isIconSetType, } from '../core/conditional-formatting.ts';
10
- export { type DataValidation, type DataValidationEntry, type DataValidationErrorStyle, type DataValidationOperator, type DataValidationType, isDataValidationErrorStyle, isDataValidationOperator, isDataValidationType, } from '../core/data-validation.ts';
9
+ export { type CfIcon, type CfIconSetType, type CfTimePeriod, type CfValueObject, type CfValueObjectType, type ConditionalFormatting, type ConditionalFormattingOperator, type ConditionalFormattingRule, type ConditionalFormattingType, type DataBarAxisPosition, type DataBarDirection, type IconSetType, isCfIconSetType, isCfTimePeriod, isCfValueObjectType, isConditionalFormattingOperator, isConditionalFormattingType, isDataBarAxisPosition, isDataBarDirection, isIconSetType, } from '../core/conditional-formatting.ts';
10
+ export { type Hyperlink } from '../core/hyperlink.ts';
11
+ export { type DataValidation, type DataValidationEntry, type DataValidationErrorStyle, type DataValidationImeMode, type DataValidationOperator, type DataValidationType, isDataValidationErrorStyle, isDataValidationImeMode, isDataValidationOperator, isDataValidationType, } from '../core/data-validation.ts';
11
12
  export type { AxisSplice } from '../core/grid-shift.ts';
12
- export { type AnchoredImage, type AnchorPoint, type Extent, type ImageAnchor, type ImageEditAs, isImageEditAs, isOneCellAnchor, type OneCellAnchor, type PortableImage, PX_TO_EMU, type TwoCellAnchor, type WorkbookImage, type WorksheetImages, } from '../core/image.ts';
13
+ export { type AnchoredImage, type AnchorPoint, type Extent, type ImageAnchor, type ImageCrop, type ImageEditAs, type ImageHyperlink, isImageEditAs, isOneCellAnchor, type OneCellAnchor, type PictureProperties, type PortableImage, PX_TO_EMU, type TwoCellAnchor, type WorkbookImage, type WorksheetImages, } from '../core/image.ts';
13
14
  export type { ReadPackageOptions } from '../io/opc/read-options.ts';
15
+ export type { PixelAnchor } from '../core/worksheet-pictures.ts';
14
16
  export { INVALID_SHEET_NAME_CHARS, MAX_COLUMN_WIDTH, MAX_ROW_HEIGHT, MAX_SHEET_NAME_LENGTH, MAX_TABLE_NAME_LENGTH, TABLE_NAME_PATTERN, } from '../core/limits.ts';
15
17
  export { type HeaderFooter, isPageOrder, isPageOrientation, type PageBreak, type PageMargins, type PageOrder, type PageOrientation, type PageSetup, type PrintOptions, } from '../core/page-setup.ts';
16
18
  export { type ParsedPivotField, type ParsedPivotSource, type ParsedPivotTable, type PivotCacheField, type PivotItem, type PivotMetric, type PivotNumericSummary, isDeclarablePivotSourceKind, type PivotRecordCell, type PivotSourceKind, PivotTable, type PivotTableOptions, } from '../core/pivot-table.ts';
@@ -20,11 +22,11 @@ export { Range } from '../core/range.ts';
20
22
  export { Row } from '../core/row.ts';
21
23
  export { type Alignment, type Border, type BorderEdge, type BorderStyle, type CellContent, type CellStyle, type Color, type Fill, type FillPatternType, type Font, type FontScheme, type FontVerticalAlignment, type GradientFill, type GradientStop, type HorizontalAlignment, isBorderStyle, isFillPatternType, isFontScheme, isFontVerticalAlignment, isHorizontalAlignment, isNamedUnderlineStyle, isVerticalAlignment, type PatternFill, type Protection, type UnderlineStyle, type VerticalAlignment, } from '../core/style.ts';
22
24
  export { Table, type TableColumn, type TableColumnStyle, isTotalsRowFunction, type TableGrid, type TableOptions, type TableRegion, type TableStyleInfo, type TotalsRowFunction, } from '../core/table.ts';
23
- export type { DifferentialStyle, NamedCellStyle, TableStyleNamespace, TableStyleTable, } from '../core/workbook-styles.ts';
25
+ export type { DifferentialStyle, NamedCellStyle, TableStyleDefinition, TableStyleNamespace, TableStyleTable, } from '../core/workbook-styles.ts';
24
26
  export { isTableStyleElementType, STRIPE_ELEMENT_TYPES, TABLE_STYLE_ELEMENT_TYPES, type TableStyle, type TableStyleElement, type TableStyleElementType, } from '../core/table-style.ts';
25
27
  export { estimateWrappedLines } from '../core/text-metrics.ts';
26
28
  export { DEFAULT_THEME_COLOR_SCHEME, DEFAULT_THEME_FONTS, isThemeColorSlot, THEME_COLOR_SLOTS, type ThemeColorScheme, type ThemeColorSlot, type ThemeFontScheme, type ThemeOverrides, } from '../core/theme.ts';
27
- export { type CellValue, cellValueToText, coerceCellValue, type DataTableFormulaValue, detectValueType, ERROR_CODES, type ErrorCode, type ErrorValue, type FormulaResult, type FormulaValue, type HyperlinkValue, isDataTableFormulaValue, isErrorCode, isErrorValue, isFormulaValue, isHyperlinkValue, isRichTextValue, isSharedFormulaValue, type RichTextRun, type RichTextValue, richTextToPlain, type SharedFormulaValue, ValueType, } from '../core/value.ts';
29
+ export { type ArrayFormulaValue, type CellValue, cellValueToText, coerceCellValue, type DataTableFormulaValue, detectValueType, ERROR_CODES, type ErrorCode, type ErrorValue, type FormulaResult, type FormulaValue, isArrayFormulaValue, isDataTableFormulaValue, isErrorCode, isErrorValue, isFormulaValue, isRichTextValue, isSharedFormulaValue, type RichTextRun, type RichTextValue, richTextToPlain, type SharedFormulaValue, ValueType, } from '../core/value.ts';
28
30
  export { type AddImageOptions, type AddWorksheetOptions, DEFAULT_WORKBOOK_VIEW, type DefinedName, type PreservedTheme, type PreservedWorkbookReference, Workbook, type WorkbookProperties, type WorkbookView, } from '../core/workbook.ts';
29
31
  export type { WorkbookProtection, WorkbookProtectionCredentialAttr, } from '../core/workbook-protection.ts';
30
32
  export { type CellModel, type ColumnProperties, type OutlineProperties, type RowInput, type RowProperties, type SheetView, isVisibility, type Visibility, Worksheet, type WorksheetModel, type WorksheetProperties, type WorksheetState, } from '../core/worksheet.ts';
@@ -4,8 +4,9 @@ export { Cell } from '../core/cell.js';
4
4
  export { applyTint, DEFAULT_INDEXED_COLORS, resolveColor, SYSTEM_INDEXED_COLORS, } from '../core/color-resolution.js';
5
5
  export { AxisHandle } from '../core/axis-handle.js';
6
6
  export { Column } from '../core/column.js';
7
- export { isCfTimePeriod, isCfValueObjectType, isConditionalFormattingOperator, isConditionalFormattingType, isIconSetType, } from '../core/conditional-formatting.js';
8
- export { isDataValidationErrorStyle, isDataValidationOperator, isDataValidationType, } from '../core/data-validation.js';
7
+ export { isCfIconSetType, isCfTimePeriod, isCfValueObjectType, isConditionalFormattingOperator, isConditionalFormattingType, isDataBarAxisPosition, isDataBarDirection, isIconSetType, } from '../core/conditional-formatting.js';
8
+ export {} from '../core/hyperlink.js';
9
+ export { isDataValidationErrorStyle, isDataValidationImeMode, isDataValidationOperator, isDataValidationType, } from '../core/data-validation.js';
9
10
  export { isImageEditAs, isOneCellAnchor, PX_TO_EMU, } from '../core/image.js';
10
11
  export { INVALID_SHEET_NAME_CHARS, MAX_COLUMN_WIDTH, MAX_ROW_HEIGHT, MAX_SHEET_NAME_LENGTH, MAX_TABLE_NAME_LENGTH, TABLE_NAME_PATTERN, } from '../core/limits.js';
11
12
  export { isPageOrder, isPageOrientation, } from '../core/page-setup.js';
@@ -17,6 +18,6 @@ export { Table, isTotalsRowFunction, } from '../core/table.js';
17
18
  export { isTableStyleElementType, STRIPE_ELEMENT_TYPES, TABLE_STYLE_ELEMENT_TYPES, } from '../core/table-style.js';
18
19
  export { estimateWrappedLines } from '../core/text-metrics.js';
19
20
  export { DEFAULT_THEME_COLOR_SCHEME, DEFAULT_THEME_FONTS, isThemeColorSlot, THEME_COLOR_SLOTS, } from '../core/theme.js';
20
- export { cellValueToText, coerceCellValue, detectValueType, ERROR_CODES, isDataTableFormulaValue, isErrorCode, isErrorValue, isFormulaValue, isHyperlinkValue, isRichTextValue, isSharedFormulaValue, richTextToPlain, ValueType, } from '../core/value.js';
21
+ export { cellValueToText, coerceCellValue, detectValueType, ERROR_CODES, isArrayFormulaValue, isDataTableFormulaValue, isErrorCode, isErrorValue, isFormulaValue, isRichTextValue, isSharedFormulaValue, richTextToPlain, ValueType, } from '../core/value.js';
21
22
  export { DEFAULT_WORKBOOK_VIEW, Workbook, } from '../core/workbook.js';
22
23
  export { isVisibility, Worksheet, } from '../core/worksheet.js';
@@ -1,5 +1,6 @@
1
1
  export { CustomUiParseError } from '../customui/errors.ts';
2
2
  export { AuthoringError, InternalError, XlsxError, type XlsxErrorCode } from '../errors.ts';
3
+ export { CsvParseError } from '../io/csv/errors.ts';
3
4
  export { PackageReadError, type UnsupportedFormat, UnsupportedFormatError, } from '../io/opc/errors.ts';
4
5
  export { XlsbParseError } from '../io/xlsb/errors.ts';
5
6
  export { XlsxParseError } from '../io/xlsx/errors.ts';
@@ -1,5 +1,6 @@
1
1
  export { CustomUiParseError } from '../customui/errors.js';
2
2
  export { AuthoringError, InternalError, XlsxError } from '../errors.js';
3
+ export { CsvParseError } from '../io/csv/errors.js';
3
4
  export { PackageReadError, UnsupportedFormatError, } from '../io/opc/errors.js';
4
5
  export { XlsbParseError } from '../io/xlsb/errors.js';
5
6
  export { XlsxParseError } from '../io/xlsx/errors.js';
package/dist/errors.js CHANGED
@@ -18,7 +18,7 @@ export function quoted(name) {
18
18
  return JSON.stringify(name);
19
19
  }
20
20
  export function invalidToken(kind, value) {
21
- return new AuthoringError(`Invalid ${kind} ${quoted(value)}: not a value the OOXML enumeration allows`);
21
+ return new AuthoringError(`invalid ${kind} ${quoted(value)}: not a value the OOXML enumeration allows`);
22
22
  }
23
23
  export function assertWritableNumber(value) {
24
24
  if (Number.isFinite(value))
@@ -0,0 +1,42 @@
1
+ import type { ErrorCode } from '../../core/value.ts';
2
+ /** The metadata type whose blocks mark a dynamic-array formula. */
3
+ export declare const DYNAMIC_ARRAY_TYPE = "XLDAPR";
4
+ /** The metadata type whose blocks name a rich value. */
5
+ export declare const RICH_VALUE_TYPE = "XLRICHVALUE";
6
+ /** One record of a metadata block: `type` indexes the metadata types from 1, `value` that type's blocks from 0. */
7
+ export interface MetadataRecord {
8
+ readonly type: number;
9
+ readonly value: number;
10
+ }
11
+ /** The metadata part, read as far as a cell's `cm` and `vm` can reach into it. */
12
+ export interface WorkbookMetadata {
13
+ /** Each metadata type's name, in order. */
14
+ readonly typeNames: readonly string[];
15
+ /** Whether each dynamic-array block, in order, sets `fDynamic`. */
16
+ readonly dynamicArrayBlocks: readonly boolean[];
17
+ /** The rich value each rich-value block names, in order; -1 for a block naming none it can read. */
18
+ readonly richValueBlocks: readonly number[];
19
+ /** Each cell-metadata block's records, in order: a `cm` of 1 is the first. */
20
+ readonly cellBlocks: readonly (readonly MetadataRecord[])[];
21
+ /** Each value-metadata block's records, in order: a `vm` of 1 is the first. */
22
+ readonly valueBlocks: readonly (readonly MetadataRecord[])[];
23
+ }
24
+ /** A workbook with no metadata part. */
25
+ export declare const NO_METADATA: WorkbookMetadata;
26
+ /** What a cell's metadata indices resolve to, for the readers of every sheet in the workbook. */
27
+ export interface CellMetadataIndex {
28
+ /** The `cm` values marking a dynamic-array formula. */
29
+ readonly dynamicArrayCells: ReadonlySet<number>;
30
+ /** The error each `vm` names through a rich value, where it names one. */
31
+ readonly valueErrors: ReadonlyMap<number, ErrorCode>;
32
+ }
33
+ /** The index of a workbook with no metadata part: no cell is a dynamic array, and no value names an error. */
34
+ export declare const NO_CELL_METADATA: CellMetadataIndex;
35
+ /**
36
+ * Resolve every `cm` and `vm` the metadata part can answer. `richValueErrors` is the error each rich
37
+ * value holds, by its index in the rich-value part.
38
+ *
39
+ * An index resolving to no block, to a block of another type, or to a rich value that is not an error
40
+ * marks nothing, so a cell carrying it reads as its own `<v>` says.
41
+ */
42
+ export declare function indexCellMetadata(metadata: WorkbookMetadata, richValueErrors: ReadonlyMap<number, ErrorCode>): CellMetadataIndex;
@@ -0,0 +1,35 @@
1
+ export const DYNAMIC_ARRAY_TYPE = 'XLDAPR';
2
+ export const RICH_VALUE_TYPE = 'XLRICHVALUE';
3
+ export const NO_METADATA = {
4
+ typeNames: [],
5
+ dynamicArrayBlocks: [],
6
+ richValueBlocks: [],
7
+ cellBlocks: [],
8
+ valueBlocks: [],
9
+ };
10
+ export const NO_CELL_METADATA = {
11
+ dynamicArrayCells: new Set(),
12
+ valueErrors: new Map(),
13
+ };
14
+ export function indexCellMetadata(metadata, richValueErrors) {
15
+ const typeOf = (record) => metadata.typeNames[record.type - 1];
16
+ const dynamicArrayCells = new Set();
17
+ metadata.cellBlocks.forEach((records, index) => {
18
+ const dynamic = records.some((record) => typeOf(record) === DYNAMIC_ARRAY_TYPE && metadata.dynamicArrayBlocks[record.value] === true);
19
+ if (dynamic)
20
+ dynamicArrayCells.add(index + 1);
21
+ });
22
+ const valueErrors = new Map();
23
+ metadata.valueBlocks.forEach((records, index) => {
24
+ for (const record of records) {
25
+ if (typeOf(record) !== RICH_VALUE_TYPE)
26
+ continue;
27
+ const error = richValueErrors.get(metadata.richValueBlocks[record.value] ?? -1);
28
+ if (error !== undefined) {
29
+ valueErrors.set(index + 1, error);
30
+ break;
31
+ }
32
+ }
33
+ });
34
+ return { dynamicArrayCells, valueErrors };
35
+ }
@@ -0,0 +1,11 @@
1
+ import type { ErrorCode } from '../../core/value.ts';
2
+ /** The structure type of a rich value naming an error. */
3
+ export declare const ERROR_STRUCTURE = "_error";
4
+ /** The `errorType` a rich value names each error with, for the errors Excel stores only this way. */
5
+ export declare const RICH_VALUE_ERROR_TYPES: ReadonlyMap<ErrorCode, number>;
6
+ /**
7
+ * The error each rich value holds, keyed by its 0-based index in the rich-value part. A value whose
8
+ * structure is not `_error`, has no `errorType` key, or names an `errorType` Excel was not seen to read
9
+ * back as one error holds none.
10
+ */
11
+ export declare function parseRichValueErrors(structuresXml: string, valuesXml: string): ReadonlyMap<number, ErrorCode>;
@@ -0,0 +1,80 @@
1
+ import { numInteger } from '../../xml/xml-attrs.js';
2
+ import { parseXml } from '../../xml/xml-read.js';
3
+ import { localName } from '../../xml/xml-scan.js';
4
+ export const ERROR_STRUCTURE = '_error';
5
+ export const RICH_VALUE_ERROR_TYPES = new Map([
6
+ ['#SPILL!', 8],
7
+ ['#CONNECT!', 9],
8
+ ['#BLOCKED!', 10],
9
+ ['#UNKNOWN!', 11],
10
+ ['#FIELD!', 12],
11
+ ['#CALC!', 13],
12
+ ]);
13
+ const ERROR_OF_TYPE = new Map([
14
+ [3, '#REF!'],
15
+ [4, '#NAME?'],
16
+ [6, '#N/A'],
17
+ ...[...RICH_VALUE_ERROR_TYPES].map(([code, type]) => [type, code]),
18
+ ]);
19
+ export function parseRichValueErrors(structuresXml, valuesXml) {
20
+ const errors = new Map();
21
+ if (structuresXml === '' || valuesXml === '')
22
+ return errors;
23
+ const errorTypeKeys = parseErrorTypeKeys(structuresXml);
24
+ let index = -1;
25
+ let wanted = -1;
26
+ let position = -1;
27
+ let capturing = false;
28
+ let text = '';
29
+ parseXml(valuesXml, {
30
+ onOpen(name, attrs, selfClosing) {
31
+ const local = localName(name);
32
+ if (local === 'rv') {
33
+ index++;
34
+ position = -1;
35
+ const structure = numInteger(attrs.s, 0);
36
+ wanted = structure === undefined ? -1 : (errorTypeKeys[structure] ?? -1);
37
+ }
38
+ else if (local === 'v') {
39
+ position++;
40
+ capturing = !selfClosing && position === wanted;
41
+ text = '';
42
+ }
43
+ },
44
+ onText(chunk) {
45
+ if (capturing)
46
+ text += chunk;
47
+ },
48
+ onClose(name) {
49
+ if (localName(name) !== 'v' || !capturing)
50
+ return;
51
+ capturing = false;
52
+ const error = ERROR_OF_TYPE.get(numInteger(text.trim(), 0) ?? -1);
53
+ if (error !== undefined)
54
+ errors.set(index, error);
55
+ },
56
+ });
57
+ return errors;
58
+ }
59
+ function parseErrorTypeKeys(xml) {
60
+ const keys = [];
61
+ let isError = false;
62
+ let key = -1;
63
+ parseXml(xml, {
64
+ onOpen(name, attrs) {
65
+ const local = localName(name);
66
+ if (local === 's') {
67
+ isError = attrs.t === ERROR_STRUCTURE;
68
+ key = -1;
69
+ keys.push(-1);
70
+ }
71
+ else if (local === 'k' && keys.length > 0) {
72
+ key++;
73
+ if (isError && attrs.n === 'errorType' && keys[keys.length - 1] === -1) {
74
+ keys[keys.length - 1] = key;
75
+ }
76
+ }
77
+ },
78
+ });
79
+ return keys;
80
+ }
@@ -1,9 +1,21 @@
1
1
  /**
2
- * Refuse a delimiter the codec cannot honour.
2
+ * Refuse a field delimiter the codec cannot honour.
3
3
  *
4
4
  * A `RangeError` rather than an `AuthoringError`: this is a single scalar out of range, which
5
5
  * `src/errors.ts` reserves for the native types on the grounds that they exist for exactly that.
6
6
  *
7
- * @throws {RangeError} if the delimiter is not exactly one character.
7
+ * @throws {RangeError} if the delimiter is not exactly one character, or is a quote, CR or LF.
8
8
  */
9
9
  export declare function assertDelimiter(delimiter: string): void;
10
+ /**
11
+ * Refuse a row delimiter the writer cannot keep apart from the data.
12
+ *
13
+ * Only the writer takes one: the reader recognises LF, CRLF and a bare CR, and a record boundary it
14
+ * cannot see is a choice the caller makes for a consumer other than this codec. What is refused here
15
+ * is output no consumer can split. An empty delimiter joins every row into one line. One that
16
+ * contains the field delimiter reads as an extra field at every row boundary, and one that contains a
17
+ * quote collides with the quoting that is supposed to protect a field from it.
18
+ *
19
+ * @throws {RangeError} if the row delimiter is empty, or contains the field delimiter or a quote.
20
+ */
21
+ export declare function assertRowDelimiter(rowDelimiter: string, delimiter: string): void;