@shbernal/ts-xlsx 2.1.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 +5 -4
- package/dist/core/autofilter.js +34 -35
- package/dist/core/axis-handle.d.ts +10 -0
- package/dist/core/axis-handle.js +17 -0
- package/dist/core/cell.d.ts +25 -0
- package/dist/core/cell.js +9 -3
- 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 +5 -1
- package/dist/core/column.js +34 -35
- 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 +14 -6
- package/dist/core/conditional-formatting.js +45 -43
- 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 +9 -3
- package/dist/core/data-validation.js +21 -18
- 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 +14 -10
- package/dist/core/image.js +9 -9
- 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-index.d.ts +31 -0
- package/dist/core/merge-index.js +60 -0
- package/dist/core/merge.d.ts +5 -14
- package/dist/core/merge.js +18 -27
- package/dist/core/page-setup.d.ts +72 -2
- package/dist/core/page-setup.js +34 -8
- package/dist/core/pivot-table.d.ts +1 -1
- package/dist/core/pivot-table.js +67 -53
- 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 +5 -1
- package/dist/core/row.js +22 -23
- package/dist/core/style.d.ts +134 -75
- package/dist/core/style.js +112 -53
- package/dist/core/table-style.d.ts +1 -1
- package/dist/core/table-style.js +4 -4
- package/dist/core/table.d.ts +28 -10
- package/dist/core/table.js +54 -39
- package/dist/core/theme.js +6 -5
- package/dist/core/used-extent.d.ts +44 -0
- package/dist/core/used-extent.js +102 -0
- 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 +72 -12
- package/dist/core/worksheet.js +68 -70
- package/dist/customui/ribbon.js +6 -7
- 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 +15 -1
- 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 +10 -0
- package/dist/io/opc/part-paths.js +16 -1
- package/dist/io/opc/read-opc.d.ts +69 -10
- package/dist/io/opc/read-opc.js +49 -55
- package/dist/io/opc/read-options.d.ts +5 -1
- package/dist/io/opc/rels.d.ts +1 -6
- package/dist/io/opc/rels.js +1 -4
- 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 +48 -2
- package/dist/io/style/xf-style.js +14 -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 +50 -83
- 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 +47 -29
- 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 +9 -2
- 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 -31
- package/dist/io/xlsx/conditional-formatting.d.ts +9 -5
- package/dist/io/xlsx/conditional-formatting.js +51 -46
- package/dist/io/xlsx/data-validation.d.ts +9 -7
- package/dist/io/xlsx/data-validation.js +38 -35
- package/dist/io/xlsx/edit-vba.d.ts +7 -2
- package/dist/io/xlsx/edit-vba.js +15 -29
- 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 +41 -7
- package/dist/io/xlsx/hyperlinks.js +40 -28
- package/dist/io/xlsx/images.js +24 -25
- 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 +23 -3
- package/dist/io/xlsx/package-plan.js +66 -25
- package/dist/io/xlsx/part-names.d.ts +41 -0
- package/dist/io/xlsx/part-names.js +46 -0
- 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 +3 -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.d.ts → read-rich-runs.d.ts} +1 -1
- package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +7 -3
- package/dist/io/xlsx/read-rows.d.ts +18 -5
- package/dist/io/xlsx/read-rows.js +50 -37
- package/dist/io/xlsx/read-shared-strings.js +5 -3
- package/dist/io/xlsx/read-styles.d.ts +1 -6
- package/dist/io/xlsx/read-styles.js +65 -109
- 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 +11 -1
- package/dist/io/xlsx/read-worksheet.js +51 -193
- package/dist/io/xlsx/read.d.ts +5 -13
- package/dist/io/xlsx/read.js +111 -436
- 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 +166 -37
- 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 -204
- package/dist/io/xlsx/tables.js +11 -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 +3 -1
- package/dist/io/xlsx/workbook-xml.d.ts +54 -4
- package/dist/io/xlsx/workbook-xml.js +84 -57
- package/dist/io/xlsx/worksheet-xml.d.ts +23 -70
- package/dist/io/xlsx/worksheet-xml.js +59 -242
- package/dist/io/xlsx/write-stream.d.ts +71 -16
- package/dist/io/xlsx/write-stream.js +79 -41
- package/dist/io/xlsx/write.d.ts +6 -2
- package/dist/io/xlsx/write.js +217 -153
- package/dist/rel-type.d.ts +16 -0
- package/dist/rel-type.js +6 -0
- package/dist/token-set.d.ts +28 -0
- package/dist/token-set.js +7 -0
- package/dist/vba/bytes.d.ts +14 -5
- package/dist/vba/bytes.js +16 -6
- package/dist/vba/cfb-format.d.ts +32 -0
- package/dist/vba/cfb-format.js +13 -0
- package/dist/vba/cfb-writer.d.ts +9 -0
- package/dist/vba/cfb-writer.js +28 -25
- package/dist/vba/cfb.d.ts +13 -1
- package/dist/vba/cfb.js +73 -57
- package/dist/vba/codepage.js +2 -1
- package/dist/vba/errors.d.ts +7 -0
- package/dist/vba/ms-ovba.js +79 -23
- package/dist/vba/project-editor.js +35 -40
- package/dist/vba/project.d.ts +11 -1
- package/dist/vba/project.js +40 -21
- package/dist/vba/vba-encoding.js +5 -6
- 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 +128 -81
- package/dist/xml/xml-read.js +161 -178
- package/dist/xml/xml-scan.d.ts +78 -0
- package/dist/xml/xml-scan.js +180 -0
- package/dist/xml/xml.d.ts +29 -28
- package/dist/xml/xml.js +24 -24
- package/package.json +13 -9
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { decodeRange } from '../../core/address.js';
|
|
2
|
+
import { INTERNAL } from '../../core/internal.js';
|
|
3
|
+
import { Workbook } from '../../core/workbook.js';
|
|
4
|
+
import { isAnyRelType } from '../../rel-type.js';
|
|
5
|
+
import { localName } from '../../xml/xml-scan.js';
|
|
6
|
+
import { relAttr } from '../opc/namespaces.js';
|
|
7
|
+
import { extensionOf, resolveRelativePart } from '../opc/part-paths.js';
|
|
8
|
+
import { capturePartClosure, parseRelationshipRecords, readPartRelationships, } from '../opc/read-opc.js';
|
|
9
|
+
import { parseComments } from './comments.js';
|
|
10
|
+
import { drawingHasUnmodeledContent, parseDrawing } from './images.js';
|
|
11
|
+
import { parsePivotTable } from './read-pivot.js';
|
|
12
|
+
import { admitting } from './read-repair.js';
|
|
13
|
+
import { parseTable } from './tables.js';
|
|
14
|
+
import { parseThemeColorScheme, parseThemeFontScheme } from './theme-xml.js';
|
|
15
|
+
import { buildCommentThreads, parsePersons, parseThreadedComments } from './threaded-comments.js';
|
|
16
|
+
export function readSheetComments(sheetRels) {
|
|
17
|
+
const commentsXml = sheetRels.relatedText('comments');
|
|
18
|
+
return commentsXml === undefined ? undefined : parseComments(commentsXml);
|
|
19
|
+
}
|
|
20
|
+
export function readWorkbookPersons({ workbook }, workbookRels) {
|
|
21
|
+
const xml = workbookRels.relatedText('person');
|
|
22
|
+
if (xml !== undefined)
|
|
23
|
+
workbook[INTERNAL].restorePersons(parsePersons(xml));
|
|
24
|
+
}
|
|
25
|
+
export function readWorkbookTheme(context, workbookRels) {
|
|
26
|
+
const { pkg, contentTypeOf, workbook } = context;
|
|
27
|
+
const entryPath = workbookRels.targetPath('theme');
|
|
28
|
+
if (entryPath === undefined)
|
|
29
|
+
return;
|
|
30
|
+
const parts = capturePartClosure(entryPath, pkg.partText, pkg.partBytes, contentTypeOf);
|
|
31
|
+
if (parts === undefined)
|
|
32
|
+
return;
|
|
33
|
+
const xml = pkg.partText(entryPath) ?? '';
|
|
34
|
+
workbook[INTERNAL].restoreThemePart({ entryPath, parts }, { colors: parseThemeColorScheme(xml), fonts: parseThemeFontScheme(xml) });
|
|
35
|
+
}
|
|
36
|
+
export function readSheetCommentThreads({ workbook }, sheetRels) {
|
|
37
|
+
const xml = sheetRels.relatedText('threadedComment');
|
|
38
|
+
if (xml === undefined)
|
|
39
|
+
return [];
|
|
40
|
+
return buildCommentThreads(parseThreadedComments(xml), (id) => workbook.getPerson(id));
|
|
41
|
+
}
|
|
42
|
+
export function readSheetPrinterSettings(sheetRels) {
|
|
43
|
+
return sheetRels.relatedBytes('printerSettings');
|
|
44
|
+
}
|
|
45
|
+
function internImage(context, mediaPath) {
|
|
46
|
+
const { workbook, pkg, imageIdByMediaPath } = context;
|
|
47
|
+
const known = imageIdByMediaPath.get(mediaPath);
|
|
48
|
+
if (known !== undefined)
|
|
49
|
+
return known;
|
|
50
|
+
const bytes = pkg.partBytes(mediaPath);
|
|
51
|
+
if (bytes === undefined)
|
|
52
|
+
return undefined;
|
|
53
|
+
const id = workbook.addImage({ buffer: bytes, extension: extensionOf(mediaPath) });
|
|
54
|
+
imageIdByMediaPath.set(mediaPath, id);
|
|
55
|
+
return id;
|
|
56
|
+
}
|
|
57
|
+
export function readSheetImages(context, sheetRels, sheet) {
|
|
58
|
+
const { partText } = context.pkg;
|
|
59
|
+
const drawingPath = sheetRels.targetPath('drawing');
|
|
60
|
+
if (drawingPath === undefined)
|
|
61
|
+
return;
|
|
62
|
+
const drawingXml = partText(drawingPath);
|
|
63
|
+
if (drawingXml === undefined)
|
|
64
|
+
return;
|
|
65
|
+
if (drawingHasUnmodeledContent(drawingXml))
|
|
66
|
+
return;
|
|
67
|
+
const drawingRels = readPartRelationships(drawingPath, partText);
|
|
68
|
+
for (const anchor of parseDrawing(drawingXml)) {
|
|
69
|
+
const embedded = drawingRels.byId(anchor.embed);
|
|
70
|
+
if (embedded === undefined)
|
|
71
|
+
continue;
|
|
72
|
+
const mediaPath = drawingRels.pathOf(embedded.target);
|
|
73
|
+
const id = internImage(context, mediaPath);
|
|
74
|
+
if (id === undefined)
|
|
75
|
+
continue;
|
|
76
|
+
const rot = anchor.rotation !== undefined ? { rotation: anchor.rotation } : {};
|
|
77
|
+
if (anchor.to !== undefined) {
|
|
78
|
+
const mode = anchor.editAs !== undefined ? { editAs: anchor.editAs } : {};
|
|
79
|
+
sheet.addImageAnchor(id, { from: anchor.from, to: anchor.to, ...mode, ...rot });
|
|
80
|
+
}
|
|
81
|
+
else if (anchor.ext !== undefined) {
|
|
82
|
+
sheet.addImageAnchor(id, { from: anchor.from, ext: anchor.ext, ...rot });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export function readSheetBackground(context, sheetRels, sheet) {
|
|
87
|
+
const mediaPath = sheetRels.targetPath('image');
|
|
88
|
+
if (mediaPath === undefined)
|
|
89
|
+
return;
|
|
90
|
+
const id = internImage(context, mediaPath);
|
|
91
|
+
if (id !== undefined)
|
|
92
|
+
sheet.addBackgroundImage(id);
|
|
93
|
+
}
|
|
94
|
+
export function readSheetPreservedReferences(context, sheetRels, referenceRelIds, sheet) {
|
|
95
|
+
const { contentTypeOf } = context;
|
|
96
|
+
const { partText, partBytes } = context.pkg;
|
|
97
|
+
const capture = (element, relType, target) => {
|
|
98
|
+
const entryPath = sheetRels.pathOf(target);
|
|
99
|
+
const parts = capturePartClosure(entryPath, partText, partBytes, contentTypeOf);
|
|
100
|
+
if (parts !== undefined)
|
|
101
|
+
sheet[INTERNAL].addPreservedReference({ element, relType, entryPath, parts });
|
|
102
|
+
};
|
|
103
|
+
const referenceElements = sheet.images.length === 0 ? ['drawing', 'legacyDrawingHF'] : ['legacyDrawingHF'];
|
|
104
|
+
for (const element of referenceElements) {
|
|
105
|
+
const relId = referenceRelIds[element];
|
|
106
|
+
const record = relId === undefined ? undefined : sheetRels.byId(relId);
|
|
107
|
+
if (record !== undefined && !record.external)
|
|
108
|
+
capture(element, record.type, record.target);
|
|
109
|
+
}
|
|
110
|
+
for (const record of sheetRels.records) {
|
|
111
|
+
if (record.external)
|
|
112
|
+
continue;
|
|
113
|
+
if (isPreservedSheetRelType(record.type))
|
|
114
|
+
capture(undefined, record.type, record.target);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function isPreservedSheetRelType(type) {
|
|
118
|
+
return isAnyRelType(type, 'pivotTable', 'slicer');
|
|
119
|
+
}
|
|
120
|
+
export function readWorkbookPreservedReferences(context, workbookRels, registrations) {
|
|
121
|
+
const { contentTypeOf, workbook } = context;
|
|
122
|
+
const { partText, partBytes } = context.pkg;
|
|
123
|
+
const { cacheIdByRelId, externalIndexByRelId } = registrations;
|
|
124
|
+
for (const record of workbookRels.records) {
|
|
125
|
+
if (record.external || !isPreservedWorkbookRelType(record.type))
|
|
126
|
+
continue;
|
|
127
|
+
const entryPath = workbookRels.pathOf(record.target);
|
|
128
|
+
const parts = capturePartClosure(entryPath, partText, partBytes, contentTypeOf);
|
|
129
|
+
if (parts === undefined)
|
|
130
|
+
continue;
|
|
131
|
+
const cacheId = cacheIdByRelId.get(record.id);
|
|
132
|
+
const externalReferenceIndex = externalIndexByRelId.get(record.id);
|
|
133
|
+
workbook[INTERNAL].addPreservedReference({
|
|
134
|
+
relType: record.type,
|
|
135
|
+
entryPath,
|
|
136
|
+
parts,
|
|
137
|
+
...(cacheId !== undefined ? { pivotCacheId: cacheId } : {}),
|
|
138
|
+
...(externalReferenceIndex !== undefined ? { externalReferenceIndex } : {}),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export function readRootPreservedReferences(context) {
|
|
143
|
+
const { contentTypeOf, workbook } = context;
|
|
144
|
+
const { partText, partBytes } = context.pkg;
|
|
145
|
+
const relsXml = partText('_rels/.rels');
|
|
146
|
+
if (relsXml === undefined)
|
|
147
|
+
return;
|
|
148
|
+
for (const record of parseRelationshipRecords(relsXml)) {
|
|
149
|
+
if (record.external || isRegeneratedRootRelType(record.type))
|
|
150
|
+
continue;
|
|
151
|
+
const entryPath = resolveRelativePart('', record.target);
|
|
152
|
+
const parts = capturePartClosure(entryPath, partText, partBytes, contentTypeOf);
|
|
153
|
+
if (parts === undefined)
|
|
154
|
+
continue;
|
|
155
|
+
workbook[INTERNAL].addPreservedRootReference({ relType: record.type, entryPath, parts });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function isRegeneratedRootRelType(type) {
|
|
159
|
+
return isAnyRelType(type, 'officeDocument', 'core-properties', 'extended-properties');
|
|
160
|
+
}
|
|
161
|
+
function isPreservedWorkbookRelType(type) {
|
|
162
|
+
return isAnyRelType(type, 'pivotCacheDefinition', 'slicerCache', 'vbaProject', 'externalLink');
|
|
163
|
+
}
|
|
164
|
+
export function pivotCacheRegistrationsPass() {
|
|
165
|
+
const byRelId = new Map();
|
|
166
|
+
return {
|
|
167
|
+
handlers: {
|
|
168
|
+
onOpen(name, attrs, _selfClosing, scope) {
|
|
169
|
+
if (localName(name) !== 'pivotCache')
|
|
170
|
+
return;
|
|
171
|
+
const relId = relAttr(scope, attrs, 'id');
|
|
172
|
+
if (relId !== undefined && attrs.cacheId !== undefined)
|
|
173
|
+
byRelId.set(relId, attrs.cacheId);
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
result: () => byRelId,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
export function externalReferenceRegistrationsPass() {
|
|
180
|
+
const byRelId = new Map();
|
|
181
|
+
let index = 0;
|
|
182
|
+
return {
|
|
183
|
+
handlers: {
|
|
184
|
+
onOpen(name, attrs, _selfClosing, scope) {
|
|
185
|
+
if (localName(name) !== 'externalReference')
|
|
186
|
+
return;
|
|
187
|
+
const relId = relAttr(scope, attrs, 'id');
|
|
188
|
+
if (relId !== undefined)
|
|
189
|
+
byRelId.set(relId, index++);
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
result: () => byRelId,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
export function worksheetReferencePass() {
|
|
196
|
+
const relIds = {};
|
|
197
|
+
return {
|
|
198
|
+
handlers: {
|
|
199
|
+
onOpen(name, attrs, _selfClosing, scope) {
|
|
200
|
+
const local = localName(name);
|
|
201
|
+
if (local !== 'drawing' && local !== 'legacyDrawingHF')
|
|
202
|
+
return;
|
|
203
|
+
if (relIds[local] !== undefined)
|
|
204
|
+
return;
|
|
205
|
+
const relId = relAttr(scope, attrs, 'id');
|
|
206
|
+
if (relId !== undefined)
|
|
207
|
+
relIds[local] = relId;
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
result: () => relIds,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
export function readSheetTables({ pkg }, sheetRels, sheet) {
|
|
214
|
+
for (const tablePath of sheetRels.targetPaths('table')) {
|
|
215
|
+
const tableXml = pkg.partText(tablePath);
|
|
216
|
+
if (tableXml === undefined)
|
|
217
|
+
continue;
|
|
218
|
+
const options = parseTable(tableXml);
|
|
219
|
+
if (options !== undefined) {
|
|
220
|
+
admitting(() => {
|
|
221
|
+
sheet.addTable(options);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
dropMergesInsideTables(sheet);
|
|
226
|
+
}
|
|
227
|
+
export function readSheetPivotTables({ pkg }, sheetRels, sheet) {
|
|
228
|
+
const { partText } = pkg;
|
|
229
|
+
for (const tablePath of sheetRels.targetPaths('pivotTable')) {
|
|
230
|
+
const tableXml = partText(tablePath);
|
|
231
|
+
if (tableXml === undefined)
|
|
232
|
+
continue;
|
|
233
|
+
const cacheXml = readPartRelationships(tablePath, partText).relatedText('pivotCacheDefinition') ?? '';
|
|
234
|
+
sheet[INTERNAL].addLoadedPivotTable(parsePivotTable(tableXml, cacheXml));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function dropMergesInsideTables(sheet) {
|
|
238
|
+
const regions = sheet.tables.map((table) => table.region);
|
|
239
|
+
if (regions.length === 0)
|
|
240
|
+
return;
|
|
241
|
+
for (const range of [...sheet.merges]) {
|
|
242
|
+
const { top, left, bottom, right } = decodeRange(range);
|
|
243
|
+
if (top === undefined || left === undefined || bottom === undefined || right === undefined)
|
|
244
|
+
continue;
|
|
245
|
+
const overlaps = regions.some((region) => left <= region.right &&
|
|
246
|
+
right >= region.left &&
|
|
247
|
+
top <= region.bottom &&
|
|
248
|
+
bottom >= region.top);
|
|
249
|
+
if (overlaps)
|
|
250
|
+
sheet.unmergeCells(range);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { isDeclarablePivotSourceKind, pivotMetricFromSubtotal, } from '../../core/pivot-table.js';
|
|
2
|
-
import {
|
|
2
|
+
import { numInteger } from '../../xml/xml-attrs.js';
|
|
3
|
+
import { parseXml } from '../../xml/xml-read.js';
|
|
4
|
+
import { localName } from '../../xml/xml-scan.js';
|
|
3
5
|
export function parsePivotTable(tableXml, cacheXml) {
|
|
4
6
|
const { fields, source } = parsePivotCacheDefinition(cacheXml);
|
|
5
7
|
const def = parsePivotTableDefinition(tableXml);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A sheet name from a file, rewritten into one the model will accept.
|
|
3
|
+
*
|
|
4
|
+
* Excel's own repair, in the order the constraints interact: forbidden characters go first (they
|
|
5
|
+
* can be anywhere), then the length ceiling, then the apostrophe rule *again*, because truncating
|
|
6
|
+
* can expose an interior apostrophe at the new edge. An empty result becomes `Sheet{n}`, and a
|
|
7
|
+
* collision takes a ` (2)` suffix that is itself made to fit inside the 31-character limit.
|
|
8
|
+
*
|
|
9
|
+
* @param taken the lower-cased names already in the workbook; sheet names collide
|
|
10
|
+
* case-insensitively, which is the comparison `Workbook.getWorksheet` makes.
|
|
11
|
+
*/
|
|
12
|
+
export declare function repairSheetName(name: string, taken: ReadonlySet<string>): string;
|
|
13
|
+
/**
|
|
14
|
+
* Run a model call that is being handed foreign input, and answer `undefined` where the model
|
|
15
|
+
* refuses it.
|
|
16
|
+
*
|
|
17
|
+
* The three caught types are the three a model method raises *about its argument*: an
|
|
18
|
+
* `AuthoringError` for a composite that cannot exist, and the native `RangeError` / `SyntaxError`
|
|
19
|
+
* the taxonomy assigns to a single scalar that is out of range or does not parse. Every one of them
|
|
20
|
+
* is a statement about the caller, and on this path the caller is a file.
|
|
21
|
+
*
|
|
22
|
+
* Nothing else is caught. An `XlsxError` raised by a layer below is a real failure of the read and
|
|
23
|
+
* keeps its identity; an `InternalError` is a bug of ours and must not be swallowed by a reader
|
|
24
|
+
* being tolerant about somebody else's file.
|
|
25
|
+
*/
|
|
26
|
+
export declare function admitting<T>(build: () => T): T | undefined;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { INVALID_SHEET_NAME_CHARS, MAX_SHEET_NAME_LENGTH } from '../../core/limits.js';
|
|
2
|
+
import { AuthoringError } from '../../errors.js';
|
|
3
|
+
const INVALID_SHEET_NAME_CHARS_GLOBAL = new RegExp(INVALID_SHEET_NAME_CHARS.source, 'g');
|
|
4
|
+
export function repairSheetName(name, taken) {
|
|
5
|
+
const stripped = trimApostrophes(name.replace(INVALID_SHEET_NAME_CHARS_GLOBAL, '')).slice(0, MAX_SHEET_NAME_LENGTH);
|
|
6
|
+
const base = trimApostrophes(stripped);
|
|
7
|
+
if (base.length === 0)
|
|
8
|
+
return firstFree((n) => `Sheet${n}`, taken);
|
|
9
|
+
if (!taken.has(base.toLowerCase()))
|
|
10
|
+
return base;
|
|
11
|
+
return firstFree((n) => withSuffix(base, ` (${n})`), taken, 2);
|
|
12
|
+
}
|
|
13
|
+
function trimApostrophes(name) {
|
|
14
|
+
return name.replace(/^'+/, '').replace(/'+$/, '');
|
|
15
|
+
}
|
|
16
|
+
function firstFree(candidate, taken, from = 1) {
|
|
17
|
+
for (let n = from;; n++) {
|
|
18
|
+
const name = candidate(n);
|
|
19
|
+
if (!taken.has(name.toLowerCase()))
|
|
20
|
+
return name;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function withSuffix(base, suffix) {
|
|
24
|
+
const room = MAX_SHEET_NAME_LENGTH - suffix.length;
|
|
25
|
+
return trimApostrophes(base.slice(0, room)) + suffix;
|
|
26
|
+
}
|
|
27
|
+
export function admitting(build) {
|
|
28
|
+
try {
|
|
29
|
+
return build();
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
if (error instanceof AuthoringError ||
|
|
33
|
+
error instanceof RangeError ||
|
|
34
|
+
error instanceof SyntaxError) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RichTextRun } from '../../core/value.ts';
|
|
2
|
-
import { type XmlAttributes } from '../../xml/xml-
|
|
2
|
+
import { type XmlAttributes } from '../../xml/xml-scan.ts';
|
|
3
3
|
/**
|
|
4
4
|
* What {@link RunAccumulator.close} did with an element: `'container'` means the `<si>`/`<is>` itself
|
|
5
5
|
* closed and the caller should commit whatever it makes of the gathered runs, the one step the two
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { decodeSpreadsheetText
|
|
2
|
-
import {
|
|
1
|
+
import { decodeSpreadsheetText } from '../../xml/xml-attrs.js';
|
|
2
|
+
import { TextCapture } from '../../xml/xml-read.js';
|
|
3
|
+
import {} from '../../xml/xml-scan.js';
|
|
4
|
+
import { applyFontChild } from './font-xml.js';
|
|
3
5
|
export class RunAccumulator {
|
|
4
6
|
#container;
|
|
5
7
|
#readRuns;
|
|
@@ -33,12 +35,14 @@ export class RunAccumulator {
|
|
|
33
35
|
this.#plain = '';
|
|
34
36
|
this.#inRun = false;
|
|
35
37
|
this.#isRich = false;
|
|
38
|
+
this.#inContainer = false;
|
|
39
|
+
this.#capture.reset();
|
|
36
40
|
}
|
|
37
41
|
open(local, attrs, selfClosing) {
|
|
38
42
|
switch (local) {
|
|
39
43
|
case this.#container:
|
|
40
|
-
this.#inContainer = true;
|
|
41
44
|
this.beginContainer();
|
|
45
|
+
this.#inContainer = !selfClosing;
|
|
42
46
|
return true;
|
|
43
47
|
case 'r':
|
|
44
48
|
if (!this.#readRuns || !this.#inContainer)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CellValue } from '../../core/value.ts';
|
|
2
|
-
import { type
|
|
3
|
-
export interface ReadSheetRowsOptions extends
|
|
2
|
+
import { type ReadPackageOptions, type XfStyle } from './read.ts';
|
|
3
|
+
export interface ReadSheetRowsOptions extends ReadPackageOptions {
|
|
4
4
|
/**
|
|
5
5
|
* Which worksheet to stream: its name, or its 1-based position in the workbook. Defaults to the
|
|
6
6
|
* first sheet.
|
|
@@ -11,9 +11,18 @@ export interface ReadSheetRowsOptions extends ReadXlsxOptions {
|
|
|
11
11
|
* The resolved style facets of a streamed cell: its own `<c s>` cell format, flattened exactly as
|
|
12
12
|
* the buffered reader resolves it. Present only when the cell carries a format; a consumer can copy
|
|
13
13
|
* these straight onto a writer cell to preserve its look through a streaming read→write.
|
|
14
|
+
*
|
|
15
|
+
* @unpublished A named commitment this surface is not ready to make. `entries/xlsx.ts` records the
|
|
16
|
+
* decision: the streaming reader's granular output shapes stay inferred structural types while the
|
|
17
|
+
* surface settles, so a consumer destructures them and never has to spell them.
|
|
14
18
|
*/
|
|
15
19
|
export type StreamedCellStyle = XfStyle;
|
|
16
|
-
/** One non-empty cell in a {@link StreamedRow}.
|
|
20
|
+
/** One non-empty cell in a {@link StreamedRow}.
|
|
21
|
+
*
|
|
22
|
+
* @unpublished A named commitment this surface is not ready to make. `entries/xlsx.ts` records the
|
|
23
|
+
* decision: the streaming reader's granular output shapes stay inferred structural types while the
|
|
24
|
+
* surface settles, so a consumer destructures them and never has to spell them.
|
|
25
|
+
*/
|
|
17
26
|
export interface StreamedCell {
|
|
18
27
|
/** 1-based column index. */
|
|
19
28
|
readonly col: number;
|
|
@@ -41,6 +50,10 @@ export interface StreamedRow {
|
|
|
41
50
|
* its rows have not already been consumed, so their order relative to `rows()` never matters. (When
|
|
42
51
|
* rows *are* consumed first, the streaming idiom, the accessors reuse that pass and re-scan
|
|
43
52
|
* nothing.)
|
|
53
|
+
*
|
|
54
|
+
* @unpublished A named commitment this surface is not ready to make. `entries/xlsx.ts` records the
|
|
55
|
+
* decision: the streaming reader's granular output shapes stay inferred structural types while the
|
|
56
|
+
* surface settles, so a consumer destructures them and never has to spell them.
|
|
44
57
|
*/
|
|
45
58
|
export interface StreamedSheet {
|
|
46
59
|
/** The worksheet's declared name, joined from the workbook part. Never a positional placeholder. */
|
|
@@ -76,10 +89,10 @@ export declare function readSheetRows(data: Uint8Array, options?: ReadSheetRowsO
|
|
|
76
89
|
* of walking `readXlsx(data).worksheets`.
|
|
77
90
|
*
|
|
78
91
|
* @param data The raw `.xlsx` bytes.
|
|
79
|
-
* @param options The inflate bound (see {@link
|
|
92
|
+
* @param options The inflate bound (see {@link ReadPackageOptions}).
|
|
80
93
|
* @throws {UnsupportedFormatError} if the input is not a readable `.xlsx` package (a legacy `.xls`, a
|
|
81
94
|
* binary `.xlsb`, or an unrecognised/non-ZIP blob; branch on `.format`).
|
|
82
95
|
* @throws {PackageReadError} if the input is a ZIP that cannot be unpacked: a corrupt or
|
|
83
96
|
* truncated archive, or one exceeding the inflate bound (a probable zip bomb).
|
|
84
97
|
*/
|
|
85
|
-
export declare function readWorkbookStream(data: Uint8Array, options?:
|
|
98
|
+
export declare function readWorkbookStream(data: Uint8Array, options?: ReadPackageOptions): Generator<StreamedSheet, void, undefined>;
|
|
@@ -1,46 +1,53 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AuthoringError } from '../../errors.js';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
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
|
+
import { openSpreadsheetPackage, readPartRelationships } from '../opc/read-opc.js';
|
|
6
|
+
import { unsupportedWorkbookPart } from '../opc/sniff-format.js';
|
|
6
7
|
import { CellAccumulator } from './cell-accumulator.js';
|
|
8
|
+
import { CellStyleResolver } from './cell-style-resolution.js';
|
|
9
|
+
import { ColumnRecordBudget, takeColumnSpan } from './column-budget.js';
|
|
7
10
|
import { XlsxParseError } from './errors.js';
|
|
11
|
+
import { SHARED_STRINGS_PART, STYLES_PART } from './part-names.js';
|
|
8
12
|
import { parseSharedStrings } from './read-shared-strings.js';
|
|
9
|
-
import {
|
|
13
|
+
import { workbookPropertiesPass, parseStyleTable, workbookSheetsPass, } from './read.js';
|
|
14
|
+
import { RowPositionTracker } from './row-position.js';
|
|
10
15
|
export function* readSheetRows(data, options = {}) {
|
|
11
16
|
const pkg = openPackage(data, options.maxUncompressedBytes);
|
|
12
17
|
const chosen = pickSheet(pkg.sheets, options.sheet);
|
|
13
18
|
const sheetXml = pkg.sheetXml(chosen.relId);
|
|
14
19
|
if (sheetXml === undefined)
|
|
15
20
|
return;
|
|
16
|
-
yield* scanSheet(sheetXml, pkg.sharedStrings, pkg.xfStyles, new Set(), []);
|
|
21
|
+
yield* scanSheet(sheetXml, pkg.sharedStrings, pkg.xfStyles, pkg.dateEpoch, new Set(), []);
|
|
17
22
|
}
|
|
18
23
|
export function* readWorkbookStream(data, options = {}) {
|
|
19
24
|
const pkg = openPackage(data, options.maxUncompressedBytes);
|
|
20
25
|
for (const sheet of pkg.sheets) {
|
|
21
26
|
const xml = pkg.sheetXml(sheet.relId) ?? '';
|
|
22
|
-
yield new StreamedSheetReader(sheet.name, xml, pkg.sharedStrings, pkg.xfStyles);
|
|
27
|
+
yield new StreamedSheetReader(sheet.name, xml, pkg.sharedStrings, pkg.xfStyles, pkg.dateEpoch);
|
|
23
28
|
}
|
|
24
29
|
}
|
|
25
30
|
function openPackage(data, maxUncompressedBytes) {
|
|
26
|
-
const
|
|
27
|
-
const { partText: text } =
|
|
28
|
-
const workbookXml = text('xl/workbook.xml');
|
|
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
|
-
const target = rels.
|
|
42
|
-
|
|
43
|
-
return path === undefined ? undefined : text(path);
|
|
49
|
+
const target = rels.byId(relId)?.target;
|
|
50
|
+
return target === undefined ? undefined : text(rels.pathOf(target));
|
|
44
51
|
},
|
|
45
52
|
};
|
|
46
53
|
}
|
|
@@ -58,7 +65,7 @@ function pickSheet(sheets, selector) {
|
|
|
58
65
|
}
|
|
59
66
|
const sheet = sheets.find((candidate) => candidate.name === selector);
|
|
60
67
|
if (sheet === undefined)
|
|
61
|
-
throw new AuthoringError(`no worksheet named ${
|
|
68
|
+
throw new AuthoringError(`no worksheet named ${quoted(selector)}`);
|
|
62
69
|
return sheet;
|
|
63
70
|
}
|
|
64
71
|
class StreamedSheetReader {
|
|
@@ -66,20 +73,22 @@ class StreamedSheetReader {
|
|
|
66
73
|
#xml;
|
|
67
74
|
#sharedStrings;
|
|
68
75
|
#xfStyles;
|
|
76
|
+
#dateEpoch;
|
|
69
77
|
#hiddenColumns = new Set();
|
|
70
78
|
#merges = [];
|
|
71
79
|
#scanned = false;
|
|
72
|
-
constructor(name, xml, sharedStrings, xfStyles) {
|
|
80
|
+
constructor(name, xml, sharedStrings, xfStyles, dateEpoch) {
|
|
73
81
|
this.name = name;
|
|
74
82
|
this.#xml = xml;
|
|
75
83
|
this.#sharedStrings = sharedStrings;
|
|
76
84
|
this.#xfStyles = xfStyles;
|
|
85
|
+
this.#dateEpoch = dateEpoch;
|
|
77
86
|
}
|
|
78
87
|
*rows() {
|
|
79
88
|
this.#hiddenColumns = new Set();
|
|
80
89
|
this.#merges = [];
|
|
81
90
|
this.#scanned = false;
|
|
82
|
-
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);
|
|
83
92
|
this.#scanned = true;
|
|
84
93
|
}
|
|
85
94
|
get hiddenColumns() {
|
|
@@ -88,7 +97,7 @@ class StreamedSheetReader {
|
|
|
88
97
|
}
|
|
89
98
|
get merges() {
|
|
90
99
|
this.#ensureScanned();
|
|
91
|
-
return this.#merges;
|
|
100
|
+
return [...this.#merges];
|
|
92
101
|
}
|
|
93
102
|
#ensureScanned() {
|
|
94
103
|
if (this.#scanned)
|
|
@@ -98,17 +107,20 @@ class StreamedSheetReader {
|
|
|
98
107
|
}
|
|
99
108
|
}
|
|
100
109
|
const CELL_EMPTY_CLOSE = new Set(['c']);
|
|
101
|
-
function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
|
|
110
|
+
function* scanSheet(xml, sharedStrings, xfStyles, dateEpoch, hiddenColumns, merges) {
|
|
102
111
|
let rowNumber = 0;
|
|
103
|
-
let lastRow = 0;
|
|
104
112
|
let rowHidden = false;
|
|
105
113
|
let rowInGrid = true;
|
|
106
114
|
let cells = [];
|
|
107
|
-
const
|
|
115
|
+
const columnBudget = new ColumnRecordBudget();
|
|
116
|
+
const styleResolution = new CellStyleResolver();
|
|
117
|
+
const rowPosition = new RowPositionTracker();
|
|
118
|
+
const cell = new CellAccumulator({ richRuns: false, dateEpoch });
|
|
108
119
|
const finalizeCell = () => {
|
|
109
120
|
if (cell.ref === '' || cell.col < 0 || !rowInGrid)
|
|
110
121
|
return;
|
|
111
|
-
const
|
|
122
|
+
const styleIndex = styleResolution.indexFor(cell.col, cell.styleIndex);
|
|
123
|
+
const style = styleIndex >= 0 ? xfStyles[styleIndex] : undefined;
|
|
112
124
|
const value = cell.decode(sharedStrings, style);
|
|
113
125
|
if (value !== null) {
|
|
114
126
|
const { col, ref } = cell;
|
|
@@ -126,15 +138,15 @@ function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
|
|
|
126
138
|
continue;
|
|
127
139
|
switch (local) {
|
|
128
140
|
case 'row': {
|
|
129
|
-
rowNumber =
|
|
130
|
-
lastRow = rowNumber;
|
|
131
|
-
rowInGrid = rowNumber <= MAX_ROW;
|
|
141
|
+
({ number: rowNumber, inGrid: rowInGrid } = rowPosition.open(event.attrs));
|
|
132
142
|
rowHidden = boolStrict(event.attrs.hidden);
|
|
143
|
+
cell.openRow(rowInGrid ? rowNumber : -1);
|
|
144
|
+
styleResolution.openRow(event.attrs);
|
|
133
145
|
cells = [];
|
|
134
146
|
break;
|
|
135
147
|
}
|
|
136
148
|
case 'col':
|
|
137
|
-
|
|
149
|
+
collectColumn(event.attrs, hiddenColumns, styleResolution, columnBudget);
|
|
138
150
|
break;
|
|
139
151
|
case 'mergeCell':
|
|
140
152
|
if (event.attrs.ref !== undefined)
|
|
@@ -150,19 +162,20 @@ function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
|
|
|
150
162
|
if (claimed === 'cell')
|
|
151
163
|
finalizeCell();
|
|
152
164
|
else if (claimed === 'other' && local === 'row') {
|
|
165
|
+
styleResolution.closeRow();
|
|
153
166
|
if (rowInGrid)
|
|
154
167
|
yield { number: rowNumber, hidden: rowHidden, cells };
|
|
155
168
|
}
|
|
156
169
|
}
|
|
157
170
|
}
|
|
158
|
-
function
|
|
159
|
-
|
|
171
|
+
function collectColumn(attrs, hiddenColumns, styleResolution, budget) {
|
|
172
|
+
const span = takeColumnSpan(attrs, budget);
|
|
173
|
+
if (span === undefined)
|
|
160
174
|
return;
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
if (
|
|
175
|
+
const { first: min, last } = span;
|
|
176
|
+
styleResolution.noteColumnSpan(min, last, attrs);
|
|
177
|
+
if (!boolStrict(attrs.hidden))
|
|
164
178
|
return;
|
|
165
|
-
const last = Math.min(max, MAX_COLUMN);
|
|
166
179
|
for (let index = min; index <= last; index++)
|
|
167
180
|
hiddenColumns.add(index);
|
|
168
181
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { parseXml } from '../../xml/xml-read.js';
|
|
2
|
+
import { localName } from '../../xml/xml-scan.js';
|
|
3
|
+
import { RunAccumulator } from './read-rich-runs.js';
|
|
4
|
+
const SHARED_STRING_EMPTY_CLOSES = new Set(['si']);
|
|
3
5
|
export function parseSharedStrings(xml) {
|
|
4
6
|
if (xml === '')
|
|
5
7
|
return [];
|
|
@@ -17,6 +19,6 @@ export function parseSharedStrings(xml) {
|
|
|
17
19
|
return;
|
|
18
20
|
strings.push(runs.isRich ? { richText: runs.runs } : runs.plainText);
|
|
19
21
|
},
|
|
20
|
-
});
|
|
22
|
+
}, { closeEmptyElements: SHARED_STRING_EMPTY_CLOSES });
|
|
21
23
|
return strings;
|
|
22
24
|
}
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { type XmlAttributes } from '../../xml/xml-read.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
|