@shbernal/ts-xlsx 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -10
- package/dist/bytes.d.ts +24 -0
- package/dist/bytes.js +34 -0
- package/dist/core/address.d.ts +26 -4
- package/dist/core/address.js +21 -9
- package/dist/core/autofilter.d.ts +12 -1
- package/dist/core/autofilter.js +35 -12
- package/dist/core/axis-handle.d.ts +8 -0
- package/dist/core/axis-handle.js +14 -0
- package/dist/core/cell.d.ts +24 -0
- package/dist/core/cell.js +9 -1
- package/dist/core/color-resolution.d.ts +1 -1
- package/dist/core/color-resolution.js +7 -8
- package/dist/core/column.d.ts +4 -1
- package/dist/core/column.js +31 -35
- package/dist/core/conditional-formatting-overlay.d.ts +5 -0
- package/dist/core/conditional-formatting-overlay.js +11 -0
- package/dist/core/conditional-formatting.d.ts +45 -5
- package/dist/core/conditional-formatting.js +74 -0
- package/dist/core/data-validation-overlay.d.ts +11 -0
- package/dist/core/data-validation-overlay.js +21 -2
- package/dist/core/data-validation.d.ts +9 -2
- package/dist/core/data-validation.js +26 -0
- package/dist/core/grid-edits.d.ts +16 -0
- package/dist/core/grid-edits.js +26 -8
- package/dist/core/grid-shift.d.ts +19 -0
- package/dist/core/grid-shift.js +8 -0
- package/dist/core/image.d.ts +2 -0
- package/dist/core/image.js +2 -0
- package/dist/core/merge-index.d.ts +31 -0
- package/dist/core/merge-index.js +60 -0
- package/dist/core/merge.d.ts +12 -11
- package/dist/core/merge.js +36 -10
- package/dist/core/page-setup.d.ts +86 -2
- package/dist/core/page-setup.js +34 -1
- package/dist/core/pivot-table.d.ts +2 -0
- package/dist/core/pivot-table.js +23 -18
- package/dist/core/protection.d.ts +3 -0
- package/dist/core/protection.js +20 -14
- package/dist/core/row-input.d.ts +7 -0
- package/dist/core/row-input.js +10 -8
- package/dist/core/row.d.ts +4 -1
- package/dist/core/row.js +19 -23
- package/dist/core/style.d.ts +78 -7
- package/dist/core/style.js +90 -80
- package/dist/core/table.d.ts +26 -12
- package/dist/core/table.js +67 -33
- package/dist/core/theme.d.ts +3 -1
- package/dist/core/theme.js +4 -0
- package/dist/core/used-extent.d.ts +44 -0
- package/dist/core/used-extent.js +102 -0
- package/dist/core/workbook.d.ts +2 -2
- package/dist/core/worksheet-comments.d.ts +8 -0
- package/dist/core/worksheet-comments.js +18 -0
- package/dist/core/worksheet.d.ts +31 -7
- package/dist/core/worksheet.js +72 -86
- package/dist/customui/ribbon.js +23 -24
- package/dist/entries/core.d.ts +3 -3
- package/dist/entries/csv.d.ts +1 -1
- package/dist/entries/node-unavailable.d.ts +15 -0
- package/dist/entries/node-unavailable.js +20 -0
- package/dist/entries/node.d.ts +1 -0
- package/dist/entries/node.js +1 -0
- package/dist/entries/xlsx.d.ts +0 -1
- package/dist/entries/xlsx.js +0 -1
- package/dist/io/csv/read.js +1 -1
- package/dist/io/csv/write.d.ts +12 -2
- package/dist/io/csv/write.js +17 -2
- package/dist/io/opc/inflate.js +3 -13
- package/dist/io/opc/part-paths.d.ts +1 -0
- package/dist/io/opc/part-paths.js +15 -0
- package/dist/io/opc/read-opc.d.ts +22 -3
- package/dist/io/opc/read-opc.js +11 -39
- package/dist/io/opc/rels.d.ts +12 -6
- package/dist/io/opc/rels.js +3 -5
- package/dist/io/style/xf-style.d.ts +33 -4
- package/dist/io/style/xf-style.js +12 -1
- package/dist/io/xlsb/read-styles.js +6 -3
- package/dist/io/xlsb/read.d.ts +1 -1
- package/dist/io/xlsb/read.js +5 -8
- package/dist/io/xlsx/cell-accumulator.d.ts +2 -4
- package/dist/io/xlsx/cell-accumulator.js +20 -58
- package/dist/io/xlsx/cell-value.d.ts +1 -1
- package/dist/io/xlsx/cell-value.js +7 -4
- package/dist/io/xlsx/color-xml.d.ts +1 -1
- package/dist/io/xlsx/color-xml.js +8 -7
- package/dist/io/xlsx/comments.js +6 -3
- package/dist/io/xlsx/conditional-formatting.d.ts +4 -3
- package/dist/io/xlsx/conditional-formatting.js +81 -65
- package/dist/io/xlsx/data-validation.d.ts +10 -8
- package/dist/io/xlsx/data-validation.js +44 -41
- package/dist/io/xlsx/edit-vba.js +4 -11
- package/dist/io/xlsx/hyperlinks.d.ts +4 -2
- package/dist/io/xlsx/hyperlinks.js +26 -31
- package/dist/io/xlsx/images.js +33 -35
- package/dist/io/xlsx/package-plan.d.ts +9 -1
- package/dist/io/xlsx/package-plan.js +29 -16
- package/dist/io/xlsx/part-names.d.ts +41 -0
- package/dist/io/xlsx/part-names.js +46 -0
- package/dist/io/xlsx/read-pivot.js +4 -9
- package/dist/io/xlsx/read-rows.js +12 -13
- package/dist/io/xlsx/read-shared-strings.js +9 -47
- package/dist/io/xlsx/read-styles.d.ts +1 -1
- package/dist/io/xlsx/read-styles.js +65 -43
- package/dist/io/xlsx/read-worksheet.d.ts +10 -1
- package/dist/io/xlsx/read-worksheet.js +48 -63
- package/dist/io/xlsx/read.d.ts +3 -4
- package/dist/io/xlsx/read.js +124 -146
- package/dist/io/xlsx/rich-runs.d.ts +41 -7
- package/dist/io/xlsx/rich-runs.js +95 -30
- package/dist/io/xlsx/sheet-properties.d.ts +1 -1
- package/dist/io/xlsx/sheet-properties.js +23 -26
- package/dist/io/xlsx/styles.d.ts +3 -15
- package/dist/io/xlsx/styles.js +83 -105
- package/dist/io/xlsx/tables.js +14 -13
- package/dist/io/xlsx/theme-xml.js +8 -5
- package/dist/io/xlsx/threaded-comments.js +20 -19
- package/dist/io/xlsx/workbook-xml.js +43 -36
- package/dist/io/xlsx/worksheet-xml.d.ts +1 -1
- package/dist/io/xlsx/worksheet-xml.js +47 -52
- package/dist/io/xlsx/write-stream.d.ts +14 -1
- package/dist/io/xlsx/write-stream.js +40 -33
- package/dist/io/xlsx/write.d.ts +5 -0
- package/dist/io/xlsx/write.js +155 -131
- package/dist/sha512.d.ts +2 -0
- package/dist/sha512.js +146 -0
- package/dist/token-set.d.ts +15 -0
- package/dist/token-set.js +4 -0
- package/dist/vba/bytes.d.ts +1 -2
- package/dist/vba/bytes.js +1 -12
- package/dist/vba/cfb-format.d.ts +24 -0
- package/dist/vba/cfb-format.js +12 -0
- package/dist/vba/cfb-writer.js +17 -17
- package/dist/vba/cfb.js +1 -7
- package/dist/vba/dir-records.d.ts +53 -0
- package/dist/vba/dir-records.js +28 -0
- package/dist/vba/ms-ovba.js +32 -11
- package/dist/vba/project-editor.js +5 -34
- package/dist/vba/project.js +15 -31
- package/dist/vba/vba-encoding.js +1 -1
- package/dist/xml/xml-read.d.ts +117 -72
- package/dist/xml/xml-read.js +123 -169
- package/dist/xml/xml-scan.d.ts +100 -0
- package/dist/xml/xml-scan.js +208 -0
- package/dist/xml/xml.d.ts +44 -2
- package/dist/xml/xml.js +17 -5
- package/package.json +22 -6
package/dist/io/xlsx/read.js
CHANGED
|
@@ -3,51 +3,45 @@ import { unmangleFunctions } from '../../core/formula.js';
|
|
|
3
3
|
import { INTERNAL } from '../../core/internal.js';
|
|
4
4
|
import { WORKBOOK_PROTECTION_CREDENTIAL_ATTRS, } from '../../core/workbook-protection.js';
|
|
5
5
|
import { Workbook } from '../../core/workbook.js';
|
|
6
|
-
import {
|
|
6
|
+
import { isVisibility } from '../../core/worksheet.js';
|
|
7
|
+
import { capturedText, openElements, parseXml, parseXmlPasses } from '../../xml/xml-read.js';
|
|
8
|
+
import { boolStrict, enumToken, localName, numInteger } from '../../xml/xml-scan.js';
|
|
7
9
|
import { UnsupportedFormatError } from '../opc/errors.js';
|
|
8
|
-
import { extensionOf } from '../opc/part-paths.js';
|
|
9
|
-
import { capturePartClosure, contentTypeResolver,
|
|
10
|
-
import { DEFAULT_MAX_UNCOMPRESSED } from '../opc/read-options.js';
|
|
11
|
-
import { inflateSpreadsheetPackage } from '../opc/sniff-format.js';
|
|
10
|
+
import { extensionOf, resolveRelativePart } from '../opc/part-paths.js';
|
|
11
|
+
import { capturePartClosure, contentTypeResolver, openSpreadsheetPackage, parseRelationshipRecords, readPartRelationships, } from '../opc/read-opc.js';
|
|
12
12
|
import { readXlsbPackage, XLSB_WORKBOOK_PART } from '../xlsb/read.js';
|
|
13
13
|
import { applyNotes, parseComments } from './comments.js';
|
|
14
|
-
import {
|
|
15
|
-
import { applyDataValidations,
|
|
16
|
-
import { applyHyperlinks,
|
|
14
|
+
import { conditionalFormattingPass } from './conditional-formatting.js';
|
|
15
|
+
import { applyDataValidations, dataValidationPass, extendedDataValidationPass, } from './data-validation.js';
|
|
16
|
+
import { applyHyperlinks, sheetHyperlinkPass } from './hyperlinks.js';
|
|
17
17
|
import { drawingHasUnmodeledContent, parseDrawing } from './images.js';
|
|
18
18
|
import { parsePivotTable } from './read-pivot.js';
|
|
19
19
|
import { parseSharedStrings } from './read-shared-strings.js';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
20
|
+
import { parseStyleTable } from './read-styles.js';
|
|
21
|
+
import { worksheetPass } from './read-worksheet.js';
|
|
22
22
|
import { parseTable } from './tables.js';
|
|
23
23
|
import { parseThemeColorScheme, parseThemeFontScheme } from './theme-xml.js';
|
|
24
24
|
import { buildCommentThreads, parsePersons, parseThreadedComments } from './threaded-comments.js';
|
|
25
|
-
export { parseRelationships, resolveWorkbookPart } from '../opc/read-opc.js';
|
|
26
|
-
export { DEFAULT_MAX_UNCOMPRESSED } from '../opc/read-options.js';
|
|
27
25
|
export { parseStyleTable } from './read-styles.js';
|
|
28
26
|
export function readXlsx(data, options = {}) {
|
|
29
|
-
const
|
|
30
|
-
const files = inflateSpreadsheetPackage(data, cap);
|
|
31
|
-
const pkg = packageAccessors(files);
|
|
27
|
+
const { files, pkg, workbookXml } = openSpreadsheetPackage(data, options.maxUncompressedBytes);
|
|
32
28
|
const { partText } = pkg;
|
|
33
|
-
const workbookXml = partText('xl/workbook.xml');
|
|
34
29
|
if (workbookXml === undefined) {
|
|
35
30
|
if (files[XLSB_WORKBOOK_PART] !== undefined)
|
|
36
31
|
return readXlsbPackage(files);
|
|
37
32
|
throw new UnsupportedFormatError('unknown');
|
|
38
33
|
}
|
|
39
34
|
const contentTypeOf = contentTypeResolver(partText('[Content_Types].xml') ?? '');
|
|
40
|
-
const
|
|
41
|
-
const rels = parseRelationships(workbookRelsXml);
|
|
35
|
+
const workbookRels = readPartRelationships('xl/workbook.xml', partText);
|
|
42
36
|
const sharedStrings = parseSharedStrings(partText('xl/sharedStrings.xml') ?? '');
|
|
43
37
|
const stylesXml = partText('xl/styles.xml') ?? '';
|
|
44
|
-
const { cellXfs: xfStyles, namedStyles, defaultFont } = parseStyleTable(stylesXml);
|
|
38
|
+
const { cellXfs: xfStyles, namedStyles, defaultFont, preserved } = parseStyleTable(stylesXml);
|
|
45
39
|
const workbook = new Workbook();
|
|
46
|
-
workbook[INTERNAL].restoreDifferentialStyles(
|
|
47
|
-
workbook[INTERNAL].restoreIndexedColors(
|
|
48
|
-
workbook[INTERNAL].restoreMruColors(
|
|
49
|
-
workbook[INTERNAL].restoreTableStyles(
|
|
50
|
-
readWorkbookTheme(
|
|
40
|
+
workbook[INTERNAL].restoreDifferentialStyles([...preserved.dxfs]);
|
|
41
|
+
workbook[INTERNAL].restoreIndexedColors([...preserved.indexedColors]);
|
|
42
|
+
workbook[INTERNAL].restoreMruColors([...preserved.mruColors]);
|
|
43
|
+
workbook[INTERNAL].restoreTableStyles(preserved.tableStyles);
|
|
44
|
+
readWorkbookTheme(workbookRels, pkg, contentTypeOf, workbook);
|
|
51
45
|
if (namedStyles.length > 1)
|
|
52
46
|
workbook[INTERNAL].restoreNamedStyles(namedStyles);
|
|
53
47
|
workbook[INTERNAL].restoreDefaultFont(defaultFont);
|
|
@@ -59,53 +53,72 @@ export function readXlsx(data, options = {}) {
|
|
|
59
53
|
applyAppProperties(workbook, app);
|
|
60
54
|
workbook.protection = parseWorkbookProtection(workbookXml);
|
|
61
55
|
applyWorkbookView(workbook.view, workbookXml);
|
|
62
|
-
readWorkbookPersons(
|
|
63
|
-
const
|
|
56
|
+
readWorkbookPersons(workbookRels, pkg, workbook);
|
|
57
|
+
const context = {
|
|
58
|
+
pkg,
|
|
59
|
+
workbook,
|
|
60
|
+
contentTypeOf,
|
|
61
|
+
sharedStrings,
|
|
62
|
+
xfStyles,
|
|
63
|
+
imageIdByMediaPath: new Map(),
|
|
64
|
+
};
|
|
64
65
|
const sheetOrder = [];
|
|
65
66
|
for (const { name, relId, state } of parseWorkbookSheets(workbookXml)) {
|
|
66
|
-
const target =
|
|
67
|
+
const target = workbookRels.byId(relId)?.target;
|
|
67
68
|
const sheet = workbook.addWorksheet(name, state === undefined ? undefined : { state });
|
|
68
69
|
sheetOrder.push(name);
|
|
69
|
-
|
|
70
|
-
const sheetXml = path === undefined ? undefined : partText(path);
|
|
71
|
-
if (sheetXml !== undefined)
|
|
72
|
-
parseWorksheet(sheetXml, sheet, sharedStrings, xfStyles);
|
|
73
|
-
if (path !== undefined) {
|
|
74
|
-
const sheetRels = readPartRelationships(path, partText);
|
|
75
|
-
if (sheetXml !== undefined) {
|
|
76
|
-
applyHyperlinks(sheet, parseSheetHyperlinks(sheetXml), (id) => sheetRels.byId(id)?.target);
|
|
77
|
-
applyDataValidations(sheet, [
|
|
78
|
-
...parseDataValidations(sheetXml),
|
|
79
|
-
...parseExtendedDataValidations(sheetXml),
|
|
80
|
-
]);
|
|
81
|
-
for (const cf of parseConditionalFormattings(sheetXml))
|
|
82
|
-
sheet.addConditionalFormatting(cf);
|
|
83
|
-
}
|
|
84
|
-
const threads = readSheetCommentThreads(sheetRels, pkg, workbook);
|
|
85
|
-
if (threads.length > 0)
|
|
86
|
-
sheet[INTERNAL].restoreCommentThreads(threads);
|
|
87
|
-
const comments = readSheetComments(sheetRels, pkg);
|
|
88
|
-
if (comments !== undefined)
|
|
89
|
-
applyNotes(sheet, comments);
|
|
90
|
-
readSheetImages(sheetRels, pkg, workbook, sheet, imageIdByMediaPath);
|
|
91
|
-
readSheetBackground(sheetRels, pkg, workbook, sheet, imageIdByMediaPath);
|
|
92
|
-
if (sheetXml !== undefined) {
|
|
93
|
-
readSheetPreservedReferences(sheetRels, sheetXml, pkg, contentTypeOf, sheet);
|
|
94
|
-
}
|
|
95
|
-
readSheetTables(sheetRels, pkg, sheet);
|
|
96
|
-
readSheetPivotTables(sheetRels, pkg, sheet);
|
|
97
|
-
const printerSettings = readSheetPrinterSettings(sheetRels, pkg);
|
|
98
|
-
if (printerSettings !== undefined)
|
|
99
|
-
sheet.pageSetup.printerSettings = printerSettings;
|
|
100
|
-
}
|
|
70
|
+
readSheet(sheet, target === undefined ? undefined : workbookRels.pathOf(target), context);
|
|
101
71
|
}
|
|
102
|
-
readWorkbookPreservedReferences(workbookXml, pkg, contentTypeOf, workbook);
|
|
72
|
+
readWorkbookPreservedReferences(workbookXml, workbookRels, pkg, contentTypeOf, workbook);
|
|
103
73
|
readRootPreservedReferences(pkg, contentTypeOf, workbook);
|
|
104
74
|
for (const name of parseWorkbookDefinedNames(workbookXml, sheetOrder)) {
|
|
105
75
|
workbook.defineName(name);
|
|
106
76
|
}
|
|
107
77
|
return workbook;
|
|
108
78
|
}
|
|
79
|
+
function readSheet(sheet, path, context) {
|
|
80
|
+
const { pkg, workbook, contentTypeOf, sharedStrings, xfStyles, imageIdByMediaPath } = context;
|
|
81
|
+
const { partText } = pkg;
|
|
82
|
+
const sheetXml = path === undefined ? undefined : partText(path);
|
|
83
|
+
const hyperlinks = sheetHyperlinkPass();
|
|
84
|
+
const validations = dataValidationPass();
|
|
85
|
+
const extendedValidations = extendedDataValidationPass();
|
|
86
|
+
const formattings = conditionalFormattingPass();
|
|
87
|
+
if (sheetXml !== undefined) {
|
|
88
|
+
parseXmlPasses(sheetXml, [
|
|
89
|
+
worksheetPass(sheet, sharedStrings, xfStyles),
|
|
90
|
+
hyperlinks,
|
|
91
|
+
validations,
|
|
92
|
+
extendedValidations,
|
|
93
|
+
formattings,
|
|
94
|
+
]);
|
|
95
|
+
}
|
|
96
|
+
if (path === undefined)
|
|
97
|
+
return;
|
|
98
|
+
const sheetRels = readPartRelationships(path, partText);
|
|
99
|
+
if (sheetXml !== undefined) {
|
|
100
|
+
applyHyperlinks(sheet, hyperlinks.result(), (id) => sheetRels.byId(id)?.target);
|
|
101
|
+
applyDataValidations(sheet, [...validations.result(), ...extendedValidations.result()]);
|
|
102
|
+
for (const cf of formattings.result())
|
|
103
|
+
sheet.addConditionalFormatting(cf);
|
|
104
|
+
}
|
|
105
|
+
const threads = readSheetCommentThreads(sheetRels, pkg, workbook);
|
|
106
|
+
if (threads.length > 0)
|
|
107
|
+
sheet[INTERNAL].restoreCommentThreads(threads);
|
|
108
|
+
const comments = readSheetComments(sheetRels, pkg);
|
|
109
|
+
if (comments !== undefined)
|
|
110
|
+
applyNotes(sheet, comments);
|
|
111
|
+
readSheetImages(sheetRels, pkg, workbook, sheet, imageIdByMediaPath);
|
|
112
|
+
readSheetBackground(sheetRels, pkg, workbook, sheet, imageIdByMediaPath);
|
|
113
|
+
if (sheetXml !== undefined) {
|
|
114
|
+
readSheetPreservedReferences(sheetRels, sheetXml, pkg, contentTypeOf, sheet);
|
|
115
|
+
}
|
|
116
|
+
readSheetTables(sheetRels, pkg, sheet);
|
|
117
|
+
readSheetPivotTables(sheetRels, pkg, sheet);
|
|
118
|
+
const printerSettings = readSheetPrinterSettings(sheetRels, pkg);
|
|
119
|
+
if (printerSettings !== undefined)
|
|
120
|
+
sheet.pageSetup.printerSettings = printerSettings;
|
|
121
|
+
}
|
|
109
122
|
function readSheetComments(sheetRels, pkg) {
|
|
110
123
|
const commentsPath = sheetRels.targetPath('comments');
|
|
111
124
|
if (commentsPath === undefined)
|
|
@@ -115,17 +128,16 @@ function readSheetComments(sheetRels, pkg) {
|
|
|
115
128
|
return undefined;
|
|
116
129
|
return parseComments(commentsXml);
|
|
117
130
|
}
|
|
118
|
-
function readWorkbookPersons(
|
|
119
|
-
const
|
|
120
|
-
const xml =
|
|
131
|
+
function readWorkbookPersons(workbookRels, pkg, workbook) {
|
|
132
|
+
const path = workbookRels.targetPath('person');
|
|
133
|
+
const xml = path === undefined ? undefined : pkg.partText(path);
|
|
121
134
|
if (xml !== undefined)
|
|
122
135
|
workbook[INTERNAL].restorePersons(parsePersons(xml));
|
|
123
136
|
}
|
|
124
|
-
function readWorkbookTheme(
|
|
125
|
-
const
|
|
126
|
-
if (
|
|
137
|
+
function readWorkbookTheme(workbookRels, pkg, contentTypeOf, workbook) {
|
|
138
|
+
const entryPath = workbookRels.targetPath('theme');
|
|
139
|
+
if (entryPath === undefined)
|
|
127
140
|
return;
|
|
128
|
-
const entryPath = resolveWorkbookPart(target);
|
|
129
141
|
const parts = capturePartClosure(entryPath, pkg.partText, pkg.partBytes, contentTypeOf);
|
|
130
142
|
if (parts === undefined)
|
|
131
143
|
return;
|
|
@@ -143,8 +155,19 @@ function readSheetPrinterSettings(sheetRels, pkg) {
|
|
|
143
155
|
const path = sheetRels.targetPath('printerSettings');
|
|
144
156
|
return path === undefined ? undefined : pkg.partBytes(path);
|
|
145
157
|
}
|
|
158
|
+
function internImage(workbook, pkg, imageIdByMediaPath, mediaPath) {
|
|
159
|
+
const known = imageIdByMediaPath.get(mediaPath);
|
|
160
|
+
if (known !== undefined)
|
|
161
|
+
return known;
|
|
162
|
+
const bytes = pkg.partBytes(mediaPath);
|
|
163
|
+
if (bytes === undefined)
|
|
164
|
+
return undefined;
|
|
165
|
+
const id = workbook.addImage({ buffer: bytes, extension: extensionOf(mediaPath) });
|
|
166
|
+
imageIdByMediaPath.set(mediaPath, id);
|
|
167
|
+
return id;
|
|
168
|
+
}
|
|
146
169
|
function readSheetImages(sheetRels, pkg, workbook, sheet, imageIdByMediaPath) {
|
|
147
|
-
const { partText
|
|
170
|
+
const { partText } = pkg;
|
|
148
171
|
const drawingPath = sheetRels.targetPath('drawing');
|
|
149
172
|
if (drawingPath === undefined)
|
|
150
173
|
return;
|
|
@@ -159,14 +182,9 @@ function readSheetImages(sheetRels, pkg, workbook, sheet, imageIdByMediaPath) {
|
|
|
159
182
|
if (embedded === undefined)
|
|
160
183
|
continue;
|
|
161
184
|
const mediaPath = drawingRels.pathOf(embedded.target);
|
|
162
|
-
|
|
163
|
-
if (id === undefined)
|
|
164
|
-
|
|
165
|
-
if (bytes === undefined)
|
|
166
|
-
continue;
|
|
167
|
-
id = workbook.addImage({ buffer: bytes, extension: extensionOf(mediaPath) });
|
|
168
|
-
imageIdByMediaPath.set(mediaPath, id);
|
|
169
|
-
}
|
|
185
|
+
const id = internImage(workbook, pkg, imageIdByMediaPath, mediaPath);
|
|
186
|
+
if (id === undefined)
|
|
187
|
+
continue;
|
|
170
188
|
const rot = anchor.rotation !== undefined ? { rotation: anchor.rotation } : {};
|
|
171
189
|
if (anchor.to !== undefined) {
|
|
172
190
|
const mode = anchor.editAs !== undefined ? { editAs: anchor.editAs } : {};
|
|
@@ -181,15 +199,9 @@ function readSheetBackground(sheetRels, pkg, workbook, sheet, imageIdByMediaPath
|
|
|
181
199
|
const mediaPath = sheetRels.targetPath('image');
|
|
182
200
|
if (mediaPath === undefined)
|
|
183
201
|
return;
|
|
184
|
-
|
|
185
|
-
if (id
|
|
186
|
-
|
|
187
|
-
if (bytes === undefined)
|
|
188
|
-
return;
|
|
189
|
-
id = workbook.addImage({ buffer: bytes, extension: extensionOf(mediaPath) });
|
|
190
|
-
imageIdByMediaPath.set(mediaPath, id);
|
|
191
|
-
}
|
|
192
|
-
sheet.addBackgroundImage(id);
|
|
202
|
+
const id = internImage(workbook, pkg, imageIdByMediaPath, mediaPath);
|
|
203
|
+
if (id !== undefined)
|
|
204
|
+
sheet.addBackgroundImage(id);
|
|
193
205
|
}
|
|
194
206
|
function readSheetPreservedReferences(sheetRels, sheetXml, pkg, contentTypeOf, sheet) {
|
|
195
207
|
const { partText, partBytes } = pkg;
|
|
@@ -216,17 +228,14 @@ function readSheetPreservedReferences(sheetRels, sheetXml, pkg, contentTypeOf, s
|
|
|
216
228
|
function isPreservedSheetRelType(type) {
|
|
217
229
|
return type.endsWith('/pivotTable') || type.endsWith('/slicer');
|
|
218
230
|
}
|
|
219
|
-
function readWorkbookPreservedReferences(workbookXml, pkg, contentTypeOf, workbook) {
|
|
231
|
+
function readWorkbookPreservedReferences(workbookXml, workbookRels, pkg, contentTypeOf, workbook) {
|
|
220
232
|
const { partText, partBytes } = pkg;
|
|
221
|
-
const relsXml = partText('xl/_rels/workbook.xml.rels');
|
|
222
|
-
if (relsXml === undefined)
|
|
223
|
-
return;
|
|
224
233
|
const cacheIdByRelId = parsePivotCacheRegistrations(workbookXml);
|
|
225
234
|
const externalIndexByRelId = parseExternalReferenceRegistrations(workbookXml);
|
|
226
|
-
for (const record of
|
|
235
|
+
for (const record of workbookRels.records) {
|
|
227
236
|
if (record.external || !isPreservedWorkbookRelType(record.type))
|
|
228
237
|
continue;
|
|
229
|
-
const entryPath =
|
|
238
|
+
const entryPath = workbookRels.pathOf(record.target);
|
|
230
239
|
const parts = capturePartClosure(entryPath, partText, partBytes, contentTypeOf);
|
|
231
240
|
if (parts === undefined)
|
|
232
241
|
continue;
|
|
@@ -337,8 +346,9 @@ export function parseWorkbookSheets(xml) {
|
|
|
337
346
|
name: attrs.name ?? '',
|
|
338
347
|
relId: attrs['r:id'] ?? '',
|
|
339
348
|
};
|
|
340
|
-
|
|
341
|
-
|
|
349
|
+
const state = enumToken(attrs.state, isVisibility);
|
|
350
|
+
if (state !== undefined && state !== 'visible')
|
|
351
|
+
entry.state = state;
|
|
342
352
|
sheets.push(entry);
|
|
343
353
|
}
|
|
344
354
|
return sheets;
|
|
@@ -386,9 +396,9 @@ export function applyWorkbookView(view, xml) {
|
|
|
386
396
|
const activeTab = numInteger(attrs.activeTab, 0);
|
|
387
397
|
if (activeTab !== undefined)
|
|
388
398
|
view.activeTab = activeTab;
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
399
|
+
const visibility = enumToken(attrs.visibility, isVisibility);
|
|
400
|
+
if (visibility !== undefined && visibility !== 'visible')
|
|
401
|
+
view.visibility = visibility;
|
|
392
402
|
if (boolStrict(attrs.minimized))
|
|
393
403
|
view.minimized = true;
|
|
394
404
|
return;
|
|
@@ -439,57 +449,25 @@ const CORE_PROPERTY_LOCAL_NAMES = new Set([
|
|
|
439
449
|
'modified',
|
|
440
450
|
]);
|
|
441
451
|
function applyCoreProperties(workbook, xml) {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
if (
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
return;
|
|
457
|
-
if (capture === 'title')
|
|
458
|
-
workbook.properties.title = text;
|
|
459
|
-
else if (capture === 'creator')
|
|
460
|
-
workbook.properties.creator = text;
|
|
461
|
-
else if (capture === 'lastModifiedBy')
|
|
462
|
-
workbook.properties.lastModifiedBy = text;
|
|
463
|
-
else {
|
|
464
|
-
const date = new Date(text);
|
|
465
|
-
if (!Number.isNaN(date.getTime())) {
|
|
466
|
-
if (capture === 'created')
|
|
467
|
-
workbook.properties.created = date;
|
|
468
|
-
else
|
|
469
|
-
workbook.properties.modified = date;
|
|
470
|
-
}
|
|
452
|
+
for (const { local, text } of capturedText(xml, CORE_PROPERTY_LOCAL_NAMES)) {
|
|
453
|
+
if (local === 'title')
|
|
454
|
+
workbook.properties.title = text;
|
|
455
|
+
else if (local === 'creator')
|
|
456
|
+
workbook.properties.creator = text;
|
|
457
|
+
else if (local === 'lastModifiedBy')
|
|
458
|
+
workbook.properties.lastModifiedBy = text;
|
|
459
|
+
else {
|
|
460
|
+
const date = new Date(text);
|
|
461
|
+
if (!Number.isNaN(date.getTime())) {
|
|
462
|
+
if (local === 'created')
|
|
463
|
+
workbook.properties.created = date;
|
|
464
|
+
else
|
|
465
|
+
workbook.properties.modified = date;
|
|
471
466
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
});
|
|
467
|
+
}
|
|
468
|
+
}
|
|
475
469
|
}
|
|
476
470
|
function applyAppProperties(workbook, xml) {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
parseXml(xml, {
|
|
480
|
-
onOpen(name) {
|
|
481
|
-
capture = localName(name) === 'Company';
|
|
482
|
-
text = '';
|
|
483
|
-
},
|
|
484
|
-
onText(chunk) {
|
|
485
|
-
if (capture)
|
|
486
|
-
text += chunk;
|
|
487
|
-
},
|
|
488
|
-
onClose(name) {
|
|
489
|
-
if (!capture || localName(name) !== 'Company')
|
|
490
|
-
return;
|
|
491
|
-
workbook.properties.company = text;
|
|
492
|
-
capture = false;
|
|
493
|
-
},
|
|
494
|
-
});
|
|
471
|
+
for (const { text } of capturedText(xml, 'Company'))
|
|
472
|
+
workbook.properties.company = text;
|
|
495
473
|
}
|
|
@@ -1,13 +1,47 @@
|
|
|
1
1
|
import type { RichTextRun } from '../../core/value.ts';
|
|
2
|
-
import type
|
|
2
|
+
import { type XmlAttributes } from '../../xml/xml-scan.ts';
|
|
3
|
+
/**
|
|
4
|
+
* What {@link RunAccumulator.close} did with an element: `'container'` means the `<si>`/`<is>` itself
|
|
5
|
+
* closed and the caller should commit whatever it makes of the gathered runs, the one step the two
|
|
6
|
+
* readers do differently; `'claimed'` means the machine handled it; `'other'` leaves it to the caller.
|
|
7
|
+
*
|
|
8
|
+
* Three values rather than a boolean because both callers need to tell "the machine dealt with it"
|
|
9
|
+
* from "your string is complete", and a boolean would mean something different to each of them.
|
|
10
|
+
*/
|
|
11
|
+
export type RunClose = 'claimed' | 'container' | 'other';
|
|
3
12
|
export declare class RunAccumulator {
|
|
4
13
|
#private;
|
|
5
|
-
|
|
14
|
+
/**
|
|
15
|
+
* @param options.container the element that opens one string: `'si'` for the shared-string pool,
|
|
16
|
+
* `'is'` for an inline string in a worksheet body.
|
|
17
|
+
* @param options.readRuns whether `<r>`/`<rPr>` open a rich-text run. The buffered readers read
|
|
18
|
+
* them; the row stream deliberately does not, and with runs off every `<t>` falls through to
|
|
19
|
+
* {@link plainText}, which is exactly the documented flattening.
|
|
20
|
+
*/
|
|
21
|
+
constructor(options: {
|
|
22
|
+
readonly container: 'si' | 'is';
|
|
23
|
+
readonly readRuns: boolean;
|
|
24
|
+
});
|
|
6
25
|
/** The runs gathered so far. */
|
|
7
26
|
get runs(): RichTextRun[];
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
27
|
+
/** Whether the container held at least one `<r>`: what decides rich text from a plain string. */
|
|
28
|
+
get isRich(): boolean;
|
|
29
|
+
/** The container's own text: every `<t>` no run claimed, concatenated and already unescaped. */
|
|
30
|
+
get plainText(): string;
|
|
31
|
+
/**
|
|
32
|
+
* Open a string container by discarding whatever the last one gathered. Called for the machine's
|
|
33
|
+
* own container automatically; a caller whose own element may *hold* one (a `<c>` around an
|
|
34
|
+
* `<is>`) calls it too, or that container inherits the previous one's runs, which is the one way
|
|
35
|
+
* this accumulator can be misused.
|
|
36
|
+
*
|
|
37
|
+
* A new array is installed rather than the existing one emptied, so a value already built from the
|
|
38
|
+
* last container's runs keeps its own array.
|
|
39
|
+
*/
|
|
40
|
+
beginContainer(): void;
|
|
41
|
+
/** Drive one element open, and return whether it was one of this machine's own. */
|
|
42
|
+
open(local: string, attrs: XmlAttributes, selfClosing: boolean): boolean;
|
|
43
|
+
/** Feed one run of character data. Ignored unless a `<t>` is open. */
|
|
44
|
+
text(chunk: string): void;
|
|
45
|
+
/** Drive one element close. See {@link RunClose}. */
|
|
46
|
+
close(local: string): RunClose;
|
|
13
47
|
}
|
|
@@ -1,43 +1,108 @@
|
|
|
1
|
+
import { TextCapture } from '../../xml/xml-read.js';
|
|
2
|
+
import { decodeSpreadsheetText } from '../../xml/xml-scan.js';
|
|
1
3
|
import { applyFontChild } from './read-styles.js';
|
|
2
4
|
export class RunAccumulator {
|
|
5
|
+
#container;
|
|
6
|
+
#readRuns;
|
|
7
|
+
#capture = new TextCapture('t');
|
|
3
8
|
#runs = [];
|
|
4
9
|
#font = null;
|
|
5
|
-
#
|
|
10
|
+
#inProperties = false;
|
|
11
|
+
#runText = '';
|
|
12
|
+
#plain = '';
|
|
6
13
|
#inRun = false;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
this.#
|
|
14
|
+
#isRich = false;
|
|
15
|
+
#inContainer = false;
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.#container = options.container;
|
|
18
|
+
this.#readRuns = options.readRuns;
|
|
11
19
|
}
|
|
12
20
|
get runs() {
|
|
13
21
|
return this.#runs;
|
|
14
22
|
}
|
|
15
|
-
|
|
16
|
-
this.#
|
|
23
|
+
get isRich() {
|
|
24
|
+
return this.#isRich;
|
|
25
|
+
}
|
|
26
|
+
get plainText() {
|
|
27
|
+
return this.#plain;
|
|
28
|
+
}
|
|
29
|
+
beginContainer() {
|
|
30
|
+
this.#runs = [];
|
|
17
31
|
this.#font = null;
|
|
18
|
-
this.#
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (this.#inRun)
|
|
22
|
-
this.#font = {};
|
|
23
|
-
}
|
|
24
|
-
applyProperty(local, attrs) {
|
|
25
|
-
if (this.#font !== null)
|
|
26
|
-
applyFontChild(this.#font, local, attrs);
|
|
27
|
-
}
|
|
28
|
-
appendText(text) {
|
|
29
|
-
if (!this.#inRun)
|
|
30
|
-
return false;
|
|
31
|
-
this.#text += text;
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
endRun() {
|
|
35
|
-
if (!this.#inRun)
|
|
36
|
-
return;
|
|
37
|
-
const run = { text: this.#text };
|
|
38
|
-
if (this.#font !== null && Object.keys(this.#font).length > 0)
|
|
39
|
-
run.font = this.#font;
|
|
40
|
-
this.#runs.push(run);
|
|
32
|
+
this.#inProperties = false;
|
|
33
|
+
this.#runText = '';
|
|
34
|
+
this.#plain = '';
|
|
41
35
|
this.#inRun = false;
|
|
36
|
+
this.#isRich = false;
|
|
37
|
+
}
|
|
38
|
+
open(local, attrs, selfClosing) {
|
|
39
|
+
switch (local) {
|
|
40
|
+
case this.#container:
|
|
41
|
+
this.#inContainer = true;
|
|
42
|
+
this.beginContainer();
|
|
43
|
+
return true;
|
|
44
|
+
case 'r':
|
|
45
|
+
if (!this.#readRuns || !this.#inContainer)
|
|
46
|
+
return false;
|
|
47
|
+
this.#isRich = true;
|
|
48
|
+
this.#inRun = true;
|
|
49
|
+
this.#font = null;
|
|
50
|
+
this.#inProperties = false;
|
|
51
|
+
this.#runText = '';
|
|
52
|
+
return true;
|
|
53
|
+
case 'rPr':
|
|
54
|
+
if (!this.#readRuns || !this.#inRun)
|
|
55
|
+
return false;
|
|
56
|
+
this.#font = {};
|
|
57
|
+
this.#inProperties = true;
|
|
58
|
+
return true;
|
|
59
|
+
case 't':
|
|
60
|
+
this.#capture.open(local, selfClosing);
|
|
61
|
+
return true;
|
|
62
|
+
default:
|
|
63
|
+
if (!this.#inProperties || this.#font === null)
|
|
64
|
+
return false;
|
|
65
|
+
applyFontChild(this.#font, local, attrs);
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
text(chunk) {
|
|
70
|
+
this.#capture.text(chunk);
|
|
71
|
+
}
|
|
72
|
+
close(local) {
|
|
73
|
+
switch (local) {
|
|
74
|
+
case 't': {
|
|
75
|
+
const text = this.#capture.close(local);
|
|
76
|
+
if (text !== undefined) {
|
|
77
|
+
const decoded = decodeSpreadsheetText(text);
|
|
78
|
+
if (this.#inRun)
|
|
79
|
+
this.#runText += decoded;
|
|
80
|
+
else if (this.#inContainer)
|
|
81
|
+
this.#plain += decoded;
|
|
82
|
+
}
|
|
83
|
+
return 'claimed';
|
|
84
|
+
}
|
|
85
|
+
case 'rPr':
|
|
86
|
+
if (!this.#readRuns || !this.#inProperties)
|
|
87
|
+
return 'other';
|
|
88
|
+
this.#inProperties = false;
|
|
89
|
+
return 'claimed';
|
|
90
|
+
case 'r': {
|
|
91
|
+
if (!this.#readRuns || !this.#inRun)
|
|
92
|
+
return 'other';
|
|
93
|
+
this.#inProperties = false;
|
|
94
|
+
const run = { text: this.#runText };
|
|
95
|
+
if (this.#font !== null && Object.keys(this.#font).length > 0)
|
|
96
|
+
run.font = this.#font;
|
|
97
|
+
this.#runs.push(run);
|
|
98
|
+
this.#inRun = false;
|
|
99
|
+
return 'claimed';
|
|
100
|
+
}
|
|
101
|
+
case this.#container:
|
|
102
|
+
this.#inContainer = false;
|
|
103
|
+
return 'container';
|
|
104
|
+
default:
|
|
105
|
+
return 'other';
|
|
106
|
+
}
|
|
42
107
|
}
|
|
43
108
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AutoFilter } from '../../core/autofilter.ts';
|
|
2
|
-
import type
|
|
2
|
+
import { type HeaderFooter, type PageBreak, type PageMargins, type PageSetup, type PrintOptions } from '../../core/page-setup.ts';
|
|
3
3
|
import { type SheetProtection } from '../../core/protection.ts';
|
|
4
4
|
import type { SheetView, Worksheet } from '../../core/worksheet.ts';
|
|
5
5
|
export declare function sheetViewsXml(view: SheetView, active: boolean): string;
|