@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.
- package/README.md +5 -0
- package/dist/core/address.d.ts +49 -2
- package/dist/core/address.js +31 -3
- package/dist/core/autofilter.d.ts +2 -2
- package/dist/core/cell.d.ts +17 -16
- package/dist/core/cell.js +3 -7
- package/dist/core/color-resolution.d.ts +7 -7
- package/dist/core/column.d.ts +8 -9
- package/dist/core/column.js +2 -4
- package/dist/core/comment-thread.d.ts +32 -23
- package/dist/core/comment-thread.js +4 -4
- package/dist/core/conditional-formatting-overlay.d.ts +1 -1
- package/dist/core/conditional-formatting.d.ts +3 -3
- package/dist/core/data-validation-overlay.d.ts +1 -1
- package/dist/core/data-validation.d.ts +3 -3
- package/dist/core/date.d.ts +3 -3
- package/dist/core/formula.d.ts +6 -6
- package/dist/core/grid-edits.js +3 -3
- package/dist/core/image.d.ts +37 -2
- package/dist/core/image.js +6 -0
- package/dist/core/internal.d.ts +9 -1
- package/dist/core/limits.d.ts +4 -4
- package/dist/core/merge.d.ts +6 -12
- package/dist/core/merge.js +0 -3
- package/dist/core/page-setup.d.ts +4 -4
- package/dist/core/pivot-table.d.ts +2 -4
- package/dist/core/pivot-table.js +5 -5
- package/dist/core/preserved.d.ts +3 -3
- package/dist/core/protection.d.ts +4 -4
- package/dist/core/range.d.ts +16 -14
- package/dist/core/range.js +5 -5
- package/dist/core/row-input.d.ts +2 -8
- package/dist/core/row-input.js +2 -2
- package/dist/core/row.d.ts +7 -8
- package/dist/core/row.js +2 -4
- package/dist/core/style.d.ts +14 -14
- package/dist/core/table-style.d.ts +9 -9
- package/dist/core/table-style.js +1 -1
- package/dist/core/table.d.ts +30 -42
- package/dist/core/table.js +16 -10
- package/dist/core/theme.d.ts +13 -43
- package/dist/core/theme.js +2 -148
- package/dist/core/value.d.ts +7 -7
- package/dist/core/workbook-protection.d.ts +2 -2
- package/dist/core/workbook-styles.d.ts +26 -0
- package/dist/core/workbook-styles.js +48 -0
- package/dist/core/workbook-theme.d.ts +25 -0
- package/dist/core/workbook-theme.js +49 -0
- package/dist/core/workbook-vba.d.ts +17 -0
- package/dist/core/workbook-vba.js +79 -0
- package/dist/core/workbook.d.ts +141 -83
- package/dist/core/workbook.js +74 -133
- package/dist/core/worksheet-comments.d.ts +9 -0
- package/dist/core/worksheet-comments.js +52 -0
- package/dist/core/worksheet-model.d.ts +4 -4
- package/dist/core/worksheet-model.js +1 -0
- package/dist/core/worksheet-pictures.d.ts +29 -0
- package/dist/core/worksheet-pictures.js +42 -0
- package/dist/core/worksheet.d.ts +94 -77
- package/dist/core/worksheet.js +36 -95
- package/dist/customui/errors.d.ts +1 -1
- package/dist/customui/ribbon.d.ts +3 -3
- package/dist/entries/core.d.ts +4 -4
- package/dist/entries/core.js +1 -1
- package/dist/entries/vba.d.ts +1 -1
- package/dist/entries/vba.js +1 -1
- package/dist/entries/xlsx.d.ts +1 -0
- package/dist/entries/xlsx.js +1 -0
- package/dist/errors.d.ts +12 -12
- package/dist/io/csv/read.js +1 -2
- package/dist/io/csv/write.d.ts +8 -3
- package/dist/io/csv/write.js +17 -2
- package/dist/io/opc/errors.d.ts +6 -6
- package/dist/io/opc/inflate.d.ts +1 -1
- package/dist/io/opc/namespaces.d.ts +1 -1
- package/dist/io/opc/read-opc.d.ts +19 -3
- package/dist/io/opc/read-opc.js +14 -8
- package/dist/io/opc/read-options.d.ts +2 -2
- package/dist/io/opc/sniff-format.d.ts +2 -2
- package/dist/io/opc/zip-mtime.d.ts +5 -0
- package/dist/io/opc/zip-mtime.js +1 -0
- package/dist/io/style/xf-style.d.ts +38 -6
- package/dist/io/style/xf-style.js +22 -0
- package/dist/io/xlsb/errors.d.ts +1 -1
- package/dist/io/xlsb/formula.d.ts +4 -4
- package/dist/io/xlsb/primitives.d.ts +8 -8
- package/dist/io/xlsb/ptg-functions.d.ts +1 -1
- package/dist/io/xlsb/read-styles.js +2 -20
- package/dist/io/xlsb/read.d.ts +2 -2
- package/dist/io/xlsx/cell-accumulator.d.ts +25 -6
- package/dist/io/xlsx/cell-accumulator.js +111 -30
- package/dist/io/xlsx/cell-value.d.ts +2 -2
- package/dist/io/xlsx/cell-value.js +3 -3
- package/dist/io/xlsx/color-xml.js +11 -17
- package/dist/io/xlsx/comments.d.ts +5 -5
- package/dist/io/xlsx/comments.js +13 -6
- package/dist/io/xlsx/conditional-formatting.d.ts +3 -3
- package/dist/io/xlsx/conditional-formatting.js +7 -16
- package/dist/io/xlsx/data-validation.d.ts +2 -2
- package/dist/io/xlsx/data-validation.js +1 -1
- package/dist/io/xlsx/edit-vba.js +2 -1
- package/dist/io/xlsx/errors.d.ts +3 -3
- package/dist/io/xlsx/hyperlinks.d.ts +4 -2
- package/dist/io/xlsx/hyperlinks.js +5 -5
- package/dist/io/xlsx/images.d.ts +1 -1
- package/dist/io/xlsx/images.js +8 -8
- package/dist/io/xlsx/namespaces.d.ts +2 -2
- package/dist/io/xlsx/package-plan.js +5 -2
- package/dist/io/xlsx/read-pivot.js +2 -5
- package/dist/io/xlsx/read-rows.d.ts +13 -13
- package/dist/io/xlsx/read-rows.js +19 -55
- package/dist/io/xlsx/read-shared-strings.js +7 -5
- package/dist/io/xlsx/read-styles.d.ts +3 -3
- package/dist/io/xlsx/read-styles.js +40 -65
- package/dist/io/xlsx/read-worksheet.js +67 -115
- package/dist/io/xlsx/read.d.ts +3 -5
- package/dist/io/xlsx/read.js +94 -71
- package/dist/io/xlsx/rich-runs.d.ts +1 -1
- package/dist/io/xlsx/rich-runs.js +1 -1
- package/dist/io/xlsx/rich-text.d.ts +1 -1
- package/dist/io/xlsx/shared-strings.d.ts +2 -2
- package/dist/io/xlsx/sheet-properties.js +5 -4
- package/dist/io/xlsx/styles.d.ts +8 -9
- package/dist/io/xlsx/styles.js +4 -3
- package/dist/io/xlsx/tables.d.ts +2 -2
- package/dist/io/xlsx/tables.js +8 -13
- package/dist/io/xlsx/theme-xml.d.ts +37 -0
- package/dist/io/xlsx/theme-xml.js +142 -0
- package/dist/io/xlsx/threaded-comments.d.ts +18 -27
- package/dist/io/xlsx/threaded-comments.js +9 -21
- package/dist/io/xlsx/workbook-xml.d.ts +1 -1
- package/dist/io/xlsx/workbook-xml.js +6 -2
- package/dist/io/xlsx/worksheet-xml.d.ts +2 -2
- package/dist/io/xlsx/worksheet-xml.js +7 -12
- package/dist/io/xlsx/write-stream.d.ts +15 -15
- package/dist/io/xlsx/write-stream.js +5 -3
- package/dist/io/xlsx/write.d.ts +12 -7
- package/dist/io/xlsx/write.js +10 -6
- package/dist/io/xlsx/x14-ext.d.ts +1 -1
- package/dist/vba/bytes.d.ts +12 -0
- package/dist/vba/bytes.js +40 -0
- package/dist/vba/cfb-writer.d.ts +1 -1
- package/dist/vba/cfb.d.ts +1 -1
- package/dist/vba/cfb.js +15 -51
- package/dist/vba/codepage.d.ts +2 -2
- package/dist/vba/errors.d.ts +2 -2
- package/dist/vba/index.d.ts +2 -2
- package/dist/vba/index.js +2 -2
- package/dist/vba/ms-ovba.d.ts +1 -1
- package/dist/vba/ms-ovba.js +1 -3
- package/dist/vba/project-editor.d.ts +9 -9
- package/dist/vba/project-editor.js +2 -11
- package/dist/vba/project.d.ts +5 -5
- package/dist/vba/project.js +1 -10
- package/dist/vba/vba-encoding.d.ts +1 -1
- package/dist/xml/errors.d.ts +1 -1
- package/dist/xml/xml-read.d.ts +38 -9
- package/dist/xml/xml-read.js +23 -0
- package/dist/xml/xml.d.ts +31 -9
- package/dist/xml/xml.js +23 -3
- package/package.json +41 -35
package/dist/core/worksheet.js
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import { AuthoringError } from '../errors.js';
|
|
2
|
-
import {
|
|
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
|
|
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
|
-
#
|
|
40
|
+
#comments = new WorksheetComments(() => this.name);
|
|
42
41
|
#merges = [];
|
|
43
|
-
#images =
|
|
44
|
-
|
|
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 } =
|
|
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
|
-
|
|
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.#
|
|
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
|
-
|
|
255
|
-
return this.#commentThreads.find((thread) => thread.ref === anchor);
|
|
220
|
+
return this.#comments.at(reference);
|
|
256
221
|
}
|
|
257
222
|
addImage(imageId, anchor) {
|
|
258
|
-
|
|
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.
|
|
226
|
+
this.#images.addAnchor(imageId, anchor);
|
|
276
227
|
}
|
|
277
228
|
removeImage(imageId) {
|
|
278
|
-
|
|
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.#
|
|
235
|
+
this.#images.setBackground(imageId);
|
|
286
236
|
}
|
|
287
237
|
removeBackgroundImage() {
|
|
288
|
-
this.#
|
|
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
|
|
345
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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}
|
|
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
|
|
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
|
|
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
|
|
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. */
|
package/dist/entries/core.d.ts
CHANGED
|
@@ -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,
|
|
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';
|
package/dist/entries/core.js
CHANGED
|
@@ -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,
|
|
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';
|
package/dist/entries/vba.d.ts
CHANGED
|
@@ -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
|
|
2
|
+
export { addVbaReference, removeVbaModule, type VbaLibraryReference } from '../vba/project-editor.ts';
|
package/dist/entries/vba.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { parseVbaProject, } from '../vba/project.js';
|
|
2
|
-
export { addVbaReference, removeVbaModule
|
|
2
|
+
export { addVbaReference, removeVbaModule } from '../vba/project-editor.js';
|
package/dist/entries/xlsx.d.ts
CHANGED
|
@@ -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';
|
package/dist/entries/xlsx.js
CHANGED
|
@@ -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'
|
|
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'
|
|
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'
|
|
10
|
-
* - `'internal'
|
|
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
|
|
15
|
-
* `.xlsb` cannot be row-streamed
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
package/dist/io/csv/read.js
CHANGED
|
@@ -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
|
|
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)
|
package/dist/io/csv/write.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
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
|
|
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
|
-
/**
|
|
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;
|
package/dist/io/csv/write.js
CHANGED
|
@@ -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 ??
|
|
32
|
-
if (!wantBom ||
|
|
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];
|
package/dist/io/opc/errors.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { XlsxError } from '../../errors.ts';
|
|
2
2
|
/**
|
|
3
3
|
* Which unsupported input the reader recognised:
|
|
4
|
-
* - `'xls'
|
|
5
|
-
* - `'xlsb'
|
|
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'
|
|
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
|
|
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?"
|
|
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
|
|
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 {
|
package/dist/io/opc/inflate.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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)
|
|
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)
|
|
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;
|
package/dist/io/opc/read-opc.js
CHANGED
|
@@ -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
|
|
5
|
-
* the archive's (untrusted, forgeable) size headers
|
|
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
|
|
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
|
|
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;
|