@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
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ConditionalFormatting } from '../../core/conditional-formatting.ts';
|
|
2
|
+
import { type CollectingPass } from '../../xml/xml-read.ts';
|
|
2
3
|
import type { StyleRegistry } from './styles.ts';
|
|
3
4
|
/**
|
|
4
5
|
* Serialise every conditional formatting on a sheet into its `<conditionalFormatting>` blocks, in
|
|
@@ -15,14 +16,14 @@ export declare function conditionalFormattingsXml(formattings: readonly Conditio
|
|
|
15
16
|
*/
|
|
16
17
|
export declare function conditionalFormattingsExtXml(formattings: readonly ConditionalFormatting[]): string;
|
|
17
18
|
/**
|
|
18
|
-
*
|
|
19
|
+
* A pass reading a worksheet's conditional formatting into the model. The classic `<conditionalFormatting>`
|
|
19
20
|
* blocks supply every rule; the x14 extension (`<x14:conditionalFormatting>` inside `<extLst>`) is
|
|
20
21
|
* read only to enrich a classic data bar with the facets the classic element cannot carry (the
|
|
21
22
|
* gradient flag and the negative-fill and axis colours) matched by the shared id the two ends link
|
|
22
23
|
* on. An extension rule with no classic counterpart (a rule that lives only in x14) is ignored, so it
|
|
23
24
|
* is never half-read into a broken classic rule.
|
|
24
25
|
*/
|
|
25
|
-
export declare function
|
|
26
|
+
export declare function conditionalFormattingPass(): CollectingPass<ConditionalFormatting[]>;
|
|
26
27
|
/**
|
|
27
28
|
* Extract the differential-style (`<dxf>`) fragments from styles.xml, each verbatim. Preserving the
|
|
28
29
|
* raw XML, rather than reparsing and re-serialising, is what keeps a foreign dxf's number format a
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { isCfValueObjectType, isConditionalFormattingOperator, isConditionalFormattingType, isIconSetType, isCfTimePeriod, } from '../../core/conditional-formatting.js';
|
|
2
|
+
import { elementSubtrees, TextCapture, } from '../../xml/xml-read.js';
|
|
3
|
+
import { boolPresent, boolStrict, coerceNumericLiteral, enumToken, localName, numFinite, numInteger, } from '../../xml/xml-scan.js';
|
|
4
|
+
import { boolAttr, checkedToken, escapeAttr, escapeText, numberText, stripFormulaEquals, textAttr, } from '../../xml/xml.js';
|
|
3
5
|
import { colorAttrs, parseColor } from './color-xml.js';
|
|
4
6
|
import { CF_EXT_URI, DATABAR_LINK_EXT_URI, XM_NS } from './namespaces.js';
|
|
5
7
|
import { x14Ext } from './x14-ext.js';
|
|
@@ -61,7 +63,7 @@ function x14DataBarXml(ref, rule, guid) {
|
|
|
61
63
|
`</x14:cfRule><xm:sqref>${escapeText(ref)}</xm:sqref></x14:conditionalFormatting>`);
|
|
62
64
|
}
|
|
63
65
|
function x14CfvoXml(cfvo) {
|
|
64
|
-
const type =
|
|
66
|
+
const type = checkedToken(cfvo.type, isCfValueObjectType, 'conditional format value type');
|
|
65
67
|
if (cfvo.value === undefined)
|
|
66
68
|
return `<x14:cfvo type="${type}"/>`;
|
|
67
69
|
return `<x14:cfvo type="${type}"><xm:f>${escapeText(String(cfvo.value))}</xm:f></x14:cfvo>`;
|
|
@@ -71,12 +73,16 @@ function cfRuleExtLinkXml(guid) {
|
|
|
71
73
|
}
|
|
72
74
|
function blockXml(cf, styles, priority, extLinks) {
|
|
73
75
|
const rules = cf.rules.map((rule) => ruleXml(rule, styles, priority, extLinks)).join('');
|
|
76
|
+
if (rules === '')
|
|
77
|
+
return '';
|
|
74
78
|
return `<conditionalFormatting sqref="${escapeAttr(cf.ref)}">${rules}</conditionalFormatting>`;
|
|
75
79
|
}
|
|
76
80
|
function ruleXml(rule, styles, priority, extLinks) {
|
|
77
81
|
const p = rule.priority ?? priority.next;
|
|
78
82
|
priority.next = Math.max(priority.next, p) + 1;
|
|
79
|
-
const attrs = [
|
|
83
|
+
const attrs = [
|
|
84
|
+
`type="${checkedToken(rule.type, isConditionalFormattingType, 'conditional formatting type')}"`,
|
|
85
|
+
];
|
|
80
86
|
const dxfId = resolveDxfId(rule, styles);
|
|
81
87
|
if (dxfId !== undefined)
|
|
82
88
|
attrs.push(`dxfId="${dxfId}"`);
|
|
@@ -91,16 +97,18 @@ function ruleXml(rule, styles, priority, extLinks) {
|
|
|
91
97
|
attrs.push('bottom="1"');
|
|
92
98
|
if (rule.percent)
|
|
93
99
|
attrs.push('percent="1"');
|
|
94
|
-
if (rule.operator !== undefined)
|
|
95
|
-
attrs.push(`operator="${
|
|
100
|
+
if (rule.operator !== undefined) {
|
|
101
|
+
attrs.push(`operator="${checkedToken(rule.operator, isConditionalFormattingOperator, 'conditional formatting operator')}"`);
|
|
102
|
+
}
|
|
96
103
|
if (rule.text !== undefined)
|
|
97
104
|
attrs.push(`text="${escapeAttr(rule.text)}"`);
|
|
98
|
-
if (rule.timePeriod !== undefined)
|
|
99
|
-
attrs.push(`timePeriod="${
|
|
105
|
+
if (rule.timePeriod !== undefined) {
|
|
106
|
+
attrs.push(`timePeriod="${checkedToken(rule.timePeriod, isCfTimePeriod, 'time period')}"`);
|
|
107
|
+
}
|
|
100
108
|
if (rule.rank !== undefined)
|
|
101
|
-
attrs.push(`rank="${rule.rank}"`);
|
|
109
|
+
attrs.push(`rank="${numberText(rule.rank)}"`);
|
|
102
110
|
if (rule.stdDev !== undefined)
|
|
103
|
-
attrs.push(`stdDev="${rule.stdDev}"`);
|
|
111
|
+
attrs.push(`stdDev="${numberText(rule.stdDev)}"`);
|
|
104
112
|
let body = SCALE_TYPES.has(rule.type) ? scaleXml(rule) : formulaeXml(rule.formulae);
|
|
105
113
|
const extGuid = extLinks.get(rule);
|
|
106
114
|
if (extGuid !== undefined)
|
|
@@ -112,8 +120,9 @@ function ruleXml(rule, styles, priority, extLinks) {
|
|
|
112
120
|
function resolveDxfId(rule, styles) {
|
|
113
121
|
if (SCALE_TYPES.has(rule.type))
|
|
114
122
|
return undefined;
|
|
115
|
-
|
|
116
|
-
|
|
123
|
+
const preserved = dxfIndex(rule.dxfId);
|
|
124
|
+
if (preserved !== undefined)
|
|
125
|
+
return preserved;
|
|
117
126
|
if (rule.style !== undefined)
|
|
118
127
|
return styles.differentialStyleId(rule.style);
|
|
119
128
|
return undefined;
|
|
@@ -142,34 +151,34 @@ function colorScaleXml(rule) {
|
|
|
142
151
|
return `<colorScale>${anchors}${colors}</colorScale>`;
|
|
143
152
|
}
|
|
144
153
|
function iconSetXml(rule) {
|
|
145
|
-
const name = rule.iconSet
|
|
154
|
+
const name = rule.iconSet === undefined
|
|
155
|
+
? ''
|
|
156
|
+
: ` iconSet="${checkedToken(rule.iconSet, isIconSetType, 'icon set')}"`;
|
|
146
157
|
const anchors = (rule.cfvo ?? []).map(cfvoXml).join('');
|
|
147
158
|
return `<iconSet${name}>${anchors}</iconSet>`;
|
|
148
159
|
}
|
|
149
160
|
function cfvoXml(cfvo) {
|
|
150
|
-
const
|
|
151
|
-
|
|
161
|
+
const type = checkedToken(cfvo.type, isCfValueObjectType, 'conditional format value type');
|
|
162
|
+
const val = cfvo.value === undefined ? '' : textAttr('val', String(cfvo.value));
|
|
163
|
+
return `<cfvo type="${type}"${val}/>`;
|
|
152
164
|
}
|
|
153
|
-
export function
|
|
165
|
+
export function conditionalFormattingPass() {
|
|
154
166
|
const blocks = [];
|
|
155
167
|
let block;
|
|
156
168
|
let draft;
|
|
157
169
|
let scale;
|
|
158
|
-
|
|
159
|
-
let formulaText = '';
|
|
170
|
+
const formulaCapture = new TextCapture('formula');
|
|
160
171
|
const linked = [];
|
|
161
172
|
const extById = new Map();
|
|
162
173
|
let x14Ext;
|
|
163
174
|
let x14ExtId;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
parseXml(xml, {
|
|
175
|
+
const x14IdCapture = new TextCapture('id');
|
|
176
|
+
const handlers = {
|
|
167
177
|
onOpen(name, attrs, selfClosing) {
|
|
168
178
|
const ln = localName(name);
|
|
169
179
|
if (name.includes(':')) {
|
|
170
180
|
if (ln === 'id' && draft !== undefined) {
|
|
171
|
-
|
|
172
|
-
x14IdText = '';
|
|
181
|
+
x14IdCapture.open(ln, selfClosing);
|
|
173
182
|
}
|
|
174
183
|
else if (ln === 'cfRule') {
|
|
175
184
|
x14Ext = attrs.type === 'dataBar' && attrs.id !== undefined ? emptyExt() : undefined;
|
|
@@ -191,7 +200,9 @@ export function parseConditionalFormattings(xml) {
|
|
|
191
200
|
}
|
|
192
201
|
else if (ln === 'cfRule' && block !== undefined) {
|
|
193
202
|
if (selfClosing) {
|
|
194
|
-
|
|
203
|
+
const rule = finalizeRule(newDraft(attrs));
|
|
204
|
+
if (rule !== undefined)
|
|
205
|
+
block.rules.push(rule);
|
|
195
206
|
}
|
|
196
207
|
else {
|
|
197
208
|
draft = newDraft(attrs);
|
|
@@ -201,8 +212,8 @@ export function parseConditionalFormattings(xml) {
|
|
|
201
212
|
else if (draft !== undefined &&
|
|
202
213
|
(ln === 'dataBar' || ln === 'colorScale' || ln === 'iconSet')) {
|
|
203
214
|
scale = ln;
|
|
204
|
-
if (ln === 'iconSet'
|
|
205
|
-
draft.iconSet = attrs.iconSet;
|
|
215
|
+
if (ln === 'iconSet')
|
|
216
|
+
draft.iconSet = enumToken(attrs.iconSet, isIconSetType);
|
|
206
217
|
}
|
|
207
218
|
else if (draft !== undefined && ln === 'cfvo') {
|
|
208
219
|
draft.cfvo.push(parseCfvo(attrs));
|
|
@@ -215,23 +226,20 @@ export function parseConditionalFormattings(xml) {
|
|
|
215
226
|
draft.colors.push(color);
|
|
216
227
|
}
|
|
217
228
|
else if (draft !== undefined && ln === 'formula') {
|
|
218
|
-
|
|
219
|
-
formulaText = '';
|
|
229
|
+
formulaCapture.open(ln, selfClosing);
|
|
220
230
|
}
|
|
221
231
|
},
|
|
222
232
|
onText(chunk) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (capturingX14Id)
|
|
226
|
-
x14IdText += chunk;
|
|
233
|
+
formulaCapture.text(chunk);
|
|
234
|
+
x14IdCapture.text(chunk);
|
|
227
235
|
},
|
|
228
236
|
onClose(name) {
|
|
229
237
|
const ln = localName(name);
|
|
230
238
|
if (name.includes(':')) {
|
|
231
|
-
|
|
239
|
+
const id = x14IdCapture.close(ln);
|
|
240
|
+
if (id !== undefined) {
|
|
232
241
|
if (draft !== undefined)
|
|
233
|
-
draft.x14Id =
|
|
234
|
-
capturingX14Id = false;
|
|
242
|
+
draft.x14Id = id;
|
|
235
243
|
}
|
|
236
244
|
else if (ln === 'cfRule' && x14Ext !== undefined && x14ExtId !== undefined) {
|
|
237
245
|
extById.set(x14ExtId, x14Ext);
|
|
@@ -240,20 +248,22 @@ export function parseConditionalFormattings(xml) {
|
|
|
240
248
|
}
|
|
241
249
|
return;
|
|
242
250
|
}
|
|
243
|
-
|
|
251
|
+
const formula = formulaCapture.close(ln);
|
|
252
|
+
if (formula !== undefined) {
|
|
244
253
|
if (draft !== undefined)
|
|
245
|
-
draft.formulae.push(coerceNumericLiteral(
|
|
246
|
-
capturingFormula = false;
|
|
254
|
+
draft.formulae.push(coerceNumericLiteral(formula));
|
|
247
255
|
}
|
|
248
256
|
else if (ln === 'dataBar' || ln === 'colorScale' || ln === 'iconSet') {
|
|
249
257
|
scale = undefined;
|
|
250
258
|
}
|
|
251
259
|
else if (ln === 'cfRule' && draft !== undefined) {
|
|
252
260
|
const rule = finalizeRule(draft);
|
|
253
|
-
if (
|
|
254
|
-
block
|
|
255
|
-
|
|
256
|
-
|
|
261
|
+
if (rule !== undefined) {
|
|
262
|
+
if (block !== undefined)
|
|
263
|
+
block.rules.push(rule);
|
|
264
|
+
if (draft.x14Id !== undefined)
|
|
265
|
+
linked.push({ rule, id: draft.x14Id });
|
|
266
|
+
}
|
|
257
267
|
draft = undefined;
|
|
258
268
|
}
|
|
259
269
|
else if (ln === 'conditionalFormatting' && block !== undefined) {
|
|
@@ -261,38 +271,38 @@ export function parseConditionalFormattings(xml) {
|
|
|
261
271
|
block = undefined;
|
|
262
272
|
}
|
|
263
273
|
},
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
274
|
+
};
|
|
275
|
+
const result = () => {
|
|
276
|
+
for (const { rule, id } of linked) {
|
|
277
|
+
const ext = extById.get(id);
|
|
278
|
+
if (ext === undefined)
|
|
279
|
+
continue;
|
|
280
|
+
if (ext.gradient !== undefined)
|
|
281
|
+
rule.gradient = ext.gradient;
|
|
282
|
+
if (ext.negativeFillColor !== undefined)
|
|
283
|
+
rule.negativeFillColor = ext.negativeFillColor;
|
|
284
|
+
if (ext.axisColor !== undefined)
|
|
285
|
+
rule.axisColor = ext.axisColor;
|
|
286
|
+
}
|
|
287
|
+
return blocks;
|
|
288
|
+
};
|
|
289
|
+
return { handlers, result };
|
|
277
290
|
}
|
|
278
291
|
function emptyExt() {
|
|
279
292
|
return { gradient: undefined, negativeFillColor: undefined, axisColor: undefined };
|
|
280
293
|
}
|
|
281
294
|
export function parseDxfs(stylesXml) {
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
return [];
|
|
285
|
-
const inner = block[1] ?? '';
|
|
286
|
-
return [...inner.matchAll(/<dxf\b[^>]*>[\s\S]*?<\/dxf>|<dxf\b[^>]*\/>/g)].map((m) => m[0] ?? '');
|
|
295
|
+
const { fragments } = elementSubtrees(stylesXml, new Map([['dxfs', 'dxf']]));
|
|
296
|
+
return [...(fragments.get('dxfs') ?? [])];
|
|
287
297
|
}
|
|
288
298
|
function newDraft(attrs) {
|
|
289
299
|
return {
|
|
290
|
-
type: attrs.type
|
|
300
|
+
type: enumToken(attrs.type, isConditionalFormattingType),
|
|
291
301
|
priority: numFinite(attrs.priority),
|
|
292
302
|
stopIfTrue: boolStrict(attrs.stopIfTrue),
|
|
293
|
-
operator: attrs.operator,
|
|
303
|
+
operator: enumToken(attrs.operator, isConditionalFormattingOperator),
|
|
294
304
|
text: attrs.text,
|
|
295
|
-
timePeriod: attrs.timePeriod,
|
|
305
|
+
timePeriod: enumToken(attrs.timePeriod, isCfTimePeriod),
|
|
296
306
|
rank: numFinite(attrs.rank),
|
|
297
307
|
stdDev: numFinite(attrs.stdDev),
|
|
298
308
|
percent: boolStrict(attrs.percent),
|
|
@@ -308,10 +318,15 @@ function newDraft(attrs) {
|
|
|
308
318
|
x14Id: undefined,
|
|
309
319
|
};
|
|
310
320
|
}
|
|
321
|
+
function dxfIndex(value) {
|
|
322
|
+
return numInteger(value, 0);
|
|
323
|
+
}
|
|
311
324
|
function parseIndexAttr(value) {
|
|
312
|
-
return
|
|
325
|
+
return dxfIndex(value) === undefined ? undefined : value;
|
|
313
326
|
}
|
|
314
327
|
function finalizeRule(draft) {
|
|
328
|
+
if (draft.type === undefined)
|
|
329
|
+
return undefined;
|
|
315
330
|
const rule = { type: draft.type };
|
|
316
331
|
if (draft.priority !== undefined)
|
|
317
332
|
rule.priority = draft.priority;
|
|
@@ -350,7 +365,8 @@ function finalizeRule(draft) {
|
|
|
350
365
|
return rule;
|
|
351
366
|
}
|
|
352
367
|
function parseCfvo(attrs) {
|
|
353
|
-
const
|
|
368
|
+
const raw = attrs.type;
|
|
369
|
+
const type = raw !== undefined && isCfValueObjectType(raw) ? raw : 'num';
|
|
354
370
|
const cfvo = { type };
|
|
355
371
|
if (attrs.val !== undefined) {
|
|
356
372
|
cfvo.value = type === 'formula' ? attrs.val : coerceNumericLiteral(attrs.val);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type DataValidationEntry } from '../../core/data-validation.ts';
|
|
2
2
|
import type { Worksheet } from '../../core/worksheet.ts';
|
|
3
|
+
import { type CollectingPass } from '../../xml/xml-read.ts';
|
|
3
4
|
/** The standard `<dataValidations>` element for the rules stored in the legacy form, or '' when the
|
|
4
5
|
* sheet has none of them, so a sheet with only extended (or no) validations stays byte-clean here.
|
|
5
6
|
* The extended rules are emitted separately by {@link dataValidationsExtXml}. */
|
|
@@ -8,13 +9,14 @@ export declare function dataValidationsXml(entries: readonly DataValidationEntry
|
|
|
8
9
|
* none. Emitted bare (no `<extLst>` wrapper) so the worksheet serialiser can gather it into a single
|
|
9
10
|
* `<extLst>` beside the conditional-formatting extension: a worksheet may carry at most one. */
|
|
10
11
|
export declare function dataValidationsExtXml(entries: readonly DataValidationEntry[]): string;
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
|
|
12
|
+
/** A pass gathering the standard `<dataValidation>` elements of a worksheet part, for a caller
|
|
13
|
+
* reading the part alongside its other readers in one parse. */
|
|
14
|
+
export declare function dataValidationPass(): CollectingPass<DataValidationEntry[]>;
|
|
15
|
+
/** A pass gathering the extended `<x14:dataValidation>` elements of a worksheet's `<extLst>`, so a
|
|
16
|
+
* cross-sheet or whole-column list validation Excel stored only in the 2009 extension form is read
|
|
17
|
+
* back rather than dropped. The standard pass ignores these (they are prefixed); this one,
|
|
18
|
+
* symmetrically, handles only the prefixed elements. */
|
|
19
|
+
export declare function extendedDataValidationPass(): CollectingPass<DataValidationEntry[]>;
|
|
18
20
|
/** Fold parsed validations onto a sheet, each bound to its original range and carrying its form: an
|
|
19
21
|
* `extended` entry is re-attached as extended so a round-trip writes it back to the x14 block. */
|
|
20
22
|
export declare function applyDataValidations(sheet: Worksheet, entries: readonly DataValidationEntry[]): void;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { isDataValidationErrorStyle, isDataValidationOperator, isDataValidationType, } from '../../core/data-validation.js';
|
|
2
|
+
import { decodeSqrefRects } from '../../core/merge.js';
|
|
3
|
+
import { TextCapture } from '../../xml/xml-read.js';
|
|
4
|
+
import { boolStrict, coerceNumericLiteral, localName } from '../../xml/xml-scan.js';
|
|
5
|
+
import { checkedToken, escapeAttr, escapeText, stripFormulaEquals, textAttr } from '../../xml/xml.js';
|
|
3
6
|
import { DATA_VALIDATION_EXT_URI, XM_NS } from './namespaces.js';
|
|
4
7
|
import { x14Ext } from './x14-ext.js';
|
|
5
8
|
const TYPED = new Set(['whole', 'decimal', 'date', 'time', 'textLength']);
|
|
@@ -18,16 +21,20 @@ export function dataValidationsExtXml(entries) {
|
|
|
18
21
|
return x14Ext(DATA_VALIDATION_EXT_URI, `<x14:dataValidations count="${extended.length}" xmlns:xm="${XM_NS}">${items}</x14:dataValidations>`);
|
|
19
22
|
}
|
|
20
23
|
function ruleAttrs(rule) {
|
|
21
|
-
return (` type="${rule.type}"` +
|
|
22
|
-
(rule.errorStyle
|
|
23
|
-
|
|
24
|
+
return (` type="${checkedToken(rule.type, isDataValidationType, 'data validation type')}"` +
|
|
25
|
+
(rule.errorStyle === undefined
|
|
26
|
+
? ''
|
|
27
|
+
: ` errorStyle="${checkedToken(rule.errorStyle, isDataValidationErrorStyle, 'data validation error style')}"`) +
|
|
28
|
+
(rule.operator === undefined
|
|
29
|
+
? ''
|
|
30
|
+
: ` operator="${checkedToken(rule.operator, isDataValidationOperator, 'data validation operator')}"`) +
|
|
24
31
|
(rule.allowBlank ? ' allowBlank="1"' : '') +
|
|
25
32
|
(rule.showInputMessage ? ' showInputMessage="1"' : '') +
|
|
26
33
|
(rule.showErrorMessage ? ' showErrorMessage="1"' : '') +
|
|
27
|
-
(
|
|
28
|
-
(
|
|
29
|
-
(
|
|
30
|
-
(
|
|
34
|
+
textAttr('errorTitle', rule.errorTitle) +
|
|
35
|
+
textAttr('error', rule.error) +
|
|
36
|
+
textAttr('promptTitle', rule.promptTitle) +
|
|
37
|
+
textAttr('prompt', rule.prompt));
|
|
31
38
|
}
|
|
32
39
|
function dataValidationXml(sqref, rule) {
|
|
33
40
|
const [f1, f2] = operands(rule);
|
|
@@ -51,11 +58,11 @@ function extendedDataValidationXml(sqref, rule) {
|
|
|
51
58
|
`<xm:sqref>${escapeText(sqref)}</xm:sqref>`;
|
|
52
59
|
return `<x14:dataValidation${ruleAttrs(rule)}>${body}</x14:dataValidation>`;
|
|
53
60
|
}
|
|
54
|
-
export function
|
|
61
|
+
export function dataValidationPass() {
|
|
55
62
|
const entries = [];
|
|
56
63
|
let current;
|
|
57
64
|
let slot;
|
|
58
|
-
|
|
65
|
+
const handlers = {
|
|
59
66
|
onOpen(name, attrs) {
|
|
60
67
|
const ln = localName(name);
|
|
61
68
|
if (ln === 'dataValidation' && !name.includes(':')) {
|
|
@@ -88,8 +95,8 @@ export function parseDataValidations(xml) {
|
|
|
88
95
|
current = undefined;
|
|
89
96
|
}
|
|
90
97
|
},
|
|
91
|
-
}
|
|
92
|
-
return entries;
|
|
98
|
+
};
|
|
99
|
+
return { handlers, result: () => entries };
|
|
93
100
|
}
|
|
94
101
|
function buildEntry(attrs, formulae) {
|
|
95
102
|
const { sqref } = attrs;
|
|
@@ -100,11 +107,12 @@ function buildEntry(attrs, formulae) {
|
|
|
100
107
|
}
|
|
101
108
|
function buildRule(attrs, formulae) {
|
|
102
109
|
const { type } = attrs;
|
|
103
|
-
if (type === undefined)
|
|
110
|
+
if (type === undefined || !isDataValidationType(type))
|
|
104
111
|
return undefined;
|
|
105
|
-
const rule = { type
|
|
112
|
+
const rule = { type };
|
|
106
113
|
if (attrs.operator !== undefined) {
|
|
107
|
-
|
|
114
|
+
if (isDataValidationOperator(attrs.operator))
|
|
115
|
+
rule.operator = attrs.operator;
|
|
108
116
|
}
|
|
109
117
|
else if (TYPED.has(type)) {
|
|
110
118
|
rule.operator = 'between';
|
|
@@ -115,7 +123,7 @@ function buildRule(attrs, formulae) {
|
|
|
115
123
|
rule.showInputMessage = true;
|
|
116
124
|
if (boolStrict(attrs.showErrorMessage))
|
|
117
125
|
rule.showErrorMessage = true;
|
|
118
|
-
if (attrs.errorStyle !== undefined)
|
|
126
|
+
if (attrs.errorStyle !== undefined && isDataValidationErrorStyle(attrs.errorStyle))
|
|
119
127
|
rule.errorStyle = attrs.errorStyle;
|
|
120
128
|
if (attrs.error !== undefined)
|
|
121
129
|
rule.error = attrs.error;
|
|
@@ -132,14 +140,13 @@ function buildRule(attrs, formulae) {
|
|
|
132
140
|
rule.formulae = parsed;
|
|
133
141
|
return rule;
|
|
134
142
|
}
|
|
135
|
-
export function
|
|
143
|
+
export function extendedDataValidationPass() {
|
|
136
144
|
const entries = [];
|
|
137
145
|
let current;
|
|
138
146
|
let slot;
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
onOpen(name, attrs) {
|
|
147
|
+
const capture = new TextCapture(['f', 'sqref']);
|
|
148
|
+
const handlers = {
|
|
149
|
+
onOpen(name, attrs, selfClosing) {
|
|
143
150
|
const ln = localName(name);
|
|
144
151
|
const prefixed = name.includes(':');
|
|
145
152
|
if (ln === 'dataValidation' && prefixed) {
|
|
@@ -151,30 +158,24 @@ export function parseExtendedDataValidations(xml) {
|
|
|
151
158
|
else if (current !== undefined && prefixed && ln === 'formula2') {
|
|
152
159
|
slot = 1;
|
|
153
160
|
}
|
|
154
|
-
else if (current !== undefined
|
|
155
|
-
capture
|
|
156
|
-
text = '';
|
|
157
|
-
}
|
|
158
|
-
else if (current !== undefined && ln === 'sqref') {
|
|
159
|
-
capture = 'sqref';
|
|
160
|
-
text = '';
|
|
161
|
+
else if (current !== undefined) {
|
|
162
|
+
capture.open(ln, selfClosing);
|
|
161
163
|
}
|
|
162
164
|
},
|
|
163
165
|
onText(chunk) {
|
|
164
|
-
|
|
165
|
-
text += chunk;
|
|
166
|
+
capture.text(chunk);
|
|
166
167
|
},
|
|
167
168
|
onClose(name) {
|
|
168
169
|
const ln = localName(name);
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
if (current !== undefined)
|
|
170
|
+
const text = capture.close(ln);
|
|
171
|
+
if (text !== undefined) {
|
|
172
|
+
if (ln === 'f') {
|
|
173
|
+
if (current !== undefined && slot !== undefined)
|
|
174
|
+
current.formulae[slot] = text;
|
|
175
|
+
}
|
|
176
|
+
else if (current !== undefined) {
|
|
176
177
|
current.sqref = text;
|
|
177
|
-
|
|
178
|
+
}
|
|
178
179
|
}
|
|
179
180
|
else if ((ln === 'formula1' || ln === 'formula2') && name.includes(':')) {
|
|
180
181
|
slot = undefined;
|
|
@@ -186,8 +187,8 @@ export function parseExtendedDataValidations(xml) {
|
|
|
186
187
|
current = undefined;
|
|
187
188
|
}
|
|
188
189
|
},
|
|
189
|
-
}
|
|
190
|
-
return entries;
|
|
190
|
+
};
|
|
191
|
+
return { handlers, result: () => entries };
|
|
191
192
|
}
|
|
192
193
|
function buildExtendedEntry(attrs, formulae, sqref) {
|
|
193
194
|
if (sqref === '')
|
|
@@ -197,6 +198,8 @@ function buildExtendedEntry(attrs, formulae, sqref) {
|
|
|
197
198
|
}
|
|
198
199
|
export function applyDataValidations(sheet, entries) {
|
|
199
200
|
for (const { sqref, rule, extended } of entries) {
|
|
201
|
+
if (decodeSqrefRects(sqref).length === 0)
|
|
202
|
+
continue;
|
|
200
203
|
sheet.addDataValidation(sqref, rule, extended ? { extended: true } : {});
|
|
201
204
|
}
|
|
202
205
|
}
|
package/dist/io/xlsx/edit-vba.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { strFromU8, strToU8, unzipSync, zipSync } from 'fflate';
|
|
2
2
|
import { VbaAuthorError } from '../../vba/errors.js';
|
|
3
3
|
import { addVbaReference, removeVbaModule, } from '../../vba/project-editor.js';
|
|
4
|
-
import { relsPathFor } from '../opc/part-paths.js';
|
|
5
|
-
import { parseRelationshipRecords, relationshipTargetByType
|
|
4
|
+
import { relsPathFor, resolveRelativePart } from '../opc/part-paths.js';
|
|
5
|
+
import { parseRelationshipRecords, relationshipTargetByType } from '../opc/read-opc.js';
|
|
6
6
|
import { FIXED_ENTRY_MTIME } from '../opc/zip-mtime.js';
|
|
7
7
|
const OFFICE_DOCUMENT_REL = 'officeDocument';
|
|
8
8
|
const VBA_PROJECT_REL = 'vbaProject';
|
|
@@ -14,7 +14,7 @@ export function editXlsxVbaAddReference(xlsx, ref) {
|
|
|
14
14
|
return applyToVbaProjectPart(xlsx, (bin) => addVbaReference(bin, ref));
|
|
15
15
|
}
|
|
16
16
|
function applyToVbaProjectPart(xlsx, apply) {
|
|
17
|
-
const files = unzipSync(xlsx);
|
|
17
|
+
const files = Object.assign(Object.create(null), unzipSync(xlsx));
|
|
18
18
|
const binPath = locateVbaProjectPart(files);
|
|
19
19
|
const bin = binPath === undefined ? undefined : files[binPath];
|
|
20
20
|
if (binPath === undefined || bin === undefined) {
|
|
@@ -38,14 +38,7 @@ function locateVbaProjectPart(files) {
|
|
|
38
38
|
const vbaTarget = relationshipTargetByType(workbookRels, VBA_PROJECT_REL);
|
|
39
39
|
if (vbaTarget === undefined)
|
|
40
40
|
return undefined;
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
function resolveVbaTarget(workbookPath, target) {
|
|
44
|
-
if (target.startsWith('/'))
|
|
45
|
-
return target.slice(1);
|
|
46
|
-
if (workbookPath.startsWith('xl/'))
|
|
47
|
-
return resolveWorkbookPart(target);
|
|
48
|
-
return resolveRelativePart(workbookPath, target);
|
|
41
|
+
return resolveRelativePart(workbookPath, vbaTarget);
|
|
49
42
|
}
|
|
50
43
|
function dropStaleSignature(files, binPath) {
|
|
51
44
|
const binRelsPath = relsPathFor(binPath);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Worksheet } from '../../core/worksheet.ts';
|
|
2
|
+
import { type CollectingPass } from '../../xml/xml-read.ts';
|
|
2
3
|
import type { SheetRelIds } from './package-plan.ts';
|
|
3
4
|
/** A hyperlink gathered from a sheet for serialisation: the cell it sits on, its target, and an
|
|
4
5
|
* optional tooltip. The visible label is the cell's own value and is serialised as that value. */
|
|
@@ -34,8 +35,9 @@ interface ParsedHyperlink {
|
|
|
34
35
|
readonly location?: string;
|
|
35
36
|
readonly tooltip?: string;
|
|
36
37
|
}
|
|
37
|
-
/**
|
|
38
|
-
|
|
38
|
+
/** A pass gathering every `<hyperlink>` element of a worksheet part, for a caller reading the part
|
|
39
|
+
* alongside its other readers in one parse. */
|
|
40
|
+
export declare function sheetHyperlinkPass(): CollectingPass<ParsedHyperlink[]>;
|
|
39
41
|
/** Fold parsed hyperlinks onto a sheet's cells, wrapping each cell's existing value (its visible
|
|
40
42
|
* label) into a {@link HyperlinkValue}. `targetOf` resolves a relationship id to its raw Target: a
|
|
41
43
|
* URL for the external links hyperlinks almost always are, so it must stay unresolved against the
|