@shbernal/ts-xlsx 3.0.0 → 3.2.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 +34 -24
- package/dist/bytes.d.ts +10 -2
- package/dist/bytes.js +22 -0
- package/dist/core/address.d.ts +96 -2
- package/dist/core/address.js +87 -33
- package/dist/core/array-formula-ranges.d.ts +33 -0
- package/dist/core/array-formula-ranges.js +62 -0
- 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 +4 -6
- package/dist/core/column.d.ts +1 -0
- package/dist/core/column.js +6 -2
- package/dist/core/comment-thread.d.ts +7 -3
- package/dist/core/comment-thread.js +2 -1
- package/dist/core/conditional-formatting-overlay.d.ts +11 -1
- package/dist/core/conditional-formatting-overlay.js +30 -3
- package/dist/core/conditional-formatting.d.ts +107 -11
- package/dist/core/conditional-formatting.js +76 -19
- package/dist/core/containers.d.ts +12 -0
- package/dist/core/containers.js +5 -0
- package/dist/core/data-validation-overlay.d.ts +7 -1
- package/dist/core/data-validation-overlay.js +19 -4
- package/dist/core/data-validation.d.ts +22 -0
- package/dist/core/data-validation.js +30 -4
- package/dist/core/date-format.d.ts +20 -0
- package/dist/core/date-format.js +170 -0
- package/dist/core/date.d.ts +43 -8
- package/dist/core/date.js +19 -3
- package/dist/core/formula-references.d.ts +26 -0
- package/dist/core/formula-references.js +173 -0
- package/dist/core/formula-scan.d.ts +2 -0
- package/dist/core/formula-scan.js +58 -0
- package/dist/core/formula.d.ts +76 -17
- package/dist/core/formula.js +87 -80
- package/dist/core/function-values.d.ts +4 -0
- package/dist/core/function-values.js +58 -0
- package/dist/core/future-functions.d.ts +3 -0
- package/dist/core/{modern-functions.js → future-functions.js} +119 -88
- package/dist/core/grid-edits.d.ts +30 -3
- package/dist/core/grid-edits.js +248 -81
- package/dist/core/grid-shift.d.ts +58 -9
- package/dist/core/grid-shift.js +26 -4
- package/dist/core/hyperlink.d.ts +39 -0
- package/dist/core/hyperlink.js +88 -0
- package/dist/core/image.d.ts +49 -14
- package/dist/core/image.js +16 -5
- package/dist/core/internal.d.ts +10 -2
- package/dist/core/limits.d.ts +25 -0
- package/dist/core/limits.js +4 -0
- package/dist/core/merge.d.ts +18 -4
- package/dist/core/merge.js +33 -20
- package/dist/core/page-setup.d.ts +26 -11
- package/dist/core/pivot-table.d.ts +49 -10
- package/dist/core/pivot-table.js +112 -60
- package/dist/core/protection.d.ts +66 -4
- package/dist/core/protection.js +6 -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 +6 -2
- package/dist/core/structured-reference.d.ts +7 -0
- package/dist/core/structured-reference.js +7 -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 +64 -16
- package/dist/core/table.js +87 -40
- package/dist/core/theme.d.ts +2 -0
- package/dist/core/theme.js +9 -5
- package/dist/core/value.d.ts +60 -28
- package/dist/core/value.js +48 -43
- package/dist/core/workbook-media.d.ts +34 -0
- package/dist/core/workbook-media.js +44 -0
- package/dist/core/workbook-styles.d.ts +83 -1
- package/dist/core/workbook-styles.js +4 -0
- package/dist/core/workbook-theme.js +5 -3
- package/dist/core/workbook-vba.js +3 -2
- package/dist/core/workbook.d.ts +41 -3
- package/dist/core/workbook.js +46 -41
- package/dist/core/worksheet-comments.d.ts +2 -1
- package/dist/core/worksheet-comments.js +20 -13
- package/dist/core/worksheet-merges.d.ts +49 -0
- package/dist/core/worksheet-merges.js +65 -0
- package/dist/core/worksheet-model.d.ts +10 -2
- package/dist/core/worksheet-model.js +28 -9
- package/dist/core/worksheet-pictures.d.ts +3 -3
- package/dist/core/worksheet-pictures.js +7 -6
- package/dist/core/worksheet.d.ts +165 -27
- package/dist/core/worksheet.js +206 -89
- package/dist/customui/ribbon.js +2 -1
- package/dist/entries/core.d.ts +21 -14
- package/dist/entries/core.js +14 -7
- package/dist/entries/errors.d.ts +1 -0
- package/dist/entries/errors.js +1 -0
- 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/cell-metadata/metadata.d.ts +42 -0
- package/dist/io/cell-metadata/metadata.js +35 -0
- package/dist/io/cell-metadata/rich-values.d.ts +11 -0
- package/dist/io/cell-metadata/rich-values.js +80 -0
- package/dist/io/csv/delimiter.d.ts +21 -0
- package/dist/io/csv/delimiter.js +18 -0
- package/dist/io/csv/errors.d.ts +14 -0
- package/dist/io/csv/errors.js +5 -0
- package/dist/io/csv/read.d.ts +6 -1
- package/dist/io/csv/read.js +51 -22
- package/dist/io/csv/write.d.ts +19 -5
- package/dist/io/csv/write.js +24 -44
- 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 +5 -5
- package/dist/io/opc/read-opc.d.ts +58 -14
- package/dist/io/opc/read-opc.js +49 -21
- 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/opc/strict-relationships.d.ts +2 -0
- package/dist/io/opc/strict-relationships.js +12 -0
- package/dist/io/read-policy/column-budget.d.ts +26 -0
- package/dist/io/read-policy/column-budget.js +18 -0
- package/dist/io/read-policy/read-repair.d.ts +74 -0
- package/dist/io/read-policy/read-repair.js +119 -0
- package/dist/io/style/cell-style-resolution.d.ts +25 -0
- package/dist/io/style/cell-style-resolution.js +30 -0
- 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 +52 -35
- 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 +495 -596
- package/dist/io/xlsb/read-metadata.d.ts +7 -0
- package/dist/io/xlsb/read-metadata.js +69 -0
- package/dist/io/xlsb/read-styles.js +45 -81
- package/dist/io/xlsb/read-worksheet.d.ts +26 -1
- package/dist/io/xlsb/read-worksheet.js +148 -106
- package/dist/io/xlsb/read.d.ts +6 -3
- package/dist/io/xlsb/read.js +70 -31
- 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 +14 -5
- package/dist/io/xlsb/record-types.js +14 -5
- package/dist/io/xlsb/sheet-protection.d.ts +20 -0
- package/dist/io/xlsb/sheet-protection.js +60 -0
- package/dist/io/xlsx/cell-accumulator.d.ts +24 -9
- package/dist/io/xlsx/cell-accumulator.js +74 -21
- package/dist/io/xlsx/cell-metadata.d.ts +39 -0
- package/dist/io/xlsx/cell-metadata.js +162 -0
- package/dist/io/xlsx/cell-value.d.ts +19 -5
- package/dist/io/xlsx/cell-value.js +45 -30
- package/dist/io/xlsx/color-xml.js +3 -2
- package/dist/io/xlsx/column-span.d.ts +11 -0
- package/dist/io/xlsx/column-span.js +9 -0
- package/dist/io/xlsx/comments.d.ts +9 -30
- package/dist/io/xlsx/comments.js +25 -83
- package/dist/io/xlsx/conditional-formatting.d.ts +43 -23
- package/dist/io/xlsx/conditional-formatting.js +437 -138
- package/dist/io/xlsx/data-validation.d.ts +12 -7
- package/dist/io/xlsx/data-validation.js +67 -53
- package/dist/io/xlsx/edit-vba.d.ts +7 -2
- package/dist/io/xlsx/edit-vba.js +52 -52
- 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 +19 -21
- package/dist/io/xlsx/hyperlinks.js +12 -32
- package/dist/io/xlsx/images.d.ts +49 -16
- package/dist/io/xlsx/images.js +149 -50
- package/dist/io/xlsx/namespaces.d.ts +24 -0
- package/dist/io/xlsx/namespaces.js +11 -0
- package/dist/io/xlsx/package-plan.d.ts +60 -15
- package/dist/io/xlsx/package-plan.js +83 -18
- package/dist/io/xlsx/part-names.d.ts +6 -8
- package/dist/io/xlsx/part-names.js +3 -7
- package/dist/io/xlsx/pivot.d.ts +5 -5
- package/dist/io/xlsx/pivot.js +26 -24
- package/dist/io/xlsx/preserved-splices.d.ts +6 -0
- package/dist/io/xlsx/preserved-splices.js +74 -0
- package/dist/io/xlsx/read-comments.d.ts +29 -0
- package/dist/io/xlsx/read-comments.js +75 -0
- package/dist/io/xlsx/read-parts.d.ts +59 -0
- package/dist/io/xlsx/read-parts.js +259 -0
- package/dist/io/xlsx/read-pivot.js +11 -4
- package/dist/io/xlsx/{rich-runs.d.ts → read-rich-runs.d.ts} +8 -5
- package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +24 -4
- package/dist/io/xlsx/read-rows.d.ts +35 -11
- package/dist/io/xlsx/read-rows.js +73 -49
- package/dist/io/xlsx/read-shared-strings.js +3 -2
- package/dist/io/xlsx/read-styles.d.ts +0 -30
- package/dist/io/xlsx/read-styles.js +45 -105
- package/dist/io/xlsx/read-workbook-xml.d.ts +42 -0
- package/dist/io/xlsx/read-workbook-xml.js +175 -0
- package/dist/io/xlsx/read-worksheet.d.ts +9 -3
- package/dist/io/xlsx/read-worksheet.js +70 -177
- package/dist/io/xlsx/read.d.ts +3 -14
- package/dist/io/xlsx/read.js +74 -411
- package/dist/io/xlsx/relationships.d.ts +3 -0
- package/dist/io/xlsx/relationships.js +4 -0
- package/dist/io/xlsx/rich-text.js +1 -1
- package/dist/io/xlsx/row-position.d.ts +20 -0
- package/dist/io/xlsx/row-position.js +11 -0
- package/dist/io/xlsx/row-xml.d.ts +139 -0
- package/dist/io/xlsx/row-xml.js +222 -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 +182 -20
- package/dist/io/xlsx/strict-parts.d.ts +7 -0
- package/dist/io/xlsx/strict-parts.js +171 -0
- package/dist/io/xlsx/style-elements.d.ts +41 -0
- package/dist/io/xlsx/style-elements.js +136 -0
- package/dist/io/xlsx/styles.d.ts +17 -3
- package/dist/io/xlsx/styles.js +13 -209
- package/dist/io/xlsx/tables.d.ts +10 -2
- package/dist/io/xlsx/tables.js +55 -52
- package/dist/io/xlsx/theme-xml.d.ts +32 -4
- package/dist/io/xlsx/theme-xml.js +106 -71
- package/dist/io/xlsx/threaded-comments.d.ts +14 -11
- package/dist/io/xlsx/threaded-comments.js +16 -8
- package/dist/io/xlsx/workbook-xml.d.ts +45 -6
- package/dist/io/xlsx/workbook-xml.js +62 -54
- package/dist/io/xlsx/worksheet-xml.d.ts +26 -70
- package/dist/io/xlsx/worksheet-xml.js +69 -282
- package/dist/io/xlsx/write-stream.d.ts +90 -19
- package/dist/io/xlsx/write-stream.js +80 -25
- package/dist/io/xlsx/write.d.ts +12 -6
- package/dist/io/xlsx/write.js +226 -123
- package/dist/rel-type.d.ts +25 -0
- package/dist/rel-type.js +9 -0
- package/dist/token-set.d.ts +13 -0
- package/dist/token-set.js +4 -1
- package/dist/vba/bytes.d.ts +16 -5
- package/dist/vba/bytes.js +27 -6
- package/dist/vba/cfb-format.d.ts +55 -0
- package/dist/vba/cfb-format.js +35 -0
- package/dist/vba/cfb-writer.d.ts +8 -0
- package/dist/vba/cfb-writer.js +40 -40
- package/dist/vba/cfb.d.ts +21 -4
- package/dist/vba/cfb.js +124 -90
- package/dist/vba/codepage.js +2 -1
- package/dist/vba/dir-records.d.ts +6 -0
- package/dist/vba/dir-records.js +10 -2
- package/dist/vba/errors.d.ts +11 -4
- package/dist/vba/index.d.ts +0 -2
- package/dist/vba/index.js +0 -2
- package/dist/vba/ms-ovba.d.ts +6 -2
- package/dist/vba/ms-ovba.js +66 -22
- package/dist/vba/project-editor.js +129 -119
- package/dist/vba/project.d.ts +15 -1
- package/dist/vba/project.js +38 -13
- package/dist/vba/vba-encoding.d.ts +4 -10
- package/dist/vba/vba-encoding.js +3 -17
- 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 +101 -11
- package/dist/xml/xml-read.js +150 -18
- package/dist/xml/xml-scan.d.ts +25 -34
- package/dist/xml/xml-scan.js +69 -46
- package/dist/xml/xml.d.ts +59 -26
- package/dist/xml/xml.js +45 -23
- package/package.json +15 -9
- package/skills/ts-xlsx-upstream/SKILL.md +21 -13
- package/dist/core/modern-functions.d.ts +0 -1
package/dist/xml/xml-read.js
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { XmlParseError } from './errors.js';
|
|
2
|
+
import { NamespaceScope } from './xml-namespaces.js';
|
|
2
3
|
import { localName, markupAt, parseAttributes, tagAt, xmlEvents, } from './xml-scan.js';
|
|
3
|
-
|
|
4
|
-
const fragments = new Map();
|
|
5
|
-
const attributes = new Map();
|
|
6
|
-
const finished = new Set();
|
|
7
|
-
let container;
|
|
8
|
-
let capture;
|
|
4
|
+
function* rawTags(source) {
|
|
9
5
|
const length = source.length;
|
|
10
6
|
let i = 0;
|
|
11
7
|
while (i < length) {
|
|
@@ -18,7 +14,17 @@ export function elementSubtrees(source, selection) {
|
|
|
18
14
|
continue;
|
|
19
15
|
}
|
|
20
16
|
const tag = tagAt(source, lt);
|
|
21
|
-
|
|
17
|
+
i = tag.next;
|
|
18
|
+
yield { lt, tag, local: localName(tag.name) };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function elementSubtrees(source, selection) {
|
|
22
|
+
const fragments = new Map();
|
|
23
|
+
const attributes = new Map();
|
|
24
|
+
const finished = new Set();
|
|
25
|
+
let container;
|
|
26
|
+
let capture;
|
|
27
|
+
for (const { lt, tag, local } of rawTags(source)) {
|
|
22
28
|
if (tag.close) {
|
|
23
29
|
if (capture !== undefined && local === capture.local) {
|
|
24
30
|
if (capture.depth > 0)
|
|
@@ -36,7 +42,6 @@ export function elementSubtrees(source, selection) {
|
|
|
36
42
|
container = undefined;
|
|
37
43
|
}
|
|
38
44
|
}
|
|
39
|
-
i = tag.next;
|
|
40
45
|
continue;
|
|
41
46
|
}
|
|
42
47
|
const { selfClosing } = tag;
|
|
@@ -66,22 +71,140 @@ export function elementSubtrees(source, selection) {
|
|
|
66
71
|
}
|
|
67
72
|
}
|
|
68
73
|
}
|
|
69
|
-
i = tag.next;
|
|
70
74
|
}
|
|
71
75
|
if (capture !== undefined) {
|
|
72
76
|
throw new XmlParseError(`unterminated <${capture.local}> element`);
|
|
73
77
|
}
|
|
74
78
|
return { fragments, attributes };
|
|
75
79
|
}
|
|
80
|
+
export function elementRange(source, path) {
|
|
81
|
+
const open = [];
|
|
82
|
+
let pending;
|
|
83
|
+
for (const { lt, tag, local } of rawTags(source)) {
|
|
84
|
+
if (tag.close) {
|
|
85
|
+
const innermost = open.at(-1);
|
|
86
|
+
if (innermost !== undefined && innermost.local === local) {
|
|
87
|
+
if (innermost.depth > 0)
|
|
88
|
+
innermost.depth -= 1;
|
|
89
|
+
else {
|
|
90
|
+
open.pop();
|
|
91
|
+
if (pending !== undefined && open.length === path.length - 1) {
|
|
92
|
+
return { ...pending, end: tag.next, contentEnd: lt };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (pending === undefined && local === path[open.length]) {
|
|
99
|
+
const last = open.length === path.length - 1;
|
|
100
|
+
if (last) {
|
|
101
|
+
if (tag.selfClosing) {
|
|
102
|
+
return {
|
|
103
|
+
start: lt,
|
|
104
|
+
end: tag.next,
|
|
105
|
+
contentStart: tag.next,
|
|
106
|
+
contentEnd: tag.next,
|
|
107
|
+
name: tag.name,
|
|
108
|
+
attrs: parseAttributes(tag.attrSource),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
pending = {
|
|
112
|
+
start: lt,
|
|
113
|
+
contentStart: tag.next,
|
|
114
|
+
name: tag.name,
|
|
115
|
+
attrs: parseAttributes(tag.attrSource),
|
|
116
|
+
};
|
|
117
|
+
open.push({ local, depth: 0 });
|
|
118
|
+
}
|
|
119
|
+
else if (!tag.selfClosing) {
|
|
120
|
+
open.push({ local, depth: 0 });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
const innermost = open.at(-1);
|
|
125
|
+
if (innermost !== undefined && !tag.selfClosing && innermost.local === local) {
|
|
126
|
+
innermost.depth += 1;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (pending !== undefined) {
|
|
131
|
+
throw new XmlParseError(`unterminated <${pending.name}> element`);
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
const NO_ATTRIBUTES = Object.freeze(Object.create(null));
|
|
136
|
+
export function* tagRanges(source) {
|
|
137
|
+
for (const { lt, tag } of rawTags(source)) {
|
|
138
|
+
yield {
|
|
139
|
+
start: lt,
|
|
140
|
+
end: tag.next,
|
|
141
|
+
name: tag.name,
|
|
142
|
+
attrs: tag.close ? NO_ATTRIBUTES : parseAttributes(tag.attrSource),
|
|
143
|
+
close: tag.close,
|
|
144
|
+
selfClosing: tag.selfClosing,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export function* elementRanges(source, local) {
|
|
149
|
+
let pending;
|
|
150
|
+
let depth = 0;
|
|
151
|
+
for (const { lt, tag, local: tagLocal } of rawTags(source)) {
|
|
152
|
+
if (tagLocal !== local)
|
|
153
|
+
continue;
|
|
154
|
+
if (pending !== undefined) {
|
|
155
|
+
if (tag.close) {
|
|
156
|
+
if (depth > 0)
|
|
157
|
+
depth -= 1;
|
|
158
|
+
else {
|
|
159
|
+
const open = pending;
|
|
160
|
+
pending = undefined;
|
|
161
|
+
yield { ...open, end: tag.next, contentEnd: lt };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else if (!tag.selfClosing) {
|
|
165
|
+
depth += 1;
|
|
166
|
+
}
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (tag.close)
|
|
170
|
+
continue;
|
|
171
|
+
const attrs = parseAttributes(tag.attrSource);
|
|
172
|
+
if (tag.selfClosing) {
|
|
173
|
+
yield {
|
|
174
|
+
start: lt,
|
|
175
|
+
end: tag.next,
|
|
176
|
+
contentStart: tag.next,
|
|
177
|
+
contentEnd: tag.next,
|
|
178
|
+
name: tag.name,
|
|
179
|
+
attrs,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
pending = { start: lt, contentStart: tag.next, name: tag.name, attrs };
|
|
184
|
+
depth = 0;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (pending !== undefined) {
|
|
188
|
+
throw new XmlParseError(`unterminated <${pending.name}> element`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
76
191
|
export function* openElements(source, ...localNames) {
|
|
77
192
|
const filter = localNames.length > 0 ? new Set(localNames) : undefined;
|
|
193
|
+
const scope = new NamespaceScope();
|
|
78
194
|
for (const event of xmlEvents(source)) {
|
|
195
|
+
if (event.kind === 'close') {
|
|
196
|
+
scope.close();
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
79
199
|
if (event.kind !== 'open')
|
|
80
200
|
continue;
|
|
201
|
+
scope.open(event.attrs);
|
|
81
202
|
const local = localName(event.name);
|
|
82
|
-
if (filter
|
|
83
|
-
|
|
84
|
-
|
|
203
|
+
if (filter === undefined || filter.has(local)) {
|
|
204
|
+
yield { name: event.name, local, attrs: event.attrs, scope };
|
|
205
|
+
}
|
|
206
|
+
if (event.selfClosing)
|
|
207
|
+
scope.close();
|
|
85
208
|
}
|
|
86
209
|
}
|
|
87
210
|
export function* closeEmptyElements(events, names) {
|
|
@@ -103,17 +226,17 @@ export function parseXmlPasses(source, passes) {
|
|
|
103
226
|
}
|
|
104
227
|
const handlers = passes.map((pass) => pass.handlers);
|
|
105
228
|
parseXml(source, {
|
|
106
|
-
onOpen(name, attrs, selfClosing) {
|
|
229
|
+
onOpen(name, attrs, selfClosing, scope) {
|
|
107
230
|
for (const handler of handlers)
|
|
108
|
-
handler.onOpen(name, attrs, selfClosing);
|
|
231
|
+
handler.onOpen(name, attrs, selfClosing, scope);
|
|
109
232
|
},
|
|
110
233
|
onText(text) {
|
|
111
234
|
for (const handler of handlers)
|
|
112
235
|
handler.onText?.(text);
|
|
113
236
|
},
|
|
114
|
-
onClose(name) {
|
|
237
|
+
onClose(name, scope) {
|
|
115
238
|
for (const handler of handlers)
|
|
116
|
-
handler.onClose?.(name);
|
|
239
|
+
handler.onClose?.(name, scope);
|
|
117
240
|
},
|
|
118
241
|
}, expanded.size > 0 ? { closeEmptyElements: expanded } : undefined);
|
|
119
242
|
}
|
|
@@ -121,16 +244,21 @@ export function parseXml(source, handlers, options) {
|
|
|
121
244
|
const events = options?.closeEmptyElements
|
|
122
245
|
? closeEmptyElements(xmlEvents(source), options.closeEmptyElements)
|
|
123
246
|
: xmlEvents(source);
|
|
247
|
+
const scope = new NamespaceScope();
|
|
124
248
|
for (const event of events) {
|
|
125
249
|
switch (event.kind) {
|
|
126
250
|
case 'open':
|
|
127
|
-
|
|
251
|
+
scope.open(event.attrs);
|
|
252
|
+
handlers.onOpen(event.name, event.attrs, event.selfClosing, scope);
|
|
253
|
+
if (event.selfClosing)
|
|
254
|
+
scope.close();
|
|
128
255
|
break;
|
|
129
256
|
case 'text':
|
|
130
257
|
handlers.onText?.(event.text);
|
|
131
258
|
break;
|
|
132
259
|
case 'close':
|
|
133
|
-
handlers.onClose?.(event.name);
|
|
260
|
+
handlers.onClose?.(event.name, scope);
|
|
261
|
+
scope.close();
|
|
134
262
|
break;
|
|
135
263
|
}
|
|
136
264
|
}
|
|
@@ -161,6 +289,10 @@ export class TextCapture {
|
|
|
161
289
|
this.#capturing = undefined;
|
|
162
290
|
return this.#text;
|
|
163
291
|
}
|
|
292
|
+
reset() {
|
|
293
|
+
this.#capturing = undefined;
|
|
294
|
+
this.#text = '';
|
|
295
|
+
}
|
|
164
296
|
}
|
|
165
297
|
export function* capturedText(source, names) {
|
|
166
298
|
const capture = new TextCapture(names);
|
package/dist/xml/xml-scan.d.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
export interface XmlAttributes {
|
|
2
2
|
readonly [name: string]: string;
|
|
3
3
|
}
|
|
4
|
+
/**
|
|
5
|
+
* One parse event from {@link xmlEvents}. The payloads are what the push adapter in `xml-read.ts`
|
|
6
|
+
* hands a handler triple, unchanged: `text` is already entity-decoded (or verbatim CDATA), and a
|
|
7
|
+
* `<x/>` yields one `open` with `selfClosing: true` and no matching `close`. The discriminated
|
|
8
|
+
* `kind` lets a *pull* consumer drive the parse: the shape the streaming reader needs, where a push
|
|
9
|
+
* callback cannot `yield`.
|
|
10
|
+
*/
|
|
4
11
|
export type XmlEvent = {
|
|
5
12
|
readonly kind: 'open';
|
|
6
13
|
readonly name: string;
|
|
@@ -18,28 +25,29 @@ export type XmlEvent = {
|
|
|
18
25
|
* `&name;` is left verbatim rather than expanded: there is no DTD, so there is nothing
|
|
19
26
|
* to expand it to, and refusing to invent one is what makes entity-expansion attacks
|
|
20
27
|
* impossible.
|
|
28
|
+
*
|
|
29
|
+
* A reference naming a code point XML 1.0 has no representation for is left verbatim too, on the
|
|
30
|
+
* same grounds as one naming no code point at all. `` is not an escape for U+0001, it is another
|
|
31
|
+
* way of spelling an ill-formed document, and decoding it puts in the model a character the writer
|
|
32
|
+
* is *guaranteed* to refuse: a hostile file would then read cleanly and fail on the next save with
|
|
33
|
+
* an `AuthoringError` blaming the caller, several layers from the input that caused it. The bound
|
|
34
|
+
* comes from `./xml-chars.ts` rather than from the writer's own guard so that this half of the
|
|
35
|
+
* codec keeps importing none of the serialisation vocabulary.
|
|
21
36
|
*/
|
|
22
37
|
export declare function decodeEntities(value: string): string;
|
|
23
38
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* `AuthoringError` and a whole serialisation vocabulary the reader has no business importing.
|
|
29
|
-
*
|
|
30
|
-
* **One left-to-right pass, and that is load-bearing.** `005F` maps to `_` like any other code
|
|
31
|
-
* point, with no special case, because a single pass already gives the underscore escape its
|
|
32
|
-
* meaning: in `_x005F_x0041_` the match at 0 yields `_` and scanning resumes at `x0041_`, which has
|
|
33
|
-
* no leading underscore left to start an escape. So the value reads back as the literal seven
|
|
34
|
-
* characters `_x0041_` the author wrote. Decoding `_x005F_` in a pass of its own, before or after
|
|
35
|
-
* the rest, collapses that to `A` and loses the distinction the encoder went to trouble to keep.
|
|
36
|
-
* Excel agrees: it reads that cell as `_x0041_`.
|
|
39
|
+
* A tag's attributes: each a name, then `=`, then a value in either quote style. Matching the quotes
|
|
40
|
+
* is what lets a delimiter-respecting scan find a tag's end even when a value holds a `>` (legal but
|
|
41
|
+
* rare). Names may carry a namespace prefix (`r:id`, `xml:space`). Anything that is not an attribute,
|
|
42
|
+
* such as a name nothing assigns or a quote never closed, is skipped rather than refused.
|
|
37
43
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
44
|
+
* Linear in the source, and that is the point of it being hand-written. The regex it replaced
|
|
45
|
+
* backtracked over a run of name characters no `=` followed from every position inside the run, so a
|
|
46
|
+
* single junk token in a tag cost the square of its length: a megabyte of one letter, a kilobyte
|
|
47
|
+
* zipped, cost minutes inside either reader. Here a dropped token resumes the scan where the token
|
|
48
|
+
* ended, and a value's closing quote is found with one `indexOf`, so no character is visited more
|
|
49
|
+
* than a constant number of times.
|
|
41
50
|
*/
|
|
42
|
-
export declare function decodeSpreadsheetText(value: string): string;
|
|
43
51
|
export declare function parseAttributes(source: string): XmlAttributes;
|
|
44
52
|
export type Markup = {
|
|
45
53
|
readonly kind: 'comment' | 'pi' | 'declaration';
|
|
@@ -81,20 +89,3 @@ export declare function boolStrict(val: string | undefined): boolean;
|
|
|
81
89
|
* token, otherwise its `"1"`/`"true"` vs `"0"`/`"false"` value. Lets a caller store only the
|
|
82
90
|
* attributes the source actually carried, so a re-write stays byte-clean. */
|
|
83
91
|
export declare function boolTristate(val: string | undefined): boolean | undefined;
|
|
84
|
-
/** An OOXML integer attribute at or above `min` (default: unbounded below); `undefined` when the
|
|
85
|
-
* attribute is absent, blank, fractional, not a number, or below the floor. Integers past
|
|
86
|
-
* `Number.MAX_SAFE_INTEGER` read as `undefined` too: no index or count is usable out there, and
|
|
87
|
-
* arithmetic on one silently lies. */
|
|
88
|
-
export declare function numInteger(val: string | undefined, min?: number): number | undefined;
|
|
89
|
-
/** An OOXML decimal attribute at or above `min` (default: unbounded below); `undefined` when the
|
|
90
|
-
* attribute is absent, blank, not a number, or below the floor. Infinities are not finite numbers
|
|
91
|
-
* and read as `undefined`. */
|
|
92
|
-
export declare function numFinite(val: string | undefined, min?: number): number | undefined;
|
|
93
|
-
/** Read an operand's text as a number only when it is a canonical decimal literal (optional sign,
|
|
94
|
-
* digits, optional fraction). A cell reference, defined name, expression, or exotically-spelled
|
|
95
|
-
* number (`1E5`, hex) keeps its verbatim text, so it is neither coerced to `NaN` and lost nor
|
|
96
|
-
* re-spelled into a number that would not re-write byte-clean. Callers layer their own type rules
|
|
97
|
-
* (a data-validation `list`/`custom` operand stays a string regardless of what it looks like). */
|
|
98
|
-
export declare function coerceNumericLiteral(text: string): string | number;
|
|
99
|
-
/** Narrow an enumerated attribute through its guard; `undefined` when absent or not a member. */
|
|
100
|
-
export declare function enumToken<T extends string>(val: string | undefined, isMember: (candidate: string) => candidate is T): T | undefined;
|
package/dist/xml/xml-scan.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { XmlParseError } from './errors.js';
|
|
2
|
+
import { isRepresentableCodePoint, stripUnrepresentable } from './xml-chars.js';
|
|
2
3
|
const PREDEFINED_ENTITIES = new Map([
|
|
3
4
|
['amp', '&'],
|
|
4
5
|
['lt', '<'],
|
|
@@ -15,35 +16,79 @@ export function decodeEntities(value) {
|
|
|
15
16
|
const codePoint = body.charCodeAt(1) === 0x78
|
|
16
17
|
? Number.parseInt(body.slice(2), 16)
|
|
17
18
|
: Number.parseInt(body.slice(1), 10);
|
|
18
|
-
if (!
|
|
19
|
+
if (!isRepresentableCodePoint(codePoint))
|
|
19
20
|
return match;
|
|
20
|
-
|
|
21
|
-
return String.fromCodePoint(codePoint);
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
return match;
|
|
25
|
-
}
|
|
21
|
+
return String.fromCodePoint(codePoint);
|
|
26
22
|
}
|
|
27
23
|
return PREDEFINED_ENTITIES.get(body) ?? match;
|
|
28
24
|
});
|
|
29
25
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
function admitText(value) {
|
|
27
|
+
return stripUnrepresentable(decodeEntities(value));
|
|
28
|
+
}
|
|
29
|
+
const EQUALS = 0x3d;
|
|
30
|
+
const SLASH = 0x2f;
|
|
31
|
+
const GREATER_THAN = 0x3e;
|
|
32
|
+
const DOUBLE_QUOTE = 0x22;
|
|
33
|
+
const SINGLE_QUOTE = 0x27;
|
|
34
|
+
const WIDE_WHITESPACE = /\s/;
|
|
35
|
+
function isScanWhitespace(code) {
|
|
36
|
+
if (code < 0x80)
|
|
37
|
+
return code === 0x20 || (code >= 0x09 && code <= 0x0d);
|
|
38
|
+
return WIDE_WHITESPACE.test(String.fromCharCode(code));
|
|
39
|
+
}
|
|
40
|
+
function skipScanWhitespace(source, from) {
|
|
41
|
+
let i = from;
|
|
42
|
+
while (i < source.length && isScanWhitespace(source.charCodeAt(i)))
|
|
43
|
+
i++;
|
|
44
|
+
return i;
|
|
45
|
+
}
|
|
46
|
+
function endsName(code) {
|
|
47
|
+
if (code > GREATER_THAN && code < 0xa0)
|
|
48
|
+
return false;
|
|
49
|
+
return isScanWhitespace(code) || code === EQUALS || code === SLASH || code === GREATER_THAN;
|
|
34
50
|
}
|
|
35
|
-
const ATTRIBUTE = /([^\s=/>]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
|
36
51
|
export function parseAttributes(source) {
|
|
37
52
|
const attrs = Object.create(null);
|
|
38
|
-
|
|
39
|
-
let
|
|
40
|
-
while (
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
53
|
+
const length = source.length;
|
|
54
|
+
let i = 0;
|
|
55
|
+
while (i < length) {
|
|
56
|
+
const nameStart = i;
|
|
57
|
+
while (i < length && !endsName(source.charCodeAt(i)))
|
|
58
|
+
i++;
|
|
59
|
+
if (i === nameStart) {
|
|
60
|
+
i++;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
let cursor = skipScanWhitespace(source, i);
|
|
64
|
+
if (source.charCodeAt(cursor) !== EQUALS) {
|
|
65
|
+
i = cursor;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
cursor = skipScanWhitespace(source, cursor + 1);
|
|
69
|
+
const quote = source.charCodeAt(cursor);
|
|
70
|
+
const close = quote === DOUBLE_QUOTE || quote === SINGLE_QUOTE
|
|
71
|
+
? source.indexOf(quote === DOUBLE_QUOTE ? '"' : "'", cursor + 1)
|
|
72
|
+
: -1;
|
|
73
|
+
if (close === -1) {
|
|
74
|
+
i = cursor;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
attrs[source.slice(nameStart, i)] = admitText(normalizeAttributeWhitespace(source.slice(cursor + 1, close)));
|
|
78
|
+
i = close + 1;
|
|
44
79
|
}
|
|
45
80
|
return attrs;
|
|
46
81
|
}
|
|
82
|
+
const ATTRIBUTE_WHITESPACE = /\r\n|[\t\n\r]/g;
|
|
83
|
+
function normalizeAttributeWhitespace(raw) {
|
|
84
|
+
for (let i = 0; i < raw.length; i++) {
|
|
85
|
+
const code = raw.charCodeAt(i);
|
|
86
|
+
if (code === 0x09 || code === 0x0a || code === 0x0d) {
|
|
87
|
+
return raw.replace(ATTRIBUTE_WHITESPACE, ' ');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return raw;
|
|
91
|
+
}
|
|
47
92
|
function findTagEnd(source, start) {
|
|
48
93
|
let quote = '';
|
|
49
94
|
for (let i = start + 1; i < source.length; i++) {
|
|
@@ -123,18 +168,21 @@ export function* xmlEvents(source) {
|
|
|
123
168
|
if (lt === -1) {
|
|
124
169
|
const chunk = source.slice(i);
|
|
125
170
|
if (chunk.length > 0)
|
|
126
|
-
yield { kind: 'text', text:
|
|
171
|
+
yield { kind: 'text', text: admitText(normalizeLineEndings(chunk)) };
|
|
127
172
|
return;
|
|
128
173
|
}
|
|
129
174
|
if (lt > i) {
|
|
130
175
|
const chunk = source.slice(i, lt);
|
|
131
176
|
if (chunk.length > 0)
|
|
132
|
-
yield { kind: 'text', text:
|
|
177
|
+
yield { kind: 'text', text: admitText(normalizeLineEndings(chunk)) };
|
|
133
178
|
}
|
|
134
179
|
const markup = markupAt(source, lt);
|
|
135
180
|
if (markup !== undefined) {
|
|
136
181
|
if (markup.kind === 'cdata') {
|
|
137
|
-
yield {
|
|
182
|
+
yield {
|
|
183
|
+
kind: 'text',
|
|
184
|
+
text: stripUnrepresentable(source.slice(markup.contentStart, markup.contentEnd)),
|
|
185
|
+
};
|
|
138
186
|
}
|
|
139
187
|
i = markup.next;
|
|
140
188
|
continue;
|
|
@@ -181,28 +229,3 @@ export function boolTristate(val) {
|
|
|
181
229
|
return false;
|
|
182
230
|
return undefined;
|
|
183
231
|
}
|
|
184
|
-
export function numInteger(val, min = -Number.MAX_SAFE_INTEGER) {
|
|
185
|
-
const n = parseAttrNumber(val);
|
|
186
|
-
if (n === undefined || !Number.isSafeInteger(n) || n < min)
|
|
187
|
-
return undefined;
|
|
188
|
-
return n;
|
|
189
|
-
}
|
|
190
|
-
export function numFinite(val, min = -Infinity) {
|
|
191
|
-
const n = parseAttrNumber(val);
|
|
192
|
-
if (n === undefined || n < min)
|
|
193
|
-
return undefined;
|
|
194
|
-
return n;
|
|
195
|
-
}
|
|
196
|
-
function parseAttrNumber(val) {
|
|
197
|
-
if (val === undefined || val.trim() === '')
|
|
198
|
-
return undefined;
|
|
199
|
-
const n = Number(val);
|
|
200
|
-
return Number.isFinite(n) ? n : undefined;
|
|
201
|
-
}
|
|
202
|
-
export function coerceNumericLiteral(text) {
|
|
203
|
-
const trimmed = text.trim();
|
|
204
|
-
return /^-?\d+(?:\.\d+)?$/.test(trimmed) ? Number(trimmed) : text;
|
|
205
|
-
}
|
|
206
|
-
export function enumToken(val, isMember) {
|
|
207
|
-
return val !== undefined && isMember(val) ? val : undefined;
|
|
208
|
-
}
|
package/dist/xml/xml.d.ts
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Refuse a string that XML cannot carry, naming the character and where it is so the author
|
|
3
|
-
* can find it in a value they never inspected. These arrive from a database column or a CSV
|
|
4
|
-
* field, not from a literal in the calling code.
|
|
5
|
-
*
|
|
6
|
-
* Exported for the one escape that cannot be {@link escapeAttr}: a number format code escapes
|
|
7
|
-
* everything but the apostrophe, and needs this guard just the same.
|
|
8
|
-
*
|
|
9
|
-
* @throws {AuthoringError} naming the code point and its offset.
|
|
10
|
-
*/
|
|
11
|
-
export declare function assertRepresentable(value: string): void;
|
|
12
1
|
/** Escape a string for use as XML element text. */
|
|
13
2
|
export declare function escapeText(value: string): string;
|
|
14
3
|
/** Escape a string for use inside a double-quoted XML attribute value. */
|
|
15
4
|
export declare function escapeAttr(value: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* {@link escapeAttr} for a number format code: the same escapes minus the apostrophe.
|
|
7
|
+
*
|
|
8
|
+
* A format code can legitimately contain `"` (a quoted literal like `"$"`), `<` and `&`, and Excel
|
|
9
|
+
* writes one with bare apostrophes. `'` is not markup-significant inside a double-quoted attribute,
|
|
10
|
+
* so leaving it keeps a round-tripped code byte-identical to the source; that divergence is the whole
|
|
11
|
+
* reason this exists.
|
|
12
|
+
*
|
|
13
|
+
* It is built by *omitting* one entry from {@link ATTR_ESCAPES} rather than by listing the escapes it
|
|
14
|
+
* does want, which is how it used to be written, in `io/xlsx/style-elements.ts`. An independently
|
|
15
|
+
* maintained list does not stay a one-character divergence: that one silently dropped the tab, line
|
|
16
|
+
* feed and carriage return escapes as well, and XML 1.0 3.3.3 requires a parser to normalise all
|
|
17
|
+
* three in an attribute value to a space, so Excel read back a format code with a space where the
|
|
18
|
+
* author wrote a tab. Our own reader preserved the raw character, so a round trip through this
|
|
19
|
+
* library returned it unchanged and no test here could see the loss.
|
|
20
|
+
*/
|
|
21
|
+
export declare function escapeFormatCode(code: string): string;
|
|
16
22
|
/**
|
|
17
23
|
* Escape a cell value: the `_xHHHH_` convention first, then XML's own escapes.
|
|
18
24
|
*
|
|
@@ -25,7 +31,7 @@ export declare function escapeAttr(value: string): string;
|
|
|
25
31
|
* `escapeText` runs last and sees no unrepresentable character left, so its guard is a
|
|
26
32
|
* standing proof that the escape was complete rather than a second check of the same thing.
|
|
27
33
|
*
|
|
28
|
-
* Reversed by `decodeSpreadsheetText` in `./xml-
|
|
34
|
+
* Reversed by `decodeSpreadsheetText` in `./xml-attrs.ts`, whose single left-to-right pass is what
|
|
29
35
|
* makes the `_x005F_` step above reversible. Change either and read its comment first.
|
|
30
36
|
*/
|
|
31
37
|
export declare function escapeSpreadsheetText(value: string): string;
|
|
@@ -37,12 +43,14 @@ export declare function escapeSpreadsheetText(value: string): string;
|
|
|
37
43
|
*/
|
|
38
44
|
export declare function textElement(value: string): string;
|
|
39
45
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
46
|
+
* Re-render an opening tag, `<name …>` or the empty `<name …/>`, from its parsed name and attributes,
|
|
47
|
+
* for an edit that changes an attribute of an element a part already carries. Attribute order is the
|
|
48
|
+
* scanner's, which is the source's, so an element whose attributes an edit merges over keeps them
|
|
49
|
+
* where they were; only the quoting and the entity spelling become this writer's.
|
|
44
50
|
*/
|
|
45
|
-
export declare function
|
|
51
|
+
export declare function startTag(name: string, attrs: {
|
|
52
|
+
readonly [attribute: string]: string | undefined;
|
|
53
|
+
}, selfClosing: boolean): string;
|
|
46
54
|
/**
|
|
47
55
|
* A boolean attribute rendered with a leading space (` name="1"` / ` name="0"`), or '' when the value
|
|
48
56
|
* is undefined. OOXML booleans serialise as 1/0; emitting the explicit `="0"` lets a writer force a
|
|
@@ -85,18 +93,43 @@ export declare function checkedToken(value: string, isValid: (candidate: string)
|
|
|
85
93
|
*/
|
|
86
94
|
export declare function numAttr(name: string, value: number | undefined): string;
|
|
87
95
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
96
|
+
* An integer attribute rendered with a leading space (` name="3"`), or '' when the value is undefined.
|
|
97
|
+
*
|
|
98
|
+
* For an `xsd:int` or `xsd:unsignedInt` attribute, whose lexical space has no spelling for a fraction
|
|
99
|
+
* any more than for a NaN: `priority="1.5"` and `rank="-1"` make a package the schema rejects, so the
|
|
100
|
+
* value is refused here rather than written. `min` is the floor the attribute's type implies, `0` for
|
|
101
|
+
* an unsigned one.
|
|
102
|
+
*
|
|
103
|
+
* @throws {AuthoringError} when the value is not finite, not a safe integer, or below `min`.
|
|
104
|
+
*/
|
|
105
|
+
export declare function intAttr(name: string, value: number | undefined, min?: number): string;
|
|
106
|
+
/**
|
|
107
|
+
* A numeric attribute written only when it differs from its schema default, with a leading space, or
|
|
108
|
+
* '' when the value is undefined or equals `defaultValue`.
|
|
109
|
+
*
|
|
110
|
+
* The number is checked before it is compared, because the two answer different questions: whether
|
|
111
|
+
* the value can be spelled, and whether it is worth spelling. Tested for truthiness instead, `NaN` is
|
|
112
|
+
* falsy and was omitted as if it were a default of zero, so a gradient fill with `degree: NaN` was
|
|
113
|
+
* written as an ordinary gradient rather than refused.
|
|
114
|
+
*
|
|
115
|
+
* @throws {AuthoringError} when the value is not finite.
|
|
116
|
+
*/
|
|
117
|
+
export declare function nonDefaultNumAttr(name: string, value: number | undefined, defaultValue: number): string;
|
|
118
|
+
/**
|
|
119
|
+
* Refuse a `Date` OOXML cannot spell, naming the property that carries it.
|
|
92
120
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
121
|
+
* Two ways a `Date` fails to have a `dcterms:W3CDTF` / `xsd:dateTime` spelling, and neither is
|
|
122
|
+
* caught by the types. An **Invalid Date** is truthy and is an instance of `Date`, so it passes
|
|
123
|
+
* every guard short of this one and reaches `toISOString()`, which throws a bare
|
|
124
|
+
* `RangeError: Invalid time value` -- outside this taxonomy, and naming neither the property nor
|
|
125
|
+
* the document it was being written into. A year **outside 0000-9999** has no four-digit form, so
|
|
126
|
+
* `toISOString()` falls back to ISO 8601's expanded `+275760-09-13T…` notation, which is not in
|
|
127
|
+
* the lexical space of either type; that one does not throw at all, it writes a package Excel
|
|
128
|
+
* offers to repair.
|
|
96
129
|
*
|
|
97
|
-
* @throws {AuthoringError} naming the
|
|
130
|
+
* @throws {AuthoringError} naming the property.
|
|
98
131
|
*/
|
|
99
|
-
export declare function
|
|
132
|
+
export declare function assertWritableDate(date: Date, property: string): void;
|
|
100
133
|
/**
|
|
101
134
|
* A finite number serialises as its shortest round-trippable decimal; a non-finite one
|
|
102
135
|
* has no OOXML numeric representation, so the writer refuses it rather than emit `NaN`.
|