@shbernal/ts-xlsx 1.2.0 → 2.0.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 (161) hide show
  1. package/README.md +5 -0
  2. package/dist/core/address.d.ts +49 -2
  3. package/dist/core/address.js +31 -3
  4. package/dist/core/autofilter.d.ts +2 -2
  5. package/dist/core/cell.d.ts +17 -16
  6. package/dist/core/cell.js +3 -7
  7. package/dist/core/color-resolution.d.ts +7 -7
  8. package/dist/core/column.d.ts +8 -9
  9. package/dist/core/column.js +2 -4
  10. package/dist/core/comment-thread.d.ts +32 -23
  11. package/dist/core/comment-thread.js +4 -4
  12. package/dist/core/conditional-formatting-overlay.d.ts +1 -1
  13. package/dist/core/conditional-formatting.d.ts +3 -3
  14. package/dist/core/data-validation-overlay.d.ts +1 -1
  15. package/dist/core/data-validation.d.ts +3 -3
  16. package/dist/core/date.d.ts +3 -3
  17. package/dist/core/formula.d.ts +6 -6
  18. package/dist/core/grid-edits.js +3 -3
  19. package/dist/core/image.d.ts +37 -2
  20. package/dist/core/image.js +6 -0
  21. package/dist/core/internal.d.ts +9 -1
  22. package/dist/core/limits.d.ts +4 -4
  23. package/dist/core/merge.d.ts +6 -12
  24. package/dist/core/merge.js +0 -3
  25. package/dist/core/page-setup.d.ts +4 -4
  26. package/dist/core/pivot-table.d.ts +2 -4
  27. package/dist/core/pivot-table.js +5 -5
  28. package/dist/core/preserved.d.ts +3 -3
  29. package/dist/core/protection.d.ts +4 -4
  30. package/dist/core/range.d.ts +16 -14
  31. package/dist/core/range.js +5 -5
  32. package/dist/core/row-input.d.ts +2 -8
  33. package/dist/core/row-input.js +2 -2
  34. package/dist/core/row.d.ts +7 -8
  35. package/dist/core/row.js +2 -4
  36. package/dist/core/style.d.ts +14 -14
  37. package/dist/core/table-style.d.ts +9 -9
  38. package/dist/core/table-style.js +1 -1
  39. package/dist/core/table.d.ts +30 -42
  40. package/dist/core/table.js +16 -10
  41. package/dist/core/theme.d.ts +13 -43
  42. package/dist/core/theme.js +2 -148
  43. package/dist/core/value.d.ts +7 -7
  44. package/dist/core/workbook-protection.d.ts +2 -2
  45. package/dist/core/workbook-styles.d.ts +26 -0
  46. package/dist/core/workbook-styles.js +48 -0
  47. package/dist/core/workbook-theme.d.ts +25 -0
  48. package/dist/core/workbook-theme.js +49 -0
  49. package/dist/core/workbook-vba.d.ts +17 -0
  50. package/dist/core/workbook-vba.js +79 -0
  51. package/dist/core/workbook.d.ts +141 -83
  52. package/dist/core/workbook.js +74 -133
  53. package/dist/core/worksheet-comments.d.ts +9 -0
  54. package/dist/core/worksheet-comments.js +52 -0
  55. package/dist/core/worksheet-model.d.ts +4 -4
  56. package/dist/core/worksheet-model.js +1 -0
  57. package/dist/core/worksheet-pictures.d.ts +29 -0
  58. package/dist/core/worksheet-pictures.js +42 -0
  59. package/dist/core/worksheet.d.ts +94 -77
  60. package/dist/core/worksheet.js +36 -95
  61. package/dist/customui/errors.d.ts +1 -1
  62. package/dist/customui/ribbon.d.ts +3 -3
  63. package/dist/entries/core.d.ts +4 -4
  64. package/dist/entries/core.js +1 -1
  65. package/dist/entries/vba.d.ts +1 -1
  66. package/dist/entries/vba.js +1 -1
  67. package/dist/entries/xlsx.d.ts +1 -0
  68. package/dist/entries/xlsx.js +1 -0
  69. package/dist/errors.d.ts +12 -12
  70. package/dist/io/csv/read.js +1 -2
  71. package/dist/io/csv/write.d.ts +8 -3
  72. package/dist/io/csv/write.js +17 -2
  73. package/dist/io/opc/errors.d.ts +6 -6
  74. package/dist/io/opc/inflate.d.ts +1 -1
  75. package/dist/io/opc/namespaces.d.ts +1 -1
  76. package/dist/io/opc/read-opc.d.ts +19 -3
  77. package/dist/io/opc/read-opc.js +14 -8
  78. package/dist/io/opc/read-options.d.ts +2 -2
  79. package/dist/io/opc/sniff-format.d.ts +2 -2
  80. package/dist/io/opc/zip-mtime.d.ts +5 -0
  81. package/dist/io/opc/zip-mtime.js +1 -0
  82. package/dist/io/style/xf-style.d.ts +38 -6
  83. package/dist/io/style/xf-style.js +22 -0
  84. package/dist/io/xlsb/errors.d.ts +1 -1
  85. package/dist/io/xlsb/formula.d.ts +4 -4
  86. package/dist/io/xlsb/primitives.d.ts +8 -8
  87. package/dist/io/xlsb/ptg-functions.d.ts +1 -1
  88. package/dist/io/xlsb/read-styles.js +2 -20
  89. package/dist/io/xlsb/read.d.ts +2 -2
  90. package/dist/io/xlsx/cell-accumulator.d.ts +25 -6
  91. package/dist/io/xlsx/cell-accumulator.js +111 -30
  92. package/dist/io/xlsx/cell-value.d.ts +2 -2
  93. package/dist/io/xlsx/cell-value.js +3 -3
  94. package/dist/io/xlsx/color-xml.js +11 -17
  95. package/dist/io/xlsx/comments.d.ts +5 -5
  96. package/dist/io/xlsx/comments.js +13 -6
  97. package/dist/io/xlsx/conditional-formatting.d.ts +3 -3
  98. package/dist/io/xlsx/conditional-formatting.js +7 -16
  99. package/dist/io/xlsx/data-validation.d.ts +2 -2
  100. package/dist/io/xlsx/data-validation.js +1 -1
  101. package/dist/io/xlsx/edit-vba.js +2 -1
  102. package/dist/io/xlsx/errors.d.ts +3 -3
  103. package/dist/io/xlsx/hyperlinks.d.ts +4 -2
  104. package/dist/io/xlsx/hyperlinks.js +5 -5
  105. package/dist/io/xlsx/images.d.ts +1 -1
  106. package/dist/io/xlsx/images.js +8 -8
  107. package/dist/io/xlsx/namespaces.d.ts +2 -2
  108. package/dist/io/xlsx/package-plan.js +5 -2
  109. package/dist/io/xlsx/read-pivot.js +2 -5
  110. package/dist/io/xlsx/read-rows.d.ts +13 -13
  111. package/dist/io/xlsx/read-rows.js +19 -55
  112. package/dist/io/xlsx/read-shared-strings.js +7 -5
  113. package/dist/io/xlsx/read-styles.d.ts +3 -3
  114. package/dist/io/xlsx/read-styles.js +40 -65
  115. package/dist/io/xlsx/read-worksheet.js +67 -115
  116. package/dist/io/xlsx/read.d.ts +3 -5
  117. package/dist/io/xlsx/read.js +94 -71
  118. package/dist/io/xlsx/rich-runs.d.ts +1 -1
  119. package/dist/io/xlsx/rich-runs.js +1 -1
  120. package/dist/io/xlsx/rich-text.d.ts +1 -1
  121. package/dist/io/xlsx/shared-strings.d.ts +2 -2
  122. package/dist/io/xlsx/sheet-properties.js +5 -4
  123. package/dist/io/xlsx/styles.d.ts +8 -9
  124. package/dist/io/xlsx/styles.js +4 -3
  125. package/dist/io/xlsx/tables.d.ts +2 -2
  126. package/dist/io/xlsx/tables.js +8 -13
  127. package/dist/io/xlsx/theme-xml.d.ts +37 -0
  128. package/dist/io/xlsx/theme-xml.js +142 -0
  129. package/dist/io/xlsx/threaded-comments.d.ts +18 -27
  130. package/dist/io/xlsx/threaded-comments.js +9 -21
  131. package/dist/io/xlsx/workbook-xml.d.ts +1 -1
  132. package/dist/io/xlsx/workbook-xml.js +6 -2
  133. package/dist/io/xlsx/worksheet-xml.d.ts +2 -2
  134. package/dist/io/xlsx/worksheet-xml.js +7 -12
  135. package/dist/io/xlsx/write-stream.d.ts +15 -15
  136. package/dist/io/xlsx/write-stream.js +5 -3
  137. package/dist/io/xlsx/write.d.ts +12 -7
  138. package/dist/io/xlsx/write.js +10 -6
  139. package/dist/io/xlsx/x14-ext.d.ts +1 -1
  140. package/dist/vba/bytes.d.ts +12 -0
  141. package/dist/vba/bytes.js +40 -0
  142. package/dist/vba/cfb-writer.d.ts +1 -1
  143. package/dist/vba/cfb.d.ts +1 -1
  144. package/dist/vba/cfb.js +15 -51
  145. package/dist/vba/codepage.d.ts +2 -2
  146. package/dist/vba/errors.d.ts +2 -2
  147. package/dist/vba/index.d.ts +2 -2
  148. package/dist/vba/index.js +2 -2
  149. package/dist/vba/ms-ovba.d.ts +1 -1
  150. package/dist/vba/ms-ovba.js +1 -3
  151. package/dist/vba/project-editor.d.ts +9 -9
  152. package/dist/vba/project-editor.js +2 -11
  153. package/dist/vba/project.d.ts +5 -5
  154. package/dist/vba/project.js +1 -10
  155. package/dist/vba/vba-encoding.d.ts +1 -1
  156. package/dist/xml/errors.d.ts +1 -1
  157. package/dist/xml/xml-read.d.ts +38 -9
  158. package/dist/xml/xml-read.js +23 -0
  159. package/dist/xml/xml.d.ts +31 -9
  160. package/dist/xml/xml.js +23 -3
  161. package/package.json +41 -35
