@shbernal/ts-xlsx 1.3.1 → 2.1.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 +20 -10
- package/dist/bytes.d.ts +24 -0
- package/dist/bytes.js +34 -0
- package/dist/core/address.d.ts +72 -3
- package/dist/core/address.js +50 -10
- package/dist/core/autofilter.d.ts +13 -2
- package/dist/core/autofilter.js +35 -10
- package/dist/core/cell.d.ts +17 -16
- package/dist/core/cell.js +3 -7
- package/dist/core/color-resolution.d.ts +8 -8
- package/dist/core/color-resolution.js +7 -8
- 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 +6 -1
- package/dist/core/conditional-formatting-overlay.js +11 -0
- package/dist/core/conditional-formatting.d.ts +48 -8
- package/dist/core/conditional-formatting.js +88 -0
- package/dist/core/data-validation-overlay.d.ts +12 -1
- package/dist/core/data-validation-overlay.js +21 -2
- package/dist/core/data-validation.d.ts +12 -5
- package/dist/core/data-validation.js +34 -0
- package/dist/core/date.d.ts +3 -3
- package/dist/core/formula.d.ts +6 -6
- package/dist/core/grid-edits.d.ts +16 -0
- package/dist/core/grid-edits.js +29 -11
- package/dist/core/grid-shift.d.ts +19 -0
- package/dist/core/grid-shift.js +8 -0
- package/dist/core/image.d.ts +39 -2
- package/dist/core/image.js +10 -0
- package/dist/core/internal.d.ts +9 -1
- package/dist/core/limits.d.ts +4 -4
- package/dist/core/merge.d.ts +17 -12
- package/dist/core/merge.js +36 -5
- package/dist/core/page-setup.d.ts +20 -6
- package/dist/core/page-setup.js +8 -1
- package/dist/core/pivot-table.d.ts +4 -4
- package/dist/core/pivot-table.js +29 -20
- package/dist/core/preserved.d.ts +3 -3
- package/dist/core/protection.d.ts +7 -4
- package/dist/core/protection.js +20 -14
- package/dist/core/range.d.ts +16 -14
- package/dist/core/range.js +5 -5
- package/dist/core/row-input.d.ts +9 -8
- package/dist/core/row-input.js +12 -10
- package/dist/core/row.d.ts +7 -8
- package/dist/core/row.js +2 -4
- package/dist/core/style.d.ts +41 -14
- package/dist/core/style.js +82 -67
- package/dist/core/table-style.d.ts +9 -9
- package/dist/core/table-style.js +1 -1
- package/dist/core/table.d.ts +53 -51
- package/dist/core/table.js +83 -41
- package/dist/core/theme.d.ts +16 -44
- package/dist/core/theme.js +6 -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 +133 -87
- package/dist/core/workbook.js +74 -133
- package/dist/core/worksheet-comments.d.ts +17 -0
- package/dist/core/worksheet-comments.js +70 -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 +100 -79
- package/dist/core/worksheet.js +63 -142
- package/dist/customui/errors.d.ts +1 -1
- package/dist/customui/ribbon.d.ts +3 -3
- package/dist/customui/ribbon.js +24 -23
- package/dist/entries/core.d.ts +7 -7
- package/dist/entries/core.js +1 -1
- package/dist/entries/csv.d.ts +1 -1
- package/dist/entries/node-unavailable.d.ts +15 -0
- package/dist/entries/node-unavailable.js +20 -0
- package/dist/entries/node.d.ts +1 -0
- package/dist/entries/node.js +1 -0
- package/dist/entries/vba.d.ts +1 -1
- package/dist/entries/vba.js +1 -1
- package/dist/entries/xlsx.d.ts +1 -1
- package/dist/entries/xlsx.js +1 -1
- package/dist/errors.d.ts +12 -12
- package/dist/io/csv/read.js +2 -3
- package/dist/io/csv/write.d.ts +19 -4
- package/dist/io/csv/write.js +34 -4
- package/dist/io/opc/errors.d.ts +6 -6
- package/dist/io/opc/inflate.d.ts +1 -1
- package/dist/io/opc/inflate.js +2 -12
- 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/rels.d.ts +11 -0
- package/dist/io/opc/rels.js +3 -2
- package/dist/io/opc/sniff-format.d.ts +2 -2
- package/dist/io/style/xf-style.d.ts +44 -7
- package/dist/io/style/xf-style.js +27 -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 +26 -9
- package/dist/io/xlsx/cell-accumulator.js +89 -46
- package/dist/io/xlsx/cell-value.d.ts +3 -3
- package/dist/io/xlsx/cell-value.js +9 -6
- package/dist/io/xlsx/color-xml.d.ts +1 -1
- package/dist/io/xlsx/color-xml.js +18 -23
- package/dist/io/xlsx/comments.d.ts +5 -5
- package/dist/io/xlsx/comments.js +17 -8
- package/dist/io/xlsx/conditional-formatting.d.ts +4 -4
- package/dist/io/xlsx/conditional-formatting.js +64 -58
- package/dist/io/xlsx/data-validation.d.ts +3 -3
- package/dist/io/xlsx/data-validation.js +35 -33
- package/dist/io/xlsx/errors.d.ts +3 -3
- package/dist/io/xlsx/hyperlinks.d.ts +4 -2
- package/dist/io/xlsx/hyperlinks.js +10 -18
- package/dist/io/xlsx/images.d.ts +1 -1
- package/dist/io/xlsx/images.js +25 -28
- 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 +4 -13
- 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 -44
- package/dist/io/xlsx/read-styles.d.ts +3 -3
- package/dist/io/xlsx/read-styles.js +42 -66
- package/dist/io/xlsx/read-worksheet.js +73 -129
- package/dist/io/xlsx/read.d.ts +4 -6
- package/dist/io/xlsx/read.js +104 -142
- package/dist/io/xlsx/rich-runs.d.ts +41 -7
- package/dist/io/xlsx/rich-runs.js +94 -30
- 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.d.ts +1 -1
- package/dist/io/xlsx/sheet-properties.js +14 -10
- package/dist/io/xlsx/styles.d.ts +9 -22
- package/dist/io/xlsx/styles.js +65 -89
- package/dist/io/xlsx/tables.d.ts +2 -2
- package/dist/io/xlsx/tables.js +20 -25
- package/dist/io/xlsx/theme-xml.d.ts +37 -0
- package/dist/io/xlsx/theme-xml.js +145 -0
- package/dist/io/xlsx/threaded-comments.d.ts +18 -27
- package/dist/io/xlsx/threaded-comments.js +26 -38
- package/dist/io/xlsx/workbook-xml.js +14 -8
- package/dist/io/xlsx/worksheet-xml.d.ts +2 -2
- package/dist/io/xlsx/worksheet-xml.js +40 -48
- package/dist/io/xlsx/write-stream.d.ts +23 -16
- package/dist/io/xlsx/write-stream.js +13 -14
- package/dist/io/xlsx/write.d.ts +8 -7
- package/dist/io/xlsx/write.js +6 -3
- package/dist/io/xlsx/x14-ext.d.ts +1 -1
- package/dist/sha512.d.ts +2 -0
- package/dist/sha512.js +146 -0
- package/dist/vba/bytes.d.ts +11 -0
- package/dist/vba/bytes.js +29 -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/dir-records.d.ts +53 -0
- package/dist/vba/dir-records.js +28 -0
- 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 +6 -44
- package/dist/vba/project.d.ts +5 -5
- package/dist/vba/project.js +3 -28
- package/dist/vba/vba-encoding.d.ts +1 -1
- package/dist/xml/errors.d.ts +1 -1
- package/dist/xml/xml-read.d.ts +98 -9
- package/dist/xml/xml-read.js +70 -0
- package/dist/xml/xml.d.ts +74 -10
- package/dist/xml/xml.js +39 -7
- package/package.json +59 -36
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* container rather than the spreadsheet inside it, and live in `../opc/namespaces.ts`.
|
|
11
11
|
*/
|
|
12
12
|
/**
|
|
13
|
-
* SpreadsheetML main namespace
|
|
13
|
+
* SpreadsheetML main namespace: the default `xmlns` of the workbook,
|
|
14
14
|
* worksheet, styles, sharedStrings, comments, table and pivot parts.
|
|
15
15
|
*/
|
|
16
16
|
export declare const SPREADSHEETML_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
|
|
@@ -25,7 +25,7 @@ export declare const MARKUP_COMPATIBILITY_NS = "http://schemas.openxmlformats.or
|
|
|
25
25
|
*/
|
|
26
26
|
export declare const REVISION_NS = "http://schemas.microsoft.com/office/spreadsheetml/2014/revision";
|
|
27
27
|
/**
|
|
28
|
-
* The 2018 threaded-comments namespace, shared by both parts of the feature
|
|
28
|
+
* The 2018 threaded-comments namespace, shared by both parts of the feature: a sheet's
|
|
29
29
|
* `threadedComment{n}.xml` and the workbook's `person.xml`. Note the plural `threadedcomments`, all
|
|
30
30
|
* lower-case: Excel matches the URI exactly and reads neither part under any other spelling.
|
|
31
31
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AuthoringError } from '../../errors.js';
|
|
2
2
|
import { extensionOf, relativePartPath, relsPathFor, THEME_PART_PATH } from '../opc/part-paths.js';
|
|
3
3
|
import { preservedRelsXml } from '../opc/rels.js';
|
|
4
|
+
import { applyThemeOverrides } from './theme-xml.js';
|
|
4
5
|
export class SheetRelIds {
|
|
5
6
|
#next = 1;
|
|
6
7
|
next() {
|
|
@@ -75,10 +76,12 @@ export function planPreservedParts(workbook, generatedDrawingCount, generatedMed
|
|
|
75
76
|
? []
|
|
76
77
|
: [{ id: rel.id, type: rel.type, target: relativePartPath(newPath, target) }];
|
|
77
78
|
});
|
|
78
|
-
const
|
|
79
|
+
const overrides = newPath === THEME_PART_PATH ? workbook.themeOverrides : undefined;
|
|
79
80
|
emitted.set(newPath, {
|
|
80
81
|
path: newPath,
|
|
81
|
-
bytes:
|
|
82
|
+
bytes: overrides === undefined
|
|
83
|
+
? part.bytes
|
|
84
|
+
: new TextEncoder().encode(applyThemeOverrides(new TextDecoder().decode(part.bytes), overrides)),
|
|
82
85
|
contentType: part.contentType,
|
|
83
86
|
relsPath: rels.length === 0 ? null : relsPathFor(newPath),
|
|
84
87
|
relsXml: rels.length === 0 ? null : preservedRelsXml(rels),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { pivotMetricFromSubtotal, } from '../../core/pivot-table.js';
|
|
2
|
-
import { localName, parseXml } from '../../xml/xml-read.js';
|
|
1
|
+
import { isDeclarablePivotSourceKind, pivotMetricFromSubtotal, } from '../../core/pivot-table.js';
|
|
2
|
+
import { localName, numInteger, parseXml } from '../../xml/xml-read.js';
|
|
3
3
|
export function parsePivotTable(tableXml, cacheXml) {
|
|
4
4
|
const { fields, source } = parsePivotCacheDefinition(cacheXml);
|
|
5
5
|
const def = parsePivotTableDefinition(tableXml);
|
|
@@ -85,20 +85,11 @@ function parsePivotTableDefinition(tableXml) {
|
|
|
85
85
|
});
|
|
86
86
|
return { name, cacheId, rowFields, columnFields, valueField, valueCaption, metric };
|
|
87
87
|
}
|
|
88
|
-
const SOURCE_KINDS = new Set([
|
|
89
|
-
'worksheet',
|
|
90
|
-
'external',
|
|
91
|
-
'consolidation',
|
|
92
|
-
'scenario',
|
|
93
|
-
]);
|
|
94
88
|
function sourceKind(type) {
|
|
95
89
|
if (type === undefined)
|
|
96
90
|
return 'worksheet';
|
|
97
|
-
return
|
|
91
|
+
return isDeclarablePivotSourceKind(type) ? type : 'unknown';
|
|
98
92
|
}
|
|
99
93
|
function toIndex(value) {
|
|
100
|
-
|
|
101
|
-
return -1;
|
|
102
|
-
const index = Number(value);
|
|
103
|
-
return Number.isInteger(index) && index >= 0 ? index : -1;
|
|
94
|
+
return numInteger(value, 0) ?? -1;
|
|
104
95
|
}
|
|
@@ -8,7 +8,7 @@ export interface ReadSheetRowsOptions extends ReadXlsxOptions {
|
|
|
8
8
|
readonly sheet?: string | number;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* The resolved style facets of a streamed cell
|
|
11
|
+
* The resolved style facets of a streamed cell: its own `<c s>` cell format, flattened exactly as
|
|
12
12
|
* the buffered reader resolves it. Present only when the cell carries a format; a consumer can copy
|
|
13
13
|
* these straight onto a writer cell to preserve its look through a streaming read→write.
|
|
14
14
|
*/
|
|
@@ -19,7 +19,7 @@ export interface StreamedCell {
|
|
|
19
19
|
readonly col: number;
|
|
20
20
|
/** Canonical A1 address (`"B3"`). */
|
|
21
21
|
readonly address: string;
|
|
22
|
-
/** The decoded value
|
|
22
|
+
/** The decoded value, identical to what `readXlsx` would produce for the same cell. */
|
|
23
23
|
readonly value: CellValue;
|
|
24
24
|
/** The cell's resolved style facets, or absent when the cell carries no format of its own. */
|
|
25
25
|
readonly style?: StreamedCellStyle;
|
|
@@ -39,14 +39,14 @@ export interface StreamedRow {
|
|
|
39
39
|
*
|
|
40
40
|
* The two summaries are resolved lazily: reading either accessor drives a full scan of the sheet if
|
|
41
41
|
* its rows have not already been consumed, so their order relative to `rows()` never matters. (When
|
|
42
|
-
* rows *are* consumed first
|
|
42
|
+
* rows *are* consumed first, the streaming idiom, the accessors reuse that pass and re-scan
|
|
43
43
|
* nothing.)
|
|
44
44
|
*/
|
|
45
45
|
export interface StreamedSheet {
|
|
46
|
-
/** The worksheet's declared name, joined from the workbook part
|
|
46
|
+
/** The worksheet's declared name, joined from the workbook part. Never a positional placeholder. */
|
|
47
47
|
readonly name: string;
|
|
48
48
|
/** Stream this sheet's rows, one at a time, in sheet order. */
|
|
49
|
-
rows(): Generator<StreamedRow>;
|
|
49
|
+
rows(): Generator<StreamedRow, void, undefined>;
|
|
50
50
|
/** 1-based indices of columns the sheet declares hidden, ascending. */
|
|
51
51
|
readonly hiddenColumns: readonly number[];
|
|
52
52
|
/** The sheet's merged ranges, as canonical A1 range strings, in declaration order. */
|
|
@@ -55,31 +55,31 @@ export interface StreamedSheet {
|
|
|
55
55
|
/**
|
|
56
56
|
* Stream a worksheet's rows from an `.xlsx` package, yielding each in sheet order without building
|
|
57
57
|
* the workbook model. Only rows the sheet actually declares are yielded, and within a row only its
|
|
58
|
-
* non-empty cells
|
|
58
|
+
* non-empty cells: a blank or style-only cell contributes nothing, matching the intent of a data
|
|
59
59
|
* read.
|
|
60
60
|
*
|
|
61
61
|
* @param data The raw `.xlsx` bytes.
|
|
62
62
|
* @param options Sheet selector and the inflate bound (see {@link ReadSheetRowsOptions}).
|
|
63
63
|
* @throws {UnsupportedFormatError} if the input is not a readable `.xlsx` package (a legacy `.xls`, a
|
|
64
|
-
* binary `.xlsb`, or an unrecognised/non-ZIP blob
|
|
65
|
-
* @throws {PackageReadError} if the input is a ZIP that cannot be unpacked
|
|
64
|
+
* binary `.xlsb`, or an unrecognised/non-ZIP blob; branch on `.format`).
|
|
65
|
+
* @throws {PackageReadError} if the input is a ZIP that cannot be unpacked: a corrupt or
|
|
66
66
|
* truncated archive, or one exceeding the inflate bound (a probable zip bomb).
|
|
67
67
|
* @throws {XlsxParseError} if the package's workbook part declares no worksheets.
|
|
68
68
|
* @throws {RangeError} / {@link AuthoringError} if `options.sheet` selects a position, or a name,
|
|
69
69
|
* that no worksheet has.
|
|
70
70
|
*/
|
|
71
|
-
export declare function readSheetRows(data: Uint8Array, options?: ReadSheetRowsOptions): Generator<StreamedRow>;
|
|
71
|
+
export declare function readSheetRows(data: Uint8Array, options?: ReadSheetRowsOptions): Generator<StreamedRow, void, undefined>;
|
|
72
72
|
/**
|
|
73
73
|
* Stream every worksheet of an `.xlsx` package in workbook order, without building the workbook
|
|
74
74
|
* model. Each yielded {@link StreamedSheet} carries the declared sheet name and lets the caller
|
|
75
|
-
* stream that sheet's rows and read its hidden-column and merge summaries
|
|
75
|
+
* stream that sheet's rows and read its hidden-column and merge summaries: the streaming analogue
|
|
76
76
|
* of walking `readXlsx(data).worksheets`.
|
|
77
77
|
*
|
|
78
78
|
* @param data The raw `.xlsx` bytes.
|
|
79
79
|
* @param options The inflate bound (see {@link ReadXlsxOptions}).
|
|
80
80
|
* @throws {UnsupportedFormatError} if the input is not a readable `.xlsx` package (a legacy `.xls`, a
|
|
81
|
-
* binary `.xlsb`, or an unrecognised/non-ZIP blob
|
|
82
|
-
* @throws {PackageReadError} if the input is a ZIP that cannot be unpacked
|
|
81
|
+
* binary `.xlsb`, or an unrecognised/non-ZIP blob; branch on `.format`).
|
|
82
|
+
* @throws {PackageReadError} if the input is a ZIP that cannot be unpacked: a corrupt or
|
|
83
83
|
* truncated archive, or one exceeding the inflate bound (a probable zip bomb).
|
|
84
84
|
*/
|
|
85
|
-
export declare function readWorkbookStream(data: Uint8Array, options?: ReadXlsxOptions): Generator<StreamedSheet>;
|
|
85
|
+
export declare function readWorkbookStream(data: Uint8Array, options?: ReadXlsxOptions): Generator<StreamedSheet, void, undefined>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { MAX_COLUMN } from '../../core/address.js';
|
|
1
|
+
import { MAX_COLUMN, MAX_ROW } from '../../core/address.js';
|
|
2
2
|
import { AuthoringError } from '../../errors.js';
|
|
3
|
-
import { boolStrict, closeEmptyElements, localName, xmlEvents } from '../../xml/xml-read.js';
|
|
3
|
+
import { boolStrict, closeEmptyElements, localName, numInteger, xmlEvents, } from '../../xml/xml-read.js';
|
|
4
4
|
import { packageAccessors } from '../opc/read-opc.js';
|
|
5
5
|
import { inflateSpreadsheetPackage, unsupportedWorkbookPart } from '../opc/sniff-format.js';
|
|
6
6
|
import { CellAccumulator } from './cell-accumulator.js';
|
|
7
7
|
import { XlsxParseError } from './errors.js';
|
|
8
|
-
import { DEFAULT_MAX_UNCOMPRESSED, parseRelationships, parseStyleTable, parseWorkbookSheets, resolveWorkbookPart, } from './read.js';
|
|
9
8
|
import { parseSharedStrings } from './read-shared-strings.js';
|
|
9
|
+
import { DEFAULT_MAX_UNCOMPRESSED, parseRelationships, parseStyleTable, parseWorkbookSheets, resolveWorkbookPart, } from './read.js';
|
|
10
10
|
export function* readSheetRows(data, options = {}) {
|
|
11
11
|
const pkg = openPackage(data, options.maxUncompressedBytes);
|
|
12
12
|
const chosen = pickSheet(pkg.sheets, options.sheet);
|
|
@@ -102,13 +102,11 @@ function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
|
|
|
102
102
|
let rowNumber = 0;
|
|
103
103
|
let lastRow = 0;
|
|
104
104
|
let rowHidden = false;
|
|
105
|
+
let rowInGrid = true;
|
|
105
106
|
let cells = [];
|
|
106
|
-
const cell = new CellAccumulator();
|
|
107
|
-
let inInlineString = false;
|
|
108
|
-
let capture = false;
|
|
109
|
-
let text = '';
|
|
107
|
+
const cell = new CellAccumulator({ richRuns: false });
|
|
110
108
|
const finalizeCell = () => {
|
|
111
|
-
if (cell.ref === '' || cell.col < 0)
|
|
109
|
+
if (cell.ref === '' || cell.col < 0 || !rowInGrid)
|
|
112
110
|
return;
|
|
113
111
|
const style = cell.styleIndex >= 0 ? xfStyles[cell.styleIndex] : undefined;
|
|
114
112
|
const value = cell.decode(sharedStrings, style);
|
|
@@ -119,19 +117,18 @@ function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
|
|
|
119
117
|
};
|
|
120
118
|
for (const event of closeEmptyElements(xmlEvents(xml), CELL_EMPTY_CLOSE)) {
|
|
121
119
|
if (event.kind === 'text') {
|
|
122
|
-
|
|
123
|
-
text += event.text;
|
|
120
|
+
cell.appendChunk(event.text);
|
|
124
121
|
continue;
|
|
125
122
|
}
|
|
126
123
|
if (event.kind === 'open') {
|
|
127
124
|
const local = localName(event.name);
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
if (cell.openElement(local, event.attrs, event.selfClosing))
|
|
126
|
+
continue;
|
|
130
127
|
switch (local) {
|
|
131
128
|
case 'row': {
|
|
132
|
-
|
|
133
|
-
rowNumber = Number.isInteger(declared) && declared >= 1 ? declared : lastRow + 1;
|
|
129
|
+
rowNumber = numInteger(event.attrs.r, 1) ?? lastRow + 1;
|
|
134
130
|
lastRow = rowNumber;
|
|
131
|
+
rowInGrid = rowNumber <= MAX_ROW;
|
|
135
132
|
rowHidden = boolStrict(event.attrs.hidden);
|
|
136
133
|
cells = [];
|
|
137
134
|
break;
|
|
@@ -143,60 +140,27 @@ function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
|
|
|
143
140
|
if (event.attrs.ref !== undefined)
|
|
144
141
|
merges.push(event.attrs.ref);
|
|
145
142
|
break;
|
|
146
|
-
case 'c':
|
|
147
|
-
cell.beginCell(event.attrs);
|
|
148
|
-
break;
|
|
149
|
-
case 'is':
|
|
150
|
-
inInlineString = true;
|
|
151
|
-
cell.beginInlineString();
|
|
152
|
-
break;
|
|
153
|
-
case 'f':
|
|
154
|
-
capture = true;
|
|
155
|
-
cell.beginFormula(event.attrs, event.selfClosing);
|
|
156
|
-
break;
|
|
157
|
-
case 'v':
|
|
158
|
-
case 't':
|
|
159
|
-
capture = true;
|
|
160
|
-
break;
|
|
161
143
|
default:
|
|
162
144
|
break;
|
|
163
145
|
}
|
|
164
|
-
if (event.selfClosing && (local === 'f' || local === 'v'))
|
|
165
|
-
capture = false;
|
|
166
146
|
continue;
|
|
167
147
|
}
|
|
168
148
|
const local = localName(event.name);
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
cell.setValue(text);
|
|
175
|
-
break;
|
|
176
|
-
case 't':
|
|
177
|
-
cell.appendText(text, inInlineString);
|
|
178
|
-
break;
|
|
179
|
-
case 'is':
|
|
180
|
-
inInlineString = false;
|
|
181
|
-
break;
|
|
182
|
-
case 'c':
|
|
183
|
-
finalizeCell();
|
|
184
|
-
break;
|
|
185
|
-
case 'row':
|
|
149
|
+
const claimed = cell.closeElement(local);
|
|
150
|
+
if (claimed === 'cell')
|
|
151
|
+
finalizeCell();
|
|
152
|
+
else if (claimed === 'other' && local === 'row') {
|
|
153
|
+
if (rowInGrid)
|
|
186
154
|
yield { number: rowNumber, hidden: rowHidden, cells };
|
|
187
|
-
break;
|
|
188
|
-
default:
|
|
189
|
-
break;
|
|
190
155
|
}
|
|
191
|
-
capture = false;
|
|
192
156
|
}
|
|
193
157
|
}
|
|
194
158
|
function collectHiddenColumn(attrs, hiddenColumns) {
|
|
195
159
|
if (attrs.hidden !== '1' && attrs.hidden !== 'true')
|
|
196
160
|
return;
|
|
197
|
-
const min =
|
|
198
|
-
const max =
|
|
199
|
-
if (
|
|
161
|
+
const min = numInteger(attrs.min, 1);
|
|
162
|
+
const max = numInteger(attrs.max, 1);
|
|
163
|
+
if (min === undefined || max === undefined)
|
|
200
164
|
return;
|
|
201
165
|
const last = Math.min(max, MAX_COLUMN);
|
|
202
166
|
for (let index = min; index <= last; index++)
|
|
@@ -4,55 +4,18 @@ export function parseSharedStrings(xml) {
|
|
|
4
4
|
if (xml === '')
|
|
5
5
|
return [];
|
|
6
6
|
const strings = [];
|
|
7
|
-
|
|
8
|
-
const runs = new RunAccumulator();
|
|
9
|
-
let isRich = false;
|
|
10
|
-
let capture = false;
|
|
11
|
-
let text = '';
|
|
7
|
+
const runs = new RunAccumulator({ container: 'si', readRuns: true });
|
|
12
8
|
parseXml(xml, {
|
|
13
|
-
onOpen(name, attrs) {
|
|
14
|
-
|
|
15
|
-
switch (local) {
|
|
16
|
-
case 'si':
|
|
17
|
-
plain = '';
|
|
18
|
-
runs.reset();
|
|
19
|
-
isRich = false;
|
|
20
|
-
break;
|
|
21
|
-
case 'r':
|
|
22
|
-
isRich = true;
|
|
23
|
-
runs.beginRun();
|
|
24
|
-
break;
|
|
25
|
-
case 'rPr':
|
|
26
|
-
runs.beginProperties();
|
|
27
|
-
break;
|
|
28
|
-
case 't':
|
|
29
|
-
capture = true;
|
|
30
|
-
text = '';
|
|
31
|
-
break;
|
|
32
|
-
default:
|
|
33
|
-
runs.applyProperty(local, attrs);
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
9
|
+
onOpen(name, attrs, selfClosing) {
|
|
10
|
+
runs.open(localName(name), attrs, selfClosing);
|
|
36
11
|
},
|
|
37
12
|
onText(chunk) {
|
|
38
|
-
|
|
39
|
-
text += chunk;
|
|
13
|
+
runs.text(chunk);
|
|
40
14
|
},
|
|
41
15
|
onClose(name) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (!runs.appendText(text))
|
|
46
|
-
plain += text;
|
|
47
|
-
capture = false;
|
|
48
|
-
break;
|
|
49
|
-
case 'r':
|
|
50
|
-
runs.endRun();
|
|
51
|
-
break;
|
|
52
|
-
case 'si':
|
|
53
|
-
strings.push(isRich ? { richText: runs.runs } : plain);
|
|
54
|
-
break;
|
|
55
|
-
}
|
|
16
|
+
if (runs.close(localName(name)) !== 'container')
|
|
17
|
+
return;
|
|
18
|
+
strings.push(runs.isRich ? { richText: runs.runs } : runs.plainText);
|
|
56
19
|
},
|
|
57
20
|
});
|
|
58
21
|
return strings;
|
|
@@ -9,7 +9,7 @@ export declare function applyFontChild(draft: FontDraft, local: string, attrs: X
|
|
|
9
9
|
/**
|
|
10
10
|
* Extract the custom indexed-color palette (`<colors><indexedColors>`) from styles.xml as verbatim
|
|
11
11
|
* `<rgbColor rgb="…"/>` fragments, or an empty list when the file rides the default palette. Kept raw
|
|
12
|
-
*
|
|
12
|
+
* rather than parsed into RGB and re-serialised, so the exact entries (count, order, casing) a
|
|
13
13
|
* source file declared survive a round-trip and every `indexed="…"` reference keeps its RGB.
|
|
14
14
|
*/
|
|
15
15
|
export declare function parseIndexedColors(stylesXml: string): string[];
|
|
@@ -25,8 +25,8 @@ export declare function parseMruColors(stylesXml: string): string[];
|
|
|
25
25
|
* container's nominated `defaultTableStyle`/`defaultPivotStyle`. See {@link TableStyleTable} for why
|
|
26
26
|
* the definitions stay raw while the two names are decoded.
|
|
27
27
|
*
|
|
28
|
-
* A file with no such block
|
|
29
|
-
* only defaults to state
|
|
28
|
+
* A file with no such block, or with the self-closing `count="0"` container Excel writes when it has
|
|
29
|
+
* only defaults to state, yields an empty {@link TableStyleTable.styles} and whichever names it did
|
|
30
30
|
* carry.
|
|
31
31
|
*/
|
|
32
32
|
export declare function parseTableStyles(stylesXml: string): TableStyleTable;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { boolPresent, boolStrict, closeEmptyElements, localName, openElements, xmlEvents, } from '../../xml/xml-read.js';
|
|
3
|
-
import { numFmtCodeFor } from '../style/xf-style.js';
|
|
1
|
+
import { isBorderStyle, isFillPatternType, isFontScheme, isFontVerticalAlignment, isHorizontalAlignment, isNamedUnderlineStyle, isVerticalAlignment, } from '../../core/style.js';
|
|
2
|
+
import { boolPresent, boolStrict, closeEmptyElements, localName, numFinite, numInteger, openElements, xmlEvents, } from '../../xml/xml-read.js';
|
|
3
|
+
import { numFmtCodeFor, resolveStyleTable, } from '../style/xf-style.js';
|
|
4
4
|
import { parseColor } from './color-xml.js';
|
|
5
5
|
const BORDER_EDGE_NAMES = ['left', 'right', 'top', 'bottom', 'diagonal'];
|
|
6
6
|
const BORDER_EDGES = new Set(BORDER_EDGE_NAMES);
|
|
7
|
+
const isBorderEdgeName = (name) => BORDER_EDGES.has(name);
|
|
7
8
|
const STYLE_EMPTY_CLOSES = new Set([
|
|
8
9
|
'font',
|
|
9
10
|
'border',
|
|
@@ -53,24 +54,7 @@ export function parseStyleTable(xml) {
|
|
|
53
54
|
}
|
|
54
55
|
next = events.next();
|
|
55
56
|
}
|
|
56
|
-
|
|
57
|
-
if (xf.xfId === undefined)
|
|
58
|
-
return xf;
|
|
59
|
-
const named = namedXfs[xf.xfId];
|
|
60
|
-
return named === undefined ? xf : { ...named, ...xf };
|
|
61
|
-
});
|
|
62
|
-
const namedStyles = namedXfs.map((xf, index) => {
|
|
63
|
-
const label = cellStyleNames.find((entry) => entry.xfId === index);
|
|
64
|
-
const style = {};
|
|
65
|
-
assignStyleFacets(style, xf);
|
|
66
|
-
if (label?.name !== undefined)
|
|
67
|
-
style.name = label.name;
|
|
68
|
-
if (label?.builtinId !== undefined)
|
|
69
|
-
style.builtinId = label.builtinId;
|
|
70
|
-
return style;
|
|
71
|
-
});
|
|
72
|
-
const defaultFont = fonts[0];
|
|
73
|
-
return defaultFont === undefined ? { cellXfs, namedStyles } : { cellXfs, namedStyles, defaultFont };
|
|
57
|
+
return resolveStyleTable({ directXfs: xfStyles, namedXfs, labels: cellStyleNames, fonts });
|
|
74
58
|
}
|
|
75
59
|
function* until(events, container) {
|
|
76
60
|
let next = events.next();
|
|
@@ -86,8 +70,8 @@ function parseNumFmts(events) {
|
|
|
86
70
|
const codes = new Map();
|
|
87
71
|
for (const event of until(events, 'numFmts')) {
|
|
88
72
|
if (event.kind === 'open' && localName(event.name) === 'numFmt') {
|
|
89
|
-
const id =
|
|
90
|
-
if (
|
|
73
|
+
const id = numInteger(event.attrs.numFmtId, 1);
|
|
74
|
+
if (id !== undefined && event.attrs.formatCode !== undefined) {
|
|
91
75
|
codes.set(id, event.attrs.formatCode);
|
|
92
76
|
}
|
|
93
77
|
}
|
|
@@ -151,8 +135,7 @@ function parseFills(events) {
|
|
|
151
135
|
break;
|
|
152
136
|
case 'stop':
|
|
153
137
|
if (gradientDraft !== null) {
|
|
154
|
-
|
|
155
|
-
gradientDraft.stopPosition = Number.isFinite(position) ? position : 0;
|
|
138
|
+
gradientDraft.stopPosition = numFinite(attrs.position) ?? 0;
|
|
156
139
|
gradientDraft.stopColor = undefined;
|
|
157
140
|
}
|
|
158
141
|
break;
|
|
@@ -210,7 +193,7 @@ function parseBorders(events) {
|
|
|
210
193
|
borderDraft.diagonalDown = true;
|
|
211
194
|
}
|
|
212
195
|
else if (borderDraft !== null) {
|
|
213
|
-
if (
|
|
196
|
+
if (isBorderEdgeName(local)) {
|
|
214
197
|
if (attrs.style !== undefined && isBorderStyle(attrs.style)) {
|
|
215
198
|
currentEdge = local;
|
|
216
199
|
borderDraft[currentEdge] = { style: attrs.style };
|
|
@@ -271,12 +254,12 @@ function parseXfTable(events, container, deps) {
|
|
|
271
254
|
return xfs;
|
|
272
255
|
}
|
|
273
256
|
function resolveXf(attrs, deps, captureXfId) {
|
|
274
|
-
const fillId =
|
|
275
|
-
const fill =
|
|
276
|
-
const fontId =
|
|
277
|
-
const font =
|
|
278
|
-
const borderId =
|
|
279
|
-
const border =
|
|
257
|
+
const fillId = numInteger(attrs.fillId, 0);
|
|
258
|
+
const fill = fillId !== undefined ? deps.fills[fillId] : undefined;
|
|
259
|
+
const fontId = numInteger(attrs.fontId, 0);
|
|
260
|
+
const font = fontId !== undefined ? deps.fonts[fontId] : undefined;
|
|
261
|
+
const borderId = numInteger(attrs.borderId, 1);
|
|
262
|
+
const border = borderId !== undefined ? deps.borders[borderId] : undefined;
|
|
280
263
|
const numFmt = resolveNumFmt(attrs.numFmtId, deps.numFmtCodes);
|
|
281
264
|
const draft = {};
|
|
282
265
|
if (fill)
|
|
@@ -289,9 +272,9 @@ function resolveXf(attrs, deps, captureXfId) {
|
|
|
289
272
|
draft.border = border;
|
|
290
273
|
if (boolStrict(attrs.quotePrefix))
|
|
291
274
|
draft.quotePrefix = true;
|
|
292
|
-
if (captureXfId
|
|
293
|
-
const xfId =
|
|
294
|
-
if (
|
|
275
|
+
if (captureXfId) {
|
|
276
|
+
const xfId = numInteger(attrs.xfId, 1);
|
|
277
|
+
if (xfId !== undefined)
|
|
295
278
|
draft.xfId = xfId;
|
|
296
279
|
}
|
|
297
280
|
return draft;
|
|
@@ -301,16 +284,14 @@ function parseCellStyles(events) {
|
|
|
301
284
|
for (const event of until(events, 'cellStyles')) {
|
|
302
285
|
if (event.kind === 'open' && localName(event.name) === 'cellStyle') {
|
|
303
286
|
const attrs = event.attrs;
|
|
304
|
-
const xfId =
|
|
305
|
-
if (
|
|
287
|
+
const xfId = numInteger(attrs.xfId);
|
|
288
|
+
if (xfId !== undefined) {
|
|
306
289
|
const entry = { xfId };
|
|
307
290
|
if (attrs.name !== undefined)
|
|
308
291
|
entry.name = attrs.name;
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
entry.builtinId = builtinId;
|
|
313
|
-
}
|
|
292
|
+
const builtinId = numInteger(attrs.builtinId);
|
|
293
|
+
if (builtinId !== undefined)
|
|
294
|
+
entry.builtinId = builtinId;
|
|
314
295
|
names.push(entry);
|
|
315
296
|
}
|
|
316
297
|
}
|
|
@@ -346,8 +327,8 @@ export function applyFontChild(draft, local, attrs) {
|
|
|
346
327
|
draft.vertAlign = attrs.val;
|
|
347
328
|
break;
|
|
348
329
|
case 'sz': {
|
|
349
|
-
const size =
|
|
350
|
-
if (
|
|
330
|
+
const size = numFinite(attrs.val);
|
|
331
|
+
if (size !== undefined)
|
|
351
332
|
draft.size = size;
|
|
352
333
|
break;
|
|
353
334
|
}
|
|
@@ -360,14 +341,14 @@ export function applyFontChild(draft, local, attrs) {
|
|
|
360
341
|
draft.name = attrs.val;
|
|
361
342
|
break;
|
|
362
343
|
case 'family': {
|
|
363
|
-
const family =
|
|
364
|
-
if (
|
|
344
|
+
const family = numInteger(attrs.val);
|
|
345
|
+
if (family !== undefined)
|
|
365
346
|
draft.family = family;
|
|
366
347
|
break;
|
|
367
348
|
}
|
|
368
349
|
case 'charset': {
|
|
369
|
-
const charset =
|
|
370
|
-
if (
|
|
350
|
+
const charset = numInteger(attrs.val);
|
|
351
|
+
if (charset !== undefined)
|
|
371
352
|
draft.charset = charset;
|
|
372
353
|
break;
|
|
373
354
|
}
|
|
@@ -380,7 +361,8 @@ export function applyFontChild(draft, local, attrs) {
|
|
|
380
361
|
}
|
|
381
362
|
}
|
|
382
363
|
function resolveNumFmt(raw, custom) {
|
|
383
|
-
|
|
364
|
+
const id = numInteger(raw, 1);
|
|
365
|
+
return id === undefined ? undefined : numFmtCodeFor(id, custom);
|
|
384
366
|
}
|
|
385
367
|
function toFill(pattern, fgColor, bgColor) {
|
|
386
368
|
if (!isFillPatternType(pattern) || pattern === 'none')
|
|
@@ -394,8 +376,8 @@ function toFill(pattern, fgColor, bgColor) {
|
|
|
394
376
|
}
|
|
395
377
|
function assignGradientNumbers(fill, attrs) {
|
|
396
378
|
for (const key of ['degree', 'left', 'right', 'top', 'bottom']) {
|
|
397
|
-
const value =
|
|
398
|
-
if (
|
|
379
|
+
const value = numFinite(attrs[key]);
|
|
380
|
+
if (value !== undefined)
|
|
399
381
|
fill[key] = value;
|
|
400
382
|
}
|
|
401
383
|
}
|
|
@@ -414,25 +396,19 @@ function parseAlignment(attrs) {
|
|
|
414
396
|
}
|
|
415
397
|
if (attrs.vertical !== undefined && isVerticalAlignment(attrs.vertical))
|
|
416
398
|
out.vertical = attrs.vertical;
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
out.textRotation = rotation;
|
|
421
|
-
}
|
|
399
|
+
const rotation = numFinite(attrs.textRotation);
|
|
400
|
+
if (rotation !== undefined && rotation !== 0)
|
|
401
|
+
out.textRotation = rotation;
|
|
422
402
|
if (boolStrict(attrs.wrapText))
|
|
423
403
|
out.wrapText = true;
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
out.indent = indent;
|
|
428
|
-
}
|
|
404
|
+
const indent = numInteger(attrs.indent);
|
|
405
|
+
if (indent !== undefined && indent !== 0)
|
|
406
|
+
out.indent = indent;
|
|
429
407
|
if (boolStrict(attrs.shrinkToFit))
|
|
430
408
|
out.shrinkToFit = true;
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
out.readingOrder = order;
|
|
435
|
-
}
|
|
409
|
+
const order = numInteger(attrs.readingOrder);
|
|
410
|
+
if (order !== undefined && order !== 0)
|
|
411
|
+
out.readingOrder = order;
|
|
436
412
|
return Object.keys(out).length > 0 ? out : undefined;
|
|
437
413
|
}
|
|
438
414
|
function parseProtection(attrs) {
|