@shbernal/ts-xlsx 3.0.0 → 3.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 +4 -1
- package/dist/bytes.d.ts +7 -0
- package/dist/bytes.js +22 -0
- package/dist/core/address.d.ts +60 -2
- package/dist/core/address.js +40 -24
- package/dist/core/autofilter.d.ts +4 -3
- package/dist/core/autofilter.js +31 -30
- package/dist/core/axis-handle.d.ts +2 -0
- package/dist/core/axis-handle.js +5 -2
- package/dist/core/cell.d.ts +4 -3
- package/dist/core/cell.js +4 -6
- package/dist/core/clone.d.ts +29 -0
- package/dist/core/clone.js +24 -0
- package/dist/core/color-resolution.js +2 -4
- package/dist/core/column.d.ts +1 -0
- package/dist/core/column.js +3 -0
- package/dist/core/comment-thread.js +2 -1
- package/dist/core/conditional-formatting-overlay.d.ts +2 -1
- package/dist/core/conditional-formatting-overlay.js +2 -2
- package/dist/core/conditional-formatting.d.ts +9 -1
- package/dist/core/conditional-formatting.js +34 -18
- package/dist/core/containers.d.ts +12 -0
- package/dist/core/containers.js +5 -0
- package/dist/core/data-validation-overlay.d.ts +2 -1
- package/dist/core/data-validation-overlay.js +4 -4
- package/dist/core/data-validation.d.ts +6 -0
- package/dist/core/data-validation.js +15 -4
- package/dist/core/date-format.d.ts +20 -0
- package/dist/core/date-format.js +160 -0
- package/dist/core/date.d.ts +43 -8
- package/dist/core/date.js +18 -2
- package/dist/core/formula.d.ts +26 -0
- package/dist/core/formula.js +20 -4
- package/dist/core/grid-edits.d.ts +2 -3
- package/dist/core/grid-edits.js +69 -70
- package/dist/core/grid-shift.d.ts +58 -9
- package/dist/core/grid-shift.js +26 -4
- package/dist/core/image.d.ts +13 -9
- package/dist/core/image.js +7 -5
- package/dist/core/internal.d.ts +8 -2
- package/dist/core/limits.d.ts +23 -0
- package/dist/core/limits.js +4 -0
- package/dist/core/merge.d.ts +5 -4
- package/dist/core/merge.js +18 -19
- package/dist/core/pivot-table.js +63 -45
- package/dist/core/protection.js +2 -11
- package/dist/core/range.js +34 -30
- package/dist/core/row-input.js +2 -2
- package/dist/core/row.d.ts +1 -0
- package/dist/core/row.js +3 -0
- package/dist/core/style.d.ts +85 -70
- package/dist/core/style.js +92 -28
- package/dist/core/table-style.d.ts +1 -1
- package/dist/core/table-style.js +4 -4
- package/dist/core/table.d.ts +27 -9
- package/dist/core/table.js +51 -34
- package/dist/core/theme.js +6 -5
- package/dist/core/value.d.ts +9 -0
- package/dist/core/value.js +36 -34
- package/dist/core/workbook-media.d.ts +34 -0
- package/dist/core/workbook-media.js +44 -0
- package/dist/core/workbook-styles.d.ts +67 -1
- package/dist/core/workbook-vba.js +3 -2
- package/dist/core/workbook.d.ts +23 -2
- package/dist/core/workbook.js +24 -40
- package/dist/core/worksheet-comments.d.ts +2 -1
- package/dist/core/worksheet-comments.js +20 -13
- package/dist/core/worksheet-merges.d.ts +44 -0
- package/dist/core/worksheet-merges.js +59 -0
- package/dist/core/worksheet-model.d.ts +9 -1
- package/dist/core/worksheet-model.js +24 -9
- package/dist/core/worksheet.d.ts +55 -6
- package/dist/core/worksheet.js +36 -44
- package/dist/customui/ribbon.js +2 -1
- package/dist/entries/core.d.ts +18 -13
- package/dist/entries/core.js +12 -6
- package/dist/entries/xlsx.d.ts +1 -1
- package/dist/errors.d.ts +64 -0
- package/dist/errors.js +22 -0
- package/dist/hex.d.ts +8 -0
- package/dist/hex.js +3 -0
- package/dist/io/csv/delimiter.d.ts +9 -0
- package/dist/io/csv/delimiter.js +6 -0
- package/dist/io/csv/read.js +11 -4
- package/dist/io/csv/write.d.ts +9 -2
- package/dist/io/csv/write.js +9 -38
- package/dist/io/opc/inflate.js +14 -0
- package/dist/io/opc/namespaces.d.ts +16 -0
- package/dist/io/opc/namespaces.js +4 -0
- package/dist/io/opc/part-paths.d.ts +9 -0
- package/dist/io/opc/part-paths.js +1 -1
- package/dist/io/opc/read-opc.d.ts +54 -14
- package/dist/io/opc/read-opc.js +42 -20
- package/dist/io/opc/read-options.d.ts +5 -1
- package/dist/io/opc/sniff-format.d.ts +3 -3
- package/dist/io/opc/sniff-format.js +2 -2
- package/dist/io/style/xf-style.d.ts +23 -1
- package/dist/io/style/xf-style.js +8 -0
- package/dist/io/xlsb/formula.d.ts +2 -2
- package/dist/io/xlsb/formula.js +49 -34
- package/dist/io/xlsb/primitives.js +8 -14
- package/dist/io/xlsb/ptg-functions.d.ts +19 -10
- package/dist/io/xlsb/ptg-functions.js +385 -596
- package/dist/io/xlsb/read-styles.js +45 -81
- package/dist/io/xlsb/read-worksheet.d.ts +20 -1
- package/dist/io/xlsb/read-worksheet.js +73 -89
- package/dist/io/xlsb/read.d.ts +6 -3
- package/dist/io/xlsb/read.js +44 -23
- package/dist/io/xlsb/record-stream.d.ts +30 -0
- package/dist/io/xlsb/record-stream.js +20 -0
- package/dist/io/xlsb/record-types.d.ts +1 -5
- package/dist/io/xlsb/record-types.js +1 -5
- package/dist/io/xlsx/cell-accumulator.d.ts +8 -1
- package/dist/io/xlsx/cell-accumulator.js +32 -9
- package/dist/io/xlsx/cell-style-resolution.d.ts +25 -0
- package/dist/io/xlsx/cell-style-resolution.js +29 -0
- package/dist/io/xlsx/cell-value.d.ts +5 -3
- package/dist/io/xlsx/cell-value.js +13 -15
- package/dist/io/xlsx/color-xml.js +3 -2
- package/dist/io/xlsx/column-budget.d.ts +26 -0
- package/dist/io/xlsx/column-budget.js +22 -0
- package/dist/io/xlsx/comments.d.ts +6 -2
- package/dist/io/xlsx/comments.js +36 -32
- package/dist/io/xlsx/conditional-formatting.d.ts +6 -3
- package/dist/io/xlsx/conditional-formatting.js +30 -26
- package/dist/io/xlsx/data-validation.js +29 -27
- package/dist/io/xlsx/edit-vba.d.ts +7 -2
- package/dist/io/xlsx/edit-vba.js +14 -21
- package/dist/io/xlsx/font-xml.d.ts +7 -0
- package/dist/io/xlsx/font-xml.js +104 -0
- package/dist/io/xlsx/hyperlinks.d.ts +37 -5
- package/dist/io/xlsx/hyperlinks.js +22 -13
- package/dist/io/xlsx/images.js +11 -13
- package/dist/io/xlsx/namespaces.d.ts +16 -0
- package/dist/io/xlsx/namespaces.js +7 -0
- package/dist/io/xlsx/package-plan.d.ts +14 -2
- package/dist/io/xlsx/package-plan.js +39 -11
- package/dist/io/xlsx/pivot.js +8 -7
- package/dist/io/xlsx/read-parts.d.ts +59 -0
- package/dist/io/xlsx/read-parts.js +252 -0
- package/dist/io/xlsx/read-pivot.js +2 -1
- package/dist/io/xlsx/read-repair.d.ts +26 -0
- package/dist/io/xlsx/read-repair.js +39 -0
- package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +6 -3
- package/dist/io/xlsx/read-rows.d.ts +18 -5
- package/dist/io/xlsx/read-rows.js +45 -31
- package/dist/io/xlsx/read-shared-strings.js +3 -2
- package/dist/io/xlsx/read-styles.d.ts +1 -6
- package/dist/io/xlsx/read-styles.js +6 -71
- package/dist/io/xlsx/read-workbook-xml.d.ts +36 -0
- package/dist/io/xlsx/read-workbook-xml.js +170 -0
- package/dist/io/xlsx/read-worksheet.d.ts +2 -1
- package/dist/io/xlsx/read-worksheet.js +35 -164
- package/dist/io/xlsx/read.d.ts +5 -12
- package/dist/io/xlsx/read.js +73 -406
- package/dist/io/xlsx/rich-text.js +1 -1
- package/dist/io/xlsx/row-position.d.ts +18 -0
- package/dist/io/xlsx/row-position.js +11 -0
- package/dist/io/xlsx/row-xml.d.ts +128 -0
- package/dist/io/xlsx/row-xml.js +203 -0
- package/dist/io/xlsx/shared-formulas.js +2 -2
- package/dist/io/xlsx/sheet-properties.d.ts +10 -1
- package/dist/io/xlsx/sheet-properties.js +145 -9
- package/dist/io/xlsx/style-elements.d.ts +43 -0
- package/dist/io/xlsx/style-elements.js +156 -0
- package/dist/io/xlsx/styles.d.ts +12 -3
- package/dist/io/xlsx/styles.js +5 -207
- package/dist/io/xlsx/tables.js +10 -14
- package/dist/io/xlsx/theme-xml.d.ts +26 -4
- package/dist/io/xlsx/theme-xml.js +107 -69
- package/dist/io/xlsx/threaded-comments.d.ts +8 -10
- package/dist/io/xlsx/threaded-comments.js +2 -1
- package/dist/io/xlsx/workbook-xml.d.ts +54 -4
- package/dist/io/xlsx/workbook-xml.js +60 -34
- package/dist/io/xlsx/worksheet-xml.d.ts +23 -70
- package/dist/io/xlsx/worksheet-xml.js +48 -229
- package/dist/io/xlsx/write-stream.d.ts +65 -16
- package/dist/io/xlsx/write-stream.js +50 -20
- package/dist/io/xlsx/write.d.ts +1 -2
- package/dist/io/xlsx/write.js +114 -74
- package/dist/rel-type.d.ts +16 -0
- package/dist/rel-type.js +6 -0
- package/dist/token-set.d.ts +13 -0
- package/dist/token-set.js +4 -1
- package/dist/vba/bytes.d.ts +14 -5
- package/dist/vba/bytes.js +16 -6
- package/dist/vba/cfb-format.d.ts +8 -0
- package/dist/vba/cfb-format.js +1 -0
- package/dist/vba/cfb-writer.d.ts +9 -0
- package/dist/vba/cfb-writer.js +12 -9
- package/dist/vba/cfb.d.ts +13 -1
- package/dist/vba/cfb.js +73 -51
- package/dist/vba/codepage.js +2 -1
- package/dist/vba/errors.d.ts +7 -0
- package/dist/vba/ms-ovba.js +51 -16
- package/dist/vba/project-editor.js +35 -40
- package/dist/vba/project.d.ts +11 -1
- package/dist/vba/project.js +27 -8
- package/dist/vba/vba-encoding.js +4 -5
- package/dist/xml/xml-attrs.d.ts +37 -0
- package/dist/xml/xml-attrs.js +30 -0
- package/dist/xml/xml-chars.d.ts +40 -0
- package/dist/xml/xml-chars.js +12 -0
- package/dist/xml/xml-namespaces.d.ts +31 -0
- package/dist/xml/xml-namespaces.js +50 -0
- package/dist/xml/xml-read.d.ts +72 -10
- package/dist/xml/xml-read.js +94 -18
- package/dist/xml/xml-scan.d.ts +15 -37
- package/dist/xml/xml-scan.js +12 -40
- package/dist/xml/xml.d.ts +28 -27
- package/dist/xml/xml.js +24 -24
- package/package.json +12 -7
- /package/dist/io/xlsx/{rich-runs.d.ts → read-rich-runs.d.ts} +0 -0
|
@@ -1,42 +1,50 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AuthoringError } from '../../errors.js';
|
|
3
|
-
import { closeEmptyElements } from '../../xml/xml-read.js';
|
|
4
|
-
import { boolStrict, localName,
|
|
1
|
+
import { Workbook } from '../../core/workbook.js';
|
|
2
|
+
import { AuthoringError, quoted } from '../../errors.js';
|
|
3
|
+
import { closeEmptyElements, parseXmlPasses } from '../../xml/xml-read.js';
|
|
4
|
+
import { boolStrict, localName, xmlEvents } from '../../xml/xml-scan.js';
|
|
5
5
|
import { openSpreadsheetPackage, readPartRelationships } from '../opc/read-opc.js';
|
|
6
6
|
import { unsupportedWorkbookPart } from '../opc/sniff-format.js';
|
|
7
7
|
import { CellAccumulator } from './cell-accumulator.js';
|
|
8
|
+
import { CellStyleResolver } from './cell-style-resolution.js';
|
|
9
|
+
import { ColumnRecordBudget, takeColumnSpan } from './column-budget.js';
|
|
8
10
|
import { XlsxParseError } from './errors.js';
|
|
11
|
+
import { SHARED_STRINGS_PART, STYLES_PART } from './part-names.js';
|
|
9
12
|
import { parseSharedStrings } from './read-shared-strings.js';
|
|
10
|
-
import { parseStyleTable,
|
|
13
|
+
import { workbookPropertiesPass, parseStyleTable, workbookSheetsPass, } from './read.js';
|
|
14
|
+
import { RowPositionTracker } from './row-position.js';
|
|
11
15
|
export function* readSheetRows(data, options = {}) {
|
|
12
16
|
const pkg = openPackage(data, options.maxUncompressedBytes);
|
|
13
17
|
const chosen = pickSheet(pkg.sheets, options.sheet);
|
|
14
18
|
const sheetXml = pkg.sheetXml(chosen.relId);
|
|
15
19
|
if (sheetXml === undefined)
|
|
16
20
|
return;
|
|
17
|
-
yield* scanSheet(sheetXml, pkg.sharedStrings, pkg.xfStyles, new Set(), []);
|
|
21
|
+
yield* scanSheet(sheetXml, pkg.sharedStrings, pkg.xfStyles, pkg.dateEpoch, new Set(), []);
|
|
18
22
|
}
|
|
19
23
|
export function* readWorkbookStream(data, options = {}) {
|
|
20
24
|
const pkg = openPackage(data, options.maxUncompressedBytes);
|
|
21
25
|
for (const sheet of pkg.sheets) {
|
|
22
26
|
const xml = pkg.sheetXml(sheet.relId) ?? '';
|
|
23
|
-
yield new StreamedSheetReader(sheet.name, xml, pkg.sharedStrings, pkg.xfStyles);
|
|
27
|
+
yield new StreamedSheetReader(sheet.name, xml, pkg.sharedStrings, pkg.xfStyles, pkg.dateEpoch);
|
|
24
28
|
}
|
|
25
29
|
}
|
|
26
30
|
function openPackage(data, maxUncompressedBytes) {
|
|
27
|
-
const { pkg, workbookXml } = openSpreadsheetPackage(data, maxUncompressedBytes);
|
|
28
|
-
const { partText: text } = pkg;
|
|
31
|
+
const { pkg, documentPath, workbookXml } = openSpreadsheetPackage(data, maxUncompressedBytes);
|
|
32
|
+
const { partText: text, partBytes } = pkg;
|
|
29
33
|
if (workbookXml === undefined) {
|
|
30
|
-
throw unsupportedWorkbookPart(
|
|
34
|
+
throw unsupportedWorkbookPart(partBytes, documentPath, 'the binary .xlsb format (BIFF12) cannot be row-streamed yet; read it with readXlsx or readXlsb');
|
|
31
35
|
}
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
+
const properties = new Workbook();
|
|
37
|
+
const sheetsPass = workbookSheetsPass();
|
|
38
|
+
parseXmlPasses(workbookXml, [sheetsPass, workbookPropertiesPass(properties)]);
|
|
39
|
+
const sheets = sheetsPass.result();
|
|
40
|
+
const rels = readPartRelationships(documentPath, text);
|
|
41
|
+
const sharedStrings = parseSharedStrings(rels.relatedTextOrPath('sharedStrings', SHARED_STRINGS_PART));
|
|
42
|
+
const { cellXfs: xfStyles } = parseStyleTable(rels.relatedTextOrPath('styles', STYLES_PART));
|
|
36
43
|
return {
|
|
37
44
|
sheets,
|
|
38
45
|
sharedStrings,
|
|
39
46
|
xfStyles,
|
|
47
|
+
dateEpoch: properties.dateEpoch,
|
|
40
48
|
sheetXml(relId) {
|
|
41
49
|
const target = rels.byId(relId)?.target;
|
|
42
50
|
return target === undefined ? undefined : text(rels.pathOf(target));
|
|
@@ -57,7 +65,7 @@ function pickSheet(sheets, selector) {
|
|
|
57
65
|
}
|
|
58
66
|
const sheet = sheets.find((candidate) => candidate.name === selector);
|
|
59
67
|
if (sheet === undefined)
|
|
60
|
-
throw new AuthoringError(`no worksheet named ${
|
|
68
|
+
throw new AuthoringError(`no worksheet named ${quoted(selector)}`);
|
|
61
69
|
return sheet;
|
|
62
70
|
}
|
|
63
71
|
class StreamedSheetReader {
|
|
@@ -65,20 +73,22 @@ class StreamedSheetReader {
|
|
|
65
73
|
#xml;
|
|
66
74
|
#sharedStrings;
|
|
67
75
|
#xfStyles;
|
|
76
|
+
#dateEpoch;
|
|
68
77
|
#hiddenColumns = new Set();
|
|
69
78
|
#merges = [];
|
|
70
79
|
#scanned = false;
|
|
71
|
-
constructor(name, xml, sharedStrings, xfStyles) {
|
|
80
|
+
constructor(name, xml, sharedStrings, xfStyles, dateEpoch) {
|
|
72
81
|
this.name = name;
|
|
73
82
|
this.#xml = xml;
|
|
74
83
|
this.#sharedStrings = sharedStrings;
|
|
75
84
|
this.#xfStyles = xfStyles;
|
|
85
|
+
this.#dateEpoch = dateEpoch;
|
|
76
86
|
}
|
|
77
87
|
*rows() {
|
|
78
88
|
this.#hiddenColumns = new Set();
|
|
79
89
|
this.#merges = [];
|
|
80
90
|
this.#scanned = false;
|
|
81
|
-
yield* scanSheet(this.#xml, this.#sharedStrings, this.#xfStyles, this.#hiddenColumns, this.#merges);
|
|
91
|
+
yield* scanSheet(this.#xml, this.#sharedStrings, this.#xfStyles, this.#dateEpoch, this.#hiddenColumns, this.#merges);
|
|
82
92
|
this.#scanned = true;
|
|
83
93
|
}
|
|
84
94
|
get hiddenColumns() {
|
|
@@ -97,17 +107,20 @@ class StreamedSheetReader {
|
|
|
97
107
|
}
|
|
98
108
|
}
|
|
99
109
|
const CELL_EMPTY_CLOSE = new Set(['c']);
|
|
100
|
-
function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
|
|
110
|
+
function* scanSheet(xml, sharedStrings, xfStyles, dateEpoch, hiddenColumns, merges) {
|
|
101
111
|
let rowNumber = 0;
|
|
102
|
-
let lastRow = 0;
|
|
103
112
|
let rowHidden = false;
|
|
104
113
|
let rowInGrid = true;
|
|
105
114
|
let cells = [];
|
|
106
|
-
const
|
|
115
|
+
const columnBudget = new ColumnRecordBudget();
|
|
116
|
+
const styleResolution = new CellStyleResolver();
|
|
117
|
+
const rowPosition = new RowPositionTracker();
|
|
118
|
+
const cell = new CellAccumulator({ richRuns: false, dateEpoch });
|
|
107
119
|
const finalizeCell = () => {
|
|
108
120
|
if (cell.ref === '' || cell.col < 0 || !rowInGrid)
|
|
109
121
|
return;
|
|
110
|
-
const
|
|
122
|
+
const styleIndex = styleResolution.indexFor(cell.col, cell.styleIndex);
|
|
123
|
+
const style = styleIndex >= 0 ? xfStyles[styleIndex] : undefined;
|
|
111
124
|
const value = cell.decode(sharedStrings, style);
|
|
112
125
|
if (value !== null) {
|
|
113
126
|
const { col, ref } = cell;
|
|
@@ -125,15 +138,15 @@ function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
|
|
|
125
138
|
continue;
|
|
126
139
|
switch (local) {
|
|
127
140
|
case 'row': {
|
|
128
|
-
rowNumber =
|
|
129
|
-
lastRow = rowNumber;
|
|
130
|
-
rowInGrid = rowNumber <= MAX_ROW;
|
|
141
|
+
({ number: rowNumber, inGrid: rowInGrid } = rowPosition.open(event.attrs));
|
|
131
142
|
rowHidden = boolStrict(event.attrs.hidden);
|
|
143
|
+
cell.openRow(rowInGrid ? rowNumber : -1);
|
|
144
|
+
styleResolution.openRow(event.attrs);
|
|
132
145
|
cells = [];
|
|
133
146
|
break;
|
|
134
147
|
}
|
|
135
148
|
case 'col':
|
|
136
|
-
|
|
149
|
+
collectColumn(event.attrs, hiddenColumns, styleResolution, columnBudget);
|
|
137
150
|
break;
|
|
138
151
|
case 'mergeCell':
|
|
139
152
|
if (event.attrs.ref !== undefined)
|
|
@@ -149,19 +162,20 @@ function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
|
|
|
149
162
|
if (claimed === 'cell')
|
|
150
163
|
finalizeCell();
|
|
151
164
|
else if (claimed === 'other' && local === 'row') {
|
|
165
|
+
styleResolution.closeRow();
|
|
152
166
|
if (rowInGrid)
|
|
153
167
|
yield { number: rowNumber, hidden: rowHidden, cells };
|
|
154
168
|
}
|
|
155
169
|
}
|
|
156
170
|
}
|
|
157
|
-
function
|
|
158
|
-
|
|
171
|
+
function collectColumn(attrs, hiddenColumns, styleResolution, budget) {
|
|
172
|
+
const span = takeColumnSpan(attrs, budget);
|
|
173
|
+
if (span === undefined)
|
|
159
174
|
return;
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
if (
|
|
175
|
+
const { first: min, last } = span;
|
|
176
|
+
styleResolution.noteColumnSpan(min, last, attrs);
|
|
177
|
+
if (!boolStrict(attrs.hidden))
|
|
163
178
|
return;
|
|
164
|
-
const last = Math.min(max, MAX_COLUMN);
|
|
165
179
|
for (let index = min; index <= last; index++)
|
|
166
180
|
hiddenColumns.add(index);
|
|
167
181
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { parseXml } from '../../xml/xml-read.js';
|
|
2
2
|
import { localName } from '../../xml/xml-scan.js';
|
|
3
|
-
import { RunAccumulator } from './rich-runs.js';
|
|
3
|
+
import { RunAccumulator } from './read-rich-runs.js';
|
|
4
|
+
const SHARED_STRING_EMPTY_CLOSES = new Set(['si']);
|
|
4
5
|
export function parseSharedStrings(xml) {
|
|
5
6
|
if (xml === '')
|
|
6
7
|
return [];
|
|
@@ -18,6 +19,6 @@ export function parseSharedStrings(xml) {
|
|
|
18
19
|
return;
|
|
19
20
|
strings.push(runs.isRich ? { richText: runs.runs } : runs.plainText);
|
|
20
21
|
},
|
|
21
|
-
});
|
|
22
|
+
}, { closeEmptyElements: SHARED_STRING_EMPTY_CLOSES });
|
|
22
23
|
return strings;
|
|
23
24
|
}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { type XmlAttributes } from '../../xml/xml-scan.ts';
|
|
1
|
+
import type { TableStyleTable } from '../../core/workbook-styles.ts';
|
|
3
2
|
import { type StyleTable } from '../style/xf-style.ts';
|
|
4
|
-
export type FontDraft = {
|
|
5
|
-
-readonly [K in keyof Font]?: Font[K];
|
|
6
|
-
};
|
|
7
3
|
export declare function parseStyleTable(xml: string): StyleTable;
|
|
8
|
-
export declare function applyFontChild(draft: FontDraft, local: string, attrs: XmlAttributes): void;
|
|
9
4
|
/**
|
|
10
5
|
* Extract the custom indexed-color palette (`<colors><indexedColors>`) from styles.xml as verbatim
|
|
11
6
|
* `<rgbColor rgb="…"/>` fragments, or an empty list when the file rides the default palette. Kept raw
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { ALIGNMENT_FACETS, isBorderStyle, isFillPatternType,
|
|
1
|
+
import { ALIGNMENT_FACETS, isBorderStyle, isFillPatternType, } from '../../core/style.js';
|
|
2
|
+
import { numFinite, numInteger } from '../../xml/xml-attrs.js';
|
|
2
3
|
import { closeEmptyElements, elementSubtrees, openElements, } from '../../xml/xml-read.js';
|
|
3
|
-
import {
|
|
4
|
-
import { NO_PRESERVED_STYLE_TABLES, numFmtCodeFor, resolveStyleTable, } from '../style/xf-style.js';
|
|
4
|
+
import { boolStrict, boolTristate, localName, xmlEvents, } from '../../xml/xml-scan.js';
|
|
5
|
+
import { NO_PRESERVED_STYLE_TABLES, numFmtCodeFor, protectionFrom, resolveStyleTable, } from '../style/xf-style.js';
|
|
5
6
|
import { parseColor } from './color-xml.js';
|
|
7
|
+
import { applyFontChild } from './font-xml.js';
|
|
6
8
|
const BORDER_EDGE_NAMES = ['left', 'right', 'top', 'bottom', 'diagonal'];
|
|
7
9
|
const BORDER_EDGES = new Set(BORDER_EDGE_NAMES);
|
|
8
10
|
const isBorderEdgeName = (name) => BORDER_EDGES.has(name);
|
|
@@ -309,68 +311,6 @@ function parseCellStyles(events) {
|
|
|
309
311
|
}
|
|
310
312
|
return names;
|
|
311
313
|
}
|
|
312
|
-
export function applyFontChild(draft, local, attrs) {
|
|
313
|
-
switch (local) {
|
|
314
|
-
case 'b':
|
|
315
|
-
draft.bold = boolPresent(attrs.val);
|
|
316
|
-
break;
|
|
317
|
-
case 'i':
|
|
318
|
-
draft.italic = boolPresent(attrs.val);
|
|
319
|
-
break;
|
|
320
|
-
case 'strike':
|
|
321
|
-
draft.strike = boolPresent(attrs.val);
|
|
322
|
-
break;
|
|
323
|
-
case 'outline':
|
|
324
|
-
draft.outline = boolPresent(attrs.val);
|
|
325
|
-
break;
|
|
326
|
-
case 'u':
|
|
327
|
-
draft.underline =
|
|
328
|
-
attrs.val === undefined
|
|
329
|
-
? true
|
|
330
|
-
: attrs.val === 'none'
|
|
331
|
-
? false
|
|
332
|
-
: isNamedUnderlineStyle(attrs.val)
|
|
333
|
-
? attrs.val
|
|
334
|
-
: true;
|
|
335
|
-
break;
|
|
336
|
-
case 'vertAlign':
|
|
337
|
-
if (attrs.val !== undefined && isFontVerticalAlignment(attrs.val))
|
|
338
|
-
draft.vertAlign = attrs.val;
|
|
339
|
-
break;
|
|
340
|
-
case 'sz': {
|
|
341
|
-
const size = numFinite(attrs.val);
|
|
342
|
-
if (size !== undefined)
|
|
343
|
-
draft.size = size;
|
|
344
|
-
break;
|
|
345
|
-
}
|
|
346
|
-
case 'color':
|
|
347
|
-
draft.color = parseColor(attrs);
|
|
348
|
-
break;
|
|
349
|
-
case 'name':
|
|
350
|
-
case 'rFont':
|
|
351
|
-
if (attrs.val !== undefined)
|
|
352
|
-
draft.name = attrs.val;
|
|
353
|
-
break;
|
|
354
|
-
case 'family': {
|
|
355
|
-
const family = numInteger(attrs.val);
|
|
356
|
-
if (family !== undefined)
|
|
357
|
-
draft.family = family;
|
|
358
|
-
break;
|
|
359
|
-
}
|
|
360
|
-
case 'charset': {
|
|
361
|
-
const charset = numInteger(attrs.val);
|
|
362
|
-
if (charset !== undefined)
|
|
363
|
-
draft.charset = charset;
|
|
364
|
-
break;
|
|
365
|
-
}
|
|
366
|
-
case 'scheme':
|
|
367
|
-
if (attrs.val !== undefined && isFontScheme(attrs.val))
|
|
368
|
-
draft.scheme = attrs.val;
|
|
369
|
-
break;
|
|
370
|
-
default:
|
|
371
|
-
break;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
314
|
function resolveNumFmt(raw, custom) {
|
|
375
315
|
const id = numInteger(raw, 1);
|
|
376
316
|
return id === undefined ? undefined : numFmtCodeFor(id, custom);
|
|
@@ -426,12 +366,7 @@ function assignAlignmentToken(out, key, raw) {
|
|
|
426
366
|
out[key] = raw;
|
|
427
367
|
}
|
|
428
368
|
function parseProtection(attrs) {
|
|
429
|
-
|
|
430
|
-
if (boolTristate(attrs.locked) === false)
|
|
431
|
-
out.locked = false;
|
|
432
|
-
if (boolStrict(attrs.hidden))
|
|
433
|
-
out.hidden = true;
|
|
434
|
-
return Object.keys(out).length > 0 ? out : undefined;
|
|
369
|
+
return protectionFrom({ locked: boolTristate(attrs.locked), hidden: boolStrict(attrs.hidden) });
|
|
435
370
|
}
|
|
436
371
|
export function parseIndexedColors(stylesXml) {
|
|
437
372
|
return capturedFragments(stylesXml, 'indexedColors');
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type WorkbookProtection } from '../../core/workbook-protection.ts';
|
|
2
|
+
import type { DefinedName, Workbook, WorkbookView } from '../../core/workbook.ts';
|
|
3
|
+
import { type WorksheetState } from '../../core/worksheet.ts';
|
|
4
|
+
import { type CollectingPass, type SaxPass } from '../../xml/xml-read.ts';
|
|
5
|
+
export interface SheetEntry {
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly relId: string;
|
|
8
|
+
readonly state?: WorksheetState['state'];
|
|
9
|
+
}
|
|
10
|
+
export declare function workbookSheetsPass(): CollectingPass<SheetEntry[]>;
|
|
11
|
+
export declare function workbookProtectionPass(): CollectingPass<WorkbookProtection | undefined>;
|
|
12
|
+
/**
|
|
13
|
+
* Apply `<workbookPr>`: the workbook's date system and its VBA code name.
|
|
14
|
+
*
|
|
15
|
+
* Both are read for the same reason and it is not that the model computes anything from them. The
|
|
16
|
+
* date system is what every serial in every sheet counts from, so a workbook read without it is read
|
|
17
|
+
* with every date four years and a day out; the code name is what the VBA project means by
|
|
18
|
+
* `ThisWorkbook`, so a `.xlsm` written back without it has had its macros unbound from its document.
|
|
19
|
+
* Neither has any signal in the file other than this element.
|
|
20
|
+
*/
|
|
21
|
+
export declare function workbookPropertiesPass(workbook: Workbook): SaxPass;
|
|
22
|
+
export declare function workbookViewPass(view: WorkbookView): SaxPass;
|
|
23
|
+
export interface DefinedNamesPass extends SaxPass {
|
|
24
|
+
/**
|
|
25
|
+
* The names, scoped against the sheet order.
|
|
26
|
+
*
|
|
27
|
+
* The order is supplied here rather than to the pass, and that is what lets the names ride the same
|
|
28
|
+
* scan as everything else this part carries. A scoped name's `localSheetId` indexes the sheets in
|
|
29
|
+
* declaration order, and the model's answer for index n is known only after the sheet loop has run
|
|
30
|
+
* and repaired the names it had to; resolving during the scan would have forced a second one.
|
|
31
|
+
*/
|
|
32
|
+
result(sheetOrder: readonly string[]): DefinedName[];
|
|
33
|
+
}
|
|
34
|
+
export declare function definedNamesPass(): DefinedNamesPass;
|
|
35
|
+
export declare function applyCoreProperties(workbook: Workbook, xml: string): void;
|
|
36
|
+
export declare function applyAppProperties(workbook: Workbook, xml: string): void;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { parseDateText } from '../../core/date.js';
|
|
2
|
+
import { unmangleFunctions } from '../../core/formula.js';
|
|
3
|
+
import { WORKBOOK_PROTECTION_CREDENTIAL_ATTRS, } from '../../core/workbook-protection.js';
|
|
4
|
+
import { isVisibility } from '../../core/worksheet.js';
|
|
5
|
+
import { enumToken, numInteger } from '../../xml/xml-attrs.js';
|
|
6
|
+
import { capturedText, TextCapture } from '../../xml/xml-read.js';
|
|
7
|
+
import { boolStrict, localName } from '../../xml/xml-scan.js';
|
|
8
|
+
import { relAttr } from '../opc/namespaces.js';
|
|
9
|
+
export function workbookSheetsPass() {
|
|
10
|
+
const sheets = [];
|
|
11
|
+
return {
|
|
12
|
+
handlers: {
|
|
13
|
+
onOpen(name, attrs, _selfClosing, scope) {
|
|
14
|
+
if (localName(name) !== 'sheet')
|
|
15
|
+
return;
|
|
16
|
+
const entry = {
|
|
17
|
+
name: attrs.name ?? '',
|
|
18
|
+
relId: relAttr(scope, attrs, 'id') ?? '',
|
|
19
|
+
};
|
|
20
|
+
const state = enumToken(attrs.state, isVisibility);
|
|
21
|
+
if (state !== undefined && state !== 'visible')
|
|
22
|
+
entry.state = state;
|
|
23
|
+
sheets.push(entry);
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
result: () => sheets,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function workbookProtectionPass() {
|
|
30
|
+
let found;
|
|
31
|
+
const handlers = {
|
|
32
|
+
onOpen(name, attrs) {
|
|
33
|
+
if (localName(name) !== 'workbookProtection')
|
|
34
|
+
return;
|
|
35
|
+
const protection = {};
|
|
36
|
+
if (boolStrict(attrs.lockStructure))
|
|
37
|
+
protection.lockStructure = true;
|
|
38
|
+
if (boolStrict(attrs.lockWindows))
|
|
39
|
+
protection.lockWindows = true;
|
|
40
|
+
if (boolStrict(attrs.lockRevision))
|
|
41
|
+
protection.lockRevision = true;
|
|
42
|
+
const credentials = {};
|
|
43
|
+
for (const key of WORKBOOK_PROTECTION_CREDENTIAL_ATTRS) {
|
|
44
|
+
const value = attrs[key];
|
|
45
|
+
if (value !== undefined)
|
|
46
|
+
credentials[key] = value;
|
|
47
|
+
}
|
|
48
|
+
if (Object.keys(credentials).length > 0)
|
|
49
|
+
protection.credentials = credentials;
|
|
50
|
+
found = protection;
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
return { handlers, result: () => found };
|
|
54
|
+
}
|
|
55
|
+
export function workbookPropertiesPass(workbook) {
|
|
56
|
+
let seen = false;
|
|
57
|
+
return {
|
|
58
|
+
handlers: {
|
|
59
|
+
onOpen(name, attrs) {
|
|
60
|
+
if (seen || localName(name) !== 'workbookPr')
|
|
61
|
+
return;
|
|
62
|
+
seen = true;
|
|
63
|
+
if (boolStrict(attrs.date1904))
|
|
64
|
+
workbook.dateEpoch = 1904;
|
|
65
|
+
if (attrs.codeName !== undefined)
|
|
66
|
+
workbook.codeName = attrs.codeName;
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export function workbookViewPass(view) {
|
|
72
|
+
let seen = false;
|
|
73
|
+
return {
|
|
74
|
+
handlers: {
|
|
75
|
+
onOpen(name, attrs) {
|
|
76
|
+
if (seen || localName(name) !== 'workbookView')
|
|
77
|
+
return;
|
|
78
|
+
seen = true;
|
|
79
|
+
const x = numInteger(attrs.xWindow);
|
|
80
|
+
if (x !== undefined)
|
|
81
|
+
view.x = x;
|
|
82
|
+
const y = numInteger(attrs.yWindow);
|
|
83
|
+
if (y !== undefined)
|
|
84
|
+
view.y = y;
|
|
85
|
+
const width = numInteger(attrs.windowWidth, 0);
|
|
86
|
+
if (width !== undefined)
|
|
87
|
+
view.width = width;
|
|
88
|
+
const height = numInteger(attrs.windowHeight, 0);
|
|
89
|
+
if (height !== undefined)
|
|
90
|
+
view.height = height;
|
|
91
|
+
const activeTab = numInteger(attrs.activeTab, 0);
|
|
92
|
+
if (activeTab !== undefined)
|
|
93
|
+
view.activeTab = activeTab;
|
|
94
|
+
const visibility = enumToken(attrs.visibility, isVisibility);
|
|
95
|
+
if (visibility !== undefined && visibility !== 'visible')
|
|
96
|
+
view.visibility = visibility;
|
|
97
|
+
if (boolStrict(attrs.minimized))
|
|
98
|
+
view.minimized = true;
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export function definedNamesPass() {
|
|
104
|
+
const drafts = [];
|
|
105
|
+
const refersTo = new TextCapture('definedName');
|
|
106
|
+
let pending;
|
|
107
|
+
return {
|
|
108
|
+
handlers: {
|
|
109
|
+
onOpen(name, attrs, selfClosing) {
|
|
110
|
+
if (localName(name) !== 'definedName' || attrs.name === undefined)
|
|
111
|
+
return;
|
|
112
|
+
if (attrs.name === '_xlnm._FilterDatabase')
|
|
113
|
+
return;
|
|
114
|
+
refersTo.open(localName(name), selfClosing);
|
|
115
|
+
pending = { name: attrs.name, localSheetId: numInteger(attrs.localSheetId, 0) ?? -1 };
|
|
116
|
+
if (attrs.comment !== undefined)
|
|
117
|
+
pending.comment = attrs.comment;
|
|
118
|
+
if (boolStrict(attrs.hidden))
|
|
119
|
+
pending.hidden = true;
|
|
120
|
+
},
|
|
121
|
+
onText(chunk) {
|
|
122
|
+
refersTo.text(chunk);
|
|
123
|
+
},
|
|
124
|
+
onClose(name) {
|
|
125
|
+
const text = refersTo.close(localName(name));
|
|
126
|
+
if (text === undefined || pending === undefined)
|
|
127
|
+
return;
|
|
128
|
+
drafts.push({ ...pending, refersTo: unmangleFunctions(text) });
|
|
129
|
+
pending = undefined;
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
closeEmptyElements: new Set(['definedName']),
|
|
133
|
+
result(sheetOrder) {
|
|
134
|
+
return drafts.map(({ localSheetId, ...draft }) => {
|
|
135
|
+
const scope = sheetOrder[localSheetId];
|
|
136
|
+
return scope === undefined ? draft : { ...draft, scope };
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
const CORE_PROPERTY_LOCAL_NAMES = new Set([
|
|
142
|
+
'title',
|
|
143
|
+
'creator',
|
|
144
|
+
'lastModifiedBy',
|
|
145
|
+
'created',
|
|
146
|
+
'modified',
|
|
147
|
+
]);
|
|
148
|
+
export function applyCoreProperties(workbook, xml) {
|
|
149
|
+
for (const { local, text } of capturedText(xml, CORE_PROPERTY_LOCAL_NAMES)) {
|
|
150
|
+
if (local === 'title')
|
|
151
|
+
workbook.properties.title = text;
|
|
152
|
+
else if (local === 'creator')
|
|
153
|
+
workbook.properties.creator = text;
|
|
154
|
+
else if (local === 'lastModifiedBy')
|
|
155
|
+
workbook.properties.lastModifiedBy = text;
|
|
156
|
+
else {
|
|
157
|
+
const date = parseDateText(text);
|
|
158
|
+
if (date !== null) {
|
|
159
|
+
if (local === 'created')
|
|
160
|
+
workbook.properties.created = date;
|
|
161
|
+
else
|
|
162
|
+
workbook.properties.modified = date;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
export function applyAppProperties(workbook, xml) {
|
|
168
|
+
for (const { text } of capturedText(xml, 'Company'))
|
|
169
|
+
workbook.properties.company = text;
|
|
170
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DateEpoch } from '../../core/date.ts';
|
|
1
2
|
import type { Worksheet } from '../../core/worksheet.ts';
|
|
2
3
|
import { type SaxPass } from '../../xml/xml-read.ts';
|
|
3
4
|
import type { XfStyle } from '../style/xf-style.ts';
|
|
@@ -10,4 +11,4 @@ import type { SharedString } from './cell-value.ts';
|
|
|
10
11
|
* Offered as a pass because the worksheet is the largest part in a package and four other readers
|
|
11
12
|
* want the same events, so the five share one parse of it rather than scanning it once each.
|
|
12
13
|
*/
|
|
13
|
-
export declare function worksheetPass(sheet: Worksheet, sharedStrings: readonly SharedString[], xfStyles: ReadonlyArray<XfStyle
|
|
14
|
+
export declare function worksheetPass(sheet: Worksheet, sharedStrings: readonly SharedString[], xfStyles: ReadonlyArray<XfStyle>, dateEpoch: DateEpoch): SaxPass;
|