@@ -1,23 +1,22 @@
1
1
  import { AuthoringError } from '../errors.js';
2
- import { decodeAddress, decodeRange, encodeAddress } from './address.js';
2
+ import { decodeCellRef, decodeRange, encodeAddress, rectsOverlap, tryDecodeCellRef, } from './address.js';
3
3
  import { canonicalizeAutoFilter } from './autofilter.js';
4
4
  import { applyCellStyle, Cell, copyCellContent } from './cell.js';
5
5
  import { Column } from './column.js';
6
- import { commentThreadGuid, commentThreadOffset } from './comment-thread.js';
7
6
  import { ConditionalFormattingOverlay } from './conditional-formatting-overlay.js';
8
- import { replaceContents } from './containers.js';
9
7
  import { DataValidationOverlay } from './data-validation-overlay.js';
10
8
  import { GridEdits } from './grid-edits.js';
11
- import { PX_TO_EMU, resolveAnchorPoint, } from './image.js';
12
9
  import { INTERNAL } from './internal.js';
13
- import { clearCoveredValues, masterOf, rectsOverlap } from './merge.js';
10
+ import { clearCoveredValues, masterOf } from './merge.js';
14
11
  import { PivotTable } from './pivot-table.js';
15
12
  import { deriveCredential, } from './protection.js';
16
13
  import { Range, rangeFrom } from './range.js';
17
- import { Row } from './row.js';
18
14
  import { buildRowCells, rowPlacements } from './row-input.js';
15
+ import { Row } from './row.js';
19
16
  import { Table, TOTALS_ROW_SUBTOTAL_CODE } from './table.js';
17
+ import { WorksheetComments } from './worksheet-comments.js';
20
18
  import { WORKSHEET_MODEL_FACETS } from './worksheet-model.js';
19
+ import { WorksheetPictures } from './worksheet-pictures.js';
21
20
  export class Worksheet {
22
21
  name;
23
22
  id;
@@ -38,10 +37,12 @@ export class Worksheet {
38
37
  #tables = [];
39
38
  #pivotTables = [];
40
39
  #loadedPivotTables = [];
41
- #commentThreads = [];
40
+ #comments = new WorksheetComments(() => this.name);
42
41
  #merges = [];
43
- #images = [];
44
- #backgroundImageId;
42
+ #images = new WorksheetPictures({
43
+ columnWidth: (col) => this.#columns.get(col + 1)?.width ?? this.properties.defaultColWidth,
44
+ rowHeight: (row) => this.#rowProperties.get(row + 1)?.height ?? this.properties.defaultRowHeight,
45
+ });
45
46
  #preservedReferences = [];
46
47
  #mergeRects = [];
47
48
  #dataValidations = new DataValidationOverlay();
