@shbernal/ts-xlsx 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/bytes.d.ts +7 -0
- package/dist/bytes.js +22 -0
- package/dist/core/address.d.ts +60 -2
- package/dist/core/address.js +40 -24
- package/dist/core/autofilter.d.ts +4 -3
- package/dist/core/autofilter.js +31 -30
- package/dist/core/axis-handle.d.ts +2 -0
- package/dist/core/axis-handle.js +5 -2
- package/dist/core/cell.d.ts +4 -3
- package/dist/core/cell.js +4 -6
- package/dist/core/clone.d.ts +29 -0
- package/dist/core/clone.js +24 -0
- package/dist/core/color-resolution.js +2 -4
- package/dist/core/column.d.ts +1 -0
- package/dist/core/column.js +3 -0
- package/dist/core/comment-thread.js +2 -1
- package/dist/core/conditional-formatting-overlay.d.ts +2 -1
- package/dist/core/conditional-formatting-overlay.js +2 -2
- package/dist/core/conditional-formatting.d.ts +9 -1
- package/dist/core/conditional-formatting.js +34 -18
- package/dist/core/containers.d.ts +12 -0
- package/dist/core/containers.js +5 -0
- package/dist/core/data-validation-overlay.d.ts +2 -1
- package/dist/core/data-validation-overlay.js +4 -4
- package/dist/core/data-validation.d.ts +6 -0
- package/dist/core/data-validation.js +15 -4
- package/dist/core/date-format.d.ts +20 -0
- package/dist/core/date-format.js +160 -0
- package/dist/core/date.d.ts +43 -8
- package/dist/core/date.js +18 -2
- package/dist/core/formula.d.ts +26 -0
- package/dist/core/formula.js +20 -4
- package/dist/core/grid-edits.d.ts +2 -3
- package/dist/core/grid-edits.js +69 -70
- package/dist/core/grid-shift.d.ts +58 -9
- package/dist/core/grid-shift.js +26 -4
- package/dist/core/image.d.ts +13 -9
- package/dist/core/image.js +7 -5
- package/dist/core/internal.d.ts +8 -2
- package/dist/core/limits.d.ts +23 -0
- package/dist/core/limits.js +4 -0
- package/dist/core/merge.d.ts +5 -4
- package/dist/core/merge.js +18 -19
- package/dist/core/pivot-table.js +63 -45
- package/dist/core/protection.js +2 -11
- package/dist/core/range.js +34 -30
- package/dist/core/row-input.js +2 -2
- package/dist/core/row.d.ts +1 -0
- package/dist/core/row.js +3 -0
- package/dist/core/style.d.ts +85 -70
- package/dist/core/style.js +92 -28
- package/dist/core/table-style.d.ts +1 -1
- package/dist/core/table-style.js +4 -4
- package/dist/core/table.d.ts +27 -9
- package/dist/core/table.js +51 -34
- package/dist/core/theme.js +6 -5
- package/dist/core/value.d.ts +9 -0
- package/dist/core/value.js +36 -34
- package/dist/core/workbook-media.d.ts +34 -0
- package/dist/core/workbook-media.js +44 -0
- package/dist/core/workbook-styles.d.ts +67 -1
- package/dist/core/workbook-vba.js +3 -2
- package/dist/core/workbook.d.ts +23 -2
- package/dist/core/workbook.js +24 -40
- package/dist/core/worksheet-comments.d.ts +2 -1
- package/dist/core/worksheet-comments.js +20 -13
- package/dist/core/worksheet-merges.d.ts +44 -0
- package/dist/core/worksheet-merges.js +59 -0
- package/dist/core/worksheet-model.d.ts +9 -1
- package/dist/core/worksheet-model.js +24 -9
- package/dist/core/worksheet.d.ts +55 -6
- package/dist/core/worksheet.js +36 -44
- package/dist/customui/ribbon.js +2 -1
- package/dist/entries/core.d.ts +18 -13
- package/dist/entries/core.js +12 -6
- package/dist/entries/xlsx.d.ts +1 -1
- package/dist/errors.d.ts +64 -0
- package/dist/errors.js +22 -0
- package/dist/hex.d.ts +8 -0
- package/dist/hex.js +3 -0
- package/dist/io/csv/delimiter.d.ts +9 -0
- package/dist/io/csv/delimiter.js +6 -0
- package/dist/io/csv/read.js +11 -4
- package/dist/io/csv/write.d.ts +9 -2
- package/dist/io/csv/write.js +9 -38
- package/dist/io/opc/inflate.js +14 -0
- package/dist/io/opc/namespaces.d.ts +16 -0
- package/dist/io/opc/namespaces.js +4 -0
- package/dist/io/opc/part-paths.d.ts +9 -0
- package/dist/io/opc/part-paths.js +1 -1
- package/dist/io/opc/read-opc.d.ts +54 -14
- package/dist/io/opc/read-opc.js +42 -20
- package/dist/io/opc/read-options.d.ts +5 -1
- package/dist/io/opc/sniff-format.d.ts +3 -3
- package/dist/io/opc/sniff-format.js +2 -2
- package/dist/io/style/xf-style.d.ts +23 -1
- package/dist/io/style/xf-style.js +8 -0
- package/dist/io/xlsb/formula.d.ts +2 -2
- package/dist/io/xlsb/formula.js +49 -34
- package/dist/io/xlsb/primitives.js +8 -14
- package/dist/io/xlsb/ptg-functions.d.ts +19 -10
- package/dist/io/xlsb/ptg-functions.js +385 -596
- package/dist/io/xlsb/read-styles.js +45 -81
- package/dist/io/xlsb/read-worksheet.d.ts +20 -1
- package/dist/io/xlsb/read-worksheet.js +73 -89
- package/dist/io/xlsb/read.d.ts +6 -3
- package/dist/io/xlsb/read.js +44 -23
- package/dist/io/xlsb/record-stream.d.ts +30 -0
- package/dist/io/xlsb/record-stream.js +20 -0
- package/dist/io/xlsb/record-types.d.ts +1 -5
- package/dist/io/xlsb/record-types.js +1 -5
- package/dist/io/xlsx/cell-accumulator.d.ts +8 -1
- package/dist/io/xlsx/cell-accumulator.js +32 -9
- package/dist/io/xlsx/cell-style-resolution.d.ts +25 -0
- package/dist/io/xlsx/cell-style-resolution.js +29 -0
- package/dist/io/xlsx/cell-value.d.ts +5 -3
- package/dist/io/xlsx/cell-value.js +13 -15
- package/dist/io/xlsx/color-xml.js +3 -2
- package/dist/io/xlsx/column-budget.d.ts +26 -0
- package/dist/io/xlsx/column-budget.js +22 -0
- package/dist/io/xlsx/comments.d.ts +6 -2
- package/dist/io/xlsx/comments.js +36 -32
- package/dist/io/xlsx/conditional-formatting.d.ts +6 -3
- package/dist/io/xlsx/conditional-formatting.js +30 -26
- package/dist/io/xlsx/data-validation.js +29 -27
- package/dist/io/xlsx/edit-vba.d.ts +7 -2
- package/dist/io/xlsx/edit-vba.js +14 -21
- package/dist/io/xlsx/font-xml.d.ts +7 -0
- package/dist/io/xlsx/font-xml.js +104 -0
- package/dist/io/xlsx/hyperlinks.d.ts +37 -5
- package/dist/io/xlsx/hyperlinks.js +22 -13
- package/dist/io/xlsx/images.js +11 -13
- package/dist/io/xlsx/namespaces.d.ts +16 -0
- package/dist/io/xlsx/namespaces.js +7 -0
- package/dist/io/xlsx/package-plan.d.ts +14 -2
- package/dist/io/xlsx/package-plan.js +39 -11
- package/dist/io/xlsx/pivot.js +8 -7
- package/dist/io/xlsx/read-parts.d.ts +59 -0
- package/dist/io/xlsx/read-parts.js +252 -0
- package/dist/io/xlsx/read-pivot.js +2 -1
- package/dist/io/xlsx/read-repair.d.ts +26 -0
- package/dist/io/xlsx/read-repair.js +39 -0
- package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +6 -3
- package/dist/io/xlsx/read-rows.d.ts +18 -5
- package/dist/io/xlsx/read-rows.js +45 -31
- package/dist/io/xlsx/read-shared-strings.js +3 -2
- package/dist/io/xlsx/read-styles.d.ts +1 -6
- package/dist/io/xlsx/read-styles.js +6 -71
- package/dist/io/xlsx/read-workbook-xml.d.ts +36 -0
- package/dist/io/xlsx/read-workbook-xml.js +170 -0
- package/dist/io/xlsx/read-worksheet.d.ts +2 -1
- package/dist/io/xlsx/read-worksheet.js +35 -164
- package/dist/io/xlsx/read.d.ts +5 -12
- package/dist/io/xlsx/read.js +73 -406
- package/dist/io/xlsx/rich-text.js +1 -1
- package/dist/io/xlsx/row-position.d.ts +18 -0
- package/dist/io/xlsx/row-position.js +11 -0
- package/dist/io/xlsx/row-xml.d.ts +128 -0
- package/dist/io/xlsx/row-xml.js +203 -0
- package/dist/io/xlsx/shared-formulas.js +2 -2
- package/dist/io/xlsx/sheet-properties.d.ts +10 -1
- package/dist/io/xlsx/sheet-properties.js +145 -9
- package/dist/io/xlsx/style-elements.d.ts +43 -0
- package/dist/io/xlsx/style-elements.js +156 -0
- package/dist/io/xlsx/styles.d.ts +12 -3
- package/dist/io/xlsx/styles.js +5 -207
- package/dist/io/xlsx/tables.js +10 -14
- package/dist/io/xlsx/theme-xml.d.ts +26 -4
- package/dist/io/xlsx/theme-xml.js +107 -69
- package/dist/io/xlsx/threaded-comments.d.ts +8 -10
- package/dist/io/xlsx/threaded-comments.js +2 -1
- package/dist/io/xlsx/workbook-xml.d.ts +54 -4
- package/dist/io/xlsx/workbook-xml.js +60 -34
- package/dist/io/xlsx/worksheet-xml.d.ts +23 -70
- package/dist/io/xlsx/worksheet-xml.js +48 -229
- package/dist/io/xlsx/write-stream.d.ts +65 -16
- package/dist/io/xlsx/write-stream.js +50 -20
- package/dist/io/xlsx/write.d.ts +1 -2
- package/dist/io/xlsx/write.js +114 -74
- package/dist/rel-type.d.ts +16 -0
- package/dist/rel-type.js +6 -0
- package/dist/token-set.d.ts +13 -0
- package/dist/token-set.js +4 -1
- package/dist/vba/bytes.d.ts +14 -5
- package/dist/vba/bytes.js +16 -6
- package/dist/vba/cfb-format.d.ts +8 -0
- package/dist/vba/cfb-format.js +1 -0
- package/dist/vba/cfb-writer.d.ts +9 -0
- package/dist/vba/cfb-writer.js +12 -9
- package/dist/vba/cfb.d.ts +13 -1
- package/dist/vba/cfb.js +73 -51
- package/dist/vba/codepage.js +2 -1
- package/dist/vba/errors.d.ts +7 -0
- package/dist/vba/ms-ovba.js +51 -16
- package/dist/vba/project-editor.js +35 -40
- package/dist/vba/project.d.ts +11 -1
- package/dist/vba/project.js +27 -8
- package/dist/vba/vba-encoding.js +4 -5
- package/dist/xml/xml-attrs.d.ts +37 -0
- package/dist/xml/xml-attrs.js +30 -0
- package/dist/xml/xml-chars.d.ts +40 -0
- package/dist/xml/xml-chars.js +12 -0
- package/dist/xml/xml-namespaces.d.ts +31 -0
- package/dist/xml/xml-namespaces.js +50 -0
- package/dist/xml/xml-read.d.ts +72 -10
- package/dist/xml/xml-read.js +94 -18
- package/dist/xml/xml-scan.d.ts +15 -37
- package/dist/xml/xml-scan.js +12 -40
- package/dist/xml/xml.d.ts +28 -27
- package/dist/xml/xml.js +24 -24
- package/package.json +12 -7
- /package/dist/io/xlsx/{rich-runs.d.ts → read-rich-runs.d.ts} +0 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { isDataValidationErrorStyle, isDataValidationOperator, isDataValidationType, } from '../../core/data-validation.js';
|
|
2
|
+
import { stripFormulaEquals } from '../../core/formula.js';
|
|
2
3
|
import { decodeSqrefRects } from '../../core/merge.js';
|
|
4
|
+
import { coerceNumericLiteral } from '../../xml/xml-attrs.js';
|
|
3
5
|
import { TextCapture } from '../../xml/xml-read.js';
|
|
4
|
-
import { boolStrict,
|
|
5
|
-
import { checkedToken, escapeAttr, escapeText,
|
|
6
|
-
import { DATA_VALIDATION_EXT_URI, XM_NS } from './namespaces.js';
|
|
6
|
+
import { boolStrict, localName } from '../../xml/xml-scan.js';
|
|
7
|
+
import { checkedToken, escapeAttr, escapeText, textAttr } from '../../xml/xml.js';
|
|
8
|
+
import { DATA_VALIDATION_EXT_URI, isExtensionElement, isMainNamespaceElement, XM_NS, } from './namespaces.js';
|
|
9
|
+
import { admitting } from './read-repair.js';
|
|
7
10
|
import { x14Ext } from './x14-ext.js';
|
|
8
11
|
const TYPED = new Set(['whole', 'decimal', 'date', 'time', 'textLength']);
|
|
9
12
|
export function dataValidationsXml(entries) {
|
|
@@ -58,34 +61,30 @@ function extendedDataValidationXml(sqref, rule) {
|
|
|
58
61
|
`<xm:sqref>${escapeText(sqref)}</xm:sqref>`;
|
|
59
62
|
return `<x14:dataValidation${ruleAttrs(rule)}>${body}</x14:dataValidation>`;
|
|
60
63
|
}
|
|
64
|
+
const FORMULA_ELEMENTS = new Set(['formula1', 'formula2']);
|
|
61
65
|
export function dataValidationPass() {
|
|
62
66
|
const entries = [];
|
|
63
67
|
let current;
|
|
64
|
-
|
|
68
|
+
const formula = new TextCapture(FORMULA_ELEMENTS);
|
|
65
69
|
const handlers = {
|
|
66
|
-
onOpen(name, attrs) {
|
|
70
|
+
onOpen(name, attrs, selfClosing, scope) {
|
|
67
71
|
const ln = localName(name);
|
|
68
|
-
if (ln === 'dataValidation' &&
|
|
72
|
+
if (ln === 'dataValidation' && isMainNamespaceElement(scope, name)) {
|
|
69
73
|
current = { attrs, formulae: [] };
|
|
70
74
|
}
|
|
71
|
-
else if (current !== undefined
|
|
72
|
-
|
|
73
|
-
current.formulae[0] = '';
|
|
74
|
-
}
|
|
75
|
-
else if (current !== undefined && ln === 'formula2') {
|
|
76
|
-
slot = 1;
|
|
77
|
-
current.formulae[1] = '';
|
|
75
|
+
else if (current !== undefined) {
|
|
76
|
+
formula.open(ln, selfClosing);
|
|
78
77
|
}
|
|
79
78
|
},
|
|
80
79
|
onText(text) {
|
|
81
|
-
|
|
82
|
-
current.formulae[slot] = (current.formulae[slot] ?? '') + text;
|
|
83
|
-
}
|
|
80
|
+
formula.text(text);
|
|
84
81
|
},
|
|
85
82
|
onClose(name) {
|
|
86
83
|
const ln = localName(name);
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
const text = formula.close(ln);
|
|
85
|
+
if (text !== undefined) {
|
|
86
|
+
if (current !== undefined)
|
|
87
|
+
current.formulae[ln === 'formula1' ? 0 : 1] = text;
|
|
89
88
|
return;
|
|
90
89
|
}
|
|
91
90
|
if (ln === 'dataValidation' && current !== undefined) {
|
|
@@ -146,16 +145,16 @@ export function extendedDataValidationPass() {
|
|
|
146
145
|
let slot;
|
|
147
146
|
const capture = new TextCapture(['f', 'sqref']);
|
|
148
147
|
const handlers = {
|
|
149
|
-
onOpen(name, attrs, selfClosing) {
|
|
148
|
+
onOpen(name, attrs, selfClosing, scope) {
|
|
150
149
|
const ln = localName(name);
|
|
151
|
-
const
|
|
152
|
-
if (ln === 'dataValidation' &&
|
|
150
|
+
const extension = isExtensionElement(scope, name);
|
|
151
|
+
if (ln === 'dataValidation' && extension) {
|
|
153
152
|
current = { attrs, formulae: [], sqref: '' };
|
|
154
153
|
}
|
|
155
|
-
else if (current !== undefined &&
|
|
154
|
+
else if (current !== undefined && extension && ln === 'formula1') {
|
|
156
155
|
slot = 0;
|
|
157
156
|
}
|
|
158
|
-
else if (current !== undefined &&
|
|
157
|
+
else if (current !== undefined && extension && ln === 'formula2') {
|
|
159
158
|
slot = 1;
|
|
160
159
|
}
|
|
161
160
|
else if (current !== undefined) {
|
|
@@ -165,8 +164,9 @@ export function extendedDataValidationPass() {
|
|
|
165
164
|
onText(chunk) {
|
|
166
165
|
capture.text(chunk);
|
|
167
166
|
},
|
|
168
|
-
onClose(name) {
|
|
167
|
+
onClose(name, scope) {
|
|
169
168
|
const ln = localName(name);
|
|
169
|
+
const extension = isExtensionElement(scope, name);
|
|
170
170
|
const text = capture.close(ln);
|
|
171
171
|
if (text !== undefined) {
|
|
172
172
|
if (ln === 'f') {
|
|
@@ -177,10 +177,10 @@ export function extendedDataValidationPass() {
|
|
|
177
177
|
current.sqref = text;
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
|
-
else if ((ln === 'formula1' || ln === 'formula2') &&
|
|
180
|
+
else if ((ln === 'formula1' || ln === 'formula2') && extension) {
|
|
181
181
|
slot = undefined;
|
|
182
182
|
}
|
|
183
|
-
else if (ln === 'dataValidation' &&
|
|
183
|
+
else if (ln === 'dataValidation' && extension && current !== undefined) {
|
|
184
184
|
const built = buildExtendedEntry(current.attrs, current.formulae, current.sqref);
|
|
185
185
|
if (built !== undefined)
|
|
186
186
|
entries.push(built);
|
|
@@ -200,6 +200,8 @@ export function applyDataValidations(sheet, entries) {
|
|
|
200
200
|
for (const { sqref, rule, extended } of entries) {
|
|
201
201
|
if (decodeSqrefRects(sqref).length === 0)
|
|
202
202
|
continue;
|
|
203
|
-
|
|
203
|
+
admitting(() => {
|
|
204
|
+
sheet.addDataValidation(sqref, rule, extended ? { extended: true } : {});
|
|
205
|
+
});
|
|
204
206
|
}
|
|
205
207
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type VbaLibraryReference } from '../../vba/project-editor.ts';
|
|
2
|
+
import { type ReadPackageOptions } from '../opc/read-options.ts';
|
|
2
3
|
/**
|
|
3
4
|
* Remove a standard module from an existing macro-enabled package's VBA project, returning new package
|
|
4
5
|
* bytes. Every part but `xl/vbaProject.bin` is preserved byte-for-byte (see {@link removeVbaModule} for
|
|
@@ -8,8 +9,10 @@ import { type VbaLibraryReference } from '../../vba/project-editor.ts';
|
|
|
8
9
|
* @throws {VbaAuthorError} if the package carries no VBA project, `name` is not in the project, or names
|
|
9
10
|
* a `document`/`designer` module.
|
|
10
11
|
* @throws {VbaParseError} if the attached `vbaProject.bin` is malformed.
|
|
12
|
+
* @throws {PackageReadError} if the input is not a readable ZIP, or exceeds the inflate bound
|
|
13
|
+
* ({@link ReadPackageOptions.maxUncompressedBytes}, defaulting as `readXlsx` does).
|
|
11
14
|
*/
|
|
12
|
-
export declare function editXlsxVbaRemoveModule(xlsx: Uint8Array, name: string): Uint8Array;
|
|
15
|
+
export declare function editXlsxVbaRemoveModule(xlsx: Uint8Array, name: string, options?: ReadPackageOptions): Uint8Array;
|
|
13
16
|
/**
|
|
14
17
|
* Add a registered (COM type-library) reference to an existing macro-enabled package's VBA project,
|
|
15
18
|
* returning new package bytes. Every part but `xl/vbaProject.bin` is preserved byte-for-byte (see
|
|
@@ -19,5 +22,7 @@ export declare function editXlsxVbaRemoveModule(xlsx: Uint8Array, name: string):
|
|
|
19
22
|
* @throws {VbaAuthorError} if the package carries no VBA project, or any field of `ref` is invalid (see
|
|
20
23
|
* {@link VbaLibraryReference}).
|
|
21
24
|
* @throws {VbaParseError} if the attached `vbaProject.bin` is malformed.
|
|
25
|
+
* @throws {PackageReadError} if the input is not a readable ZIP, or exceeds the inflate bound
|
|
26
|
+
* ({@link ReadPackageOptions.maxUncompressedBytes}, defaulting as `readXlsx` does).
|
|
22
27
|
*/
|
|
23
|
-
export declare function editXlsxVbaAddReference(xlsx: Uint8Array, ref: VbaLibraryReference): Uint8Array;
|
|
28
|
+
export declare function editXlsxVbaAddReference(xlsx: Uint8Array, ref: VbaLibraryReference, options?: ReadPackageOptions): Uint8Array;
|
package/dist/io/xlsx/edit-vba.js
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import { strFromU8, strToU8,
|
|
1
|
+
import { strFromU8, strToU8, zipSync } from 'fflate';
|
|
2
2
|
import { VbaAuthorError } from '../../vba/errors.js';
|
|
3
3
|
import { addVbaReference, removeVbaModule, } from '../../vba/project-editor.js';
|
|
4
4
|
import { relsPathFor, resolveRelativePart } from '../opc/part-paths.js';
|
|
5
|
-
import { parseRelationshipRecords,
|
|
5
|
+
import { parseRelationshipRecords, readPartRelationships } from '../opc/read-opc.js';
|
|
6
|
+
import { DEFAULT_MAX_UNCOMPRESSED } from '../opc/read-options.js';
|
|
7
|
+
import { inflateSpreadsheetPackage } from '../opc/sniff-format.js';
|
|
6
8
|
import { FIXED_ENTRY_MTIME } from '../opc/zip-mtime.js';
|
|
7
9
|
const OFFICE_DOCUMENT_REL = 'officeDocument';
|
|
8
10
|
const VBA_PROJECT_REL = 'vbaProject';
|
|
9
11
|
const VBA_SIGNATURE_REL_INFIX = 'vbaProjectSignature';
|
|
10
|
-
export function editXlsxVbaRemoveModule(xlsx, name) {
|
|
11
|
-
return applyToVbaProjectPart(xlsx, (bin) => removeVbaModule(bin, name));
|
|
12
|
+
export function editXlsxVbaRemoveModule(xlsx, name, options = {}) {
|
|
13
|
+
return applyToVbaProjectPart(xlsx, options, (bin) => removeVbaModule(bin, name));
|
|
12
14
|
}
|
|
13
|
-
export function editXlsxVbaAddReference(xlsx, ref) {
|
|
14
|
-
return applyToVbaProjectPart(xlsx, (bin) => addVbaReference(bin, ref));
|
|
15
|
+
export function editXlsxVbaAddReference(xlsx, ref, options = {}) {
|
|
16
|
+
return applyToVbaProjectPart(xlsx, options, (bin) => addVbaReference(bin, ref));
|
|
15
17
|
}
|
|
16
|
-
function applyToVbaProjectPart(xlsx, apply) {
|
|
17
|
-
const files =
|
|
18
|
+
function applyToVbaProjectPart(xlsx, options, apply) {
|
|
19
|
+
const files = inflateSpreadsheetPackage(xlsx, options.maxUncompressedBytes ?? DEFAULT_MAX_UNCOMPRESSED);
|
|
18
20
|
const binPath = locateVbaProjectPart(files);
|
|
19
21
|
const bin = binPath === undefined ? undefined : files[binPath];
|
|
20
22
|
if (binPath === undefined || bin === undefined) {
|
|
@@ -25,20 +27,11 @@ function applyToVbaProjectPart(xlsx, apply) {
|
|
|
25
27
|
return zipSync(files, { mtime: FIXED_ENTRY_MTIME });
|
|
26
28
|
}
|
|
27
29
|
function locateVbaProjectPart(files) {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
+
const partText = (path) => textPart(files, path);
|
|
31
|
+
const workbookPath = readPartRelationships('', partText).targetPath(OFFICE_DOCUMENT_REL);
|
|
32
|
+
if (workbookPath === undefined)
|
|
30
33
|
return undefined;
|
|
31
|
-
|
|
32
|
-
if (workbookTarget === undefined)
|
|
33
|
-
return undefined;
|
|
34
|
-
const workbookPath = resolveRelativePart('', workbookTarget);
|
|
35
|
-
const workbookRels = textPart(files, relsPathFor(workbookPath));
|
|
36
|
-
if (workbookRels === undefined)
|
|
37
|
-
return undefined;
|
|
38
|
-
const vbaTarget = relationshipTargetByType(workbookRels, VBA_PROJECT_REL);
|
|
39
|
-
if (vbaTarget === undefined)
|
|
40
|
-
return undefined;
|
|
41
|
-
return resolveRelativePart(workbookPath, vbaTarget);
|
|
34
|
+
return readPartRelationships(workbookPath, partText).targetPath(VBA_PROJECT_REL);
|
|
42
35
|
}
|
|
43
36
|
function dropStaleSignature(files, binPath) {
|
|
44
37
|
const binRelsPath = relsPathFor(binPath);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Font } from '../../core/style.ts';
|
|
2
|
+
import { type XmlAttributes } from '../../xml/xml-scan.ts';
|
|
3
|
+
export type FontDraft = {
|
|
4
|
+
-readonly [K in keyof Font]?: Font[K];
|
|
5
|
+
};
|
|
6
|
+
export declare function applyFontChild(draft: FontDraft, local: string, attrs: XmlAttributes): void;
|
|
7
|
+
export declare function fontXml(font: Font, nameTag?: 'name' | 'rFont'): string;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { isFontScheme, isFontVerticalAlignment, isNamedUnderlineStyle, } from '../../core/style.js';
|
|
2
|
+
import { numFinite, numInteger } from '../../xml/xml-attrs.js';
|
|
3
|
+
import { boolPresent } from '../../xml/xml-scan.js';
|
|
4
|
+
import { checkedToken, escapeAttr, numberText } from '../../xml/xml.js';
|
|
5
|
+
import { colorAttrs, parseColor } from './color-xml.js';
|
|
6
|
+
export function applyFontChild(draft, local, attrs) {
|
|
7
|
+
switch (local) {
|
|
8
|
+
case 'b':
|
|
9
|
+
draft.bold = boolPresent(attrs.val);
|
|
10
|
+
break;
|
|
11
|
+
case 'i':
|
|
12
|
+
draft.italic = boolPresent(attrs.val);
|
|
13
|
+
break;
|
|
14
|
+
case 'strike':
|
|
15
|
+
draft.strike = boolPresent(attrs.val);
|
|
16
|
+
break;
|
|
17
|
+
case 'outline':
|
|
18
|
+
draft.outline = boolPresent(attrs.val);
|
|
19
|
+
break;
|
|
20
|
+
case 'u':
|
|
21
|
+
draft.underline =
|
|
22
|
+
attrs.val === undefined
|
|
23
|
+
? true
|
|
24
|
+
: attrs.val === 'none'
|
|
25
|
+
? false
|
|
26
|
+
: isNamedUnderlineStyle(attrs.val)
|
|
27
|
+
? attrs.val
|
|
28
|
+
: true;
|
|
29
|
+
break;
|
|
30
|
+
case 'vertAlign':
|
|
31
|
+
if (attrs.val !== undefined && isFontVerticalAlignment(attrs.val))
|
|
32
|
+
draft.vertAlign = attrs.val;
|
|
33
|
+
break;
|
|
34
|
+
case 'sz': {
|
|
35
|
+
const size = numFinite(attrs.val);
|
|
36
|
+
if (size !== undefined)
|
|
37
|
+
draft.size = size;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
case 'color':
|
|
41
|
+
draft.color = parseColor(attrs);
|
|
42
|
+
break;
|
|
43
|
+
case 'name':
|
|
44
|
+
case 'rFont':
|
|
45
|
+
if (attrs.val !== undefined)
|
|
46
|
+
draft.name = attrs.val;
|
|
47
|
+
break;
|
|
48
|
+
case 'family': {
|
|
49
|
+
const family = numInteger(attrs.val);
|
|
50
|
+
if (family !== undefined)
|
|
51
|
+
draft.family = family;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
case 'charset': {
|
|
55
|
+
const charset = numInteger(attrs.val);
|
|
56
|
+
if (charset !== undefined)
|
|
57
|
+
draft.charset = charset;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case 'scheme':
|
|
61
|
+
if (attrs.val !== undefined && isFontScheme(attrs.val))
|
|
62
|
+
draft.scheme = attrs.val;
|
|
63
|
+
break;
|
|
64
|
+
default:
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function fontXml(font, nameTag = 'name') {
|
|
69
|
+
const parts = [];
|
|
70
|
+
if (font.bold)
|
|
71
|
+
parts.push('<b/>');
|
|
72
|
+
if (font.italic)
|
|
73
|
+
parts.push('<i/>');
|
|
74
|
+
if (font.strike)
|
|
75
|
+
parts.push('<strike/>');
|
|
76
|
+
if (font.outline)
|
|
77
|
+
parts.push('<outline/>');
|
|
78
|
+
const underline = underlineXml(font.underline);
|
|
79
|
+
if (underline !== '')
|
|
80
|
+
parts.push(underline);
|
|
81
|
+
if (font.vertAlign !== undefined) {
|
|
82
|
+
parts.push(`<vertAlign val="${checkedToken(font.vertAlign, isFontVerticalAlignment, 'font vertical alignment')}"/>`);
|
|
83
|
+
}
|
|
84
|
+
if (font.size !== undefined)
|
|
85
|
+
parts.push(`<sz val="${numberText(font.size)}"/>`);
|
|
86
|
+
if (font.color !== undefined)
|
|
87
|
+
parts.push(`<color ${colorAttrs(font.color)}/>`);
|
|
88
|
+
if (font.name !== undefined)
|
|
89
|
+
parts.push(`<${nameTag} val="${escapeAttr(font.name)}"/>`);
|
|
90
|
+
if (font.family !== undefined)
|
|
91
|
+
parts.push(`<family val="${numberText(font.family)}"/>`);
|
|
92
|
+
if (font.charset !== undefined)
|
|
93
|
+
parts.push(`<charset val="${numberText(font.charset)}"/>`);
|
|
94
|
+
if (font.scheme !== undefined && font.scheme !== 'none')
|
|
95
|
+
parts.push(`<scheme val="${checkedToken(font.scheme, isFontScheme, 'font scheme')}"/>`);
|
|
96
|
+
return parts.join('');
|
|
97
|
+
}
|
|
98
|
+
function underlineXml(underline) {
|
|
99
|
+
if (underline === undefined || underline === false || underline === 'none')
|
|
100
|
+
return '';
|
|
101
|
+
if (underline === true || underline === 'single')
|
|
102
|
+
return '<u/>';
|
|
103
|
+
return `<u val="${checkedToken(underline, isNamedUnderlineStyle, 'underline style')}"/>`;
|
|
104
|
+
}
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
+
import type { Cell } from '../../core/cell.ts';
|
|
1
2
|
import type { Worksheet } from '../../core/worksheet.ts';
|
|
2
3
|
import { type CollectingPass } from '../../xml/xml-read.ts';
|
|
3
|
-
import type {
|
|
4
|
+
import type { RelIdAllocator } from './package-plan.ts';
|
|
4
5
|
/** A hyperlink gathered from a sheet for serialisation: the cell it sits on, its target, and an
|
|
5
|
-
* optional tooltip. The visible label is the cell's own value and is serialised as that value.
|
|
6
|
+
* optional tooltip. The visible label is the cell's own value and is serialised as that value.
|
|
7
|
+
*
|
|
8
|
+
* `row`/`col` are the anchor's position, kept so links gathered from separate passes (the sheet's live
|
|
9
|
+
* rows, and the rows the streaming writer already flushed and evicted) can be merged back into the
|
|
10
|
+
* row-major order Excel writes them in. They are not serialised; `ref` is.
|
|
11
|
+
*/
|
|
6
12
|
export interface CollectedHyperlink {
|
|
7
13
|
readonly ref: string;
|
|
14
|
+
readonly row: number;
|
|
15
|
+
readonly col: number;
|
|
8
16
|
readonly target: string;
|
|
9
17
|
readonly tooltip?: string;
|
|
10
18
|
}
|
|
@@ -18,12 +26,36 @@ export interface HyperlinkPlan {
|
|
|
18
26
|
readonly location?: string;
|
|
19
27
|
readonly tooltip?: string;
|
|
20
28
|
}
|
|
21
|
-
/**
|
|
22
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Gather every hyperlink among a run of cells.
|
|
31
|
+
*
|
|
32
|
+
* Takes the cells rather than the sheet, because the streaming writer has to ask this question of a
|
|
33
|
+
* row at the moment it commits: after that the row's cells are evicted, and a post-hoc walk of
|
|
34
|
+
* `sheet.rows()` finds nothing. Both writers therefore ask the same function, over whatever cells
|
|
35
|
+
* they still hold.
|
|
36
|
+
*/
|
|
37
|
+
export declare function collectHyperlinks(cells: Iterable<Cell>): CollectedHyperlink[];
|
|
38
|
+
/** Every cell a sheet still holds, row-major: the live half of what a writer must gather. */
|
|
39
|
+
export declare function liveCells(sheet: Worksheet): Generator<Cell, void, undefined>;
|
|
40
|
+
/** An external hyperlink: the two fields a `TargetMode="External"` relationship needs, both present. */
|
|
41
|
+
export type ExternalHyperlinkPlan = HyperlinkPlan & {
|
|
42
|
+
readonly relId: string;
|
|
43
|
+
readonly target: string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Whether a planned hyperlink is the external kind, narrowing it so the relationship writer reads
|
|
47
|
+
* `relId` and `target` as the strings they are.
|
|
48
|
+
*
|
|
49
|
+
* A predicate rather than a filter plus two casts: the filter already proved both fields present, and
|
|
50
|
+
* a cast repeating that proof one line later is a claim the compiler cannot check against the filter
|
|
51
|
+
* it is supposed to be echoing. `planHyperlinks` sets exactly one of `relId`/`location`, so testing
|
|
52
|
+
* either field is testing the kind.
|
|
53
|
+
*/
|
|
54
|
+
export declare function isExternalHyperlink(link: HyperlinkPlan): link is ExternalHyperlinkPlan;
|
|
23
55
|
/** Split collected links into internal (location, no rel) and external (relationship) forms, drawing
|
|
24
56
|
* each external link's relationship id from the sheet's allocator so external ids follow every other
|
|
25
57
|
* sheet-local relationship in canonical order. An internal ('#'-prefixed) link consumes no id. */
|
|
26
|
-
export declare function planHyperlinks(links: readonly CollectedHyperlink[], rels:
|
|
58
|
+
export declare function planHyperlinks(links: readonly CollectedHyperlink[], rels: RelIdAllocator): HyperlinkPlan[];
|
|
27
59
|
/** The `<hyperlinks>` element, or '' when the sheet has none. Attribute order follows CT_Hyperlink:
|
|
28
60
|
* `ref`, `r:id`, `location`, `tooltip`. */
|
|
29
61
|
export declare function hyperlinksXml(links: readonly HyperlinkPlan[]): string;
|
|
@@ -3,22 +3,30 @@ import { isHyperlinkValue, isRichTextValue } from '../../core/value.js';
|
|
|
3
3
|
import {} from '../../xml/xml-read.js';
|
|
4
4
|
import { localName } from '../../xml/xml-scan.js';
|
|
5
5
|
import { escapeAttr, textAttr } from '../../xml/xml.js';
|
|
6
|
-
|
|
6
|
+
import { relAttr } from '../opc/namespaces.js';
|
|
7
|
+
export function collectHyperlinks(cells) {
|
|
7
8
|
const links = [];
|
|
8
|
-
for (const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
})
|
|
17
|
-
}
|
|
9
|
+
for (const cell of cells) {
|
|
10
|
+
const value = cell.value;
|
|
11
|
+
if (isHyperlinkValue(value)) {
|
|
12
|
+
links.push({
|
|
13
|
+
ref: value.range ?? cell.address,
|
|
14
|
+
row: cell.row,
|
|
15
|
+
col: cell.col,
|
|
16
|
+
target: value.hyperlink,
|
|
17
|
+
...(value.tooltip !== undefined ? { tooltip: value.tooltip } : {}),
|
|
18
|
+
});
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
return links;
|
|
21
22
|
}
|
|
23
|
+
export function* liveCells(sheet) {
|
|
24
|
+
for (const { cells } of sheet.rows())
|
|
25
|
+
yield* cells;
|
|
26
|
+
}
|
|
27
|
+
export function isExternalHyperlink(link) {
|
|
28
|
+
return link.relId !== undefined && link.target !== undefined;
|
|
29
|
+
}
|
|
22
30
|
export function planHyperlinks(links, rels) {
|
|
23
31
|
return links.map((link) => {
|
|
24
32
|
const tooltip = link.tooltip !== undefined ? { tooltip: link.tooltip } : {};
|
|
@@ -45,15 +53,16 @@ export function sheetHyperlinkPass() {
|
|
|
45
53
|
const links = [];
|
|
46
54
|
return {
|
|
47
55
|
handlers: {
|
|
48
|
-
onOpen(name, attrs) {
|
|
56
|
+
onOpen(name, attrs, _selfClosing, scope) {
|
|
49
57
|
if (localName(name) !== 'hyperlink')
|
|
50
58
|
return;
|
|
51
59
|
const ref = attrs.ref;
|
|
52
60
|
if (ref === undefined)
|
|
53
61
|
return;
|
|
62
|
+
const rid = relAttr(scope, attrs, 'id');
|
|
54
63
|
links.push({
|
|
55
64
|
ref,
|
|
56
|
-
...(
|
|
65
|
+
...(rid !== undefined ? { rid } : {}),
|
|
57
66
|
...(attrs.location !== undefined ? { location: attrs.location } : {}),
|
|
58
67
|
...(attrs.tooltip !== undefined ? { tooltip: attrs.tooltip } : {}),
|
|
59
68
|
});
|
package/dist/io/xlsx/images.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { isImageEditAs, isOneCellAnchor, } from '../../core/image.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { enumToken, numFinite } from '../../xml/xml-attrs.js';
|
|
3
|
+
import { openElements, parseXml, TextCapture } from '../../xml/xml-read.js';
|
|
4
|
+
import { localName } from '../../xml/xml-scan.js';
|
|
4
5
|
import { checkedToken, numAttr, numberText, XML_DECLARATION } from '../../xml/xml.js';
|
|
5
|
-
import { RELATIONSHIPS_NS } from '../opc/namespaces.js';
|
|
6
|
+
import { relAttr, RELATIONSHIPS_NS } from '../opc/namespaces.js';
|
|
6
7
|
import { relationship, relationshipsPart } from '../opc/rels.js';
|
|
7
8
|
import { DRAWINGML_NS, XDR_NS } from './namespaces.js';
|
|
8
9
|
const IMAGE_REL_TYPE = `${RELATIONSHIPS_NS}/image`;
|
|
@@ -85,7 +86,7 @@ export function parseDrawing(xml) {
|
|
|
85
86
|
let picDepth = 0;
|
|
86
87
|
const coord = new TextCapture(COORDINATES);
|
|
87
88
|
parseXml(xml, {
|
|
88
|
-
onOpen(name, attrs, selfClosing) {
|
|
89
|
+
onOpen(name, attrs, selfClosing, scope) {
|
|
89
90
|
const local = localName(name);
|
|
90
91
|
if (local === 'twoCellAnchor' || local === 'oneCellAnchor') {
|
|
91
92
|
from = blankPoint();
|
|
@@ -116,7 +117,7 @@ export function parseDrawing(xml) {
|
|
|
116
117
|
ext = { cx, cy };
|
|
117
118
|
}
|
|
118
119
|
else if (local === 'blip') {
|
|
119
|
-
const value = attrs
|
|
120
|
+
const value = relAttr(scope, attrs, 'embed');
|
|
120
121
|
if (value !== undefined)
|
|
121
122
|
embed = value;
|
|
122
123
|
}
|
|
@@ -162,14 +163,11 @@ export function parseDrawing(xml) {
|
|
|
162
163
|
}
|
|
163
164
|
const UNMODELED_DRAWING_CONTENT = new Set(['graphicFrame', 'sp', 'cxnSp', 'grpSp']);
|
|
164
165
|
export function drawingHasUnmodeledContent(xml) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
},
|
|
171
|
-
});
|
|
172
|
-
return found;
|
|
166
|
+
for (const { local } of openElements(xml)) {
|
|
167
|
+
if (UNMODELED_DRAWING_CONTENT.has(local))
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
return false;
|
|
173
171
|
}
|
|
174
172
|
const COORDINATES = new Set(['col', 'colOff', 'row', 'rowOff']);
|
|
175
173
|
function setCoordinate(point, coord, value) {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* The package-level URIs (`.rels`, content types, the relationship vocabulary) describe the
|
|
10
10
|
* container rather than the spreadsheet inside it, and live in `../opc/namespaces.ts`.
|
|
11
11
|
*/
|
|
12
|
+
import type { NamespaceScope } from '../../xml/xml-namespaces.ts';
|
|
12
13
|
/**
|
|
13
14
|
* SpreadsheetML main namespace: the default `xmlns` of the workbook,
|
|
14
15
|
* worksheet, styles, sharedStrings, comments, table and pivot parts.
|
|
@@ -53,3 +54,18 @@ export declare const DATABAR_LINK_EXT_URI = "{B025F937-C7B1-47D3-B67F-A62EFF666E
|
|
|
53
54
|
export declare const DATA_VALIDATION_EXT_URI = "{CCE6A557-97BC-4b89-ADB6-D9C93CAAB3DF}";
|
|
54
55
|
export declare const SLICER_LIST_EXT_URI = "{A8765BA9-456A-4dab-B4F3-ACF838C121DE}";
|
|
55
56
|
export declare const SLICER_CACHES_EXT_URI = "{BBE1A952-AA13-448e-AADC-164F8A28A991}";
|
|
57
|
+
/**
|
|
58
|
+
* Whether an element belongs to the standard SpreadsheetML vocabulary rather than to an extension.
|
|
59
|
+
*
|
|
60
|
+
* This used to be spelled `!name.includes(':')`, on the assumption that only extension elements carry
|
|
61
|
+
* a prefix. A worksheet may bind the *main* namespace to a prefix instead, which is legal and which
|
|
62
|
+
* real toolchains emit, and then every element has a colon in it: such a file had every one of its
|
|
63
|
+
* data validations and conditional formats read as an unknown extension and dropped, silently.
|
|
64
|
+
*
|
|
65
|
+
* An unprefixed element counts even when the part declares no default namespace. A part with no
|
|
66
|
+
* `xmlns` at all is not conforming OOXML, but this scanner does not reject it, such parts were read
|
|
67
|
+
* before, and a fix that gains files by resolving namespaces should not lose files that have none.
|
|
68
|
+
*/
|
|
69
|
+
export declare function isMainNamespaceElement(scope: NamespaceScope, name: string): boolean;
|
|
70
|
+
/** The complement of {@link isMainNamespaceElement}: an element of one of the extension vocabularies. */
|
|
71
|
+
export declare function isExtensionElement(scope: NamespaceScope, name: string): boolean;
|
|
@@ -11,3 +11,10 @@ export const DATABAR_LINK_EXT_URI = '{B025F937-C7B1-47D3-B67F-A62EFF666E3E}';
|
|
|
11
11
|
export const DATA_VALIDATION_EXT_URI = '{CCE6A557-97BC-4b89-ADB6-D9C93CAAB3DF}';
|
|
12
12
|
export const SLICER_LIST_EXT_URI = '{A8765BA9-456A-4dab-B4F3-ACF838C121DE}';
|
|
13
13
|
export const SLICER_CACHES_EXT_URI = '{BBE1A952-AA13-448e-AADC-164F8A28A991}';
|
|
14
|
+
export function isMainNamespaceElement(scope, name) {
|
|
15
|
+
const namespace = scope.elementNamespace(name);
|
|
16
|
+
return namespace === SPREADSHEETML_NS || (namespace === undefined && !name.includes(':'));
|
|
17
|
+
}
|
|
18
|
+
export function isExtensionElement(scope, name) {
|
|
19
|
+
return !isMainNamespaceElement(scope, name);
|
|
20
|
+
}
|
|
@@ -5,8 +5,9 @@ import type { Table } from '../../core/table.ts';
|
|
|
5
5
|
import type { Workbook } from '../../core/workbook.ts';
|
|
6
6
|
import type { Worksheet } from '../../core/worksheet.ts';
|
|
7
7
|
import type { CommentCell } from './comments.ts';
|
|
8
|
+
import type { HyperlinkPlan } from './hyperlinks.ts';
|
|
8
9
|
import type { DrawingImage } from './images.ts';
|
|
9
|
-
export declare class
|
|
10
|
+
export declare class RelIdAllocator {
|
|
10
11
|
#private;
|
|
11
12
|
/** The next relationship id (`rId1`, `rId2`, …), advancing the counter. */
|
|
12
13
|
next(): string;
|
|
@@ -108,4 +109,15 @@ export interface MediaPlan {
|
|
|
108
109
|
resolve(id: number): ResolvedMedia;
|
|
109
110
|
}
|
|
110
111
|
export declare function planMedia(workbook: Workbook, sheets: readonly Worksheet[]): MediaPlan;
|
|
111
|
-
export declare function planPreservedParts(workbook: Workbook, generatedDrawingCount: number, generatedMediaCount: number): PreservedPlan;
|
|
112
|
+
export declare function planPreservedParts(workbook: Workbook, generatedDrawingCount: number, generatedMediaCount: number, generatedPivotCount: number): PreservedPlan;
|
|
113
|
+
export interface SheetPlan {
|
|
114
|
+
readonly tables: TablePlan[];
|
|
115
|
+
readonly drawing: DrawingPlan | null;
|
|
116
|
+
readonly comments: CommentPlan | null;
|
|
117
|
+
readonly threadedComments: ThreadedCommentPlan | null;
|
|
118
|
+
readonly printerSettings: PrinterSettingsPlan | null;
|
|
119
|
+
readonly hyperlinks: HyperlinkPlan[];
|
|
120
|
+
readonly background: BackgroundPlan | null;
|
|
121
|
+
readonly preservedRefs: PreservedReferencePlan[];
|
|
122
|
+
readonly pivots: PivotPlan[];
|
|
123
|
+
}
|