@shbernal/ts-xlsx 3.0.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 +34 -24
- package/dist/bytes.d.ts +10 -2
- package/dist/bytes.js +22 -0
- package/dist/core/address.d.ts +96 -2
- package/dist/core/address.js +87 -33
- package/dist/core/array-formula-ranges.d.ts +33 -0
- package/dist/core/array-formula-ranges.js +62 -0
- 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 +4 -6
- package/dist/core/column.d.ts +1 -0
- package/dist/core/column.js +6 -2
- package/dist/core/comment-thread.d.ts +7 -3
- package/dist/core/comment-thread.js +2 -1
- package/dist/core/conditional-formatting-overlay.d.ts +11 -1
- package/dist/core/conditional-formatting-overlay.js +30 -3
- package/dist/core/conditional-formatting.d.ts +107 -11
- package/dist/core/conditional-formatting.js +76 -19
- package/dist/core/containers.d.ts +12 -0
- package/dist/core/containers.js +5 -0
- package/dist/core/data-validation-overlay.d.ts +7 -1
- package/dist/core/data-validation-overlay.js +19 -4
- package/dist/core/data-validation.d.ts +22 -0
- package/dist/core/data-validation.js +30 -4
- package/dist/core/date-format.d.ts +20 -0
- package/dist/core/date-format.js +170 -0
- package/dist/core/date.d.ts +43 -8
- package/dist/core/date.js +19 -3
- 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 +76 -17
- package/dist/core/formula.js +87 -80
- 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 +30 -3
- package/dist/core/grid-edits.js +248 -81
- package/dist/core/grid-shift.d.ts +58 -9
- package/dist/core/grid-shift.js +26 -4
- package/dist/core/hyperlink.d.ts +39 -0
- package/dist/core/hyperlink.js +88 -0
- package/dist/core/image.d.ts +49 -14
- package/dist/core/image.js +16 -5
- package/dist/core/internal.d.ts +10 -2
- package/dist/core/limits.d.ts +25 -0
- package/dist/core/limits.js +4 -0
- package/dist/core/merge.d.ts +18 -4
- package/dist/core/merge.js +33 -20
- package/dist/core/page-setup.d.ts +26 -11
- package/dist/core/pivot-table.d.ts +49 -10
- package/dist/core/pivot-table.js +112 -60
- package/dist/core/protection.d.ts +66 -4
- package/dist/core/protection.js +6 -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 +6 -2
- package/dist/core/structured-reference.d.ts +7 -0
- package/dist/core/structured-reference.js +7 -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 +64 -16
- package/dist/core/table.js +87 -40
- package/dist/core/theme.d.ts +2 -0
- package/dist/core/theme.js +9 -5
- package/dist/core/value.d.ts +60 -28
- package/dist/core/value.js +48 -43
- package/dist/core/workbook-media.d.ts +34 -0
- package/dist/core/workbook-media.js +44 -0
- package/dist/core/workbook-styles.d.ts +83 -1
- package/dist/core/workbook-styles.js +4 -0
- package/dist/core/workbook-theme.js +5 -3
- package/dist/core/workbook-vba.js +3 -2
- package/dist/core/workbook.d.ts +41 -3
- package/dist/core/workbook.js +46 -41
- package/dist/core/worksheet-comments.d.ts +2 -1
- package/dist/core/worksheet-comments.js +20 -13
- package/dist/core/worksheet-merges.d.ts +49 -0
- package/dist/core/worksheet-merges.js +65 -0
- package/dist/core/worksheet-model.d.ts +10 -2
- package/dist/core/worksheet-model.js +28 -9
- package/dist/core/worksheet-pictures.d.ts +3 -3
- package/dist/core/worksheet-pictures.js +7 -6
- package/dist/core/worksheet.d.ts +165 -27
- package/dist/core/worksheet.js +206 -89
- package/dist/customui/ribbon.js +2 -1
- package/dist/entries/core.d.ts +21 -14
- package/dist/entries/core.js +14 -7
- package/dist/entries/errors.d.ts +1 -0
- package/dist/entries/errors.js +1 -0
- 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/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 +21 -0
- package/dist/io/csv/delimiter.js +18 -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 +51 -22
- package/dist/io/csv/write.d.ts +19 -5
- package/dist/io/csv/write.js +24 -44
- 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 +5 -5
- package/dist/io/opc/read-opc.d.ts +58 -14
- package/dist/io/opc/read-opc.js +49 -21
- 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/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/read-policy/column-budget.js +18 -0
- 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/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 +52 -35
- 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 +495 -596
- package/dist/io/xlsb/read-metadata.d.ts +7 -0
- package/dist/io/xlsb/read-metadata.js +69 -0
- package/dist/io/xlsb/read-styles.js +45 -81
- package/dist/io/xlsb/read-worksheet.d.ts +26 -1
- package/dist/io/xlsb/read-worksheet.js +148 -106
- package/dist/io/xlsb/read.d.ts +6 -3
- package/dist/io/xlsb/read.js +70 -31
- 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 +14 -5
- package/dist/io/xlsb/record-types.js +14 -5
- 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 +24 -9
- package/dist/io/xlsx/cell-accumulator.js +74 -21
- 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 +19 -5
- package/dist/io/xlsx/cell-value.js +45 -30
- package/dist/io/xlsx/color-xml.js +3 -2
- 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 +9 -30
- package/dist/io/xlsx/comments.js +25 -83
- package/dist/io/xlsx/conditional-formatting.d.ts +43 -23
- package/dist/io/xlsx/conditional-formatting.js +437 -138
- package/dist/io/xlsx/data-validation.d.ts +12 -7
- package/dist/io/xlsx/data-validation.js +67 -53
- package/dist/io/xlsx/edit-vba.d.ts +7 -2
- package/dist/io/xlsx/edit-vba.js +52 -52
- 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 +19 -21
- package/dist/io/xlsx/hyperlinks.js +12 -32
- package/dist/io/xlsx/images.d.ts +49 -16
- package/dist/io/xlsx/images.js +149 -50
- package/dist/io/xlsx/namespaces.d.ts +24 -0
- package/dist/io/xlsx/namespaces.js +11 -0
- package/dist/io/xlsx/package-plan.d.ts +60 -15
- package/dist/io/xlsx/package-plan.js +83 -18
- 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 +26 -24
- 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 +59 -0
- package/dist/io/xlsx/read-parts.js +259 -0
- package/dist/io/xlsx/read-pivot.js +11 -4
- package/dist/io/xlsx/{rich-runs.d.ts → read-rich-runs.d.ts} +8 -5
- package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +24 -4
- package/dist/io/xlsx/read-rows.d.ts +35 -11
- package/dist/io/xlsx/read-rows.js +73 -49
- package/dist/io/xlsx/read-shared-strings.js +3 -2
- package/dist/io/xlsx/read-styles.d.ts +0 -30
- package/dist/io/xlsx/read-styles.js +45 -105
- package/dist/io/xlsx/read-workbook-xml.d.ts +42 -0
- package/dist/io/xlsx/read-workbook-xml.js +175 -0
- package/dist/io/xlsx/read-worksheet.d.ts +9 -3
- package/dist/io/xlsx/read-worksheet.js +70 -177
- package/dist/io/xlsx/read.d.ts +3 -14
- package/dist/io/xlsx/read.js +74 -411
- package/dist/io/xlsx/relationships.d.ts +3 -0
- package/dist/io/xlsx/relationships.js +4 -0
- package/dist/io/xlsx/rich-text.js +1 -1
- package/dist/io/xlsx/row-position.d.ts +20 -0
- package/dist/io/xlsx/row-position.js +11 -0
- package/dist/io/xlsx/row-xml.d.ts +139 -0
- package/dist/io/xlsx/row-xml.js +222 -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 +182 -20
- 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 +41 -0
- package/dist/io/xlsx/style-elements.js +136 -0
- package/dist/io/xlsx/styles.d.ts +17 -3
- package/dist/io/xlsx/styles.js +13 -209
- package/dist/io/xlsx/tables.d.ts +10 -2
- package/dist/io/xlsx/tables.js +55 -52
- package/dist/io/xlsx/theme-xml.d.ts +32 -4
- package/dist/io/xlsx/theme-xml.js +106 -71
- package/dist/io/xlsx/threaded-comments.d.ts +14 -11
- package/dist/io/xlsx/threaded-comments.js +16 -8
- package/dist/io/xlsx/workbook-xml.d.ts +45 -6
- package/dist/io/xlsx/workbook-xml.js +62 -54
- package/dist/io/xlsx/worksheet-xml.d.ts +26 -70
- package/dist/io/xlsx/worksheet-xml.js +69 -282
- package/dist/io/xlsx/write-stream.d.ts +90 -19
- package/dist/io/xlsx/write-stream.js +80 -25
- package/dist/io/xlsx/write.d.ts +12 -6
- package/dist/io/xlsx/write.js +226 -123
- package/dist/rel-type.d.ts +25 -0
- package/dist/rel-type.js +9 -0
- package/dist/token-set.d.ts +13 -0
- package/dist/token-set.js +4 -1
- package/dist/vba/bytes.d.ts +16 -5
- package/dist/vba/bytes.js +27 -6
- package/dist/vba/cfb-format.d.ts +55 -0
- package/dist/vba/cfb-format.js +35 -0
- package/dist/vba/cfb-writer.d.ts +8 -0
- package/dist/vba/cfb-writer.js +40 -40
- package/dist/vba/cfb.d.ts +21 -4
- package/dist/vba/cfb.js +124 -90
- package/dist/vba/codepage.js +2 -1
- package/dist/vba/dir-records.d.ts +6 -0
- package/dist/vba/dir-records.js +10 -2
- package/dist/vba/errors.d.ts +11 -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 +66 -22
- package/dist/vba/project-editor.js +129 -119
- package/dist/vba/project.d.ts +15 -1
- package/dist/vba/project.js +38 -13
- package/dist/vba/vba-encoding.d.ts +4 -10
- package/dist/vba/vba-encoding.js +3 -17
- 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 +101 -11
- package/dist/xml/xml-read.js +150 -18
- package/dist/xml/xml-scan.d.ts +25 -34
- package/dist/xml/xml-scan.js +69 -46
- package/dist/xml/xml.d.ts +59 -26
- package/dist/xml/xml.js +45 -23
- package/package.json +15 -9
- package/skills/ts-xlsx-upstream/SKILL.md +21 -13
- package/dist/core/modern-functions.d.ts +0 -1
|
@@ -1,42 +1,59 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { Workbook } from '../../core/workbook.js';
|
|
2
|
+
import { WorksheetMerges } from '../../core/worksheet-merges.js';
|
|
3
|
+
import { AuthoringError, quoted } from '../../errors.js';
|
|
4
|
+
import { numInteger } from '../../xml/xml-attrs.js';
|
|
5
|
+
import { closeEmptyElements, parseXmlPasses } from '../../xml/xml-read.js';
|
|
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 {
|
|
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';
|
|
8
15
|
import { XlsxParseError } from './errors.js';
|
|
16
|
+
import { SHARED_STRINGS_PART, STYLES_PART } from './part-names.js';
|
|
9
17
|
import { parseSharedStrings } from './read-shared-strings.js';
|
|
10
|
-
import { parseStyleTable
|
|
18
|
+
import { parseStyleTable } from './read-styles.js';
|
|
19
|
+
import { definedNamesPass, workbookPropertiesPass, workbookSheetsPass, } from './read-workbook-xml.js';
|
|
20
|
+
import { RowPositionTracker } from './row-position.js';
|
|
11
21
|
export function* readSheetRows(data, options = {}) {
|
|
12
22
|
const pkg = openPackage(data, options.maxUncompressedBytes);
|
|
13
23
|
const chosen = pickSheet(pkg.sheets, options.sheet);
|
|
14
24
|
const sheetXml = pkg.sheetXml(chosen.relId);
|
|
15
25
|
if (sheetXml === undefined)
|
|
16
26
|
return;
|
|
17
|
-
yield* scanSheet(sheetXml, pkg
|
|
27
|
+
yield* scanSheet(sheetXml, pkg, new Set(), new WorksheetMerges());
|
|
18
28
|
}
|
|
19
29
|
export function* readWorkbookStream(data, options = {}) {
|
|
20
30
|
const pkg = openPackage(data, options.maxUncompressedBytes);
|
|
21
31
|
for (const sheet of pkg.sheets) {
|
|
22
32
|
const xml = pkg.sheetXml(sheet.relId) ?? '';
|
|
23
|
-
yield new StreamedSheetReader(sheet.name, xml, pkg
|
|
33
|
+
yield new StreamedSheetReader(sheet.name, xml, pkg);
|
|
24
34
|
}
|
|
25
35
|
}
|
|
26
36
|
function openPackage(data, maxUncompressedBytes) {
|
|
27
|
-
const { pkg, workbookXml } = openSpreadsheetPackage(data, maxUncompressedBytes);
|
|
28
|
-
const { partText: text } = pkg;
|
|
37
|
+
const { pkg, documentPath, workbookXml } = openSpreadsheetPackage(data, maxUncompressedBytes);
|
|
38
|
+
const { partText: text, partBytes } = pkg;
|
|
29
39
|
if (workbookXml === undefined) {
|
|
30
|
-
throw unsupportedWorkbookPart(
|
|
40
|
+
throw unsupportedWorkbookPart(partBytes, documentPath, 'the binary .xlsb format (BIFF12) cannot be row-streamed yet; read it with readXlsx or readXlsb');
|
|
31
41
|
}
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
42
|
+
const properties = new Workbook();
|
|
43
|
+
const sheetsPass = workbookSheetsPass();
|
|
44
|
+
const namesPass = definedNamesPass();
|
|
45
|
+
parseXmlPasses(workbookXml, [sheetsPass, workbookPropertiesPass(properties), namesPass]);
|
|
46
|
+
const sheets = repairedSheetNames(sheetsPass.result());
|
|
47
|
+
const rels = readPartRelationships(documentPath, text);
|
|
48
|
+
const sharedStrings = parseSharedStrings(rels.relatedTextOrPath('sharedStrings', SHARED_STRINGS_PART));
|
|
49
|
+
const { cellXfs: xfStyles } = parseStyleTable(rels.relatedTextOrPath('styles', STYLES_PART));
|
|
36
50
|
return {
|
|
37
51
|
sheets,
|
|
38
52
|
sharedStrings,
|
|
39
53
|
xfStyles,
|
|
54
|
+
dateEpoch: properties.dateEpoch,
|
|
55
|
+
definedNames: namesPass.spellings(),
|
|
56
|
+
cellMetadata: readCellMetadata(rels),
|
|
40
57
|
sheetXml(relId) {
|
|
41
58
|
const target = rels.byId(relId)?.target;
|
|
42
59
|
return target === undefined ? undefined : text(rels.pathOf(target));
|
|
@@ -57,28 +74,26 @@ function pickSheet(sheets, selector) {
|
|
|
57
74
|
}
|
|
58
75
|
const sheet = sheets.find((candidate) => candidate.name === selector);
|
|
59
76
|
if (sheet === undefined)
|
|
60
|
-
throw new AuthoringError(`no worksheet named ${
|
|
77
|
+
throw new AuthoringError(`no worksheet named ${quoted(selector)}`);
|
|
61
78
|
return sheet;
|
|
62
79
|
}
|
|
63
80
|
class StreamedSheetReader {
|
|
64
81
|
name;
|
|
65
82
|
#xml;
|
|
66
|
-
#
|
|
67
|
-
#xfStyles;
|
|
83
|
+
#tables;
|
|
68
84
|
#hiddenColumns = new Set();
|
|
69
|
-
#merges =
|
|
85
|
+
#merges = new WorksheetMerges();
|
|
70
86
|
#scanned = false;
|
|
71
|
-
constructor(name, xml,
|
|
87
|
+
constructor(name, xml, tables) {
|
|
72
88
|
this.name = name;
|
|
73
89
|
this.#xml = xml;
|
|
74
|
-
this.#
|
|
75
|
-
this.#xfStyles = xfStyles;
|
|
90
|
+
this.#tables = tables;
|
|
76
91
|
}
|
|
77
92
|
*rows() {
|
|
78
93
|
this.#hiddenColumns = new Set();
|
|
79
|
-
this.#merges =
|
|
94
|
+
this.#merges = new WorksheetMerges();
|
|
80
95
|
this.#scanned = false;
|
|
81
|
-
yield* scanSheet(this.#xml, this.#
|
|
96
|
+
yield* scanSheet(this.#xml, this.#tables, this.#hiddenColumns, this.#merges);
|
|
82
97
|
this.#scanned = true;
|
|
83
98
|
}
|
|
84
99
|
get hiddenColumns() {
|
|
@@ -87,7 +102,7 @@ class StreamedSheetReader {
|
|
|
87
102
|
}
|
|
88
103
|
get merges() {
|
|
89
104
|
this.#ensureScanned();
|
|
90
|
-
return [...this.#merges];
|
|
105
|
+
return [...this.#merges.ranges];
|
|
91
106
|
}
|
|
92
107
|
#ensureScanned() {
|
|
93
108
|
if (this.#scanned)
|
|
@@ -96,25 +111,28 @@ class StreamedSheetReader {
|
|
|
96
111
|
}
|
|
97
112
|
}
|
|
98
113
|
}
|
|
99
|
-
|
|
100
|
-
|
|
114
|
+
function* scanSheet(xml, tables, hiddenColumns, merges) {
|
|
115
|
+
const { sharedStrings, xfStyles, dateEpoch, definedNames, cellMetadata } = tables;
|
|
101
116
|
let rowNumber = 0;
|
|
102
|
-
let lastRow = 0;
|
|
103
117
|
let rowHidden = false;
|
|
104
|
-
let rowInGrid = true;
|
|
105
118
|
let cells = [];
|
|
106
|
-
const
|
|
119
|
+
const columnBudget = new ColumnRecordBudget();
|
|
120
|
+
const styleResolution = new CellStyleResolver();
|
|
121
|
+
const rowPosition = new RowPositionTracker();
|
|
122
|
+
const cell = new CellAccumulator({ dateEpoch, definedNames, cellMetadata });
|
|
107
123
|
const finalizeCell = () => {
|
|
108
|
-
if (cell.ref === ''
|
|
124
|
+
if (cell.ref === '')
|
|
109
125
|
return;
|
|
110
|
-
const style = cell.
|
|
126
|
+
const style = styleResolution.styleFor(cell.col, cell.styleIndex, xfStyles);
|
|
111
127
|
const value = cell.decode(sharedStrings, style);
|
|
112
128
|
if (value !== null) {
|
|
113
129
|
const { col, ref } = cell;
|
|
114
|
-
cells.push(style
|
|
130
|
+
cells.push(style !== undefined && styleResolution.declaresFormat(col, cell.styleIndex)
|
|
131
|
+
? { col, address: ref, value, style }
|
|
132
|
+
: { col, address: ref, value });
|
|
115
133
|
}
|
|
116
134
|
};
|
|
117
|
-
for (const event of closeEmptyElements(xmlEvents(xml),
|
|
135
|
+
for (const event of closeEmptyElements(xmlEvents(xml), WORKSHEET_BODY_EMPTY_CLOSES)) {
|
|
118
136
|
if (event.kind === 'text') {
|
|
119
137
|
cell.appendChunk(event.text);
|
|
120
138
|
continue;
|
|
@@ -125,20 +143,22 @@ function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
|
|
|
125
143
|
continue;
|
|
126
144
|
switch (local) {
|
|
127
145
|
case 'row': {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
rowInGrid = rowNumber <= MAX_ROW;
|
|
146
|
+
const position = rowPosition.open(event.attrs);
|
|
147
|
+
rowNumber = position.number;
|
|
131
148
|
rowHidden = boolStrict(event.attrs.hidden);
|
|
132
|
-
|
|
149
|
+
cell.openRow(position.number, position.inGrid);
|
|
150
|
+
styleResolution.openRow(numInteger(event.attrs.s, 0) ?? -1, boolStrict(event.attrs.customFormat));
|
|
133
151
|
break;
|
|
134
152
|
}
|
|
135
153
|
case 'col':
|
|
136
|
-
|
|
154
|
+
collectColumn(event.attrs, hiddenColumns, styleResolution, columnBudget);
|
|
137
155
|
break;
|
|
138
|
-
case 'mergeCell':
|
|
139
|
-
|
|
140
|
-
|
|
156
|
+
case 'mergeCell': {
|
|
157
|
+
const ref = event.attrs.ref;
|
|
158
|
+
if (ref !== undefined)
|
|
159
|
+
admitting(() => merges.add(ref));
|
|
141
160
|
break;
|
|
161
|
+
}
|
|
142
162
|
default:
|
|
143
163
|
break;
|
|
144
164
|
}
|
|
@@ -149,19 +169,23 @@ function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
|
|
|
149
169
|
if (claimed === 'cell')
|
|
150
170
|
finalizeCell();
|
|
151
171
|
else if (claimed === 'other' && local === 'row') {
|
|
152
|
-
|
|
172
|
+
styleResolution.closeRow();
|
|
173
|
+
const inGrid = cell.rowOpen;
|
|
174
|
+
cell.closeRow();
|
|
175
|
+
if (inGrid)
|
|
153
176
|
yield { number: rowNumber, hidden: rowHidden, cells };
|
|
177
|
+
cells = [];
|
|
154
178
|
}
|
|
155
179
|
}
|
|
156
180
|
}
|
|
157
|
-
function
|
|
158
|
-
|
|
181
|
+
function collectColumn(attrs, hiddenColumns, styleResolution, budget) {
|
|
182
|
+
const span = takeColumnSpan(attrs, budget);
|
|
183
|
+
if (span === undefined)
|
|
159
184
|
return;
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
if (
|
|
185
|
+
const { first: min, last } = span;
|
|
186
|
+
styleResolution.noteColumnSpan(min, last, numInteger(attrs.style, 0) ?? -1);
|
|
187
|
+
if (!boolStrict(attrs.hidden))
|
|
163
188
|
return;
|
|
164
|
-
const last = Math.min(max, MAX_COLUMN);
|
|
165
189
|
for (let index = min; index <= last; index++)
|
|
166
190
|
hiddenColumns.add(index);
|
|
167
191
|
}
|
|
@@ -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,32 +1,2 @@
|
|
|
1
|
-
import { type Font, type TableStyleTable } from '../../core/style.ts';
|
|
2
|
-
import { type XmlAttributes } from '../../xml/xml-scan.ts';
|
|
3
1
|
import { type StyleTable } from '../style/xf-style.ts';
|
|
4
|
-
export type FontDraft = {
|
|
5
|
-
-readonly [K in keyof Font]?: Font[K];
|
|
6
|
-
};
|
|
7
2
|
export declare function parseStyleTable(xml: string): StyleTable;
|
|
8
|
-
export declare function applyFontChild(draft: FontDraft, local: string, attrs: XmlAttributes): void;
|
|
9
|
-
/**
|
|
10
|
-
* Extract the custom indexed-color palette (`<colors><indexedColors>`) from styles.xml as verbatim
|
|
11
|
-
* `<rgbColor rgb="…"/>` fragments, or an empty list when the file rides the default palette. Kept raw
|
|
12
|
-
* rather than parsed into RGB and re-serialised, so the exact entries (count, order, casing) a
|
|
13
|
-
* source file declared survive a round-trip and every `indexed="…"` reference keeps its RGB.
|
|
14
|
-
*/
|
|
15
|
-
export declare function parseIndexedColors(stylesXml: string): string[];
|
|
16
|
-
/**
|
|
17
|
-
* Extract the most-recently-used colour swatches (`<colors><mruColors>`) from styles.xml as verbatim
|
|
18
|
-
* `<color .../>` fragments, or an empty list when the file declares none. Kept raw for the same reason
|
|
19
|
-
* the indexed palette is: the list is the author's own working set of colours and the model has no
|
|
20
|
-
* use for its contents, only for not losing them.
|
|
21
|
-
*/
|
|
22
|
-
export declare function parseMruColors(stylesXml: string): string[];
|
|
23
|
-
/**
|
|
24
|
-
* Extract the `<tableStyles>` block from styles.xml: each `<tableStyle>` definition verbatim, plus the
|
|
25
|
-
* container's nominated `defaultTableStyle`/`defaultPivotStyle`. See {@link TableStyleTable} for why
|
|
26
|
-
* the definitions stay raw while the two names are decoded.
|
|
27
|
-
*
|
|
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
|
-
* carry.
|
|
31
|
-
*/
|
|
32
|
-
export declare function parseTableStyles(stylesXml: string): TableStyleTable;
|
|
@@ -1,14 +1,17 @@
|
|
|
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);
|
|
9
11
|
const STYLE_EMPTY_CLOSES = new Set([
|
|
10
12
|
'font',
|
|
11
13
|
'border',
|
|
14
|
+
'fill',
|
|
12
15
|
'patternFill',
|
|
13
16
|
'gradientFill',
|
|
14
17
|
'xf',
|
|
@@ -109,30 +112,37 @@ function parseFonts(events) {
|
|
|
109
112
|
}
|
|
110
113
|
function parseFills(events) {
|
|
111
114
|
const fills = [];
|
|
112
|
-
let
|
|
113
|
-
let
|
|
114
|
-
let bgColor;
|
|
115
|
+
let fillDraft = null;
|
|
116
|
+
let patternDraft = null;
|
|
115
117
|
let gradientDraft = null;
|
|
116
|
-
let fillSlotAt = -1;
|
|
117
118
|
for (const event of until(events, 'fills')) {
|
|
118
119
|
if (event.kind === 'open') {
|
|
119
120
|
const attrs = event.attrs;
|
|
121
|
+
const bodyExpected = fillDraft !== null && !fillDraft.bodyRead;
|
|
120
122
|
switch (localName(event.name)) {
|
|
121
123
|
case 'fill':
|
|
122
|
-
|
|
124
|
+
fillDraft = { body: undefined, bodyRead: false };
|
|
123
125
|
break;
|
|
124
126
|
case 'patternFill':
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
127
|
+
if (!bodyExpected)
|
|
128
|
+
break;
|
|
129
|
+
patternDraft = {
|
|
130
|
+
pattern: attrs.patternType ?? 'none',
|
|
131
|
+
fgColor: undefined,
|
|
132
|
+
bgColor: undefined,
|
|
133
|
+
};
|
|
128
134
|
break;
|
|
129
135
|
case 'fgColor':
|
|
130
|
-
|
|
136
|
+
if (patternDraft !== null)
|
|
137
|
+
patternDraft.fgColor = parseColor(attrs);
|
|
131
138
|
break;
|
|
132
139
|
case 'bgColor':
|
|
133
|
-
|
|
140
|
+
if (patternDraft !== null)
|
|
141
|
+
patternDraft.bgColor = parseColor(attrs);
|
|
134
142
|
break;
|
|
135
143
|
case 'gradientFill':
|
|
144
|
+
if (!bodyExpected)
|
|
145
|
+
break;
|
|
136
146
|
gradientDraft = {
|
|
137
147
|
fill: {
|
|
138
148
|
type: 'gradient',
|
|
@@ -159,7 +169,12 @@ function parseFills(events) {
|
|
|
159
169
|
else if (event.kind === 'close') {
|
|
160
170
|
switch (localName(event.name)) {
|
|
161
171
|
case 'patternFill':
|
|
162
|
-
|
|
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
|
+
}
|
|
163
178
|
break;
|
|
164
179
|
case 'stop':
|
|
165
180
|
if (gradientDraft !== null && gradientDraft.stopPosition !== null) {
|
|
@@ -173,14 +188,18 @@ function parseFills(events) {
|
|
|
173
188
|
}
|
|
174
189
|
break;
|
|
175
190
|
case 'gradientFill':
|
|
176
|
-
if (gradientDraft !== null) {
|
|
177
|
-
|
|
191
|
+
if (fillDraft !== null && gradientDraft !== null) {
|
|
192
|
+
fillDraft.body = gradientDraft.fill;
|
|
193
|
+
fillDraft.bodyRead = true;
|
|
178
194
|
gradientDraft = null;
|
|
179
195
|
}
|
|
180
196
|
break;
|
|
181
197
|
case 'fill':
|
|
182
|
-
if (
|
|
183
|
-
fills.push(
|
|
198
|
+
if (fillDraft !== null)
|
|
199
|
+
fills.push(fillDraft.body);
|
|
200
|
+
fillDraft = null;
|
|
201
|
+
patternDraft = null;
|
|
202
|
+
gradientDraft = null;
|
|
184
203
|
break;
|
|
185
204
|
}
|
|
186
205
|
}
|
|
@@ -309,68 +328,6 @@ function parseCellStyles(events) {
|
|
|
309
328
|
}
|
|
310
329
|
return names;
|
|
311
330
|
}
|
|
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
331
|
function resolveNumFmt(raw, custom) {
|
|
375
332
|
const id = numInteger(raw, 1);
|
|
376
333
|
return id === undefined ? undefined : numFmtCodeFor(id, custom);
|
|
@@ -426,36 +383,26 @@ function assignAlignmentToken(out, key, raw) {
|
|
|
426
383
|
out[key] = raw;
|
|
427
384
|
}
|
|
428
385
|
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;
|
|
435
|
-
}
|
|
436
|
-
export function parseIndexedColors(stylesXml) {
|
|
437
|
-
return capturedFragments(stylesXml, 'indexedColors');
|
|
438
|
-
}
|
|
439
|
-
export function parseMruColors(stylesXml) {
|
|
440
|
-
return capturedFragments(stylesXml, 'mruColors');
|
|
441
|
-
}
|
|
442
|
-
export function parseTableStyles(stylesXml) {
|
|
443
|
-
const { fragments, attributes } = elementSubtrees(stylesXml, new Map([['tableStyles', 'tableStyle']]));
|
|
444
|
-
return buildTableStyleTable(stylesXml, fragments.get('tableStyles') ?? [], attributes.get('tableStyles'));
|
|
386
|
+
return protectionFrom({ locked: boolTristate(attrs.locked), hidden: boolStrict(attrs.hidden) });
|
|
445
387
|
}
|
|
446
388
|
function buildTableStyleTable(stylesXml, styles, containerAttrs) {
|
|
447
|
-
const table = { styles:
|
|
389
|
+
const table = { styles: styles.map((xml) => ({ name: tableStyleNameOf(xml), xml })) };
|
|
448
390
|
if (containerAttrs?.defaultTableStyle !== undefined) {
|
|
449
391
|
table.defaultTableStyle = containerAttrs.defaultTableStyle;
|
|
450
392
|
}
|
|
451
393
|
if (containerAttrs?.defaultPivotStyle !== undefined) {
|
|
452
394
|
table.defaultPivotStyle = containerAttrs.defaultPivotStyle;
|
|
453
395
|
}
|
|
454
|
-
const namespaces = fragmentNamespaces(stylesXml,
|
|
396
|
+
const namespaces = fragmentNamespaces(stylesXml, styles);
|
|
455
397
|
if (namespaces.length > 0)
|
|
456
398
|
table.namespaces = namespaces;
|
|
457
399
|
return table;
|
|
458
400
|
}
|
|
401
|
+
function tableStyleNameOf(fragment) {
|
|
402
|
+
for (const { attrs } of openElements(fragment, 'tableStyle'))
|
|
403
|
+
return attrs.name ?? '';
|
|
404
|
+
return '';
|
|
405
|
+
}
|
|
459
406
|
function fragmentNamespaces(stylesXml, fragments) {
|
|
460
407
|
if (fragments.length === 0)
|
|
461
408
|
return [];
|
|
@@ -492,10 +439,3 @@ const PRESERVED_SUBTREES = new Map([
|
|
|
492
439
|
['mruColors', 'color'],
|
|
493
440
|
['tableStyles', 'tableStyle'],
|
|
494
441
|
]);
|
|
495
|
-
function capturedFragments(xml, container) {
|
|
496
|
-
const child = PRESERVED_SUBTREES.get(container);
|
|
497
|
-
if (child === undefined)
|
|
498
|
-
return [];
|
|
499
|
-
const { fragments } = elementSubtrees(xml, new Map([[container, child]]));
|
|
500
|
-
return [...(fragments.get(container) ?? [])];
|
|
501
|
-
}
|
|
@@ -0,0 +1,42 @@
|
|
|
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
|
+
* 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>;
|
|
39
|
+
}
|
|
40
|
+
export declare function definedNamesPass(): DefinedNamesPass;
|
|
41
|
+
export declare function applyCoreProperties(workbook: Workbook, xml: string): void;
|
|
42
|
+
export declare function applyAppProperties(workbook: Workbook, xml: string): void;
|