@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
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import { Workbook } from '../../core/workbook.js';
|
|
2
|
+
import { WorksheetMerges } from '../../core/worksheet-merges.js';
|
|
2
3
|
import { AuthoringError, quoted } from '../../errors.js';
|
|
4
|
+
import { numInteger } from '../../xml/xml-attrs.js';
|
|
3
5
|
import { closeEmptyElements, parseXmlPasses } from '../../xml/xml-read.js';
|
|
4
6
|
import { boolStrict, localName, xmlEvents } from '../../xml/xml-scan.js';
|
|
5
7
|
import { openSpreadsheetPackage, readPartRelationships } from '../opc/read-opc.js';
|
|
6
8
|
import { unsupportedWorkbookPart } from '../opc/sniff-format.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
9
|
+
import { ColumnRecordBudget } from '../read-policy/column-budget.js';
|
|
10
|
+
import { admitting, repairedSheetNames } from '../read-policy/read-repair.js';
|
|
11
|
+
import { CellStyleResolver } from '../style/cell-style-resolution.js';
|
|
12
|
+
import { CellAccumulator, WORKSHEET_BODY_EMPTY_CLOSES } from './cell-accumulator.js';
|
|
13
|
+
import { readCellMetadata } from './cell-metadata.js';
|
|
14
|
+
import { takeColumnSpan } from './column-span.js';
|
|
10
15
|
import { XlsxParseError } from './errors.js';
|
|
11
16
|
import { SHARED_STRINGS_PART, STYLES_PART } from './part-names.js';
|
|
12
17
|
import { parseSharedStrings } from './read-shared-strings.js';
|
|
13
|
-
import {
|
|
18
|
+
import { parseStyleTable } from './read-styles.js';
|
|
19
|
+
import { definedNamesPass, workbookPropertiesPass, workbookSheetsPass, } from './read-workbook-xml.js';
|
|
14
20
|
import { RowPositionTracker } from './row-position.js';
|
|
15
21
|
export function* readSheetRows(data, options = {}) {
|
|
16
22
|
const pkg = openPackage(data, options.maxUncompressedBytes);
|
|
@@ -18,13 +24,13 @@ export function* readSheetRows(data, options = {}) {
|
|
|
18
24
|
const sheetXml = pkg.sheetXml(chosen.relId);
|
|
19
25
|
if (sheetXml === undefined)
|
|
20
26
|
return;
|
|
21
|
-
yield* scanSheet(sheetXml, pkg
|
|
27
|
+
yield* scanSheet(sheetXml, pkg, new Set(), new WorksheetMerges());
|
|
22
28
|
}
|
|
23
29
|
export function* readWorkbookStream(data, options = {}) {
|
|
24
30
|
const pkg = openPackage(data, options.maxUncompressedBytes);
|
|
25
31
|
for (const sheet of pkg.sheets) {
|
|
26
32
|
const xml = pkg.sheetXml(sheet.relId) ?? '';
|
|
27
|
-
yield new StreamedSheetReader(sheet.name, xml, pkg
|
|
33
|
+
yield new StreamedSheetReader(sheet.name, xml, pkg);
|
|
28
34
|
}
|
|
29
35
|
}
|
|
30
36
|
function openPackage(data, maxUncompressedBytes) {
|
|
@@ -35,8 +41,9 @@ function openPackage(data, maxUncompressedBytes) {
|
|
|
35
41
|
}
|
|
36
42
|
const properties = new Workbook();
|
|
37
43
|
const sheetsPass = workbookSheetsPass();
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
const namesPass = definedNamesPass();
|
|
45
|
+
parseXmlPasses(workbookXml, [sheetsPass, workbookPropertiesPass(properties), namesPass]);
|
|
46
|
+
const sheets = repairedSheetNames(sheetsPass.result());
|
|
40
47
|
const rels = readPartRelationships(documentPath, text);
|
|
41
48
|
const sharedStrings = parseSharedStrings(rels.relatedTextOrPath('sharedStrings', SHARED_STRINGS_PART));
|
|
42
49
|
const { cellXfs: xfStyles } = parseStyleTable(rels.relatedTextOrPath('styles', STYLES_PART));
|
|
@@ -45,6 +52,8 @@ function openPackage(data, maxUncompressedBytes) {
|
|
|
45
52
|
sharedStrings,
|
|
46
53
|
xfStyles,
|
|
47
54
|
dateEpoch: properties.dateEpoch,
|
|
55
|
+
definedNames: namesPass.spellings(),
|
|
56
|
+
cellMetadata: readCellMetadata(rels),
|
|
48
57
|
sheetXml(relId) {
|
|
49
58
|
const target = rels.byId(relId)?.target;
|
|
50
59
|
return target === undefined ? undefined : text(rels.pathOf(target));
|
|
@@ -71,24 +80,20 @@ function pickSheet(sheets, selector) {
|
|
|
71
80
|
class StreamedSheetReader {
|
|
72
81
|
name;
|
|
73
82
|
#xml;
|
|
74
|
-
#
|
|
75
|
-
#xfStyles;
|
|
76
|
-
#dateEpoch;
|
|
83
|
+
#tables;
|
|
77
84
|
#hiddenColumns = new Set();
|
|
78
|
-
#merges =
|
|
85
|
+
#merges = new WorksheetMerges();
|
|
79
86
|
#scanned = false;
|
|
80
|
-
constructor(name, xml,
|
|
87
|
+
constructor(name, xml, tables) {
|
|
81
88
|
this.name = name;
|
|
82
89
|
this.#xml = xml;
|
|
83
|
-
this.#
|
|
84
|
-
this.#xfStyles = xfStyles;
|
|
85
|
-
this.#dateEpoch = dateEpoch;
|
|
90
|
+
this.#tables = tables;
|
|
86
91
|
}
|
|
87
92
|
*rows() {
|
|
88
93
|
this.#hiddenColumns = new Set();
|
|
89
|
-
this.#merges =
|
|
94
|
+
this.#merges = new WorksheetMerges();
|
|
90
95
|
this.#scanned = false;
|
|
91
|
-
yield* scanSheet(this.#xml, this.#
|
|
96
|
+
yield* scanSheet(this.#xml, this.#tables, this.#hiddenColumns, this.#merges);
|
|
92
97
|
this.#scanned = true;
|
|
93
98
|
}
|
|
94
99
|
get hiddenColumns() {
|
|
@@ -97,7 +102,7 @@ class StreamedSheetReader {
|
|
|
97
102
|
}
|
|
98
103
|
get merges() {
|
|
99
104
|
this.#ensureScanned();
|
|
100
|
-
return [...this.#merges];
|
|
105
|
+
return [...this.#merges.ranges];
|
|
101
106
|
}
|
|
102
107
|
#ensureScanned() {
|
|
103
108
|
if (this.#scanned)
|
|
@@ -106,28 +111,28 @@ class StreamedSheetReader {
|
|
|
106
111
|
}
|
|
107
112
|
}
|
|
108
113
|
}
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
function* scanSheet(xml, tables, hiddenColumns, merges) {
|
|
115
|
+
const { sharedStrings, xfStyles, dateEpoch, definedNames, cellMetadata } = tables;
|
|
111
116
|
let rowNumber = 0;
|
|
112
117
|
let rowHidden = false;
|
|
113
|
-
let rowInGrid = true;
|
|
114
118
|
let cells = [];
|
|
115
119
|
const columnBudget = new ColumnRecordBudget();
|
|
116
120
|
const styleResolution = new CellStyleResolver();
|
|
117
121
|
const rowPosition = new RowPositionTracker();
|
|
118
|
-
const cell = new CellAccumulator({
|
|
122
|
+
const cell = new CellAccumulator({ dateEpoch, definedNames, cellMetadata });
|
|
119
123
|
const finalizeCell = () => {
|
|
120
|
-
if (cell.ref === ''
|
|
124
|
+
if (cell.ref === '')
|
|
121
125
|
return;
|
|
122
|
-
const
|
|
123
|
-
const style = styleIndex >= 0 ? xfStyles[styleIndex] : undefined;
|
|
126
|
+
const style = styleResolution.styleFor(cell.col, cell.styleIndex, xfStyles);
|
|
124
127
|
const value = cell.decode(sharedStrings, style);
|
|
125
128
|
if (value !== null) {
|
|
126
129
|
const { col, ref } = cell;
|
|
127
|
-
cells.push(style
|
|
130
|
+
cells.push(style !== undefined && styleResolution.declaresFormat(col, cell.styleIndex)
|
|
131
|
+
? { col, address: ref, value, style }
|
|
132
|
+
: { col, address: ref, value });
|
|
128
133
|
}
|
|
129
134
|
};
|
|
130
|
-
for (const event of closeEmptyElements(xmlEvents(xml),
|
|
135
|
+
for (const event of closeEmptyElements(xmlEvents(xml), WORKSHEET_BODY_EMPTY_CLOSES)) {
|
|
131
136
|
if (event.kind === 'text') {
|
|
132
137
|
cell.appendChunk(event.text);
|
|
133
138
|
continue;
|
|
@@ -138,20 +143,22 @@ function* scanSheet(xml, sharedStrings, xfStyles, dateEpoch, hiddenColumns, merg
|
|
|
138
143
|
continue;
|
|
139
144
|
switch (local) {
|
|
140
145
|
case 'row': {
|
|
141
|
-
|
|
146
|
+
const position = rowPosition.open(event.attrs);
|
|
147
|
+
rowNumber = position.number;
|
|
142
148
|
rowHidden = boolStrict(event.attrs.hidden);
|
|
143
|
-
cell.openRow(
|
|
144
|
-
styleResolution.openRow(event.attrs);
|
|
145
|
-
cells = [];
|
|
149
|
+
cell.openRow(position.number, position.inGrid);
|
|
150
|
+
styleResolution.openRow(numInteger(event.attrs.s, 0) ?? -1, boolStrict(event.attrs.customFormat));
|
|
146
151
|
break;
|
|
147
152
|
}
|
|
148
153
|
case 'col':
|
|
149
154
|
collectColumn(event.attrs, hiddenColumns, styleResolution, columnBudget);
|
|
150
155
|
break;
|
|
151
|
-
case 'mergeCell':
|
|
152
|
-
|
|
153
|
-
|
|
156
|
+
case 'mergeCell': {
|
|
157
|
+
const ref = event.attrs.ref;
|
|
158
|
+
if (ref !== undefined)
|
|
159
|
+
admitting(() => merges.add(ref));
|
|
154
160
|
break;
|
|
161
|
+
}
|
|
155
162
|
default:
|
|
156
163
|
break;
|
|
157
164
|
}
|
|
@@ -163,8 +170,11 @@ function* scanSheet(xml, sharedStrings, xfStyles, dateEpoch, hiddenColumns, merg
|
|
|
163
170
|
finalizeCell();
|
|
164
171
|
else if (claimed === 'other' && local === 'row') {
|
|
165
172
|
styleResolution.closeRow();
|
|
166
|
-
|
|
173
|
+
const inGrid = cell.rowOpen;
|
|
174
|
+
cell.closeRow();
|
|
175
|
+
if (inGrid)
|
|
167
176
|
yield { number: rowNumber, hidden: rowHidden, cells };
|
|
177
|
+
cells = [];
|
|
168
178
|
}
|
|
169
179
|
}
|
|
170
180
|
}
|
|
@@ -173,7 +183,7 @@ function collectColumn(attrs, hiddenColumns, styleResolution, budget) {
|
|
|
173
183
|
if (span === undefined)
|
|
174
184
|
return;
|
|
175
185
|
const { first: min, last } = span;
|
|
176
|
-
styleResolution.noteColumnSpan(min, last, attrs);
|
|
186
|
+
styleResolution.noteColumnSpan(min, last, numInteger(attrs.style, 0) ?? -1);
|
|
177
187
|
if (!boolStrict(attrs.hidden))
|
|
178
188
|
return;
|
|
179
189
|
for (let index = min; index <= last; index++)
|
|
@@ -1,27 +1,2 @@
|
|
|
1
|
-
import type { TableStyleTable } from '../../core/workbook-styles.ts';
|
|
2
1
|
import { type StyleTable } from '../style/xf-style.ts';
|
|
3
2
|
export declare function parseStyleTable(xml: string): StyleTable;
|
|
4
|
-
/**
|
|
5
|
-
* Extract the custom indexed-color palette (`<colors><indexedColors>`) from styles.xml as verbatim
|
|
6
|
-
* `<rgbColor rgb="…"/>` fragments, or an empty list when the file rides the default palette. Kept raw
|
|
7
|
-
* rather than parsed into RGB and re-serialised, so the exact entries (count, order, casing) a
|
|
8
|
-
* source file declared survive a round-trip and every `indexed="…"` reference keeps its RGB.
|
|
9
|
-
*/
|
|
10
|
-
export declare function parseIndexedColors(stylesXml: string): string[];
|
|
11
|
-
/**
|
|
12
|
-
* Extract the most-recently-used colour swatches (`<colors><mruColors>`) from styles.xml as verbatim
|
|
13
|
-
* `<color .../>` fragments, or an empty list when the file declares none. Kept raw for the same reason
|
|
14
|
-
* the indexed palette is: the list is the author's own working set of colours and the model has no
|
|
15
|
-
* use for its contents, only for not losing them.
|
|
16
|
-
*/
|
|
17
|
-
export declare function parseMruColors(stylesXml: string): string[];
|
|
18
|
-
/**
|
|
19
|
-
* Extract the `<tableStyles>` block from styles.xml: each `<tableStyle>` definition verbatim, plus the
|
|
20
|
-
* container's nominated `defaultTableStyle`/`defaultPivotStyle`. See {@link TableStyleTable} for why
|
|
21
|
-
* the definitions stay raw while the two names are decoded.
|
|
22
|
-
*
|
|
23
|
-
* A file with no such block, or with the self-closing `count="0"` container Excel writes when it has
|
|
24
|
-
* only defaults to state, yields an empty {@link TableStyleTable.styles} and whichever names it did
|
|
25
|
-
* carry.
|
|
26
|
-
*/
|
|
27
|
-
export declare function parseTableStyles(stylesXml: string): TableStyleTable;
|
|
@@ -11,6 +11,7 @@ const isBorderEdgeName = (name) => BORDER_EDGES.has(name);
|
|
|
11
11
|
const STYLE_EMPTY_CLOSES = new Set([
|
|
12
12
|
'font',
|
|
13
13
|
'border',
|
|
14
|
+
'fill',
|
|
14
15
|
'patternFill',
|
|
15
16
|
'gradientFill',
|
|
16
17
|
'xf',
|
|
@@ -111,30 +112,37 @@ function parseFonts(events) {
|
|
|
111
112
|
}
|
|
112
113
|
function parseFills(events) {
|
|
113
114
|
const fills = [];
|
|
114
|
-
let
|
|
115
|
-
let
|
|
116
|
-
let bgColor;
|
|
115
|
+
let fillDraft = null;
|
|
116
|
+
let patternDraft = null;
|
|
117
117
|
let gradientDraft = null;
|
|
118
|
-
let fillSlotAt = -1;
|
|
119
118
|
for (const event of until(events, 'fills')) {
|
|
120
119
|
if (event.kind === 'open') {
|
|
121
120
|
const attrs = event.attrs;
|
|
121
|
+
const bodyExpected = fillDraft !== null && !fillDraft.bodyRead;
|
|
122
122
|
switch (localName(event.name)) {
|
|
123
123
|
case 'fill':
|
|
124
|
-
|
|
124
|
+
fillDraft = { body: undefined, bodyRead: false };
|
|
125
125
|
break;
|
|
126
126
|
case 'patternFill':
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
if (!bodyExpected)
|
|
128
|
+
break;
|
|
129
|
+
patternDraft = {
|
|
130
|
+
pattern: attrs.patternType ?? 'none',
|
|
131
|
+
fgColor: undefined,
|
|
132
|
+
bgColor: undefined,
|
|
133
|
+
};
|
|
130
134
|
break;
|
|
131
135
|
case 'fgColor':
|
|
132
|
-
|
|
136
|
+
if (patternDraft !== null)
|
|
137
|
+
patternDraft.fgColor = parseColor(attrs);
|
|
133
138
|
break;
|
|
134
139
|
case 'bgColor':
|
|
135
|
-
|
|
140
|
+
if (patternDraft !== null)
|
|
141
|
+
patternDraft.bgColor = parseColor(attrs);
|
|
136
142
|
break;
|
|
137
143
|
case 'gradientFill':
|
|
144
|
+
if (!bodyExpected)
|
|
145
|
+
break;
|
|
138
146
|
gradientDraft = {
|
|
139
147
|
fill: {
|
|
140
148
|
type: 'gradient',
|
|
@@ -161,7 +169,12 @@ function parseFills(events) {
|
|
|
161
169
|
else if (event.kind === 'close') {
|
|
162
170
|
switch (localName(event.name)) {
|
|
163
171
|
case 'patternFill':
|
|
164
|
-
|
|
172
|
+
if (fillDraft !== null && patternDraft !== null) {
|
|
173
|
+
const { pattern, fgColor, bgColor } = patternDraft;
|
|
174
|
+
fillDraft.body = toFill(pattern, fgColor, bgColor);
|
|
175
|
+
fillDraft.bodyRead = true;
|
|
176
|
+
patternDraft = null;
|
|
177
|
+
}
|
|
165
178
|
break;
|
|
166
179
|
case 'stop':
|
|
167
180
|
if (gradientDraft !== null && gradientDraft.stopPosition !== null) {
|
|
@@ -175,14 +188,18 @@ function parseFills(events) {
|
|
|
175
188
|
}
|
|
176
189
|
break;
|
|
177
190
|
case 'gradientFill':
|
|
178
|
-
if (gradientDraft !== null) {
|
|
179
|
-
|
|
191
|
+
if (fillDraft !== null && gradientDraft !== null) {
|
|
192
|
+
fillDraft.body = gradientDraft.fill;
|
|
193
|
+
fillDraft.bodyRead = true;
|
|
180
194
|
gradientDraft = null;
|
|
181
195
|
}
|
|
182
196
|
break;
|
|
183
197
|
case 'fill':
|
|
184
|
-
if (
|
|
185
|
-
fills.push(
|
|
198
|
+
if (fillDraft !== null)
|
|
199
|
+
fills.push(fillDraft.body);
|
|
200
|
+
fillDraft = null;
|
|
201
|
+
patternDraft = null;
|
|
202
|
+
gradientDraft = null;
|
|
186
203
|
break;
|
|
187
204
|
}
|
|
188
205
|
}
|
|
@@ -368,29 +385,24 @@ function assignAlignmentToken(out, key, raw) {
|
|
|
368
385
|
function parseProtection(attrs) {
|
|
369
386
|
return protectionFrom({ locked: boolTristate(attrs.locked), hidden: boolStrict(attrs.hidden) });
|
|
370
387
|
}
|
|
371
|
-
export function parseIndexedColors(stylesXml) {
|
|
372
|
-
return capturedFragments(stylesXml, 'indexedColors');
|
|
373
|
-
}
|
|
374
|
-
export function parseMruColors(stylesXml) {
|
|
375
|
-
return capturedFragments(stylesXml, 'mruColors');
|
|
376
|
-
}
|
|
377
|
-
export function parseTableStyles(stylesXml) {
|
|
378
|
-
const { fragments, attributes } = elementSubtrees(stylesXml, new Map([['tableStyles', 'tableStyle']]));
|
|
379
|
-
return buildTableStyleTable(stylesXml, fragments.get('tableStyles') ?? [], attributes.get('tableStyles'));
|
|
380
|
-
}
|
|
381
388
|
function buildTableStyleTable(stylesXml, styles, containerAttrs) {
|
|
382
|
-
const table = { styles:
|
|
389
|
+
const table = { styles: styles.map((xml) => ({ name: tableStyleNameOf(xml), xml })) };
|
|
383
390
|
if (containerAttrs?.defaultTableStyle !== undefined) {
|
|
384
391
|
table.defaultTableStyle = containerAttrs.defaultTableStyle;
|
|
385
392
|
}
|
|
386
393
|
if (containerAttrs?.defaultPivotStyle !== undefined) {
|
|
387
394
|
table.defaultPivotStyle = containerAttrs.defaultPivotStyle;
|
|
388
395
|
}
|
|
389
|
-
const namespaces = fragmentNamespaces(stylesXml,
|
|
396
|
+
const namespaces = fragmentNamespaces(stylesXml, styles);
|
|
390
397
|
if (namespaces.length > 0)
|
|
391
398
|
table.namespaces = namespaces;
|
|
392
399
|
return table;
|
|
393
400
|
}
|
|
401
|
+
function tableStyleNameOf(fragment) {
|
|
402
|
+
for (const { attrs } of openElements(fragment, 'tableStyle'))
|
|
403
|
+
return attrs.name ?? '';
|
|
404
|
+
return '';
|
|
405
|
+
}
|
|
394
406
|
function fragmentNamespaces(stylesXml, fragments) {
|
|
395
407
|
if (fragments.length === 0)
|
|
396
408
|
return [];
|
|
@@ -427,10 +439,3 @@ const PRESERVED_SUBTREES = new Map([
|
|
|
427
439
|
['mruColors', 'color'],
|
|
428
440
|
['tableStyles', 'tableStyle'],
|
|
429
441
|
]);
|
|
430
|
-
function capturedFragments(xml, container) {
|
|
431
|
-
const child = PRESERVED_SUBTREES.get(container);
|
|
432
|
-
if (child === undefined)
|
|
433
|
-
return [];
|
|
434
|
-
const { fragments } = elementSubtrees(xml, new Map([[container, child]]));
|
|
435
|
-
return [...(fragments.get(container) ?? [])];
|
|
436
|
-
}
|
|
@@ -30,6 +30,12 @@ export interface DefinedNamesPass extends SaxPass {
|
|
|
30
30
|
* and repaired the names it had to; resolving during the scan would have forced a second one.
|
|
31
31
|
*/
|
|
32
32
|
result(sheetOrder: readonly string[]): DefinedName[];
|
|
33
|
+
/**
|
|
34
|
+
* Every name the part defines, whatever its scope, as `definedNameKeys` spells them. Known once the
|
|
35
|
+
* scan ends, before any sheet is read, and needed then: whether a function a formula passes as a value
|
|
36
|
+
* sheds its `_xleta.` depends on them.
|
|
37
|
+
*/
|
|
38
|
+
spellings(): ReadonlySet<string>;
|
|
33
39
|
}
|
|
34
40
|
export declare function definedNamesPass(): DefinedNamesPass;
|
|
35
41
|
export declare function applyCoreProperties(workbook: Workbook, xml: string): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parseDateText } from '../../core/date.js';
|
|
2
|
-
import { unmangleFunctions } from '../../core/formula.js';
|
|
2
|
+
import { definedNameKeys, unmangleFunctions } from '../../core/formula.js';
|
|
3
3
|
import { WORKBOOK_PROTECTION_CREDENTIAL_ATTRS, } from '../../core/workbook-protection.js';
|
|
4
4
|
import { isVisibility } from '../../core/worksheet.js';
|
|
5
5
|
import { enumToken, numInteger } from '../../xml/xml-attrs.js';
|
|
@@ -125,17 +125,22 @@ export function definedNamesPass() {
|
|
|
125
125
|
const text = refersTo.close(localName(name));
|
|
126
126
|
if (text === undefined || pending === undefined)
|
|
127
127
|
return;
|
|
128
|
-
drafts.push({ ...pending, refersTo:
|
|
128
|
+
drafts.push({ ...pending, refersTo: text });
|
|
129
129
|
pending = undefined;
|
|
130
130
|
},
|
|
131
131
|
},
|
|
132
132
|
closeEmptyElements: new Set(['definedName']),
|
|
133
133
|
result(sheetOrder) {
|
|
134
|
-
|
|
134
|
+
const names = definedNameKeys(drafts);
|
|
135
|
+
return drafts.map(({ localSheetId, refersTo: stored, ...draft }) => {
|
|
136
|
+
const named = { ...draft, refersTo: unmangleFunctions(stored, names) };
|
|
135
137
|
const scope = sheetOrder[localSheetId];
|
|
136
|
-
return scope === undefined ?
|
|
138
|
+
return scope === undefined ? named : { ...named, scope };
|
|
137
139
|
});
|
|
138
140
|
},
|
|
141
|
+
spellings() {
|
|
142
|
+
return definedNameKeys(drafts);
|
|
143
|
+
},
|
|
139
144
|
};
|
|
140
145
|
}
|
|
141
146
|
const CORE_PROPERTY_LOCAL_NAMES = new Set([
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DateEpoch } from '../../core/date.ts';
|
|
2
2
|
import type { Worksheet } from '../../core/worksheet.ts';
|
|
3
3
|
import { type SaxPass } from '../../xml/xml-read.ts';
|
|
4
|
+
import type { CellMetadataIndex } from '../cell-metadata/metadata.ts';
|
|
4
5
|
import type { XfStyle } from '../style/xf-style.ts';
|
|
5
6
|
import type { SharedString } from './cell-value.ts';
|
|
6
7
|
/**
|
|
@@ -8,7 +9,11 @@ import type { SharedString } from './cell-value.ts';
|
|
|
8
9
|
* merges, the autofilter, page breaks, and the view and print layout. It commits as it goes rather
|
|
9
10
|
* than gathering, so it has nothing to hand back once the parse ends.
|
|
10
11
|
*
|
|
11
|
-
* Offered as a pass because the worksheet is the largest part in a package and
|
|
12
|
-
*
|
|
12
|
+
* Offered as a pass because the worksheet is the largest part in a package and other readers want
|
|
13
|
+
* the same events, so they all share one parse of it rather than scanning it once each.
|
|
14
|
+
*
|
|
15
|
+
* `definedNames` is every name the workbook defines, as `definedNameKeys` spells them: the workbook
|
|
16
|
+
* part is read before any sheet, so they are known before the first formula is. `cellMetadata` is
|
|
17
|
+
* what the workbook's `cm` and `vm` values resolve to, read from the parts they index.
|
|
13
18
|
*/
|
|
14
|
-
export declare function worksheetPass(sheet: Worksheet, sharedStrings: readonly SharedString[], xfStyles: ReadonlyArray<XfStyle>, dateEpoch: DateEpoch): SaxPass;
|
|
19
|
+
export declare function worksheetPass(sheet: Worksheet, sharedStrings: readonly SharedString[], xfStyles: ReadonlyArray<XfStyle>, dateEpoch: DateEpoch, definedNames: ReadonlySet<string>, cellMetadata: CellMetadataIndex): SaxPass;
|
|
@@ -1,22 +1,26 @@
|
|
|
1
|
-
import { tryDecodeRange } from '../../core/address.js';
|
|
1
|
+
import { boundedRect, tryDecodeRange } from '../../core/address.js';
|
|
2
2
|
import { isCustomFilterOperator, } from '../../core/autofilter.js';
|
|
3
3
|
import { INTERNAL } from '../../core/internal.js';
|
|
4
4
|
import { HEADER_FOOTER_ELEMENTS } from '../../core/page-setup.js';
|
|
5
5
|
import { assignStyleFacets } from '../../core/style.js';
|
|
6
6
|
import { decodeSpreadsheetText, numFinite, numInteger } from '../../xml/xml-attrs.js';
|
|
7
|
-
import {} from '../../xml/xml-read.js';
|
|
7
|
+
import { TextCapture } from '../../xml/xml-read.js';
|
|
8
8
|
import { boolPresent, boolStrict, localName } from '../../xml/xml-scan.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
9
|
+
import { ColumnRecordBudget } from '../read-policy/column-budget.js';
|
|
10
|
+
import { admitting } from '../read-policy/read-repair.js';
|
|
11
|
+
import { CellStyleResolver } from '../style/cell-style-resolution.js';
|
|
12
|
+
import { CellAccumulator, WORKSHEET_BODY_EMPTY_CLOSES } from './cell-accumulator.js';
|
|
13
|
+
import { takeColumnSpan } from './column-span.js';
|
|
13
14
|
import { RowPositionTracker } from './row-position.js';
|
|
14
15
|
import { applySheetProperties, PageBreakAccumulator, parseSheetProtection, } from './sheet-properties.js';
|
|
15
16
|
const HEADER_FOOTER_CHILDREN = new Set(HEADER_FOOTER_ELEMENTS);
|
|
16
17
|
function isHeaderFooterElement(local) {
|
|
17
18
|
return HEADER_FOOTER_CHILDREN.has(local);
|
|
18
19
|
}
|
|
19
|
-
const WORKSHEET_EMPTY_CLOSES = new Set([
|
|
20
|
+
const WORKSHEET_EMPTY_CLOSES = new Set([
|
|
21
|
+
...WORKSHEET_BODY_EMPTY_CLOSES,
|
|
22
|
+
'autoFilter',
|
|
23
|
+
]);
|
|
20
24
|
function pendingFilterCriteria(values, blank, predicates, and) {
|
|
21
25
|
if (values !== null && (values.length > 0 || blank)) {
|
|
22
26
|
return { kind: 'values', values, blank };
|
|
@@ -75,35 +79,44 @@ class AutoFilterAccumulator {
|
|
|
75
79
|
if (this.#ref === null)
|
|
76
80
|
return;
|
|
77
81
|
const decoded = tryDecodeRange(this.#ref);
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const width = right - left + 1;
|
|
82
|
+
const rect = decoded === undefined ? undefined : boundedRect(decoded);
|
|
83
|
+
if (rect !== undefined) {
|
|
84
|
+
const width = rect.right - rect.left + 1;
|
|
82
85
|
sheet.autoFilter = { ref: this.#ref, columns: this.#columns.filter((c) => c.colId < width) };
|
|
83
86
|
}
|
|
84
87
|
this.#ref = null;
|
|
85
88
|
this.#columns = [];
|
|
86
89
|
}
|
|
87
90
|
}
|
|
88
|
-
export function worksheetPass(sheet, sharedStrings, xfStyles, dateEpoch) {
|
|
89
|
-
const cell = new CellAccumulator({
|
|
91
|
+
export function worksheetPass(sheet, sharedStrings, xfStyles, dateEpoch, definedNames, cellMetadata) {
|
|
92
|
+
const cell = new CellAccumulator({ dateEpoch, definedNames, cellMetadata });
|
|
90
93
|
const autoFilter = new AutoFilterAccumulator();
|
|
91
94
|
const pageBreaks = new PageBreakAccumulator();
|
|
92
95
|
const styleResolution = new CellStyleResolver();
|
|
93
96
|
const columnBudget = new ColumnRecordBudget();
|
|
94
97
|
const rowPosition = new RowPositionTracker();
|
|
98
|
+
const headerFooterText = new TextCapture(HEADER_FOOTER_ELEMENTS);
|
|
99
|
+
let customViewDepth = 0;
|
|
95
100
|
const finalizeCellFromState = () => {
|
|
96
|
-
|
|
97
|
-
const style = styleIndex >= 0 ? xfStyles[styleIndex] : xfStyles[0];
|
|
98
|
-
cell.finalize(sheet, sharedStrings, style);
|
|
101
|
+
cell.finalize(sheet, sharedStrings, styleResolution.styleFor(cell.col, cell.styleIndex, xfStyles));
|
|
99
102
|
};
|
|
100
103
|
const handlers = {
|
|
101
104
|
onOpen(name, attrs, selfClosing) {
|
|
102
105
|
const local = localName(name);
|
|
106
|
+
if (customViewDepth > 0) {
|
|
107
|
+
if (!selfClosing)
|
|
108
|
+
customViewDepth++;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (local === 'customSheetViews') {
|
|
112
|
+
if (!selfClosing)
|
|
113
|
+
customViewDepth = 1;
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
103
116
|
if (cell.openElement(local, attrs, selfClosing))
|
|
104
117
|
return;
|
|
105
|
-
if (
|
|
106
|
-
|
|
118
|
+
if (isHeaderFooterElement(local)) {
|
|
119
|
+
headerFooterText.open(local, selfClosing);
|
|
107
120
|
return;
|
|
108
121
|
}
|
|
109
122
|
switch (local) {
|
|
@@ -114,8 +127,8 @@ export function worksheetPass(sheet, sharedStrings, xfStyles, dateEpoch) {
|
|
|
114
127
|
const { number, inGrid } = rowPosition.open(attrs);
|
|
115
128
|
if (inGrid)
|
|
116
129
|
applyRow(sheet, number, attrs);
|
|
117
|
-
cell.openRow(
|
|
118
|
-
styleResolution.openRow(attrs);
|
|
130
|
+
cell.openRow(number, inGrid);
|
|
131
|
+
styleResolution.openRow(numInteger(attrs.s, 0) ?? -1, boolStrict(attrs.customFormat));
|
|
119
132
|
break;
|
|
120
133
|
}
|
|
121
134
|
case 'mergeCell':
|
|
@@ -173,9 +186,16 @@ export function worksheetPass(sheet, sharedStrings, xfStyles, dateEpoch) {
|
|
|
173
186
|
}
|
|
174
187
|
},
|
|
175
188
|
onText(chunk) {
|
|
189
|
+
if (customViewDepth > 0)
|
|
190
|
+
return;
|
|
176
191
|
cell.appendChunk(chunk);
|
|
192
|
+
headerFooterText.text(chunk);
|
|
177
193
|
},
|
|
178
194
|
onClose(name) {
|
|
195
|
+
if (customViewDepth > 0) {
|
|
196
|
+
customViewDepth--;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
179
199
|
const local = localName(name);
|
|
180
200
|
const claimed = cell.closeElement(local);
|
|
181
201
|
if (claimed === 'cell') {
|
|
@@ -184,13 +204,15 @@ export function worksheetPass(sheet, sharedStrings, xfStyles, dateEpoch) {
|
|
|
184
204
|
}
|
|
185
205
|
if (claimed === 'claimed')
|
|
186
206
|
return;
|
|
187
|
-
|
|
188
|
-
|
|
207
|
+
const headerFooter = headerFooterText.close(local);
|
|
208
|
+
if (headerFooter !== undefined && isHeaderFooterElement(local)) {
|
|
209
|
+
sheet.headerFooter[local] = decodeSpreadsheetText(headerFooter);
|
|
189
210
|
return;
|
|
190
211
|
}
|
|
191
212
|
switch (local) {
|
|
192
213
|
case 'row':
|
|
193
214
|
styleResolution.closeRow();
|
|
215
|
+
cell.closeRow();
|
|
194
216
|
break;
|
|
195
217
|
case 'filterColumn':
|
|
196
218
|
autoFilter.endColumn();
|
|
@@ -232,7 +254,7 @@ function applyColumn(sheet, attrs, xfStyles, styleResolution, budget) {
|
|
|
232
254
|
if (style !== undefined)
|
|
233
255
|
assignStyleFacets(column, style);
|
|
234
256
|
}
|
|
235
|
-
styleResolution.noteColumnSpan(min, last, attrs);
|
|
257
|
+
styleResolution.noteColumnSpan(min, last, numInteger(attrs.style, 0) ?? -1);
|
|
236
258
|
}
|
|
237
259
|
function applyRow(sheet, number, attrs) {
|
|
238
260
|
const row = sheet.getRow(number);
|
package/dist/io/xlsx/read.d.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { Workbook } from '../../core/workbook.ts';
|
|
2
2
|
import type { ReadPackageOptions } from '../opc/read-options.ts';
|
|
3
|
-
export type { ReadPackageOptions } from '../opc/read-options.ts';
|
|
4
|
-
export type { StyleTable, XfStyle } from '../style/xf-style.ts';
|
|
5
|
-
export { parseStyleTable } from './read-styles.ts';
|
|
6
|
-
export { type SheetEntry, workbookPropertiesPass, workbookSheetsPass, workbookViewPass, } from './read-workbook-xml.ts';
|
|
7
3
|
/**
|
|
8
4
|
* Read a spreadsheet package into a {@link Workbook}.
|
|
9
5
|
*
|