@@ -60,14 +61,11 @@ export class Worksheet {
60
61
  merges: this.#merges,
61
62
  mergeRects: this.#mergeRects,
62
63
  tables: this.#tables,
63
- images: this.#images,
64
+ images: this.#images.anchors,
64
65
  });
65
66
  }
66
67
  getCell(reference) {
67
- const { col, row } = decodeAddress(reference);
68
- if (col === undefined || row === undefined) {
69
- throw new SyntaxError(`"${reference}" is not a single-cell reference — it omits a column or row`);
70
- }
68
+ const { col, row } = decodeCellRef(reference);
71
69
  const master = masterOf(this.#mergeRects, row, col);
72
70
  return this.#cellAt(master.row, master.col);
73
71
  }
@@ -213,82 +211,34 @@ export class Worksheet {
213
211
  return this.#loadedPivotTables;
214
212
  }
215
213
  addCommentThread(thread) {
216
- const taken = new Set(this.#commentThreads.flatMap((held) => held.comments.map((comment) => comment.id)));
217
- const comments = thread.comments.map((comment) => {
218
- const id = commentThreadGuid(comment.id, 'a comment id');
219
- if (taken.has(id)) {
220
- throw new SyntaxError(`a comment id must be unique within a sheet, but "${id}" is already used on "${this.name}" — ` +
221
- 'a reply and the legacy fallback comment both find their thread by it');
222
- }
223
- taken.add(id);
224
- return {
225
- ...comment,
226
- id,
227
- ...(comment.personId !== undefined
228
- ? { personId: commentThreadGuid(comment.personId, "a comment's author id") }
229
- : {}),
230
- mentions: comment.mentions.map((mention) => ({
231
- ...mention,
232
- personId: commentThreadGuid(mention.personId, "a mention's person id"),
233
- startIndex: commentThreadOffset(mention.startIndex, "a mention's startIndex"),
234
- length: commentThreadOffset(mention.length, "a mention's length"),
235
- ...(mention.mentionId !== undefined
236
- ? { mentionId: commentThreadGuid(mention.mentionId, 'a mention id') }
237
- : {}),
238
- })),
239
- };
240
- });
241
- this.#commentThreads.push({ ...thread, ref: this.#anchorRef(thread.ref), comments });
214
+ this.#comments.add(thread);
242
215
  }
243
216
  get commentThreads() {
244
- return this.#commentThreads;
245
- }
246
- #anchorRef(reference) {
247
- const { col, row } = decodeAddress(reference);
248
- if (col === undefined || row === undefined) {
249
- throw new SyntaxError(`"${reference}" is not a single-cell reference — it omits a column or row`);
250
- }
251
- return encodeAddress(col, row);
217
+ return this.#comments.threads;
252
218
  }
253
219
  commentThreadAt(reference) {
254
- const anchor = this.#anchorRef(reference);
255
- return this.#commentThreads.find((thread) => thread.ref === anchor);
220
+ return this.#comments.at(reference);
256
221
  }
257
222
  addImage(imageId, anchor) {
258
- const columnWidth = (col) => this.#columns.get(col + 1)?.width ?? this.properties.defaultColWidth;
259
- const rowHeight = (row) => this.#rowProperties.get(row + 1)?.height ?? this.properties.defaultRowHeight;
260
- if ('ext' in anchor) {
261
- const ext = {
262
- cx: Math.round(anchor.ext.width * PX_TO_EMU),
263
- cy: Math.round(anchor.ext.height * PX_TO_EMU),
264
- };
265
- const from = resolveAnchorPoint(anchor.tl, columnWidth, rowHeight);
266
- this.#images.push({ imageId, anchor: { from, ext } });
267
- return;
268
- }
269
- const from = resolveAnchorPoint(anchor.tl, columnWidth, rowHeight);
270
- const to = resolveAnchorPoint(anchor.br, columnWidth, rowHeight);
271
- const twoCell = anchor.editAs !== undefined ? { from, to, editAs: anchor.editAs } : { from, to };
272
- this.#images.push({ imageId, anchor: twoCell });
223
+ this.#images.add(imageId, anchor);
273
224
  }
274
225
  addImageAnchor(imageId, anchor) {
275
- this.#images.push({ imageId, anchor });
226
+ this.#images.addAnchor(imageId, anchor);
276
227
  }
277
228
  removeImage(imageId) {
278
- const kept = this.#images.filter((image) => image.imageId !== imageId);
279
- replaceContents(this.#images, kept);
229
+ this.#images.remove(imageId);
280
230
  }
281
231
  get images() {
282
- return this.#images;
232
+ return this.#images.anchors;
283
233
  }
284
234
  addBackgroundImage(imageId) {
285
- this.#backgroundImageId = imageId;
235
+ this.#images.setBackground(imageId);
286
236
  }
287
237
  removeBackgroundImage() {
288
- this.#backgroundImageId = undefined;
238
+ this.#images.setBackground(undefined);
289
239
  }
290
240
  get backgroundImageId() {
291
- return this.#backgroundImageId;
241
+ return this.#images.backgroundImageId;
292
242
  }
293
243
  get preservedReferences() {
294
244
  return this.#preservedReferences;
@@ -341,18 +291,11 @@ export class Worksheet {
341
291
  return this.#conditionalFormattings.entries;
342
292
  }
343
293
  dataValidationAt(reference) {
344
- const { col, row } = decodeAddress(reference);
345
- if (col === undefined || row === undefined)
346
- return undefined;
347
- return this.#dataValidations.at(col, row);
294
+ const cell = tryDecodeCellRef(reference);
295
+ return cell === undefined ? undefined : this.#dataValidations.at(cell.col, cell.row);
348
296
  }
349
297
  spliceRows(start, count, ...inserts) {
350
- if (!Number.isInteger(start) || start < 1) {
351
- throw new RangeError(`splice start ${start} is out of bounds — rows start at 1`);
352
- }
353
- if (!Number.isInteger(count) || count < 0) {
354
- throw new RangeError(`splice count ${count} is invalid — it must be a non-negative integer`);
355
- }
298
+ assertStartAndCount('splice', 'row', start, count);
356
299
  const inserted = inserts.map((values, i) => buildRowCells(start + i, values, this.#columns));
357
300
  this.#edits.spliceRows(start, count, inserted);
358
301
  }
@@ -394,12 +337,7 @@ export class Worksheet {
394
337
  }
395
338
  duplicateRow(start, options = {}) {
396
339
  const { count = 1, insert = true } = options;
397
- if (!Number.isInteger(start) || start < 1) {
398
- throw new RangeError(`duplicate start ${start} is out of bounds — rows start at 1`);
399
- }
400
- if (!Number.isInteger(count) || count < 0) {
401
- throw new RangeError(`duplicate count ${count} is invalid — it must be a non-negative integer`);
402
- }
340
+ assertStartAndCount('duplicate', 'row', start, count);
403
341
  const source = this.#rows.get(start);
404
342
  const snapshot = (destRow) => {
405
343
  const row = new Map();
@@ -422,12 +360,7 @@ export class Worksheet {
422
360
  }
423
361
  }
424
362
  spliceColumns(start, count, ...inserts) {
425
- if (!Number.isInteger(start) || start < 1) {
426
- throw new RangeError(`splice start ${start} is out of bounds — columns start at 1`);
427
- }
428
- if (!Number.isInteger(count) || count < 0) {
429
- throw new RangeError(`splice count ${count} is invalid — it must be a non-negative integer`);
430
- }
363
+ assertStartAndCount('splice', 'column', start, count);
431
364
  this.#edits.spliceColumns(start, count, inserts);
432
365
  }
433
366
  insertColumn(pos, values) {
@@ -510,7 +443,7 @@ export class Worksheet {
510
443
  this.#loadedPivotTables.push(pivot);
511
444
  },
512
445
  restoreCommentThreads: (threads) => {
513
- replaceContents(this.#commentThreads, threads);
446
+ this.#comments.restore(threads);
514
447
  },
515
448
  addPreservedReference: (reference) => {
516
449
  this.#preservedReferences.push(reference);
@@ -552,3 +485,11 @@ export class Worksheet {
552
485
  },
553
486
  };
554
487
  }
488
+ function assertStartAndCount(verb, axis, start, count) {
489
+ if (!Number.isInteger(start) || start < 1) {
490
+ throw new RangeError(`${verb} start ${start} is out of bounds: ${axis}s start at 1`);
491
+ }
492
+ if (!Number.isInteger(count) || count < 0) {
493
+ throw new RangeError(`${verb} count ${count} is invalid: it must be a non-negative integer`);
494
+ }
495
+ }
@@ -1,7 +1,7 @@
1
1
  import { XlsxError } from '../errors.ts';
2
2
  /**
3
3
  * Thrown when a `customUI` ribbon-customisation part (`customUI/customUI.xml` or
4
- * `customUI/customUI14.xml`) is present but cannot be parsed into a {@link CustomUiDocument} malformed
4
+ * `customUI/customUI14.xml`) is present but cannot be parsed into a {@link CustomUiDocument}: malformed
5
5
  * XML, a missing or unrecognised `<customUI>` root namespace, or nesting deep enough to look hostile.
6
6
  * A workbook with no ribbon customisation never produces this: {@link Workbook.customUI} is an empty
7
7
  * array instead.
@@ -1,4 +1,4 @@
1
- /** The `customUI` schema a part is written against the read model keys off this, not the (frequently
1
+ /** The `customUI` schema a part is written against. The read model keys off this, not the (frequently
2
2
  * mis-copied) relationship type. `2007` is the original RibbonX (`customUI.xml`); `2010` is the later
3
3
  * schema (`customUI14.xml`) that also carries backstage/QAT/commands. */
4
4
  export type RibbonDialect = '2007' | '2010';
@@ -15,7 +15,7 @@ export declare function isCustomUiRelType(type: string): boolean;
15
15
  * as `unknown` rather than dropped. The three identity attributes (`id` a document-defined control,
16
16
  * `idQ` a qualified id, `idMso` a built-in control) and the two most-consulted display/behaviour
17
17
  * attributes (`label`, `onAction`) are lifted out as typed conveniences; every attribute the element
18
- * actually carried including the many `get*` dynamic callbacks and layout hints not modelled here
18
+ * actually carried, including the many `get*` dynamic callbacks and layout hints not modelled here,
19
19
  * is preserved verbatim in {@link attributes}, so nothing is lost. Container controls (a `menu`,
20
20
  * `splitButton`, `gallery`, `dropDown`, `box`, …) carry their nested controls/items in {@link children}.
21
21
  */
@@ -29,7 +29,7 @@ export interface RibbonControl {
29
29
  readonly idMso?: string;
30
30
  /** The static label, when the element carries one (a dynamic label uses `getLabel`, in {@link attributes}). */
31
31
  readonly label?: string;
32
- /** The callback procedure name invoked on activation the macro a click runs. */
32
+ /** The callback procedure name invoked on activation: the macro a click runs. */
33
33
  readonly onAction?: string;
34
34
  /** Every attribute on the element, verbatim and entity-decoded. The typed fields above are lifted from
35
35
  * here; this map is the complete record, including attributes this model does not lift out. */
@@ -1,12 +1,12 @@
1
- export { type CellAddress, columnToNumber, decodeAddress, decodeRange, encodeAddress, MAX_COLUMN, MAX_ROW, numberToColumn, type RangeAddress, } from '../core/address.ts';
1
+ export { type CellAddress, columnToNumber, decodeAddress, decodeRange, encodeAddress, type GridRect, MAX_COLUMN, MAX_ROW, numberToColumn, type RangeAddress, } from '../core/address.ts';
2
2
  export type { AutoFilter, CustomFilter, CustomFilterOperator, CustomFilterPredicate, FilterColumn, FilterCriteria, ValuesFilter, } from '../core/autofilter.ts';
3
3
  export { Cell } from '../core/cell.ts';
4
4
  export { applyTint, type ColorResolutionContext, DEFAULT_INDEXED_COLORS, resolveColor, SYSTEM_INDEXED_COLORS, } from '../core/color-resolution.ts';
5
5
  export { Column } from '../core/column.ts';
6
- export type { Comment, CommentThread, Mention, Person } from '../core/comment-thread.ts';
6
+ export type { Comment, CommentThread, Mention, MentionRef, Person } from '../core/comment-thread.ts';
7
7
  export type { CfValueObject, ConditionalFormatting, ConditionalFormattingRule, } from '../core/conditional-formatting.ts';
8
8
  export type { DataValidation, DataValidationEntry, DataValidationErrorStyle, DataValidationOperator, DataValidationType, } from '../core/data-validation.ts';
9
- export { type AnchoredImage, type AnchorPoint, type Extent, type ImageAnchor, type ImageEditAs, isOneCellAnchor, type OneCellAnchor, PX_TO_EMU, type TwoCellAnchor, type WorkbookImage, } from '../core/image.ts';
9
+ export { type AnchoredImage, type AnchorPoint, type Extent, type ImageAnchor, type ImageEditAs, isOneCellAnchor, type OneCellAnchor, type PortableImage, PX_TO_EMU, type TwoCellAnchor, type WorkbookImage, type WorksheetImages, } from '../core/image.ts';
10
10
  export { MAX_COLUMN_WIDTH, MAX_ROW_HEIGHT } from '../core/limits.ts';
11
11
  export type { HeaderFooter, PageBreak, PageMargins, PageSetup, PrintOptions, } from '../core/page-setup.ts';
12
12
  export { type ParsedPivotField, type ParsedPivotSource, type ParsedPivotTable, type PivotCacheField, type PivotItem, type PivotMetric, type PivotNumericSummary, type PivotRecordCell, type PivotSourceKind, PivotTable, type PivotTableOptions, } from '../core/pivot-table.ts';
@@ -18,7 +18,7 @@ export type { Alignment, Border, BorderEdge, BorderStyle, CellStyle, Color, Diff
18
18
  export { Table, type TableColumn, type TableColumnStyle, type TableOptions, type TableRegion, type TableStyleInfo, } from '../core/table.ts';
19
19
  export { isTableStyleElementType, STRIPE_ELEMENT_TYPES, TABLE_STYLE_ELEMENT_TYPES, type TableStyle, type TableStyleElement, type TableStyleElementType, } from '../core/table-style.ts';
20
20
  export { estimateWrappedLines } from '../core/text-metrics.ts';
21
- export { DEFAULT_THEME_COLOR_SCHEME, DEFAULT_THEME_FONTS, parseThemeColorScheme, THEME_COLOR_SLOTS, type ThemeColorScheme, type ThemeColorSlot, type ThemeFontScheme, type ThemeOverrides, } from '../core/theme.ts';
21
+ export { DEFAULT_THEME_COLOR_SCHEME, DEFAULT_THEME_FONTS, THEME_COLOR_SLOTS, type ThemeColorScheme, type ThemeColorSlot, type ThemeFontScheme, type ThemeOverrides, } from '../core/theme.ts';
22
22
  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';
23
23
  export { type AddImageOptions, type AddWorksheetOptions, DEFAULT_WORKBOOK_VIEW, type DefinedName, type PreservedWorkbookReference, Workbook, type WorkbookProperties, type WorkbookView, } from '../core/workbook.ts';
24
24
  export type { WorkbookProtection, WorkbookProtectionCredentialAttr, } from '../core/workbook-protection.ts';
@@ -10,7 +10,7 @@ export { Row } from '../core/row.js';
10
10
  export { Table, } from '../core/table.js';
11
11
  export { isTableStyleElementType, STRIPE_ELEMENT_TYPES, TABLE_STYLE_ELEMENT_TYPES, } from '../core/table-style.js';
12
12
  export { estimateWrappedLines } from '../core/text-metrics.js';
13
- export { DEFAULT_THEME_COLOR_SCHEME, DEFAULT_THEME_FONTS, parseThemeColorScheme, THEME_COLOR_SLOTS, } from '../core/theme.js';
13
+ export { DEFAULT_THEME_COLOR_SCHEME, DEFAULT_THEME_FONTS, THEME_COLOR_SLOTS, } from '../core/theme.js';
14
14
  export { cellValueToText, coerceCellValue, detectValueType, ERROR_CODES, isDataTableFormulaValue, isErrorCode, isErrorValue, isFormulaValue, isHyperlinkValue, isRichTextValue, isSharedFormulaValue, richTextToPlain, ValueType, } from '../core/value.js';
15
15
  export { DEFAULT_WORKBOOK_VIEW, Workbook, } from '../core/workbook.js';
16
16
  export { Worksheet, } from '../core/worksheet.js';
@@ -1,2 +1,2 @@
1
1
  export { parseVbaProject, type VbaModule, type VbaModuleKind, type VbaProject, type VbaProjectSignature, type VbaProjectSignatureKind, } from '../vba/project.ts';
2
- export { addVbaReference, removeVbaModule, type VbaLibraryReference, } from '../vba/project-editor.ts';
2
+ export { addVbaReference, removeVbaModule, type VbaLibraryReference } from '../vba/project-editor.ts';
@@ -1,2 +1,2 @@
1
1
  export { parseVbaProject, } from '../vba/project.js';
2
- export { addVbaReference, removeVbaModule, } from '../vba/project-editor.js';
2
+ export { addVbaReference, removeVbaModule } from '../vba/project-editor.js';
@@ -1,5 +1,6 @@
1
1
  export { editXlsxVbaAddReference, editXlsxVbaRemoveModule } from '../io/xlsx/edit-vba.ts';
2
2
  export { type ReadXlsxOptions, readXlsx } from '../io/xlsx/read.ts';
3
3
  export { type ReadSheetRowsOptions, readSheetRows, readWorkbookStream, } from '../io/xlsx/read-rows.ts';
4
+ export { DEFAULT_THEME_XML, parseThemeColorScheme, parseThemeFontScheme, } from '../io/xlsx/theme-xml.ts';
4
5
  export { type WriteOptions, writeXlsx, writeXlsxAsync } from '../io/xlsx/write.ts';
5
6
  export { type CalcProperties, StreamedRow, WorkbookStreamWriter, type WorkbookStreamWriterOptions, WorksheetStreamWriter, } from '../io/xlsx/write-stream.ts';
@@ -1,5 +1,6 @@
1
1
  export { editXlsxVbaAddReference, editXlsxVbaRemoveModule } from '../io/xlsx/edit-vba.js';
2
2
  export { readXlsx } from '../io/xlsx/read.js';
3
3
  export { readSheetRows, readWorkbookStream, } from '../io/xlsx/read-rows.js';
4
+ export { DEFAULT_THEME_XML, parseThemeColorScheme, parseThemeFontScheme, } from '../io/xlsx/theme-xml.js';
4
5
  export { writeXlsx, writeXlsxAsync } from '../io/xlsx/write.js';
5
6
  export { StreamedRow, WorkbookStreamWriter, WorksheetStreamWriter, } from '../io/xlsx/write-stream.js';
package/dist/errors.d.ts CHANGED
@@ -2,22 +2,22 @@
2
2
  * What kind of failure an {@link XlsxError} reports. This is the branch most callers want, and it is
3
3
  * deliberately coarse: the four answers are the four different things a caller would *do* next.
4
4
  *
5
- * - `'unsupported-format'` the input is not a container this library reads at all (a legacy `.xls`,
5
+ * - `'unsupported-format'`: the input is not a container this library reads at all (a legacy `.xls`,
6
6
  * a blob that is not a spreadsheet). Nothing is wrong with the file; it is the wrong file *for us*.
7
- * - `'malformed-input'` a part we do read is corrupt or does not conform to its specification. The
7
+ * - `'malformed-input'`: a part we do read is corrupt or does not conform to its specification. The
8
8
  * file is broken, or hostile.
9
- * - `'authoring'` the caller described a document that cannot exist. The bug is in the calling code.
10
- * - `'internal'` an invariant this library maintains did not hold. It should be unreachable; if it
9
+ * - `'authoring'`: the caller described a document that cannot exist. The bug is in the calling code.
10
+ * - `'internal'`: an invariant this library maintains did not hold. It should be unreachable; if it
11
11
  * fires, the bug is ours.
12
12
  *
13
13
  * There is deliberately no "not implemented yet" code. Every candidate for one turned out to be an
14
- * unreachable exhaustiveness guard (so: `'internal'`), and the one genuine feature gap a binary
15
- * `.xlsb` cannot be row-streamed is already reported by {@link UnsupportedFormatError}'s `format`
14
+ * unreachable exhaustiveness guard (so: `'internal'`), and the one genuine feature gap (a binary
15
+ * `.xlsb` cannot be row-streamed) is already reported by {@link UnsupportedFormatError}'s `format`
16
16
  * branch. A code with no throw site would be a promise the library does not keep.
17
17
  *
18
18
  * **Which of these is worth reporting upstream.** `'internal'` always is, and says so at runtime.
19
19
  * `'unsupported-format'` and `'malformed-input'` are worth reporting when the file in hand opens
20
- * cleanly in Excel that combination means we are the ones who cannot read it, which is a gap, not
20
+ * cleanly in Excel: that combination means we are the ones who cannot read it, which is a gap, not
21
21
  * a corrupt input. `'authoring'` is worth reporting only if the document it refused is one a real
22
22
  * workbook can express. See `skills/ts-xlsx-upstream` for how to file one.
23
23
  */
@@ -29,7 +29,7 @@ export type XlsxErrorCode = 'unsupported-format' | 'malformed-input' | 'authorin
29
29
  *
30
30
  * Abstract on purpose: a failure always has a kind, so there is never a reason to throw the base.
31
31
  * Every subclass fixes {@link code} to a literal, which makes the class hierarchy a discriminated
32
- * union narrowing on `error.code` narrows the type.
32
+ * union, so narrowing on `error.code` narrows the type.
33
33
  *
34
34
  * The constructor is inherited from `Error`, so every subclass accepts `{cause}`; layers that wrap a
35
35
  * lower-level failure are expected to pass it rather than flatten it into the message.
@@ -43,13 +43,13 @@ export declare abstract class XlsxError extends Error {
43
43
  * worksheets. The document model, not a single argument, is what is wrong.
44
44
  *
45
45
  * **Where the line falls against native errors.** A single scalar that is out of range, unparseable,
46
- * or the wrong type stays a native `RangeError` / `SyntaxError` / `TypeError` those types exist for
46
+ * or the wrong type stays a native `RangeError` / `SyntaxError` / `TypeError`: those types exist for
47
47
  * exactly that, every caller already reads them, and wrapping them would make this taxonomy a
48
48
  * re-implementation of the language's. `AuthoringError` starts where a *composite* is internally
49
49
  * inconsistent, or contradicts something a workbook can express. `getColumn(0)` is a `RangeError`;
50
50
  * a table that names a column twice is an `AuthoringError`.
51
51
  *
52
- * It is always the calling code that is wrong, never the input file a malformed file raises a
52
+ * It is always the calling code that is wrong, never the input file; a malformed file raises a
53
53
  * `'malformed-input'` error instead.
54
54
  */
55
55
  export declare class AuthoringError extends XlsxError {
@@ -57,7 +57,7 @@ export declare class AuthoringError extends XlsxError {
57
57
  readonly code = "authoring";
58
58
  }
59
59
  /**
60
- * Thrown where an invariant the library itself maintains turns out not to hold typically an index
60
+ * Thrown where an invariant the library itself maintains turns out not to hold: typically an index
61
61
  * that a preceding pass proved to be in range, re-checked because `noUncheckedIndexedAccess` makes
62
62
  * the possibility of `undefined` explicit and casting it away would be worse.
63
63
  *
@@ -67,7 +67,7 @@ export declare class AuthoringError extends XlsxError {
67
67
  *
68
68
  * It is the one class in the taxonomy that rewrites its own message, appending {@link REPORT_NOTICE}
69
69
  * below the invariant that broke. The constructor is where that lives so a throw site added later
70
- * inherits it the alternative, a notice pasted at each of the throw sites, is one every future
70
+ * inherits it; the alternative, a notice pasted at each of the throw sites, is one every future
71
71
  * site can forget. Every other class leaves `message` exactly as given: `'malformed-input'` is a
72
72
  * routine outcome for a library that reads untrusted files, and a "report this" banner on each
73
73
  * corrupt input would train callers to ignore the one banner that always means something.
@@ -1,10 +1,9 @@
1
1
  import { Workbook } from '../../core/workbook.js';
2
- import { AuthoringError } from '../../errors.js';
3
2
  export function readCsv(input, options = {}) {
4
3
  const text = stripBom(typeof input === 'string' ? input : Buffer.from(input).toString('utf8'));
5
4
  const delimiter = options.delimiter ?? ',';
6
5
  if (delimiter.length !== 1) {
7
- throw new AuthoringError(`CSV delimiter must be a single character, got ${JSON.stringify(delimiter)}`);
6
+ throw new RangeError(`CSV delimiter must be a single character, got ${JSON.stringify(delimiter)}`);
8
7
  }
9
8
  let rows = parseCsvRows(text, delimiter);
10
9
  if (options.headers)
@@ -1,4 +1,4 @@
1
- import type { CellValue } from '../../core/value.ts';
1
+ import { type CellValue } from '../../core/value.ts';
2
2
  import type { Workbook } from '../../core/workbook.ts';
3
3
  export interface CsvWriteOptions {
4
4
  /** Which worksheet to write; defaults to the first. A name matching no sheet throws rather than
@@ -22,7 +22,12 @@ export interface CsvWriteOptions {
22
22
  * still applied to the returned text. */
23
23
  readonly map?: (value: CellValue, index: number) => string;
24
24
  }
25
- /** The logical CSV text of one worksheet no BOM, no byte encoding. */
25
+ /** The logical CSV text of one worksheet: no BOM, no byte encoding. */
26
26
  export declare function writeCsvText(workbook: Workbook, options?: CsvWriteOptions): string;
27
- /** The CSV bytes of one worksheet in the requested encoding, with a UTF-8 BOM by default. */
27
+ /**
28
+ * The CSV bytes of one worksheet in the requested encoding, with a UTF-8 BOM by default.
29
+ *
30
+ * @throws {AuthoringError} if a field holds an unpaired surrogate and the encoding is UTF-8, which
31
+ * cannot represent one. The alternative is `Buffer.from`'s silent U+FFFD substitution.
32
+ */
28
33
  export declare function writeCsv(workbook: Workbook, options?: CsvWriteOptions): Uint8Array;
@@ -27,15 +27,30 @@ export function writeCsvText(workbook, options = {}) {
27
27
  export function writeCsv(workbook, options = {}) {
28
28
  const text = writeCsvText(workbook, options);
29
29
  const encoding = options.encoding ?? 'utf8';
30
+ const utf8 = isUtf8(encoding);
31
+ if (utf8)
32
+ assertEncodable(text);
30
33
  const body = Buffer.from(text, encoding);
31
- const wantBom = options.bom ?? encoding === 'utf8';
32
- if (!wantBom || encoding !== 'utf8')
34
+ const wantBom = options.bom ?? utf8;
35
+ if (!wantBom || !utf8)
33
36
  return Uint8Array.from(body);
34
37
  const out = new Uint8Array(UTF8_BOM.length + body.length);
35
38
  out.set(UTF8_BOM, 0);
36
39
  out.set(body, UTF8_BOM.length);
37
40
  return out;
38
41
  }
42
+ function isUtf8(encoding) {
43
+ return encoding === 'utf8' || encoding === 'utf-8';
44
+ }
45
+ function assertEncodable(text) {
46
+ const found = LONE_SURROGATE.exec(text);
47
+ if (found === null)
48
+ return;
49
+ const codePoint = text.codePointAt(found.index).toString(16).toUpperCase();
50
+ throw new AuthoringError(`cannot write U+${codePoint} at offset ${found.index} of the CSV text: it is an unpaired ` +
51
+ 'surrogate, which UTF-8 cannot encode and CSV has no escape for');
52
+ }
53
+ const LONE_SURROGATE = /[\u{D800}-\u{DFFF}]/u;
39
54
  function selectSheet(workbook, name) {
40
55
  if (name === undefined) {
41
56
  const first = workbook.worksheets[0];
@@ -1,11 +1,11 @@
1
1
  import { XlsxError } from '../../errors.ts';
2
2
  /**
3
3
  * Which unsupported input the reader recognised:
4
- * - `'xls'` a legacy BIFF `.xls` (an OLE2/CFB compound file), detected by its magic bytes.
5
- * - `'xlsb'` a binary BIFF12 `.xlsb`: the same OPC/ZIP container as `.xlsx`, but its office document
4
+ * - `'xls'`: a legacy BIFF `.xls` (an OLE2/CFB compound file), detected by its magic bytes.
5
+ * - `'xlsb'`: a binary BIFF12 `.xlsb`, the same OPC/ZIP container as `.xlsx`, but its office document
6
6
  * is `xl/workbook.bin` rather than `xl/workbook.xml`. `readXlsx`/`readXlsb` read one; the entry points
7
7
  * that cannot yet (the row streamer) report it under this format with their own message.
8
- * - `'unknown'` not a recognised spreadsheet at all: not a ZIP, or a ZIP carrying no OOXML workbook
8
+ * - `'unknown'`: not a recognised spreadsheet at all, meaning not a ZIP, or a ZIP carrying no OOXML workbook
9
9
  * part (nor a `.xlsb` binary one).
10
10
  */
11
11
  export type UnsupportedFormat = 'xls' | 'xlsb' | 'unknown';
@@ -14,7 +14,7 @@ export type UnsupportedFormat = 'xls' | 'xlsb' | 'unknown';
14
14
  * caller keys on (rather than a subclass per format), so a `catch` can distinguish a legacy `.xls`, a
15
15
  * binary `.xlsb`, and an unrecognised blob without string-matching the message.
16
16
  *
17
- * The message never carries a filesystem path or the underlying zip library's internals the whole
17
+ * The message never carries a filesystem path or the underlying zip library's internals. The whole
18
18
  * point of the type is that the classification, not a leaked lower-layer string, is what the caller sees.
19
19
  *
20
20
  * {@link format} stays the branch for *which* unsupported input this was; the inherited
@@ -33,11 +33,11 @@ export declare class UnsupportedFormatError extends XlsxError {
33
33
  *
34
34
  * The neighbouring {@link UnsupportedFormatError} says the input is a different *kind* of thing; this
35
35
  * one says it is the right kind and we will not (or cannot) unpack it. Keeping them apart is what
36
- * lets a caller answer "should I try another reader, or reject this file?" and it is what replaced
36
+ * lets a caller answer "should I try another reader, or reject this file?", and it is what replaced
37
37
  * the message-prefix match the bomb refusal used to be recognised by.
38
38
  *
39
39
  * The zip library's own failure text never survives into either the message or `cause`: it can name
40
- * internals or an absolute filesystem path from the layer below, and this type carries the
40
+ * internals, or an absolute filesystem path, from the layer below, and this type carries the
41
41
  * classification precisely so no lower-layer string has to.
42
42
  */
43
43
  export declare class PackageReadError extends XlsxError {
@@ -6,7 +6,7 @@
6
6
  * @param cap Maximum total uncompressed output, in bytes, across all parts. Enforced
7
7
  * against bytes actually produced, never against the archive's declared sizes.
8
8
  * @returns A map of part path to inflated bytes.
9
- * @throws {PackageReadError} if inflation would exceed `cap` a probable zip bomb.
9
+ * @throws {PackageReadError} if inflation would exceed `cap`, a probable zip bomb.
10
10
  * @throws {Error} raised by the zip layer if the archive is malformed or a part uses an unsupported
11
11
  * compression method. Callers reach this through {@link inflateSpreadsheetPackage}, which is where
12
12
  * those are classified; the raw error is deliberately not re-typed here, because its text is the
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The namespace URIs the Open Packaging Conventions layer itself owns the ones that describe a
2
+ * The namespace URIs the Open Packaging Conventions layer itself owns: the ones that describe a
3
3
  * *package* rather than the spreadsheet inside it. Every OOXML package carries these regardless of
4
4
  * which serialisation its office document uses, so an `.xlsb` and an `.xlsx` agree on them exactly.
5
5
  *
@@ -2,14 +2,13 @@ import type { PreservedPart } from '../../core/preserved.ts';
2
2
  export interface PackageAccessors {
3
3
  /** A part's decoded text, or undefined when the package holds no such part. Decodes lazily, so a
4
4
  * part the reader never asks for is never stringified. */
5
- partText(path: string): string | undefined;
5
+ partText: (path: string) => string | undefined;
6
6
  /** A part's raw bytes, or undefined when the package holds no such part. */
7
- partBytes(path: string): Uint8Array | undefined;
7
+ partBytes: (path: string) => Uint8Array | undefined;
8
8
  }
9
9
  export declare function packageAccessors(files: Record<string, Uint8Array>): PackageAccessors;
10
10
  export declare function relationshipTargetByType(xml: string, suffix: string): string | undefined;
11
11
  export declare function relationshipTargetsByType(xml: string, suffix: string): string[];
12
- export declare function sheetRelTarget(sheetPath: string, partText: (path: string) => string | undefined, type: string): string | undefined;
13
12
  export declare function resolveRelativePart(basePart: string, target: string): string;
14
13
  export declare function resolveWorkbookPart(target: string): string;
15
14
  export declare function parseRelationships(xml: string): Map<string, string>;
@@ -20,5 +19,22 @@ export interface RelationshipRecord {
20
19
  readonly external: boolean;
21
20
  }
22
21
  export declare function parseRelationshipRecords(xml: string): RelationshipRecord[];
22
+ export interface PartRelationships {
23
+ /** Every relationship the part declares, in declaration order. */
24
+ readonly records: readonly RelationshipRecord[];
25
+ /** The relationship with this id, or undefined. Its `target` is raw: an external one is a URL, not a
26
+ * package path, so a caller that may see `TargetMode="External"` must read it before resolving. */
27
+ byId(id: string): RelationshipRecord | undefined;
28
+ /** Resolve one of this part's targets against the part's own directory. */
29
+ pathOf(target: string): string;
30
+ /** The package part reached through the first relationship whose Type ends with `/<suffix>`, or
31
+ * undefined when the part declares none: the single-part lookup (notes, printer settings, drawing,
32
+ * background) in one call. */
33
+ targetPath(suffix: string): string | undefined;
34
+ /** Every package part reached through a relationship of this type, in declaration order. For a part
35
+ * class one sheet may reference more than once (tables, pivot tables). */
36
+ targetPaths(suffix: string): string[];
37
+ }
38
+ export declare function readPartRelationships(partPath: string, partText: (path: string) => string | undefined): PartRelationships;
23
39
  export declare function contentTypeResolver(contentTypesXml: string): (path: string) => string;
24
40
  export declare function capturePartClosure(entryPath: string, partText: (path: string) => string | undefined, partBytes: (path: string) => Uint8Array | undefined, contentTypeOf: (path: string) => string): readonly PreservedPart[] | undefined;
@@ -3,7 +3,7 @@ import { openElements } from '../../xml/xml-read.js';
3
3
  import { extensionOf, relsPathFor } from './part-paths.js';
4
4
  export function packageAccessors(files) {
5
5
  return {
6
- partText(path) {
6
+ partText: (path) => {
7
7
  const bytes = files[path];
8
8
  return bytes === undefined ? undefined : strFromU8(bytes);
9
9
  },
@@ -24,13 +24,6 @@ export function relationshipTargetsByType(xml, suffix) {
24
24
  }
25
25
  return targets;
26
26
  }
27
- export function sheetRelTarget(sheetPath, partText, type) {
28
- const relsXml = partText(relsPathFor(sheetPath));
29
- if (relsXml === undefined)
30
- return undefined;
31
- const target = relationshipTargetByType(relsXml, type);
32
- return target === undefined ? undefined : resolveRelativePart(sheetPath, target);
33
- }
34
27
  export function resolveRelativePart(basePart, target) {
35
28
  if (target.startsWith('/'))
36
29
  return target.slice(1);
@@ -74,6 +67,19 @@ export function parseRelationshipRecords(xml) {
74
67
  }
75
68
  return records;
76
69
  }
70
+ export function readPartRelationships(partPath, partText) {
71
+ const records = parseRelationshipRecords(partText(relsPathFor(partPath)) ?? '');
72
+ const byId = new Map(records.map((record) => [record.id, record]));
73
+ const pathOf = (target) => resolveRelativePart(partPath, target);
74
+ const targetsOf = (suffix) => records.filter((record) => record.type.endsWith(`/${suffix}`)).map((record) => record.target);
75
+ return {
76
+ records,
77
+ byId: (id) => byId.get(id),
78
+ pathOf,
79
+ targetPath: (suffix) => targetsOf(suffix).map(pathOf)[0],
80
+ targetPaths: (suffix) => targetsOf(suffix).map(pathOf),
81
+ };
82
+ }
77
83
  export function contentTypeResolver(contentTypesXml) {
78
84
  const overrides = new Map();
79
85
  const defaults = new Map();
@@ -1,8 +1,8 @@
1
1
  export interface ReadXlsxOptions {
2
2
  /**
3
3
  * Maximum total uncompressed output, in bytes, produced while inflating the package.
4
- * The bound is enforced by a running counter as bytes are decompressed never read from
5
- * the archive's (untrusted, forgeable) size headers so a zip bomb that lies about its
4
+ * The bound is enforced by a running counter as bytes are decompressed, never read from
5
+ * the archive's (untrusted, forgeable) size headers, so a zip bomb that lies about its
6
6
  * uncompressed size is rejected all the same. Defaults to 512 MiB.
7
7
  */
8
8
  readonly maxUncompressedBytes?: number;
@@ -1,10 +1,10 @@
1
1
  import { UnsupportedFormatError } from './errors.ts';
2
2
  /** The container kind a leading magic-byte sniff distinguishes, before any inflation. */
3
3
  export type Container = 'cfb' | 'zip' | 'other';
4
- /** Classify a blob's container by its leading magic bytes alone no allocation, no inflation. */
4
+ /** Classify a blob's container by its leading magic bytes alone: no allocation, no inflation. */
5
5
  export declare function sniffContainer(data: Uint8Array): Container;
6
6
  /**
7
- * Inflate a spreadsheet package (`.xlsx` or `.xlsb` the container is the same), translating input
7
+ * Inflate a spreadsheet package (`.xlsx` or `.xlsb`; the container is the same), translating input
8
8
  * that is neither into a typed error before or instead of a raw zip failure:
9
9
  * - a legacy `.xls` (CFB) blob → {@link UnsupportedFormatError} `'xls'`, caught by the magic sniff so
10
10
  * fflate never runs on it;