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