@shbernal/ts-xlsx 3.1.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 +30 -23
- package/dist/bytes.d.ts +3 -2
- package/dist/core/address.d.ts +36 -0
- package/dist/core/address.js +47 -9
- package/dist/core/array-formula-ranges.d.ts +33 -0
- package/dist/core/array-formula-ranges.js +62 -0
- package/dist/core/color-resolution.js +2 -2
- package/dist/core/column.js +3 -2
- package/dist/core/comment-thread.d.ts +7 -3
- package/dist/core/conditional-formatting-overlay.d.ts +9 -0
- package/dist/core/conditional-formatting-overlay.js +28 -1
- package/dist/core/conditional-formatting.d.ts +98 -10
- package/dist/core/conditional-formatting.js +42 -1
- package/dist/core/data-validation-overlay.d.ts +5 -0
- package/dist/core/data-validation-overlay.js +15 -0
- package/dist/core/data-validation.d.ts +16 -0
- package/dist/core/data-validation.js +15 -0
- package/dist/core/date-format.js +14 -4
- package/dist/core/date.js +1 -1
- 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 +51 -18
- package/dist/core/formula.js +77 -86
- 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 +28 -0
- package/dist/core/grid-edits.js +193 -25
- package/dist/core/hyperlink.d.ts +39 -0
- package/dist/core/hyperlink.js +88 -0
- package/dist/core/image.d.ts +36 -5
- package/dist/core/image.js +9 -0
- package/dist/core/internal.d.ts +3 -1
- package/dist/core/limits.d.ts +5 -3
- package/dist/core/merge.d.ts +13 -0
- package/dist/core/merge.js +15 -1
- package/dist/core/page-setup.d.ts +26 -11
- package/dist/core/pivot-table.d.ts +49 -10
- package/dist/core/pivot-table.js +55 -21
- package/dist/core/protection.d.ts +66 -4
- package/dist/core/protection.js +4 -0
- package/dist/core/row.js +3 -2
- package/dist/core/structured-reference.d.ts +7 -0
- package/dist/core/structured-reference.js +7 -0
- package/dist/core/table.d.ts +38 -8
- package/dist/core/table.js +37 -7
- package/dist/core/theme.d.ts +2 -0
- package/dist/core/theme.js +4 -1
- package/dist/core/value.d.ts +51 -28
- package/dist/core/value.js +15 -12
- package/dist/core/workbook-styles.d.ts +17 -1
- package/dist/core/workbook-styles.js +4 -0
- package/dist/core/workbook-theme.js +5 -3
- package/dist/core/workbook.d.ts +20 -3
- package/dist/core/workbook.js +26 -5
- package/dist/core/worksheet-merges.d.ts +9 -4
- package/dist/core/worksheet-merges.js +17 -11
- package/dist/core/worksheet-model.d.ts +1 -1
- package/dist/core/worksheet-model.js +4 -0
- package/dist/core/worksheet-pictures.d.ts +3 -3
- package/dist/core/worksheet-pictures.js +7 -6
- package/dist/core/worksheet.d.ts +110 -21
- package/dist/core/worksheet.js +174 -49
- package/dist/entries/core.d.ts +7 -5
- package/dist/entries/core.js +4 -3
- package/dist/entries/errors.d.ts +1 -0
- package/dist/entries/errors.js +1 -0
- package/dist/errors.js +1 -1
- 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 +14 -2
- package/dist/io/csv/delimiter.js +12 -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 +46 -24
- package/dist/io/csv/write.d.ts +10 -3
- package/dist/io/csv/write.js +16 -7
- package/dist/io/opc/part-paths.js +4 -4
- package/dist/io/opc/read-opc.d.ts +4 -0
- package/dist/io/opc/read-opc.js +10 -4
- 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/{xlsx → read-policy}/column-budget.js +4 -8
- 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/xlsb/formula.js +4 -2
- package/dist/io/xlsb/ptg-functions.js +110 -0
- package/dist/io/xlsb/read-metadata.d.ts +7 -0
- package/dist/io/xlsb/read-metadata.js +69 -0
- package/dist/io/xlsb/read-worksheet.d.ts +6 -0
- package/dist/io/xlsb/read-worksheet.js +95 -37
- package/dist/io/xlsb/read.js +26 -8
- package/dist/io/xlsb/record-types.d.ts +13 -0
- package/dist/io/xlsb/record-types.js +13 -0
- 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 +20 -12
- package/dist/io/xlsx/cell-accumulator.js +49 -19
- 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 +16 -4
- package/dist/io/xlsx/cell-value.js +38 -21
- package/dist/io/xlsx/color-xml.js +1 -1
- 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 +3 -28
- package/dist/io/xlsx/comments.js +3 -65
- package/dist/io/xlsx/conditional-formatting.d.ts +42 -25
- package/dist/io/xlsx/conditional-formatting.js +424 -129
- package/dist/io/xlsx/data-validation.d.ts +12 -7
- package/dist/io/xlsx/data-validation.js +41 -29
- package/dist/io/xlsx/edit-vba.js +43 -36
- package/dist/io/xlsx/hyperlinks.d.ts +16 -50
- package/dist/io/xlsx/hyperlinks.js +8 -37
- package/dist/io/xlsx/images.d.ts +49 -16
- package/dist/io/xlsx/images.js +145 -44
- package/dist/io/xlsx/namespaces.d.ts +8 -0
- package/dist/io/xlsx/namespaces.js +4 -0
- package/dist/io/xlsx/package-plan.d.ts +48 -15
- package/dist/io/xlsx/package-plan.js +46 -9
- 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 +23 -22
- 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 +2 -2
- package/dist/io/xlsx/read-parts.js +44 -37
- package/dist/io/xlsx/read-pivot.js +9 -3
- package/dist/io/xlsx/read-rich-runs.d.ts +8 -5
- package/dist/io/xlsx/read-rich-runs.js +18 -1
- package/dist/io/xlsx/read-rows.d.ts +18 -7
- package/dist/io/xlsx/read-rows.js +47 -37
- package/dist/io/xlsx/read-styles.d.ts +0 -25
- package/dist/io/xlsx/read-styles.js +39 -34
- package/dist/io/xlsx/read-workbook-xml.d.ts +6 -0
- package/dist/io/xlsx/read-workbook-xml.js +9 -4
- package/dist/io/xlsx/read-worksheet.d.ts +8 -3
- package/dist/io/xlsx/read-worksheet.js +45 -23
- package/dist/io/xlsx/read.d.ts +0 -4
- package/dist/io/xlsx/read.js +17 -21
- package/dist/io/xlsx/relationships.d.ts +3 -0
- package/dist/io/xlsx/relationships.js +4 -0
- package/dist/io/xlsx/row-position.d.ts +3 -1
- package/dist/io/xlsx/row-xml.d.ts +18 -7
- package/dist/io/xlsx/row-xml.js +54 -35
- package/dist/io/xlsx/sheet-properties.js +68 -42
- 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 +0 -2
- package/dist/io/xlsx/style-elements.js +9 -29
- package/dist/io/xlsx/styles.d.ts +5 -0
- package/dist/io/xlsx/styles.js +11 -5
- package/dist/io/xlsx/tables.d.ts +10 -2
- package/dist/io/xlsx/tables.js +49 -42
- package/dist/io/xlsx/theme-xml.d.ts +6 -0
- package/dist/io/xlsx/theme-xml.js +16 -19
- package/dist/io/xlsx/threaded-comments.d.ts +6 -1
- package/dist/io/xlsx/threaded-comments.js +14 -7
- package/dist/io/xlsx/workbook-xml.d.ts +13 -24
- package/dist/io/xlsx/workbook-xml.js +15 -33
- package/dist/io/xlsx/worksheet-xml.d.ts +5 -2
- package/dist/io/xlsx/worksheet-xml.js +37 -69
- package/dist/io/xlsx/write-stream.d.ts +28 -6
- package/dist/io/xlsx/write-stream.js +42 -17
- package/dist/io/xlsx/write.d.ts +11 -4
- package/dist/io/xlsx/write.js +153 -90
- package/dist/rel-type.d.ts +9 -0
- package/dist/rel-type.js +3 -0
- package/dist/vba/bytes.d.ts +2 -0
- package/dist/vba/bytes.js +11 -0
- package/dist/vba/cfb-format.d.ts +47 -0
- package/dist/vba/cfb-format.js +34 -0
- package/dist/vba/cfb-writer.d.ts +1 -2
- package/dist/vba/cfb-writer.js +33 -36
- package/dist/vba/cfb.d.ts +9 -4
- package/dist/vba/cfb.js +55 -43
- package/dist/vba/dir-records.d.ts +6 -0
- package/dist/vba/dir-records.js +10 -2
- package/dist/vba/errors.d.ts +4 -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 +15 -6
- package/dist/vba/project-editor.js +102 -87
- package/dist/vba/project.d.ts +4 -0
- package/dist/vba/project.js +12 -6
- package/dist/vba/vba-encoding.d.ts +4 -10
- package/dist/vba/vba-encoding.js +2 -15
- package/dist/xml/xml-read.d.ts +29 -1
- package/dist/xml/xml-read.js +56 -0
- package/dist/xml/xml-scan.d.ts +13 -0
- package/dist/xml/xml-scan.js +58 -7
- package/dist/xml/xml.d.ts +33 -1
- package/dist/xml/xml.js +22 -0
- package/package.json +5 -4
- package/skills/ts-xlsx-upstream/SKILL.md +21 -13
- package/dist/core/modern-functions.d.ts +0 -1
- package/dist/io/xlsx/cell-style-resolution.d.ts +0 -25
- package/dist/io/xlsx/cell-style-resolution.js +0 -29
- package/dist/io/xlsx/column-budget.d.ts +0 -26
- package/dist/io/xlsx/read-repair.d.ts +0 -26
- package/dist/io/xlsx/read-repair.js +0 -39
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { XmlParseError } from '../../xml/errors.js';
|
|
2
|
+
import { NamespaceScope } from '../../xml/xml-namespaces.js';
|
|
3
|
+
import { tagRanges } from '../../xml/xml-read.js';
|
|
4
|
+
import { localName } from '../../xml/xml-scan.js';
|
|
5
|
+
import { startTag } from '../../xml/xml.js';
|
|
6
|
+
const STRICT = 'http://purl.oclc.org/ooxml/';
|
|
7
|
+
const TRANSITIONAL = 'http://schemas.openxmlformats.org/';
|
|
8
|
+
const NAMESPACES = new Map([
|
|
9
|
+
'drawingml/chart drawingml/2006/chart',
|
|
10
|
+
'drawingml/chartDrawing drawingml/2006/chartDrawing',
|
|
11
|
+
'drawingml/diagram drawingml/2006/diagram',
|
|
12
|
+
'drawingml/lockedCanvas drawingml/2006/lockedCanvas',
|
|
13
|
+
'drawingml/main drawingml/2006/main',
|
|
14
|
+
'drawingml/picture drawingml/2006/picture',
|
|
15
|
+
'drawingml/spreadsheetDrawing drawingml/2006/spreadsheetDrawing',
|
|
16
|
+
'drawingml/wordprocessingDrawing drawingml/2006/wordprocessingDrawing',
|
|
17
|
+
'officeDocument/bibliography officeDocument/2006/bibliography',
|
|
18
|
+
'officeDocument/characteristics officeDocument/2006/characteristics',
|
|
19
|
+
'officeDocument/customProperties officeDocument/2006/custom-properties',
|
|
20
|
+
'officeDocument/customXml officeDocument/2006/customXml',
|
|
21
|
+
'officeDocument/docPropsVTypes officeDocument/2006/docPropsVTypes',
|
|
22
|
+
'officeDocument/extendedProperties officeDocument/2006/extended-properties',
|
|
23
|
+
'officeDocument/math officeDocument/2006/math',
|
|
24
|
+
'officeDocument/relationships officeDocument/2006/relationships',
|
|
25
|
+
'officeDocument/sharedTypes officeDocument/2006/sharedTypes',
|
|
26
|
+
'presentationml/main presentationml/2006/main',
|
|
27
|
+
'schemaLibrary/main schemaLibrary/2006/main',
|
|
28
|
+
'spreadsheetml/main spreadsheetml/2006/main',
|
|
29
|
+
'wordprocessingml/main wordprocessingml/2006/main',
|
|
30
|
+
].map((pair) => {
|
|
31
|
+
const [strict, transitional] = pair.split(' ');
|
|
32
|
+
return [`${STRICT}${strict}`, `${TRANSITIONAL}${transitional}`];
|
|
33
|
+
}));
|
|
34
|
+
const DRAWINGML = `${TRANSITIONAL}drawingml/2006/main`;
|
|
35
|
+
const PERCENTAGES = new Map([
|
|
36
|
+
[
|
|
37
|
+
DRAWINGML,
|
|
38
|
+
percentageTable(1000, {
|
|
39
|
+
a: 'alphaRepl',
|
|
40
|
+
amt: 'alphaModFix tint',
|
|
41
|
+
b: 'fillRect fillToRect scrgbClr srcRect tileRect',
|
|
42
|
+
baseline: 'defRPr endParaRPr rPr',
|
|
43
|
+
bright: 'lum',
|
|
44
|
+
contrast: 'lum',
|
|
45
|
+
d: 'ds',
|
|
46
|
+
endA: 'reflection',
|
|
47
|
+
endPos: 'reflection',
|
|
48
|
+
fontScale: 'normAutofit',
|
|
49
|
+
g: 'scrgbClr',
|
|
50
|
+
l: 'fillRect fillToRect srcRect tileRect',
|
|
51
|
+
lim: 'miter',
|
|
52
|
+
lnSpcReduction: 'normAutofit',
|
|
53
|
+
lum: 'hsl hslClr',
|
|
54
|
+
pos: 'gs',
|
|
55
|
+
r: 'fillRect fillToRect scrgbClr srcRect tileRect',
|
|
56
|
+
sat: 'hsl hslClr',
|
|
57
|
+
sp: 'ds',
|
|
58
|
+
stA: 'reflection',
|
|
59
|
+
stPos: 'reflection',
|
|
60
|
+
sx: 'outerShdw reflection tile xfrm',
|
|
61
|
+
sy: 'outerShdw reflection tile xfrm',
|
|
62
|
+
t: 'fillRect fillToRect srcRect tileRect',
|
|
63
|
+
thresh: 'alphaBiLevel biLevel',
|
|
64
|
+
tx: 'relOff',
|
|
65
|
+
ty: 'relOff',
|
|
66
|
+
val: 'alpha alphaMod alphaOff blue blueMod blueOff green greenMod greenOff hueMod lum lumMod ' +
|
|
67
|
+
'lumOff red redMod redOff sat satMod satOff shade spcPct tint',
|
|
68
|
+
zoom: 'camera',
|
|
69
|
+
}),
|
|
70
|
+
],
|
|
71
|
+
[
|
|
72
|
+
`${TRANSITIONAL}drawingml/2006/chart`,
|
|
73
|
+
percentageTable(1, {
|
|
74
|
+
val: 'bubbleScale depthPercent gapDepth gapWidth hPercent holeSize lblOffset overlap ' +
|
|
75
|
+
'secondPieSize thickness',
|
|
76
|
+
}),
|
|
77
|
+
],
|
|
78
|
+
[
|
|
79
|
+
`${TRANSITIONAL}drawingml/2006/diagram`,
|
|
80
|
+
percentageTable(1000, Object.fromEntries([
|
|
81
|
+
'custLinFactNeighborX',
|
|
82
|
+
'custLinFactNeighborY',
|
|
83
|
+
'custLinFactX',
|
|
84
|
+
'custLinFactY',
|
|
85
|
+
'custRadScaleInc',
|
|
86
|
+
'custRadScaleRad',
|
|
87
|
+
'custScaleX',
|
|
88
|
+
'custScaleY',
|
|
89
|
+
].map((attribute) => [attribute, 'prSet']))),
|
|
90
|
+
],
|
|
91
|
+
]);
|
|
92
|
+
function percentageTable(scale, elementsByAttribute) {
|
|
93
|
+
const pairs = Object.entries(elementsByAttribute).flatMap(([attribute, elements]) => elements.split(' ').map((element) => `${element} ${attribute}`));
|
|
94
|
+
return { scale, pairs: new Set(pairs) };
|
|
95
|
+
}
|
|
96
|
+
const PERCENTAGE = /^-?[0-9]+(?:\.[0-9]+)?%$/;
|
|
97
|
+
const STRICT_BYTES = new TextEncoder().encode(STRICT);
|
|
98
|
+
export function transitionalPart(bytes, contentType) {
|
|
99
|
+
if (!isXmlContentType(contentType) || !includesBytes(bytes, STRICT_BYTES))
|
|
100
|
+
return bytes;
|
|
101
|
+
const source = new TextDecoder().decode(bytes);
|
|
102
|
+
let xml = '';
|
|
103
|
+
let copied = 0;
|
|
104
|
+
const scope = new NamespaceScope();
|
|
105
|
+
try {
|
|
106
|
+
for (const tag of tagRanges(source)) {
|
|
107
|
+
if (tag.close) {
|
|
108
|
+
scope.close();
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
scope.open(tag.attrs);
|
|
112
|
+
const translated = translatedAttributes(tag.name, tag.attrs, scope);
|
|
113
|
+
if (tag.selfClosing)
|
|
114
|
+
scope.close();
|
|
115
|
+
if (translated === undefined)
|
|
116
|
+
continue;
|
|
117
|
+
xml += source.slice(copied, tag.start) + startTag(tag.name, translated, tag.selfClosing);
|
|
118
|
+
copied = tag.end;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
if (error instanceof XmlParseError)
|
|
123
|
+
return bytes;
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
return copied === 0 ? bytes : new TextEncoder().encode(xml + source.slice(copied));
|
|
127
|
+
}
|
|
128
|
+
function translatedAttributes(name, attrs, scope) {
|
|
129
|
+
let translated;
|
|
130
|
+
const set = (attribute, value) => {
|
|
131
|
+
translated ??= { ...attrs };
|
|
132
|
+
translated[attribute] = value;
|
|
133
|
+
};
|
|
134
|
+
const declared = scope.elementNamespace(name);
|
|
135
|
+
const namespace = (declared === undefined ? undefined : NAMESPACES.get(declared)) ?? declared;
|
|
136
|
+
const local = localName(name);
|
|
137
|
+
const percentages = PERCENTAGES.get(namespace ?? '');
|
|
138
|
+
for (const attribute in attrs) {
|
|
139
|
+
const value = attrs[attribute] ?? '';
|
|
140
|
+
if (attribute === 'xmlns' || attribute.startsWith('xmlns:')) {
|
|
141
|
+
const uri = NAMESPACES.get(value);
|
|
142
|
+
if (uri !== undefined)
|
|
143
|
+
set(attribute, uri);
|
|
144
|
+
}
|
|
145
|
+
else if (attribute === 'uri' && local === 'graphicData' && namespace === DRAWINGML) {
|
|
146
|
+
const uri = NAMESPACES.get(value);
|
|
147
|
+
if (uri !== undefined)
|
|
148
|
+
set(attribute, uri);
|
|
149
|
+
}
|
|
150
|
+
else if (percentages?.pairs.has(`${local} ${attribute}`) === true && PERCENTAGE.test(value)) {
|
|
151
|
+
set(attribute, String(Math.round(Number.parseFloat(value) * percentages.scale)));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return translated;
|
|
155
|
+
}
|
|
156
|
+
function isXmlContentType(contentType) {
|
|
157
|
+
const type = contentType.toLowerCase();
|
|
158
|
+
return type.endsWith('+xml') || type === 'application/xml' || type === 'text/xml';
|
|
159
|
+
}
|
|
160
|
+
function includesBytes(haystack, needle) {
|
|
161
|
+
const [first = 0] = needle;
|
|
162
|
+
const last = haystack.length - needle.length;
|
|
163
|
+
for (let i = haystack.indexOf(first); i !== -1 && i <= last; i = haystack.indexOf(first, i + 1)) {
|
|
164
|
+
let matched = 1;
|
|
165
|
+
while (matched < needle.length && haystack[i + matched] === needle[matched])
|
|
166
|
+
matched += 1;
|
|
167
|
+
if (matched === needle.length)
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
@@ -34,10 +34,8 @@ export declare function cellStyleTag(entry: {
|
|
|
34
34
|
}): string;
|
|
35
35
|
export declare function alignmentAttrs(alignment: Alignment): string;
|
|
36
36
|
export declare function protectionAttrs(protection: Protection): string;
|
|
37
|
-
export declare function tableStyleName(fragment: string): string;
|
|
38
37
|
export declare function dxfXml(style: DifferentialStyle): string;
|
|
39
38
|
export declare function borderXml(border: Border): string;
|
|
40
|
-
export declare function fillSignature(fill: Fill): string;
|
|
41
39
|
export declare function patternFillXml(fill: Fill, { solidBgFallback }: {
|
|
42
40
|
solidBgFallback: boolean;
|
|
43
41
|
}): string;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ALIGNMENT_FACETS, isBorderStyle, isFillPatternType, } from '../../core/style.js';
|
|
2
|
-
import {
|
|
3
|
-
import { checkedToken, escapeAttr, escapeFormatCode, numberText } from '../../xml/xml.js';
|
|
2
|
+
import { checkedToken, escapeAttr, escapeFormatCode, nonDefaultNumAttr, numberText, } from '../../xml/xml.js';
|
|
4
3
|
import { colorAttrs } from './color-xml.js';
|
|
5
4
|
import { fontXml } from './font-xml.js';
|
|
6
5
|
export const CUSTOM_NUMFMT_BASE = 164;
|
|
@@ -56,10 +55,9 @@ export function alignmentAttrs(alignment) {
|
|
|
56
55
|
break;
|
|
57
56
|
}
|
|
58
57
|
case 'number': {
|
|
59
|
-
const
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
parts.push(`${facet.key}="${numberText(value)}"`);
|
|
58
|
+
const attr = nonDefaultNumAttr(facet.key, alignment[facet.key], 0);
|
|
59
|
+
if (attr !== '')
|
|
60
|
+
parts.push(attr.trimStart());
|
|
63
61
|
break;
|
|
64
62
|
}
|
|
65
63
|
case 'flag':
|
|
@@ -78,9 +76,6 @@ export function protectionAttrs(protection) {
|
|
|
78
76
|
parts.push('hidden="1"');
|
|
79
77
|
return parts.join(' ');
|
|
80
78
|
}
|
|
81
|
-
export function tableStyleName(fragment) {
|
|
82
|
-
return decodeEntities(/<tableStyle\b[^>]*\bname="([^"]*)"/.exec(fragment)?.[1] ?? '');
|
|
83
|
-
}
|
|
84
79
|
export function dxfXml(style) {
|
|
85
80
|
const parts = [];
|
|
86
81
|
if (style.font !== undefined) {
|
|
@@ -99,19 +94,16 @@ export function dxfXml(style) {
|
|
|
99
94
|
}
|
|
100
95
|
function gradientFillXml(fill) {
|
|
101
96
|
const attrs = (fill.gradient === 'path' ? ' type="path"' : '') +
|
|
102
|
-
(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
97
|
+
nonDefaultNumAttr('degree', fill.degree, 0) +
|
|
98
|
+
nonDefaultNumAttr('left', fill.left, 0) +
|
|
99
|
+
nonDefaultNumAttr('right', fill.right, 0) +
|
|
100
|
+
nonDefaultNumAttr('top', fill.top, 0) +
|
|
101
|
+
nonDefaultNumAttr('bottom', fill.bottom, 0);
|
|
107
102
|
const stops = fill.stops
|
|
108
103
|
.map((stop) => `<stop position="${numberText(stop.position)}"><color ${colorAttrs(stop.color)}/></stop>`)
|
|
109
104
|
.join('');
|
|
110
105
|
return `<gradientFill${attrs}>${stops}</gradientFill>`;
|
|
111
106
|
}
|
|
112
|
-
function insetAttr(name, value) {
|
|
113
|
-
return value ? ` ${name}="${numberText(value)}"` : '';
|
|
114
|
-
}
|
|
115
107
|
export function borderXml(border) {
|
|
116
108
|
const attrs = (border.diagonalUp ? ' diagonalUp="1"' : '') + (border.diagonalDown ? ' diagonalDown="1"' : '');
|
|
117
109
|
return (`<border${attrs}>` +
|
|
@@ -130,18 +122,6 @@ function edgeXml(tag, edge) {
|
|
|
130
122
|
return `<${tag} style="${style}"/>`;
|
|
131
123
|
return `<${tag} style="${style}"><color ${colorAttrs(edge.color)}/></${tag}>`;
|
|
132
124
|
}
|
|
133
|
-
export function fillSignature(fill) {
|
|
134
|
-
if (fill.type === 'gradient') {
|
|
135
|
-
const stops = fill.stops.map((s) => `${s.position}:${colorSignature(s.color)}`).join(',');
|
|
136
|
-
return `grad|${fill.gradient}|${fill.degree ?? ''}|${fill.left ?? ''}/${fill.right ?? ''}/${fill.top ?? ''}/${fill.bottom ?? ''}|${stops}`;
|
|
137
|
-
}
|
|
138
|
-
return `${fill.pattern}|${colorSignature(fill.fgColor)}|${colorSignature(fill.bgColor)}`;
|
|
139
|
-
}
|
|
140
|
-
function colorSignature(color) {
|
|
141
|
-
if (color === undefined)
|
|
142
|
-
return '';
|
|
143
|
-
return `${color.argb ?? ''}/${color.theme ?? ''}/${color.tint ?? ''}/${color.indexed ?? ''}`;
|
|
144
|
-
}
|
|
145
125
|
export function patternFillXml(fill, { solidBgFallback }) {
|
|
146
126
|
if (fill.type === 'gradient')
|
|
147
127
|
return `<fill>${gradientFillXml(fill)}</fill>`;
|
package/dist/io/xlsx/styles.d.ts
CHANGED
|
@@ -101,6 +101,11 @@ export declare class StyleRegistry {
|
|
|
101
101
|
* keeps every preserved reference pointing where it did.
|
|
102
102
|
*/
|
|
103
103
|
differentialStyleId(style: DifferentialStyle): number;
|
|
104
|
+
/**
|
|
105
|
+
* The `<dxf>` fragment at a differential-style index, or `undefined` past the end of the table: what
|
|
106
|
+
* a conditional format in the extension form writes inline, since that form names no `dxfId`.
|
|
107
|
+
*/
|
|
108
|
+
differentialStyleFragment(id: number): string | undefined;
|
|
104
109
|
/** Serialise the accumulated table into a complete, valid styles.xml part. */
|
|
105
110
|
toXml(): string;
|
|
106
111
|
}
|
package/dist/io/xlsx/styles.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {} from '../../core/style.js';
|
|
2
2
|
import { TABLE_STYLE_ELEMENT_TYPES } from '../../core/table-style.js';
|
|
3
|
-
import { escapeAttr, escapeFormatCode,
|
|
3
|
+
import { escapeAttr, escapeFormatCode, nonDefaultNumAttr, XML_DECLARATION } from '../../xml/xml.js';
|
|
4
4
|
import { fontXml } from './font-xml.js';
|
|
5
5
|
import { MARKUP_COMPATIBILITY_NS, SPREADSHEETML_NS } from './namespaces.js';
|
|
6
|
-
import { alignmentAttrs, borderXml, cellStyleTag, CUSTOM_NUMFMT_BASE, DEFAULT_BORDER, DEFAULT_FONT_BODY, DEFAULT_FORMAT, dxfXml,
|
|
6
|
+
import { alignmentAttrs, borderXml, cellStyleTag, CUSTOM_NUMFMT_BASE, DEFAULT_BORDER, DEFAULT_FONT_BODY, DEFAULT_FORMAT, dxfXml, formatSignature, isDefaultFormat, patternFillXml, protectionAttrs, xfXml, } from './style-elements.js';
|
|
7
7
|
const RESERVED_FILL_COUNT = 2;
|
|
8
8
|
const RESERVED_FONT_COUNT = 1;
|
|
9
9
|
const RESERVED_BORDER_COUNT = 1;
|
|
@@ -124,7 +124,7 @@ export class StyleRegistry {
|
|
|
124
124
|
const element = style.elements[type];
|
|
125
125
|
if (element === undefined)
|
|
126
126
|
return [];
|
|
127
|
-
const size =
|
|
127
|
+
const size = nonDefaultNumAttr('size', element.size, 1);
|
|
128
128
|
return [
|
|
129
129
|
`<tableStyleElement type="${type}"${size} dxfId="${this.differentialStyleId(element)}"/>`,
|
|
130
130
|
];
|
|
@@ -137,8 +137,12 @@ export class StyleRegistry {
|
|
|
137
137
|
const fragment = dxfXml(style);
|
|
138
138
|
return this.#dxfs.intern(fragment, fragment);
|
|
139
139
|
}
|
|
140
|
+
differentialStyleFragment(id) {
|
|
141
|
+
return this.#dxfs.entries[id];
|
|
142
|
+
}
|
|
140
143
|
#internFill(fill) {
|
|
141
|
-
|
|
144
|
+
const xml = patternFillXml(fill, { solidBgFallback: true });
|
|
145
|
+
return this.#fills.intern(xml, xml);
|
|
142
146
|
}
|
|
143
147
|
#internNumFmt(code) {
|
|
144
148
|
return this.#numFmts.intern(code, code);
|
|
@@ -193,7 +197,9 @@ export class StyleRegistry {
|
|
|
193
197
|
#tableStylesXml() {
|
|
194
198
|
const { defaultTableStyle, defaultPivotStyle } = this.#tableStyles;
|
|
195
199
|
const authored = this.#authoredTableStyles;
|
|
196
|
-
const preserved = this.#tableStyles.styles
|
|
200
|
+
const preserved = this.#tableStyles.styles
|
|
201
|
+
.filter((style) => !authored.has(style.name))
|
|
202
|
+
.map((style) => style.xml);
|
|
197
203
|
const styles = [...preserved, ...authored.values()];
|
|
198
204
|
if (styles.length === 0 && defaultTableStyle === undefined && defaultPivotStyle === undefined) {
|
|
199
205
|
return '';
|
package/dist/io/xlsx/tables.d.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { type Table, type TableOptions } from '../../core/table.ts';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* The table part. A column's calculated and totals formulas are stored with the function prefixes a
|
|
4
|
+
* cell formula takes, as Excel stores them; `formulaNames` is `formulaNamesInScope` for the table's
|
|
5
|
+
* sheet.
|
|
6
|
+
*/
|
|
7
|
+
export declare function tableXml(table: Table, id: number, formulaNames: ReadonlySet<string>): string;
|
|
3
8
|
/**
|
|
4
9
|
* Parse a `<table>` part into the options that reconstruct it, or `undefined` when the XML is not a
|
|
5
10
|
* usable table (no name, no ref, or no columns: Excel treats such a part as corrupt, so we drop it
|
|
6
11
|
* rather than fabricate a degenerate table). Duplicate column names are not resolved here, since the
|
|
7
12
|
* {@link Table} constructor disambiguates them, so authoring and loading share one implementation.
|
|
13
|
+
*
|
|
14
|
+
* A column's formulas shed their function prefixes as a cell formula's do, against `definedNames`,
|
|
15
|
+
* the workbook's names as `definedNameKeys` spells them.
|
|
8
16
|
*/
|
|
9
|
-
export declare function parseTable(xml: string): TableOptions | undefined;
|
|
17
|
+
export declare function parseTable(xml: string, definedNames: ReadonlySet<string>): TableOptions | undefined;
|
package/dist/io/xlsx/tables.js
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
import { encodeAddress,
|
|
2
|
-
import {
|
|
1
|
+
import { encodeAddress, tryDecodeRange } from '../../core/address.js';
|
|
2
|
+
import { mangleFormula, unmangleFunctions } from '../../core/formula.js';
|
|
3
|
+
import { isTotalsRowFunction, TABLE_STYLE_FLAGS, } from '../../core/table.js';
|
|
3
4
|
import { numInteger } from '../../xml/xml-attrs.js';
|
|
4
5
|
import { parseXml, TextCapture } from '../../xml/xml-read.js';
|
|
5
|
-
import {
|
|
6
|
+
import { boolTristate, localName } from '../../xml/xml-scan.js';
|
|
6
7
|
import { boolAttr, checkedToken, escapeAttr, escapeText, XML_DECLARATION } from '../../xml/xml.js';
|
|
7
8
|
import { NS } from './relationships.js';
|
|
8
|
-
export function tableXml(table, id) {
|
|
9
|
+
export function tableXml(table, id, formulaNames) {
|
|
9
10
|
const name = escapeAttr(table.name);
|
|
10
|
-
const displayName = escapeAttr(table.displayName);
|
|
11
11
|
const headerRowCount = table.headerRow ? '' : ' headerRowCount="0"';
|
|
12
12
|
const totals = table.totalsRow
|
|
13
13
|
? ' totalsRowCount="1"'
|
|
14
14
|
: boolAttr('totalsRowShown', table.totalsRowShown);
|
|
15
15
|
const autoFilter = table.autoFilterRef !== undefined ? `<autoFilter ref="${table.autoFilterRef}"/>` : '';
|
|
16
|
-
const columns = table.columns
|
|
16
|
+
const columns = table.columns
|
|
17
|
+
.map((column, i) => tableColumnXml(column, i + 1, formulaNames))
|
|
18
|
+
.join('');
|
|
17
19
|
return (XML_DECLARATION +
|
|
18
|
-
`<table xmlns="${NS.main}" id="${id}" name="${name}" displayName="${
|
|
20
|
+
`<table xmlns="${NS.main}" id="${id}" name="${name}" displayName="${name}" ` +
|
|
19
21
|
`ref="${table.range}"${headerRowCount}${totals}>` +
|
|
20
22
|
autoFilter +
|
|
21
23
|
`<tableColumns count="${table.columns.length}">${columns}</tableColumns>` +
|
|
@@ -30,14 +32,10 @@ function tableStyleInfoXml(style) {
|
|
|
30
32
|
let attrs = '';
|
|
31
33
|
if (style.name !== undefined)
|
|
32
34
|
attrs += ` name="${escapeAttr(style.name)}"`;
|
|
33
|
-
attrs +=
|
|
34
|
-
boolAttr('showFirstColumn', style.showFirstColumn) +
|
|
35
|
-
boolAttr('showLastColumn', style.showLastColumn) +
|
|
36
|
-
boolAttr('showRowStripes', style.showRowStripes) +
|
|
37
|
-
boolAttr('showColumnStripes', style.showColumnStripes);
|
|
35
|
+
attrs += TABLE_STYLE_FLAGS.map((flag) => boolAttr(flag, style[flag])).join('');
|
|
38
36
|
return `<tableStyleInfo${attrs}/>`;
|
|
39
37
|
}
|
|
40
|
-
function tableColumnXml(column, id) {
|
|
38
|
+
function tableColumnXml(column, id, formulaNames) {
|
|
41
39
|
let attrs = `id="${id}" name="${escapeAttr(column.name)}"`;
|
|
42
40
|
if (column.totalsRowLabel !== undefined) {
|
|
43
41
|
attrs += ` totalsRowLabel="${escapeAttr(column.totalsRowLabel)}"`;
|
|
@@ -45,14 +43,21 @@ function tableColumnXml(column, id) {
|
|
|
45
43
|
if (column.totalsRowFunction !== undefined) {
|
|
46
44
|
attrs += ` totalsRowFunction="${checkedToken(column.totalsRowFunction, isTotalsRowFunction, 'totals row function')}"`;
|
|
47
45
|
}
|
|
46
|
+
let children = '';
|
|
47
|
+
if (column.calculatedColumnFormula !== undefined) {
|
|
48
|
+
const stored = mangleFormula(column.calculatedColumnFormula, formulaNames);
|
|
49
|
+
children += `<calculatedColumnFormula>${escapeText(stored)}</calculatedColumnFormula>`;
|
|
50
|
+
}
|
|
48
51
|
if (column.totalsRowFormula !== undefined) {
|
|
49
|
-
|
|
52
|
+
const stored = mangleFormula(column.totalsRowFormula, formulaNames);
|
|
53
|
+
children += `<totalsRowFormula>${escapeText(stored)}</totalsRowFormula>`;
|
|
50
54
|
}
|
|
51
|
-
return
|
|
55
|
+
return children === ''
|
|
56
|
+
? `<tableColumn ${attrs}/>`
|
|
57
|
+
: `<tableColumn ${attrs}>${children}</tableColumn>`;
|
|
52
58
|
}
|
|
53
|
-
export function parseTable(xml) {
|
|
59
|
+
export function parseTable(xml, definedNames) {
|
|
54
60
|
let name;
|
|
55
|
-
let displayName;
|
|
56
61
|
let ref;
|
|
57
62
|
let headerRowCount = 1;
|
|
58
63
|
let totalsRowCount = 0;
|
|
@@ -60,18 +65,17 @@ export function parseTable(xml) {
|
|
|
60
65
|
let style;
|
|
61
66
|
let hasAutoFilter = false;
|
|
62
67
|
const columns = [];
|
|
63
|
-
|
|
68
|
+
let currentColumn;
|
|
69
|
+
const formula = new TextCapture(['totalsRowFormula', 'calculatedColumnFormula']);
|
|
64
70
|
parseXml(xml, {
|
|
65
71
|
onOpen(elementName, attrs, selfClosing) {
|
|
66
72
|
switch (localName(elementName)) {
|
|
67
73
|
case 'table':
|
|
68
|
-
name = attrs.
|
|
69
|
-
displayName = attrs.displayName ?? attrs.name;
|
|
74
|
+
name = attrs.displayName ?? attrs.name;
|
|
70
75
|
ref = attrs.ref;
|
|
71
76
|
headerRowCount = numInteger(attrs.headerRowCount, 0) ?? headerRowCount;
|
|
72
77
|
totalsRowCount = numInteger(attrs.totalsRowCount, 0) ?? totalsRowCount;
|
|
73
|
-
|
|
74
|
-
totalsRowShown = boolPresent(attrs.totalsRowShown);
|
|
78
|
+
totalsRowShown = boolTristate(attrs.totalsRowShown);
|
|
75
79
|
break;
|
|
76
80
|
case 'autoFilter':
|
|
77
81
|
hasAutoFilter = true;
|
|
@@ -80,22 +84,21 @@ export function parseTable(xml) {
|
|
|
80
84
|
const captured = {};
|
|
81
85
|
if (attrs.name !== undefined)
|
|
82
86
|
captured.name = attrs.name;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (attrs.showRowStripes !== undefined)
|
|
88
|
-
captured.showRowStripes = boolPresent(attrs.showRowStripes);
|
|
89
|
-
if (attrs.showColumnStripes !== undefined) {
|
|
90
|
-
captured.showColumnStripes = boolPresent(attrs.showColumnStripes);
|
|
87
|
+
for (const flag of TABLE_STYLE_FLAGS) {
|
|
88
|
+
const value = boolTristate(attrs[flag]);
|
|
89
|
+
if (value !== undefined)
|
|
90
|
+
captured[flag] = value;
|
|
91
91
|
}
|
|
92
92
|
style = captured;
|
|
93
93
|
break;
|
|
94
94
|
}
|
|
95
95
|
case 'tableColumn': {
|
|
96
|
-
if (attrs.name === undefined)
|
|
96
|
+
if (attrs.name === undefined) {
|
|
97
|
+
currentColumn = undefined;
|
|
97
98
|
break;
|
|
99
|
+
}
|
|
98
100
|
const column = { name: attrs.name };
|
|
101
|
+
currentColumn = column;
|
|
99
102
|
if (attrs.totalsRowLabel !== undefined)
|
|
100
103
|
column.totalsRowLabel = attrs.totalsRowLabel;
|
|
101
104
|
if (attrs.totalsRowFunction !== undefined &&
|
|
@@ -106,20 +109,24 @@ export function parseTable(xml) {
|
|
|
106
109
|
break;
|
|
107
110
|
}
|
|
108
111
|
case 'totalsRowFormula':
|
|
109
|
-
|
|
112
|
+
case 'calculatedColumnFormula':
|
|
113
|
+
formula.open(localName(elementName), selfClosing);
|
|
110
114
|
break;
|
|
111
115
|
}
|
|
112
116
|
},
|
|
113
117
|
onText(text) {
|
|
114
|
-
|
|
118
|
+
formula.text(text);
|
|
115
119
|
},
|
|
116
120
|
onClose(elementName) {
|
|
117
|
-
const
|
|
118
|
-
|
|
121
|
+
const local = localName(elementName);
|
|
122
|
+
const text = formula.close(local);
|
|
123
|
+
if (text === undefined || currentColumn === undefined)
|
|
119
124
|
return;
|
|
120
|
-
const
|
|
121
|
-
if (
|
|
122
|
-
|
|
125
|
+
const formulaText = unmangleFunctions(text, definedNames);
|
|
126
|
+
if (local === 'totalsRowFormula')
|
|
127
|
+
currentColumn.totalsRowFormula = formulaText;
|
|
128
|
+
else
|
|
129
|
+
currentColumn.calculatedColumnFormula = formulaText;
|
|
123
130
|
},
|
|
124
131
|
});
|
|
125
132
|
if (name === undefined || ref === undefined || columns.length === 0)
|
|
@@ -127,17 +134,17 @@ export function parseTable(xml) {
|
|
|
127
134
|
const decoded = tryDecodeRange(ref);
|
|
128
135
|
if (decoded === undefined)
|
|
129
136
|
return undefined;
|
|
130
|
-
const { top, left, bottom } = decoded;
|
|
131
|
-
if (top === undefined || left === undefined || bottom === undefined)
|
|
137
|
+
const { top, left, bottom, right } = decoded;
|
|
138
|
+
if (top === undefined || left === undefined || bottom === undefined || right === undefined) {
|
|
132
139
|
return undefined;
|
|
133
|
-
|
|
140
|
+
}
|
|
141
|
+
if (columns.length !== right - left + 1)
|
|
134
142
|
return undefined;
|
|
135
143
|
const headerRow = headerRowCount !== 0;
|
|
136
144
|
const totalsRow = totalsRowCount > 0;
|
|
137
145
|
const dataRows = bottom - top + 1 - (headerRow ? 1 : 0) - (totalsRow ? 1 : 0);
|
|
138
146
|
const options = {
|
|
139
147
|
name,
|
|
140
|
-
displayName: displayName ?? name,
|
|
141
148
|
ref: encodeAddress(left, top),
|
|
142
149
|
columns,
|
|
143
150
|
rowCount: Math.max(0, dataRows),
|
|
@@ -12,6 +12,12 @@ import { type ThemeColorScheme, type ThemeColorSlot, type ThemeFontScheme, type
|
|
|
12
12
|
export declare function parseThemeColorScheme(themeXml: string): ThemeColorScheme;
|
|
13
13
|
/** Extract the major/minor latin typefaces from a theme part's `<fontScheme>`. */
|
|
14
14
|
export declare function parseThemeFontScheme(themeXml: string): ThemeFontScheme;
|
|
15
|
+
/** {@link parseThemeColorScheme} and {@link parseThemeFontScheme} from one scan of the part, for the
|
|
16
|
+
* reader, which wants both. */
|
|
17
|
+
export declare function parseThemeSchemes(themeXml: string): {
|
|
18
|
+
readonly colors: ThemeColorScheme;
|
|
19
|
+
readonly fonts: ThemeFontScheme;
|
|
20
|
+
};
|
|
15
21
|
declare const SCHEME_ELEMENT_ORDER: readonly ["dk1", "lt1", "dk2", "lt2", "accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "hlink", "folHlink"];
|
|
16
22
|
/**
|
|
17
23
|
* The half of the proof the list above owes: `satisfies` covers "no invented slot", this covers "no
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { DEFAULT_THEME_COLOR_SCHEME, isThemeColorSlot,
|
|
1
|
+
import { DEFAULT_THEME_COLOR_SCHEME, isThemeColorSlot, isThemeRgb, } from '../../core/theme.js';
|
|
2
2
|
import { elementRange, parseXml } from '../../xml/xml-read.js';
|
|
3
3
|
import { localName } from '../../xml/xml-scan.js';
|
|
4
|
-
import {
|
|
4
|
+
import { startTag } from '../../xml/xml.js';
|
|
5
5
|
const COLOR_ELEMENTS = new Set(['srgbClr', 'sysClr']);
|
|
6
6
|
function readThemeScheme(themeXml) {
|
|
7
7
|
const colors = {};
|
|
@@ -12,7 +12,7 @@ function readThemeScheme(themeXml) {
|
|
|
12
12
|
let slot;
|
|
13
13
|
let fontSlot;
|
|
14
14
|
parseXml(themeXml, {
|
|
15
|
-
onOpen(name, attrs
|
|
15
|
+
onOpen(name, attrs) {
|
|
16
16
|
const local = localName(name);
|
|
17
17
|
if (local === 'theme') {
|
|
18
18
|
const colon = name.indexOf(':');
|
|
@@ -29,9 +29,9 @@ function readThemeScheme(themeXml) {
|
|
|
29
29
|
}
|
|
30
30
|
else if (slot !== undefined && COLOR_ELEMENTS.has(local)) {
|
|
31
31
|
const value = local === 'sysClr' ? attrs.lastClr : attrs.val;
|
|
32
|
-
if (value !== undefined &&
|
|
33
|
-
colors[slot] = value;
|
|
34
|
-
elements[slot] =
|
|
32
|
+
if (value !== undefined && isThemeRgb(value))
|
|
33
|
+
colors[slot] = value.toUpperCase();
|
|
34
|
+
elements[slot] = startTag(name, attrs, true);
|
|
35
35
|
slot = undefined;
|
|
36
36
|
}
|
|
37
37
|
return;
|
|
@@ -45,7 +45,6 @@ function readThemeScheme(themeXml) {
|
|
|
45
45
|
fonts[fontSlot] ??= attrs.typeface;
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
-
void scope;
|
|
49
48
|
},
|
|
50
49
|
onClose(name) {
|
|
51
50
|
const local = localName(name);
|
|
@@ -69,18 +68,16 @@ function readThemeScheme(themeXml) {
|
|
|
69
68
|
scheme.minor = fonts.minor;
|
|
70
69
|
return { colors, elements, fonts: scheme, prefix };
|
|
71
70
|
}
|
|
72
|
-
function emptyElement(name, attrs) {
|
|
73
|
-
let out = `<${name}`;
|
|
74
|
-
for (const key in attrs)
|
|
75
|
-
out += ` ${key}="${escapeAttr(attrs[key] ?? '')}"`;
|
|
76
|
-
return `${out}/>`;
|
|
77
|
-
}
|
|
78
71
|
export function parseThemeColorScheme(themeXml) {
|
|
79
72
|
return readThemeScheme(themeXml).colors;
|
|
80
73
|
}
|
|
81
74
|
export function parseThemeFontScheme(themeXml) {
|
|
82
75
|
return readThemeScheme(themeXml).fonts;
|
|
83
76
|
}
|
|
77
|
+
export function parseThemeSchemes(themeXml) {
|
|
78
|
+
const { colors, fonts } = readThemeScheme(themeXml);
|
|
79
|
+
return { colors, fonts };
|
|
80
|
+
}
|
|
84
81
|
const SCHEME_ELEMENT_ORDER = [
|
|
85
82
|
'dk1',
|
|
86
83
|
'lt1',
|
|
@@ -105,7 +102,7 @@ export function applyThemeOverrides(baseXml, overrides) {
|
|
|
105
102
|
const body = SCHEME_ELEMENT_ORDER.map((slot) => {
|
|
106
103
|
const authored = colors[slot];
|
|
107
104
|
const inner = authored !== undefined
|
|
108
|
-
? `<${prefix}srgbClr val="${
|
|
105
|
+
? `<${prefix}srgbClr val="${authored}"/>`
|
|
109
106
|
: (sourceElements[slot] ??
|
|
110
107
|
`<${prefix}srgbClr val="${DEFAULT_THEME_COLOR_SCHEME[slot]}"/>`);
|
|
111
108
|
return `<${prefix}${slot}>${inner}</${prefix}${slot}>`;
|
|
@@ -118,11 +115,11 @@ export function applyThemeOverrides(baseXml, overrides) {
|
|
|
118
115
|
const found = elementRange(baseXml, [which, 'latin']);
|
|
119
116
|
if (found === undefined)
|
|
120
117
|
return;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
118
|
+
edits.push({
|
|
119
|
+
start: found.start,
|
|
120
|
+
end: found.end,
|
|
121
|
+
text: startTag(found.name, { ...found.attrs, typeface }, true),
|
|
122
|
+
});
|
|
126
123
|
};
|
|
127
124
|
if (major !== undefined)
|
|
128
125
|
latin('majorFont', major);
|
|
@@ -78,8 +78,13 @@ export declare function buildCommentThreads(messages: readonly ParsedThreadedCom
|
|
|
78
78
|
*
|
|
79
79
|
* A thread with no messages writes nothing: it has neither text to say nor a head id for its replies and
|
|
80
80
|
* its legacy fallback to hang off.
|
|
81
|
+
*
|
|
82
|
+
* A message with no author is written under the null GUID, Excel's own spelling for one. `personById` is
|
|
83
|
+
* the workbook's registry, and a message naming an id it does not hold is refused.
|
|
84
|
+
*
|
|
85
|
+
* @throws {AuthoringError} if a message's author is not a registered person.
|
|
81
86
|
*/
|
|
82
|
-
export declare function threadedCommentsXml(threads: readonly CommentThread[]): string;
|
|
87
|
+
export declare function threadedCommentsXml(threads: readonly CommentThread[], personById: (id: string) => Person | undefined): string;
|
|
83
88
|
/**
|
|
84
89
|
* Serialise the workbook's identity registry into `xl/persons/person.xml`: singular and unnumbered,
|
|
85
90
|
* unlike the per-sheet thread parts.
|