@shbernal/ts-xlsx 1.3.1 → 2.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 +20 -10
- package/dist/bytes.d.ts +24 -0
- package/dist/bytes.js +34 -0
- package/dist/core/address.d.ts +72 -3
- package/dist/core/address.js +50 -10
- package/dist/core/autofilter.d.ts +13 -2
- package/dist/core/autofilter.js +35 -10
- package/dist/core/cell.d.ts +17 -16
- package/dist/core/cell.js +3 -7
- package/dist/core/color-resolution.d.ts +8 -8
- package/dist/core/color-resolution.js +7 -8
- package/dist/core/column.d.ts +8 -9
- package/dist/core/column.js +2 -4
- package/dist/core/comment-thread.d.ts +32 -23
- package/dist/core/comment-thread.js +4 -4
- package/dist/core/conditional-formatting-overlay.d.ts +6 -1
- package/dist/core/conditional-formatting-overlay.js +11 -0
- package/dist/core/conditional-formatting.d.ts +48 -8
- package/dist/core/conditional-formatting.js +88 -0
- package/dist/core/data-validation-overlay.d.ts +12 -1
- package/dist/core/data-validation-overlay.js +21 -2
- package/dist/core/data-validation.d.ts +12 -5
- package/dist/core/data-validation.js +34 -0
- package/dist/core/date.d.ts +3 -3
- package/dist/core/formula.d.ts +6 -6
- package/dist/core/grid-edits.d.ts +16 -0
- package/dist/core/grid-edits.js +29 -11
- package/dist/core/grid-shift.d.ts +19 -0
- package/dist/core/grid-shift.js +8 -0
- package/dist/core/image.d.ts +39 -2
- package/dist/core/image.js +10 -0
- package/dist/core/internal.d.ts +9 -1
- package/dist/core/limits.d.ts +4 -4
- package/dist/core/merge.d.ts +17 -12
- package/dist/core/merge.js +36 -5
- package/dist/core/page-setup.d.ts +20 -6
- package/dist/core/page-setup.js +8 -1
- package/dist/core/pivot-table.d.ts +4 -4
- package/dist/core/pivot-table.js +29 -20
- package/dist/core/preserved.d.ts +3 -3
- package/dist/core/protection.d.ts +7 -4
- package/dist/core/protection.js +20 -14
- package/dist/core/range.d.ts +16 -14
- package/dist/core/range.js +5 -5
- package/dist/core/row-input.d.ts +9 -8
- package/dist/core/row-input.js +12 -10
- package/dist/core/row.d.ts +7 -8
- package/dist/core/row.js +2 -4
- package/dist/core/style.d.ts +41 -14
- package/dist/core/style.js +82 -67
- package/dist/core/table-style.d.ts +9 -9
- package/dist/core/table-style.js +1 -1
- package/dist/core/table.d.ts +53 -51
- package/dist/core/table.js +83 -41
- package/dist/core/theme.d.ts +16 -44
- package/dist/core/theme.js +6 -148
- package/dist/core/value.d.ts +7 -7
- package/dist/core/workbook-protection.d.ts +2 -2
- package/dist/core/workbook-styles.d.ts +26 -0
- package/dist/core/workbook-styles.js +48 -0
- package/dist/core/workbook-theme.d.ts +25 -0
- package/dist/core/workbook-theme.js +49 -0
- package/dist/core/workbook-vba.d.ts +17 -0
- package/dist/core/workbook-vba.js +79 -0
- package/dist/core/workbook.d.ts +133 -87
- package/dist/core/workbook.js +74 -133
- package/dist/core/worksheet-comments.d.ts +17 -0
- package/dist/core/worksheet-comments.js +70 -0
- package/dist/core/worksheet-model.d.ts +4 -4
- package/dist/core/worksheet-model.js +1 -0
- package/dist/core/worksheet-pictures.d.ts +29 -0
- package/dist/core/worksheet-pictures.js +42 -0
- package/dist/core/worksheet.d.ts +100 -79
- package/dist/core/worksheet.js +63 -142
- package/dist/customui/errors.d.ts +1 -1
- package/dist/customui/ribbon.d.ts +3 -3
- package/dist/customui/ribbon.js +24 -23
- package/dist/entries/core.d.ts +7 -7
- package/dist/entries/core.js +1 -1
- 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/vba.d.ts +1 -1
- package/dist/entries/vba.js +1 -1
- package/dist/entries/xlsx.d.ts +1 -1
- package/dist/entries/xlsx.js +1 -1
- package/dist/errors.d.ts +12 -12
- package/dist/io/csv/read.js +2 -3
- package/dist/io/csv/write.d.ts +19 -4
- package/dist/io/csv/write.js +34 -4
- package/dist/io/opc/errors.d.ts +6 -6
- package/dist/io/opc/inflate.d.ts +1 -1
- package/dist/io/opc/inflate.js +2 -12
- package/dist/io/opc/namespaces.d.ts +1 -1
- package/dist/io/opc/read-opc.d.ts +19 -3
- package/dist/io/opc/read-opc.js +14 -8
- package/dist/io/opc/read-options.d.ts +2 -2
- package/dist/io/opc/rels.d.ts +11 -0
- package/dist/io/opc/rels.js +3 -2
- package/dist/io/opc/sniff-format.d.ts +2 -2
- package/dist/io/style/xf-style.d.ts +44 -7
- package/dist/io/style/xf-style.js +27 -0
- package/dist/io/xlsb/errors.d.ts +1 -1
- package/dist/io/xlsb/formula.d.ts +4 -4
- package/dist/io/xlsb/primitives.d.ts +8 -8
- package/dist/io/xlsb/ptg-functions.d.ts +1 -1
- package/dist/io/xlsb/read-styles.js +2 -20
- package/dist/io/xlsb/read.d.ts +2 -2
- package/dist/io/xlsx/cell-accumulator.d.ts +26 -9
- package/dist/io/xlsx/cell-accumulator.js +89 -46
- package/dist/io/xlsx/cell-value.d.ts +3 -3
- package/dist/io/xlsx/cell-value.js +9 -6
- package/dist/io/xlsx/color-xml.d.ts +1 -1
- package/dist/io/xlsx/color-xml.js +18 -23
- package/dist/io/xlsx/comments.d.ts +5 -5
- package/dist/io/xlsx/comments.js +17 -8
- package/dist/io/xlsx/conditional-formatting.d.ts +4 -4
- package/dist/io/xlsx/conditional-formatting.js +64 -58
- package/dist/io/xlsx/data-validation.d.ts +3 -3
- package/dist/io/xlsx/data-validation.js +35 -33
- package/dist/io/xlsx/errors.d.ts +3 -3
- package/dist/io/xlsx/hyperlinks.d.ts +4 -2
- package/dist/io/xlsx/hyperlinks.js +10 -18
- package/dist/io/xlsx/images.d.ts +1 -1
- package/dist/io/xlsx/images.js +25 -28
- package/dist/io/xlsx/namespaces.d.ts +2 -2
- package/dist/io/xlsx/package-plan.js +5 -2
- package/dist/io/xlsx/read-pivot.js +4 -13
- package/dist/io/xlsx/read-rows.d.ts +13 -13
- package/dist/io/xlsx/read-rows.js +19 -55
- package/dist/io/xlsx/read-shared-strings.js +7 -44
- package/dist/io/xlsx/read-styles.d.ts +3 -3
- package/dist/io/xlsx/read-styles.js +42 -66
- package/dist/io/xlsx/read-worksheet.js +73 -129
- package/dist/io/xlsx/read.d.ts +4 -6
- package/dist/io/xlsx/read.js +104 -142
- package/dist/io/xlsx/rich-runs.d.ts +41 -7
- package/dist/io/xlsx/rich-runs.js +94 -30
- package/dist/io/xlsx/rich-text.d.ts +1 -1
- package/dist/io/xlsx/shared-strings.d.ts +2 -2
- package/dist/io/xlsx/sheet-properties.d.ts +1 -1
- package/dist/io/xlsx/sheet-properties.js +14 -10
- package/dist/io/xlsx/styles.d.ts +9 -22
- package/dist/io/xlsx/styles.js +65 -89
- package/dist/io/xlsx/tables.d.ts +2 -2
- package/dist/io/xlsx/tables.js +20 -25
- package/dist/io/xlsx/theme-xml.d.ts +37 -0
- package/dist/io/xlsx/theme-xml.js +145 -0
- package/dist/io/xlsx/threaded-comments.d.ts +18 -27
- package/dist/io/xlsx/threaded-comments.js +26 -38
- package/dist/io/xlsx/workbook-xml.js +14 -8
- package/dist/io/xlsx/worksheet-xml.d.ts +2 -2
- package/dist/io/xlsx/worksheet-xml.js +40 -48
- package/dist/io/xlsx/write-stream.d.ts +23 -16
- package/dist/io/xlsx/write-stream.js +13 -14
- package/dist/io/xlsx/write.d.ts +8 -7
- package/dist/io/xlsx/write.js +6 -3
- package/dist/io/xlsx/x14-ext.d.ts +1 -1
- package/dist/sha512.d.ts +2 -0
- package/dist/sha512.js +146 -0
- package/dist/vba/bytes.d.ts +11 -0
- package/dist/vba/bytes.js +29 -0
- package/dist/vba/cfb-writer.d.ts +1 -1
- package/dist/vba/cfb.d.ts +1 -1
- package/dist/vba/cfb.js +15 -51
- package/dist/vba/codepage.d.ts +2 -2
- package/dist/vba/dir-records.d.ts +53 -0
- package/dist/vba/dir-records.js +28 -0
- package/dist/vba/errors.d.ts +2 -2
- package/dist/vba/index.d.ts +2 -2
- package/dist/vba/index.js +2 -2
- package/dist/vba/ms-ovba.d.ts +1 -1
- package/dist/vba/ms-ovba.js +1 -3
- package/dist/vba/project-editor.d.ts +9 -9
- package/dist/vba/project-editor.js +6 -44
- package/dist/vba/project.d.ts +5 -5
- package/dist/vba/project.js +3 -28
- package/dist/vba/vba-encoding.d.ts +1 -1
- package/dist/xml/errors.d.ts +1 -1
- package/dist/xml/xml-read.d.ts +98 -9
- package/dist/xml/xml-read.js +70 -0
- package/dist/xml/xml.d.ts +74 -10
- package/dist/xml/xml.js +39 -7
- package/package.json +59 -36
package/dist/io/xlsx/read.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { decodeRange } from '../../core/address.js';
|
|
2
2
|
import { unmangleFunctions } from '../../core/formula.js';
|
|
3
3
|
import { INTERNAL } from '../../core/internal.js';
|
|
4
|
-
import { Workbook } from '../../core/workbook.js';
|
|
5
4
|
import { WORKBOOK_PROTECTION_CREDENTIAL_ATTRS, } from '../../core/workbook-protection.js';
|
|
6
|
-
import {
|
|
5
|
+
import { Workbook } from '../../core/workbook.js';
|
|
6
|
+
import { isVisibility } from '../../core/worksheet.js';
|
|
7
|
+
import { boolStrict, capturedText, enumToken, localName, numInteger, openElements, parseXml, } from '../../xml/xml-read.js';
|
|
7
8
|
import { UnsupportedFormatError } from '../opc/errors.js';
|
|
8
|
-
import { extensionOf
|
|
9
|
-
import { capturePartClosure, contentTypeResolver, packageAccessors, parseRelationshipRecords, parseRelationships,
|
|
9
|
+
import { extensionOf } from '../opc/part-paths.js';
|
|
10
|
+
import { capturePartClosure, contentTypeResolver, packageAccessors, parseRelationshipRecords, parseRelationships, readPartRelationships, relationshipTargetByType, resolveRelativePart, resolveWorkbookPart, } from '../opc/read-opc.js';
|
|
10
11
|
import { DEFAULT_MAX_UNCOMPRESSED } from '../opc/read-options.js';
|
|
11
12
|
import { inflateSpreadsheetPackage } from '../opc/sniff-format.js';
|
|
12
13
|
import { readXlsbPackage, XLSB_WORKBOOK_PART } from '../xlsb/read.js';
|
|
@@ -20,6 +21,7 @@ import { parseSharedStrings } from './read-shared-strings.js';
|
|
|
20
21
|
import { parseIndexedColors, parseMruColors, parseStyleTable, parseTableStyles, } from './read-styles.js';
|
|
21
22
|
import { parseWorksheet } from './read-worksheet.js';
|
|
22
23
|
import { parseTable } from './tables.js';
|
|
24
|
+
import { parseThemeColorScheme, parseThemeFontScheme } from './theme-xml.js';
|
|
23
25
|
import { buildCommentThreads, parsePersons, parseThreadedComments } from './threaded-comments.js';
|
|
24
26
|
export { parseRelationships, resolveWorkbookPart } from '../opc/read-opc.js';
|
|
25
27
|
export { DEFAULT_MAX_UNCOMPRESSED } from '../opc/read-options.js';
|
|
@@ -70,9 +72,9 @@ export function readXlsx(data, options = {}) {
|
|
|
70
72
|
if (sheetXml !== undefined)
|
|
71
73
|
parseWorksheet(sheetXml, sheet, sharedStrings, xfStyles);
|
|
72
74
|
if (path !== undefined) {
|
|
75
|
+
const sheetRels = readPartRelationships(path, partText);
|
|
73
76
|
if (sheetXml !== undefined) {
|
|
74
|
-
|
|
75
|
-
applyHyperlinks(sheet, parseSheetHyperlinks(sheetXml), sheetRels);
|
|
77
|
+
applyHyperlinks(sheet, parseSheetHyperlinks(sheetXml), (id) => sheetRels.byId(id)?.target);
|
|
76
78
|
applyDataValidations(sheet, [
|
|
77
79
|
...parseDataValidations(sheetXml),
|
|
78
80
|
...parseExtendedDataValidations(sheetXml),
|
|
@@ -80,20 +82,20 @@ export function readXlsx(data, options = {}) {
|
|
|
80
82
|
for (const cf of parseConditionalFormattings(sheetXml))
|
|
81
83
|
sheet.addConditionalFormatting(cf);
|
|
82
84
|
}
|
|
83
|
-
const threads = readSheetCommentThreads(
|
|
85
|
+
const threads = readSheetCommentThreads(sheetRels, pkg, workbook);
|
|
84
86
|
if (threads.length > 0)
|
|
85
87
|
sheet[INTERNAL].restoreCommentThreads(threads);
|
|
86
|
-
const comments = readSheetComments(
|
|
88
|
+
const comments = readSheetComments(sheetRels, pkg);
|
|
87
89
|
if (comments !== undefined)
|
|
88
90
|
applyNotes(sheet, comments);
|
|
89
|
-
readSheetImages(
|
|
90
|
-
readSheetBackground(
|
|
91
|
+
readSheetImages(sheetRels, pkg, workbook, sheet, imageIdByMediaPath);
|
|
92
|
+
readSheetBackground(sheetRels, pkg, workbook, sheet, imageIdByMediaPath);
|
|
91
93
|
if (sheetXml !== undefined) {
|
|
92
|
-
readSheetPreservedReferences(
|
|
94
|
+
readSheetPreservedReferences(sheetRels, sheetXml, pkg, contentTypeOf, sheet);
|
|
93
95
|
}
|
|
94
|
-
readSheetTables(
|
|
95
|
-
readSheetPivotTables(
|
|
96
|
-
const printerSettings = readSheetPrinterSettings(
|
|
96
|
+
readSheetTables(sheetRels, pkg, sheet);
|
|
97
|
+
readSheetPivotTables(sheetRels, pkg, sheet);
|
|
98
|
+
const printerSettings = readSheetPrinterSettings(sheetRels, pkg);
|
|
97
99
|
if (printerSettings !== undefined)
|
|
98
100
|
sheet.pageSetup.printerSettings = printerSettings;
|
|
99
101
|
}
|
|
@@ -105,8 +107,8 @@ export function readXlsx(data, options = {}) {
|
|
|
105
107
|
}
|
|
106
108
|
return workbook;
|
|
107
109
|
}
|
|
108
|
-
function readSheetComments(
|
|
109
|
-
const commentsPath =
|
|
110
|
+
function readSheetComments(sheetRels, pkg) {
|
|
111
|
+
const commentsPath = sheetRels.targetPath('comments');
|
|
110
112
|
if (commentsPath === undefined)
|
|
111
113
|
return undefined;
|
|
112
114
|
const commentsXml = pkg.partText(commentsPath);
|
|
@@ -126,23 +128,36 @@ function readWorkbookTheme(workbookRelsXml, pkg, contentTypeOf, workbook) {
|
|
|
126
128
|
return;
|
|
127
129
|
const entryPath = resolveWorkbookPart(target);
|
|
128
130
|
const parts = capturePartClosure(entryPath, pkg.partText, pkg.partBytes, contentTypeOf);
|
|
129
|
-
if (parts
|
|
130
|
-
|
|
131
|
+
if (parts === undefined)
|
|
132
|
+
return;
|
|
133
|
+
const xml = pkg.partText(entryPath) ?? '';
|
|
134
|
+
workbook[INTERNAL].restoreThemePart({ entryPath, parts }, { colors: parseThemeColorScheme(xml), fonts: parseThemeFontScheme(xml) });
|
|
131
135
|
}
|
|
132
|
-
function readSheetCommentThreads(
|
|
133
|
-
const path =
|
|
136
|
+
function readSheetCommentThreads(sheetRels, pkg, workbook) {
|
|
137
|
+
const path = sheetRels.targetPath('threadedComment');
|
|
134
138
|
const xml = path === undefined ? undefined : pkg.partText(path);
|
|
135
139
|
if (xml === undefined)
|
|
136
140
|
return [];
|
|
137
141
|
return buildCommentThreads(parseThreadedComments(xml), (id) => workbook.getPerson(id));
|
|
138
142
|
}
|
|
139
|
-
function readSheetPrinterSettings(
|
|
140
|
-
const path =
|
|
143
|
+
function readSheetPrinterSettings(sheetRels, pkg) {
|
|
144
|
+
const path = sheetRels.targetPath('printerSettings');
|
|
141
145
|
return path === undefined ? undefined : pkg.partBytes(path);
|
|
142
146
|
}
|
|
143
|
-
function
|
|
144
|
-
const
|
|
145
|
-
|
|
147
|
+
function internImage(workbook, pkg, imageIdByMediaPath, mediaPath) {
|
|
148
|
+
const known = imageIdByMediaPath.get(mediaPath);
|
|
149
|
+
if (known !== undefined)
|
|
150
|
+
return known;
|
|
151
|
+
const bytes = pkg.partBytes(mediaPath);
|
|
152
|
+
if (bytes === undefined)
|
|
153
|
+
return undefined;
|
|
154
|
+
const id = workbook.addImage({ buffer: bytes, extension: extensionOf(mediaPath) });
|
|
155
|
+
imageIdByMediaPath.set(mediaPath, id);
|
|
156
|
+
return id;
|
|
157
|
+
}
|
|
158
|
+
function readSheetImages(sheetRels, pkg, workbook, sheet, imageIdByMediaPath) {
|
|
159
|
+
const { partText } = pkg;
|
|
160
|
+
const drawingPath = sheetRels.targetPath('drawing');
|
|
146
161
|
if (drawingPath === undefined)
|
|
147
162
|
return;
|
|
148
163
|
const drawingXml = partText(drawingPath);
|
|
@@ -150,20 +165,15 @@ function readSheetImages(sheetPath, pkg, workbook, sheet, imageIdByMediaPath) {
|
|
|
150
165
|
return;
|
|
151
166
|
if (drawingHasUnmodeledContent(drawingXml))
|
|
152
167
|
return;
|
|
153
|
-
const drawingRels =
|
|
168
|
+
const drawingRels = readPartRelationships(drawingPath, partText);
|
|
154
169
|
for (const anchor of parseDrawing(drawingXml)) {
|
|
155
|
-
const
|
|
156
|
-
if (
|
|
170
|
+
const embedded = drawingRels.byId(anchor.embed);
|
|
171
|
+
if (embedded === undefined)
|
|
172
|
+
continue;
|
|
173
|
+
const mediaPath = drawingRels.pathOf(embedded.target);
|
|
174
|
+
const id = internImage(workbook, pkg, imageIdByMediaPath, mediaPath);
|
|
175
|
+
if (id === undefined)
|
|
157
176
|
continue;
|
|
158
|
-
const mediaPath = resolveRelativePart(drawingPath, target);
|
|
159
|
-
let id = imageIdByMediaPath.get(mediaPath);
|
|
160
|
-
if (id === undefined) {
|
|
161
|
-
const bytes = partBytes(mediaPath);
|
|
162
|
-
if (bytes === undefined)
|
|
163
|
-
continue;
|
|
164
|
-
id = workbook.addImage({ buffer: bytes, extension: extensionOf(mediaPath) });
|
|
165
|
-
imageIdByMediaPath.set(mediaPath, id);
|
|
166
|
-
}
|
|
167
177
|
const rot = anchor.rotation !== undefined ? { rotation: anchor.rotation } : {};
|
|
168
178
|
if (anchor.to !== undefined) {
|
|
169
179
|
const mode = anchor.editAs !== undefined ? { editAs: anchor.editAs } : {};
|
|
@@ -174,29 +184,18 @@ function readSheetImages(sheetPath, pkg, workbook, sheet, imageIdByMediaPath) {
|
|
|
174
184
|
}
|
|
175
185
|
}
|
|
176
186
|
}
|
|
177
|
-
function readSheetBackground(
|
|
178
|
-
const mediaPath =
|
|
187
|
+
function readSheetBackground(sheetRels, pkg, workbook, sheet, imageIdByMediaPath) {
|
|
188
|
+
const mediaPath = sheetRels.targetPath('image');
|
|
179
189
|
if (mediaPath === undefined)
|
|
180
190
|
return;
|
|
181
|
-
|
|
182
|
-
if (id
|
|
183
|
-
|
|
184
|
-
if (bytes === undefined)
|
|
185
|
-
return;
|
|
186
|
-
id = workbook.addImage({ buffer: bytes, extension: extensionOf(mediaPath) });
|
|
187
|
-
imageIdByMediaPath.set(mediaPath, id);
|
|
188
|
-
}
|
|
189
|
-
sheet.addBackgroundImage(id);
|
|
191
|
+
const id = internImage(workbook, pkg, imageIdByMediaPath, mediaPath);
|
|
192
|
+
if (id !== undefined)
|
|
193
|
+
sheet.addBackgroundImage(id);
|
|
190
194
|
}
|
|
191
|
-
function readSheetPreservedReferences(
|
|
195
|
+
function readSheetPreservedReferences(sheetRels, sheetXml, pkg, contentTypeOf, sheet) {
|
|
192
196
|
const { partText, partBytes } = pkg;
|
|
193
|
-
const relsXml = partText(relsPathFor(sheetPath));
|
|
194
|
-
if (relsXml === undefined)
|
|
195
|
-
return;
|
|
196
|
-
const records = parseRelationshipRecords(relsXml);
|
|
197
|
-
const recordById = new Map(records.map((record) => [record.id, record]));
|
|
198
197
|
const capture = (element, relType, target) => {
|
|
199
|
-
const entryPath =
|
|
198
|
+
const entryPath = sheetRels.pathOf(target);
|
|
200
199
|
const parts = capturePartClosure(entryPath, partText, partBytes, contentTypeOf);
|
|
201
200
|
if (parts !== undefined)
|
|
202
201
|
sheet[INTERNAL].addPreservedReference({ element, relType, entryPath, parts });
|
|
@@ -204,11 +203,11 @@ function readSheetPreservedReferences(sheetPath, sheetXml, pkg, contentTypeOf, s
|
|
|
204
203
|
const referenceElements = sheet.images.length === 0 ? ['drawing', 'legacyDrawingHF'] : ['legacyDrawingHF'];
|
|
205
204
|
for (const element of referenceElements) {
|
|
206
205
|
const relId = worksheetReferenceRelId(sheetXml, element);
|
|
207
|
-
const record = relId === undefined ? undefined :
|
|
206
|
+
const record = relId === undefined ? undefined : sheetRels.byId(relId);
|
|
208
207
|
if (record !== undefined && !record.external)
|
|
209
208
|
capture(element, record.type, record.target);
|
|
210
209
|
}
|
|
211
|
-
for (const record of records) {
|
|
210
|
+
for (const record of sheetRels.records) {
|
|
212
211
|
if (record.external)
|
|
213
212
|
continue;
|
|
214
213
|
if (isPreservedSheetRelType(record.type))
|
|
@@ -294,12 +293,9 @@ function worksheetReferenceRelId(sheetXml, element) {
|
|
|
294
293
|
}
|
|
295
294
|
return undefined;
|
|
296
295
|
}
|
|
297
|
-
function readSheetTables(
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
return;
|
|
301
|
-
for (const target of relationshipTargetsByType(relsXml, 'table')) {
|
|
302
|
-
const tableXml = pkg.partText(resolveRelativePart(sheetPath, target));
|
|
296
|
+
function readSheetTables(sheetRels, pkg, sheet) {
|
|
297
|
+
for (const tablePath of sheetRels.targetPaths('table')) {
|
|
298
|
+
const tableXml = pkg.partText(tablePath);
|
|
303
299
|
if (tableXml === undefined)
|
|
304
300
|
continue;
|
|
305
301
|
const options = parseTable(tableXml);
|
|
@@ -308,20 +304,14 @@ function readSheetTables(sheetPath, pkg, sheet) {
|
|
|
308
304
|
}
|
|
309
305
|
dropMergesInsideTables(sheet);
|
|
310
306
|
}
|
|
311
|
-
function readSheetPivotTables(
|
|
307
|
+
function readSheetPivotTables(sheetRels, pkg, sheet) {
|
|
312
308
|
const { partText } = pkg;
|
|
313
|
-
const
|
|
314
|
-
if (relsXml === undefined)
|
|
315
|
-
return;
|
|
316
|
-
for (const target of relationshipTargetsByType(relsXml, 'pivotTable')) {
|
|
317
|
-
const tablePath = resolveRelativePart(sheetPath, target);
|
|
309
|
+
for (const tablePath of sheetRels.targetPaths('pivotTable')) {
|
|
318
310
|
const tableXml = partText(tablePath);
|
|
319
311
|
if (tableXml === undefined)
|
|
320
312
|
continue;
|
|
321
|
-
const
|
|
322
|
-
const cacheXml =
|
|
323
|
-
? ''
|
|
324
|
-
: (partText(resolveRelativePart(tablePath, cacheTarget)) ?? '');
|
|
313
|
+
const cachePath = readPartRelationships(tablePath, partText).targetPath('pivotCacheDefinition');
|
|
314
|
+
const cacheXml = cachePath === undefined ? '' : (partText(cachePath) ?? '');
|
|
325
315
|
sheet[INTERNAL].addLoadedPivotTable(parsePivotTable(tableXml, cacheXml));
|
|
326
316
|
}
|
|
327
317
|
}
|
|
@@ -348,13 +338,14 @@ export function parseWorkbookSheets(xml) {
|
|
|
348
338
|
name: attrs.name ?? '',
|
|
349
339
|
relId: attrs['r:id'] ?? '',
|
|
350
340
|
};
|
|
351
|
-
|
|
352
|
-
|
|
341
|
+
const state = enumToken(attrs.state, isVisibility);
|
|
342
|
+
if (state !== undefined && state !== 'visible')
|
|
343
|
+
entry.state = state;
|
|
353
344
|
sheets.push(entry);
|
|
354
345
|
}
|
|
355
346
|
return sheets;
|
|
356
347
|
}
|
|
357
|
-
|
|
348
|
+
function parseWorkbookProtection(xml) {
|
|
358
349
|
let result;
|
|
359
350
|
parseXml(xml, {
|
|
360
351
|
onOpen(name, attrs) {
|
|
@@ -382,26 +373,29 @@ export function parseWorkbookProtection(xml) {
|
|
|
382
373
|
}
|
|
383
374
|
export function applyWorkbookView(view, xml) {
|
|
384
375
|
for (const { attrs } of openElements(xml, 'workbookView')) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
376
|
+
const x = numInteger(attrs.xWindow);
|
|
377
|
+
if (x !== undefined)
|
|
378
|
+
view.x = x;
|
|
379
|
+
const y = numInteger(attrs.yWindow);
|
|
380
|
+
if (y !== undefined)
|
|
381
|
+
view.y = y;
|
|
382
|
+
const width = numInteger(attrs.windowWidth, 0);
|
|
383
|
+
if (width !== undefined)
|
|
384
|
+
view.width = width;
|
|
385
|
+
const height = numInteger(attrs.windowHeight, 0);
|
|
386
|
+
if (height !== undefined)
|
|
387
|
+
view.height = height;
|
|
388
|
+
const activeTab = numInteger(attrs.activeTab, 0);
|
|
389
|
+
if (activeTab !== undefined)
|
|
390
|
+
view.activeTab = activeTab;
|
|
391
|
+
const visibility = enumToken(attrs.visibility, isVisibility);
|
|
392
|
+
if (visibility !== undefined && visibility !== 'visible')
|
|
393
|
+
view.visibility = visibility;
|
|
393
394
|
if (boolStrict(attrs.minimized))
|
|
394
395
|
view.minimized = true;
|
|
395
396
|
return;
|
|
396
397
|
}
|
|
397
398
|
}
|
|
398
|
-
function applyViewNumber(raw, assign) {
|
|
399
|
-
if (raw === undefined)
|
|
400
|
-
return;
|
|
401
|
-
const value = Number(raw);
|
|
402
|
-
if (Number.isFinite(value))
|
|
403
|
-
assign(Math.trunc(value));
|
|
404
|
-
}
|
|
405
399
|
function parseWorkbookDefinedNames(xml, sheetOrder) {
|
|
406
400
|
const names = [];
|
|
407
401
|
let capture = false;
|
|
@@ -415,7 +409,7 @@ function parseWorkbookDefinedNames(xml, sheetOrder) {
|
|
|
415
409
|
return;
|
|
416
410
|
capture = true;
|
|
417
411
|
refersTo = '';
|
|
418
|
-
const scopeIndex = attrs.localSheetId
|
|
412
|
+
const scopeIndex = numInteger(attrs.localSheetId, 0) ?? -1;
|
|
419
413
|
const scope = sheetOrder[scopeIndex];
|
|
420
414
|
pending = { name: attrs.name };
|
|
421
415
|
if (scope !== undefined)
|
|
@@ -447,57 +441,25 @@ const CORE_PROPERTY_LOCAL_NAMES = new Set([
|
|
|
447
441
|
'modified',
|
|
448
442
|
]);
|
|
449
443
|
function applyCoreProperties(workbook, xml) {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
if (
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
return;
|
|
465
|
-
if (capture === 'title')
|
|
466
|
-
workbook.properties.title = text;
|
|
467
|
-
else if (capture === 'creator')
|
|
468
|
-
workbook.properties.creator = text;
|
|
469
|
-
else if (capture === 'lastModifiedBy')
|
|
470
|
-
workbook.properties.lastModifiedBy = text;
|
|
471
|
-
else {
|
|
472
|
-
const date = new Date(text);
|
|
473
|
-
if (!Number.isNaN(date.getTime())) {
|
|
474
|
-
if (capture === 'created')
|
|
475
|
-
workbook.properties.created = date;
|
|
476
|
-
else
|
|
477
|
-
workbook.properties.modified = date;
|
|
478
|
-
}
|
|
444
|
+
for (const { local, text } of capturedText(xml, CORE_PROPERTY_LOCAL_NAMES)) {
|
|
445
|
+
if (local === 'title')
|
|
446
|
+
workbook.properties.title = text;
|
|
447
|
+
else if (local === 'creator')
|
|
448
|
+
workbook.properties.creator = text;
|
|
449
|
+
else if (local === 'lastModifiedBy')
|
|
450
|
+
workbook.properties.lastModifiedBy = text;
|
|
451
|
+
else {
|
|
452
|
+
const date = new Date(text);
|
|
453
|
+
if (!Number.isNaN(date.getTime())) {
|
|
454
|
+
if (local === 'created')
|
|
455
|
+
workbook.properties.created = date;
|
|
456
|
+
else
|
|
457
|
+
workbook.properties.modified = date;
|
|
479
458
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
483
461
|
}
|
|
484
462
|
function applyAppProperties(workbook, xml) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
parseXml(xml, {
|
|
488
|
-
onOpen(name) {
|
|
489
|
-
capture = localName(name) === 'Company';
|
|
490
|
-
text = '';
|
|
491
|
-
},
|
|
492
|
-
onText(chunk) {
|
|
493
|
-
if (capture)
|
|
494
|
-
text += chunk;
|
|
495
|
-
},
|
|
496
|
-
onClose(name) {
|
|
497
|
-
if (!capture || localName(name) !== 'Company')
|
|
498
|
-
return;
|
|
499
|
-
workbook.properties.company = text;
|
|
500
|
-
capture = false;
|
|
501
|
-
},
|
|
502
|
-
});
|
|
463
|
+
for (const { text } of capturedText(xml, 'Company'))
|
|
464
|
+
workbook.properties.company = text;
|
|
503
465
|
}
|
|
@@ -1,13 +1,47 @@
|
|
|
1
1
|
import type { RichTextRun } from '../../core/value.ts';
|
|
2
|
-
import type
|
|
2
|
+
import { type XmlAttributes } from '../../xml/xml-read.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,107 @@
|
|
|
1
|
+
import { decodeSpreadsheetText, TextCapture } from '../../xml/xml-read.js';
|
|
1
2
|
import { applyFontChild } from './read-styles.js';
|
|
2
3
|
export class RunAccumulator {
|
|
4
|
+
#container;
|
|
5
|
+
#readRuns;
|
|
6
|
+
#capture = new TextCapture('t');
|
|
3
7
|
#runs = [];
|
|
4
8
|
#font = null;
|
|
5
|
-
#
|
|
9
|
+
#inProperties = false;
|
|
10
|
+
#runText = '';
|
|
11
|
+
#plain = '';
|
|
6
12
|
#inRun = false;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
this.#
|
|
13
|
+
#isRich = false;
|
|
14
|
+
#inContainer = false;
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.#container = options.container;
|
|
17
|
+
this.#readRuns = options.readRuns;
|
|
11
18
|
}
|
|
12
19
|
get runs() {
|
|
13
20
|
return this.#runs;
|
|
14
21
|
}
|
|
15
|
-
|
|
16
|
-
this.#
|
|
22
|
+
get isRich() {
|
|
23
|
+
return this.#isRich;
|
|
24
|
+
}
|
|
25
|
+
get plainText() {
|
|
26
|
+
return this.#plain;
|
|
27
|
+
}
|
|
28
|
+
beginContainer() {
|
|
29
|
+
this.#runs = [];
|
|
17
30
|
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);
|
|
31
|
+
this.#inProperties = false;
|
|
32
|
+
this.#runText = '';
|
|
33
|
+
this.#plain = '';
|
|
41
34
|
this.#inRun = false;
|
|
35
|
+
this.#isRich = false;
|
|
36
|
+
}
|
|
37
|
+
open(local, attrs, selfClosing) {
|
|
38
|
+
switch (local) {
|
|
39
|
+
case this.#container:
|
|
40
|
+
this.#inContainer = true;
|
|
41
|
+
this.beginContainer();
|
|
42
|
+
return true;
|
|
43
|
+
case 'r':
|
|
44
|
+
if (!this.#readRuns || !this.#inContainer)
|
|
45
|
+
return false;
|
|
46
|
+
this.#isRich = true;
|
|
47
|
+
this.#inRun = true;
|
|
48
|
+
this.#font = null;
|
|
49
|
+
this.#inProperties = false;
|
|
50
|
+
this.#runText = '';
|
|
51
|
+
return true;
|
|
52
|
+
case 'rPr':
|
|
53
|
+
if (!this.#readRuns || !this.#inRun)
|
|
54
|
+
return false;
|
|
55
|
+
this.#font = {};
|
|
56
|
+
this.#inProperties = true;
|
|
57
|
+
return true;
|
|
58
|
+
case 't':
|
|
59
|
+
this.#capture.open(local, selfClosing);
|
|
60
|
+
return true;
|
|
61
|
+
default:
|
|
62
|
+
if (!this.#inProperties || this.#font === null)
|
|
63
|
+
return false;
|
|
64
|
+
applyFontChild(this.#font, local, attrs);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
text(chunk) {
|
|
69
|
+
this.#capture.text(chunk);
|
|
70
|
+
}
|
|
71
|
+
close(local) {
|
|
72
|
+
switch (local) {
|
|
73
|
+
case 't': {
|
|
74
|
+
const text = this.#capture.close(local);
|
|
75
|
+
if (text !== undefined) {
|
|
76
|
+
const decoded = decodeSpreadsheetText(text);
|
|
77
|
+
if (this.#inRun)
|
|
78
|
+
this.#runText += decoded;
|
|
79
|
+
else if (this.#inContainer)
|
|
80
|
+
this.#plain += decoded;
|
|
81
|
+
}
|
|
82
|
+
return 'claimed';
|
|
83
|
+
}
|
|
84
|
+
case 'rPr':
|
|
85
|
+
if (!this.#readRuns || !this.#inProperties)
|
|
86
|
+
return 'other';
|
|
87
|
+
this.#inProperties = false;
|
|
88
|
+
return 'claimed';
|
|
89
|
+
case 'r': {
|
|
90
|
+
if (!this.#readRuns || !this.#inRun)
|
|
91
|
+
return 'other';
|
|
92
|
+
this.#inProperties = false;
|
|
93
|
+
const run = { text: this.#runText };
|
|
94
|
+
if (this.#font !== null && Object.keys(this.#font).length > 0)
|
|
95
|
+
run.font = this.#font;
|
|
96
|
+
this.#runs.push(run);
|
|
97
|
+
this.#inRun = false;
|
|
98
|
+
return 'claimed';
|
|
99
|
+
}
|
|
100
|
+
case this.#container:
|
|
101
|
+
this.#inContainer = false;
|
|
102
|
+
return 'container';
|
|
103
|
+
default:
|
|
104
|
+
return 'other';
|
|
105
|
+
}
|
|
42
106
|
}
|
|
43
107
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RichTextRun } from '../../core/value.ts';
|
|
2
2
|
/**
|
|
3
3
|
* Serialise a rich-text value's runs as the inner content of an `<is>` element. A zero-length run
|
|
4
|
-
* is dropped: an empty `<t/>` is schema-invalid
|
|
4
|
+
* is dropped: an empty `<t/>` is schema-invalid (Excel flags the file as corrupt) and an empty
|
|
5
5
|
* run contributes nothing to the rendered text, so omitting it is loss-free.
|
|
6
6
|
*/
|
|
7
7
|
export declare function richTextRunsXml(runs: readonly RichTextRun[]): string;
|
|
@@ -3,14 +3,14 @@ import type { RichTextValue } from '../../core/value.ts';
|
|
|
3
3
|
* Interns cell string values into the shared-strings pool. {@link intern} returns the index a
|
|
4
4
|
* `t="s"` cell writes as its `<v>`; identical entries collapse to one, so `count` (total references)
|
|
5
5
|
* and `uniqueCount` (distinct entries) diverge exactly as Excel records them. Each entry is stored as
|
|
6
|
-
* its rendered `<si>` inner XML, which is also its dedup key
|
|
6
|
+
* its rendered `<si>` inner XML, which is also its dedup key: a plain string (`<t>…`) and rich runs
|
|
7
7
|
* (`<r>…`) render to distinct markup, so the two kinds never collide in the pool.
|
|
8
8
|
*/
|
|
9
9
|
export declare class SharedStringTable {
|
|
10
10
|
#private;
|
|
11
11
|
/** Intern a plain or rich string and return its `<si>` index, reusing the entry when it repeats. */
|
|
12
12
|
intern(value: string | RichTextValue): number;
|
|
13
|
-
/** Whether no string has been interned
|
|
13
|
+
/** Whether no string has been interned; the writer omits the part entirely when so. */
|
|
14
14
|
get isEmpty(): boolean;
|
|
15
15
|
/** Serialise the pool as the `xl/sharedStrings.xml` part. */
|
|
16
16
|
toXml(): string;
|
|
@@ -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;
|