@bilig/xlsx 0.164.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 +25 -0
- package/dist/address.d.ts +15 -0
- package/dist/address.js +82 -0
- package/dist/address.js.map +1 -0
- package/dist/external-workbook-types.d.ts +44 -0
- package/dist/external-workbook-types.js +12 -0
- package/dist/external-workbook-types.js.map +1 -0
- package/dist/file-source.d.ts +10 -0
- package/dist/file-source.js +76 -0
- package/dist/file-source.js.map +1 -0
- package/dist/formula-cache-reader.d.ts +30 -0
- package/dist/formula-cache-reader.js +350 -0
- package/dist/formula-cache-reader.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/simple-workbook-writer.d.ts +114 -0
- package/dist/simple-workbook-writer.js +621 -0
- package/dist/simple-workbook-writer.js.map +1 -0
- package/dist/source-preserving-literal-patches.d.ts +43 -0
- package/dist/source-preserving-literal-patches.js +615 -0
- package/dist/source-preserving-literal-patches.js.map +1 -0
- package/dist/source-preserving-zip.d.ts +25 -0
- package/dist/source-preserving-zip.js +341 -0
- package/dist/source-preserving-zip.js.map +1 -0
- package/dist/streaming-native-cell-arena.d.ts +57 -0
- package/dist/streaming-native-cell-arena.js +233 -0
- package/dist/streaming-native-cell-arena.js.map +1 -0
- package/dist/streaming-native-external-cache.d.ts +13 -0
- package/dist/streaming-native-external-cache.js +753 -0
- package/dist/streaming-native-external-cache.js.map +1 -0
- package/dist/streaming-native-inspect.d.ts +42 -0
- package/dist/streaming-native-inspect.js +297 -0
- package/dist/streaming-native-inspect.js.map +1 -0
- package/dist/streaming-native-lookup-wasm.d.ts +13 -0
- package/dist/streaming-native-lookup-wasm.js +250 -0
- package/dist/streaming-native-lookup-wasm.js.map +1 -0
- package/dist/streaming-native-recalc-evaluator.d.ts +17 -0
- package/dist/streaming-native-recalc-evaluator.js +743 -0
- package/dist/streaming-native-recalc-evaluator.js.map +1 -0
- package/dist/streaming-native-recalc.d.ts +97 -0
- package/dist/streaming-native-recalc.js +652 -0
- package/dist/streaming-native-recalc.js.map +1 -0
- package/dist/streaming-native-row-chain-conditionals.d.ts +8 -0
- package/dist/streaming-native-row-chain-conditionals.js +385 -0
- package/dist/streaming-native-row-chain-conditionals.js.map +1 -0
- package/dist/streaming-native-row-chain-dependencies.d.ts +17 -0
- package/dist/streaming-native-row-chain-dependencies.js +365 -0
- package/dist/streaming-native-row-chain-dependencies.js.map +1 -0
- package/dist/streaming-native-row-chain-references.d.ts +3 -0
- package/dist/streaming-native-row-chain-references.js +36 -0
- package/dist/streaming-native-row-chain-references.js.map +1 -0
- package/dist/streaming-native-row-chain-wasm.d.ts +56 -0
- package/dist/streaming-native-row-chain-wasm.js +546 -0
- package/dist/streaming-native-row-chain-wasm.js.map +1 -0
- package/dist/streaming-native-text.d.ts +2 -0
- package/dist/streaming-native-text.js +14 -0
- package/dist/streaming-native-text.js.map +1 -0
- package/dist/streaming-native-workbook-core.d.ts +47 -0
- package/dist/streaming-native-workbook-core.js +110 -0
- package/dist/streaming-native-workbook-core.js.map +1 -0
- package/dist/targeted-cell-reader.d.ts +11 -0
- package/dist/targeted-cell-reader.js +92 -0
- package/dist/targeted-cell-reader.js.map +1 -0
- package/dist/workbook-cell-reader.d.ts +29 -0
- package/dist/workbook-cell-reader.js +200 -0
- package/dist/workbook-cell-reader.js.map +1 -0
- package/dist/workbook-compatibility-report.d.ts +101 -0
- package/dist/workbook-compatibility-report.js +654 -0
- package/dist/workbook-compatibility-report.js.map +1 -0
- package/dist/workbook-sheet-paths.d.ts +8 -0
- package/dist/workbook-sheet-paths.js +79 -0
- package/dist/workbook-sheet-paths.js.map +1 -0
- package/dist/xml-part-patch.d.ts +12 -0
- package/dist/xml-part-patch.js +45 -0
- package/dist/xml-part-patch.js.map +1 -0
- package/dist/xml.d.ts +9 -0
- package/dist/xml.js +42 -0
- package/dist/xml.js.map +1 -0
- package/dist/zip-reader.d.ts +51 -0
- package/dist/zip-reader.js +448 -0
- package/dist/zip-reader.js.map +1 -0
- package/package.json +113 -0
|
@@ -0,0 +1,621 @@
|
|
|
1
|
+
import { encodeCellRange } from './address.js';
|
|
2
|
+
import { zipSourcePreservingEntries } from './source-preserving-zip.js';
|
|
3
|
+
import { escapeXmlAttribute, escapeXmlText } from './xml.js';
|
|
4
|
+
const spreadsheetNs = 'http://schemas.openxmlformats.org/spreadsheetml/2006/main';
|
|
5
|
+
const relationshipNs = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';
|
|
6
|
+
const packageRelationshipNs = 'http://schemas.openxmlformats.org/package/2006/relationships';
|
|
7
|
+
const contentTypesNs = 'http://schemas.openxmlformats.org/package/2006/content-types';
|
|
8
|
+
const customNumberFormatStartId = 164;
|
|
9
|
+
const defaultFontXml = '<font><sz val="11"/><color theme="1"/><name val="Aptos"/><family val="2"/></font>';
|
|
10
|
+
const simpleWorkbookZipDosTimeParts = { time: 0, date: (1 << 5) | 1 };
|
|
11
|
+
const themeContentType = 'application/vnd.openxmlformats-officedocument.theme+xml';
|
|
12
|
+
function normalizeRgbColor(value) {
|
|
13
|
+
if (!value) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const normalized = value.trim().replace(/^#/u, '');
|
|
17
|
+
if (/^[0-9a-fA-F]{6}$/u.test(normalized)) {
|
|
18
|
+
return `FF${normalized.toUpperCase()}`;
|
|
19
|
+
}
|
|
20
|
+
if (/^[0-9a-fA-F]{8}$/u.test(normalized)) {
|
|
21
|
+
return normalized.toUpperCase();
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
function xmlDeclaration() {
|
|
26
|
+
return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
|
|
27
|
+
}
|
|
28
|
+
function textElement(name, value) {
|
|
29
|
+
const preserveSpace = /^\s|\s$/u.test(value) || value.includes('\n') || value.includes('\t');
|
|
30
|
+
const attributes = preserveSpace ? ' xml:space="preserve"' : '';
|
|
31
|
+
return `<${name}${attributes}>${escapeXmlText(value)}</${name}>`;
|
|
32
|
+
}
|
|
33
|
+
function formulaText(value) {
|
|
34
|
+
return escapeXmlText(value).replace(/"/gu, '"');
|
|
35
|
+
}
|
|
36
|
+
function fontXml(font) {
|
|
37
|
+
if (!font) {
|
|
38
|
+
return defaultFontXml;
|
|
39
|
+
}
|
|
40
|
+
const children = [];
|
|
41
|
+
if (font.size !== undefined && Number.isFinite(font.size) && font.size > 0) {
|
|
42
|
+
children.push(`<sz val="${escapeXmlAttribute(String(font.size))}"/>`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
children.push('<sz val="11"/>');
|
|
46
|
+
}
|
|
47
|
+
const color = normalizeRgbColor(font.color);
|
|
48
|
+
if (color) {
|
|
49
|
+
children.push(`<color rgb="${color}"/>`);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
children.push('<color theme="1"/>');
|
|
53
|
+
}
|
|
54
|
+
children.push(`<name val="${escapeXmlAttribute(font.family?.trim() || 'Aptos')}"/>`);
|
|
55
|
+
children.push('<family val="2"/>');
|
|
56
|
+
if (font.bold === true) {
|
|
57
|
+
children.push('<b/>');
|
|
58
|
+
}
|
|
59
|
+
if (font.italic === true) {
|
|
60
|
+
children.push('<i/>');
|
|
61
|
+
}
|
|
62
|
+
if (font.underline === true) {
|
|
63
|
+
children.push('<u/>');
|
|
64
|
+
}
|
|
65
|
+
return `<font>${children.join('')}</font>`;
|
|
66
|
+
}
|
|
67
|
+
function fillXml(fill) {
|
|
68
|
+
const color = normalizeRgbColor(fill?.backgroundColor);
|
|
69
|
+
return color ? `<fill><patternFill patternType="solid"><fgColor rgb="${color}"/><bgColor indexed="64"/></patternFill></fill>` : null;
|
|
70
|
+
}
|
|
71
|
+
function alignmentXml(alignment) {
|
|
72
|
+
if (!alignment) {
|
|
73
|
+
return '';
|
|
74
|
+
}
|
|
75
|
+
const attributes = [
|
|
76
|
+
alignment.horizontal ? `horizontal="${escapeXmlAttribute(alignment.horizontal)}"` : null,
|
|
77
|
+
alignment.vertical ? `vertical="${escapeXmlAttribute(alignment.vertical === 'middle' ? 'center' : alignment.vertical)}"` : null,
|
|
78
|
+
alignment.wrap === true ? 'wrapText="1"' : null,
|
|
79
|
+
alignment.indent !== undefined && alignment.indent >= 0 ? `indent="${String(alignment.indent)}"` : null,
|
|
80
|
+
alignment.shrinkToFit === true ? 'shrinkToFit="1"' : null,
|
|
81
|
+
alignment.readingOrder !== undefined ? `readingOrder="${String(alignment.readingOrder)}"` : null,
|
|
82
|
+
alignment.textRotation !== undefined ? `textRotation="${String(alignment.textRotation)}"` : null,
|
|
83
|
+
alignment.justifyLastLine === true ? 'justifyLastLine="1"' : null,
|
|
84
|
+
].filter((entry) => Boolean(entry));
|
|
85
|
+
return attributes.length > 0 ? `<alignment ${attributes.join(' ')}/>` : '';
|
|
86
|
+
}
|
|
87
|
+
function protectionXml(protection) {
|
|
88
|
+
if (!protection) {
|
|
89
|
+
return '';
|
|
90
|
+
}
|
|
91
|
+
const attributes = [
|
|
92
|
+
protection.locked !== undefined ? `locked="${protection.locked ? '1' : '0'}"` : null,
|
|
93
|
+
protection.hidden !== undefined ? `hidden="${protection.hidden ? '1' : '0'}"` : null,
|
|
94
|
+
].filter((entry) => Boolean(entry));
|
|
95
|
+
return attributes.length > 0 ? `<protection ${attributes.join(' ')}/>` : '<protection/>';
|
|
96
|
+
}
|
|
97
|
+
function borderStyle(side) {
|
|
98
|
+
if (!side) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
if (side.style === 'dashed') {
|
|
102
|
+
return side.weight === 'thin' ? 'dashed' : 'mediumDashed';
|
|
103
|
+
}
|
|
104
|
+
if (side.style === 'dotted') {
|
|
105
|
+
return 'dotted';
|
|
106
|
+
}
|
|
107
|
+
if (side.style === 'double') {
|
|
108
|
+
return 'double';
|
|
109
|
+
}
|
|
110
|
+
return side.weight;
|
|
111
|
+
}
|
|
112
|
+
function borderSideXml(name, side) {
|
|
113
|
+
const style = borderStyle(side);
|
|
114
|
+
if (!style) {
|
|
115
|
+
return `<${name}/>`;
|
|
116
|
+
}
|
|
117
|
+
const color = normalizeRgbColor(side?.color) ?? 'FF000000';
|
|
118
|
+
return `<${name} style="${style}"><color rgb="${color}"/></${name}>`;
|
|
119
|
+
}
|
|
120
|
+
function borderXml(borders) {
|
|
121
|
+
if (!borders) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
const hasBorder = Boolean(borders.top || borders.right || borders.bottom || borders.left);
|
|
125
|
+
return hasBorder
|
|
126
|
+
? `<border>${borderSideXml('left', borders.left)}${borderSideXml('right', borders.right)}${borderSideXml('top', borders.top)}${borderSideXml('bottom', borders.bottom)}<diagonal/></border>`
|
|
127
|
+
: null;
|
|
128
|
+
}
|
|
129
|
+
function styleKey(style) {
|
|
130
|
+
return `${style.styleId ?? ''}\u0000${style.numberFormat ?? ''}`;
|
|
131
|
+
}
|
|
132
|
+
function createRegisteredStyle(styleId, numberFormat) {
|
|
133
|
+
return {
|
|
134
|
+
...(styleId !== undefined ? { styleId } : {}),
|
|
135
|
+
...(numberFormat !== undefined ? { numberFormat } : {}),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function collectRegisteredStyles(workbook) {
|
|
139
|
+
const keys = new Set();
|
|
140
|
+
const output = [];
|
|
141
|
+
const add = (style) => {
|
|
142
|
+
const key = styleKey(style);
|
|
143
|
+
if (keys.has(key)) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
keys.add(key);
|
|
147
|
+
output.push(style);
|
|
148
|
+
};
|
|
149
|
+
add({});
|
|
150
|
+
for (const sheet of workbook.sheets) {
|
|
151
|
+
for (const cell of sheet.cells) {
|
|
152
|
+
if (cell.styleId || cell.numberFormat) {
|
|
153
|
+
add(createRegisteredStyle(cell.styleId, cell.numberFormat));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return output;
|
|
158
|
+
}
|
|
159
|
+
function buildStyleRegistry(workbook) {
|
|
160
|
+
if (workbook.stylesXml !== undefined) {
|
|
161
|
+
return {
|
|
162
|
+
styleIndexByKey: new Map(),
|
|
163
|
+
acceptsDirectStyleIndexes: true,
|
|
164
|
+
stylesXml: workbook.stylesXml,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
const styleById = new Map((workbook.styles ?? []).map((style) => [style.id, style]));
|
|
168
|
+
const registeredStyles = collectRegisteredStyles(workbook);
|
|
169
|
+
const customFormats = [
|
|
170
|
+
...new Set(registeredStyles.map((style) => style.numberFormat).filter((format) => Boolean(format))),
|
|
171
|
+
];
|
|
172
|
+
const numberFormatIdByCode = new Map(customFormats.map((format, index) => [format, customNumberFormatStartId + index]));
|
|
173
|
+
const fontXmls = [defaultFontXml];
|
|
174
|
+
const fillXmls = ['<fill><patternFill patternType="none"/></fill>', '<fill><patternFill patternType="gray125"/></fill>'];
|
|
175
|
+
const borderXmls = ['<border><left/><right/><top/><bottom/><diagonal/></border>'];
|
|
176
|
+
const styleIndexByKey = new Map();
|
|
177
|
+
const xfs = registeredStyles.map((registeredStyle, index) => {
|
|
178
|
+
styleIndexByKey.set(styleKey(registeredStyle), index);
|
|
179
|
+
const style = registeredStyle.styleId ? styleById.get(registeredStyle.styleId) : undefined;
|
|
180
|
+
const styleFontXml = fontXml(style?.font);
|
|
181
|
+
const fontId = style?.font ? fontXmls.push(styleFontXml) - 1 : 0;
|
|
182
|
+
const styleFillXml = fillXml(style?.fill);
|
|
183
|
+
const fillId = styleFillXml ? fillXmls.push(styleFillXml) - 1 : 0;
|
|
184
|
+
const styleBorderXml = borderXml(style?.borders);
|
|
185
|
+
const borderId = styleBorderXml ? borderXmls.push(styleBorderXml) - 1 : 0;
|
|
186
|
+
const numberFormatId = registeredStyle.numberFormat ? (numberFormatIdByCode.get(registeredStyle.numberFormat) ?? 0) : 0;
|
|
187
|
+
const alignment = alignmentXml(style?.alignment);
|
|
188
|
+
const protection = protectionXml(style?.protection);
|
|
189
|
+
const children = `${alignment}${protection}`;
|
|
190
|
+
const attributes = [
|
|
191
|
+
`numFmtId="${String(numberFormatId)}"`,
|
|
192
|
+
`fontId="${String(fontId)}"`,
|
|
193
|
+
`fillId="${String(fillId)}"`,
|
|
194
|
+
`borderId="${String(borderId)}"`,
|
|
195
|
+
'xfId="0"',
|
|
196
|
+
fontId > 0 ? 'applyFont="1"' : null,
|
|
197
|
+
fillId > 0 ? 'applyFill="1"' : null,
|
|
198
|
+
borderId > 0 ? 'applyBorder="1"' : null,
|
|
199
|
+
numberFormatId > 0 ? 'applyNumberFormat="1"' : null,
|
|
200
|
+
alignment ? 'applyAlignment="1"' : null,
|
|
201
|
+
protection ? 'applyProtection="1"' : null,
|
|
202
|
+
].filter((entry) => Boolean(entry));
|
|
203
|
+
return children ? `<xf ${attributes.join(' ')}>${children}</xf>` : `<xf ${attributes.join(' ')}/>`;
|
|
204
|
+
});
|
|
205
|
+
const numFmtsXml = customFormats.length === 0
|
|
206
|
+
? ''
|
|
207
|
+
: `<numFmts count="${String(customFormats.length)}">${customFormats
|
|
208
|
+
.map((format) => `<numFmt numFmtId="${String(numberFormatIdByCode.get(format) ?? 0)}" formatCode="${escapeXmlAttribute(format)}"/>`)
|
|
209
|
+
.join('')}</numFmts>`;
|
|
210
|
+
const stylesXml = [
|
|
211
|
+
xmlDeclaration(),
|
|
212
|
+
`<styleSheet xmlns="${spreadsheetNs}">`,
|
|
213
|
+
numFmtsXml,
|
|
214
|
+
`<fonts count="${String(fontXmls.length)}">${fontXmls.join('')}</fonts>`,
|
|
215
|
+
`<fills count="${String(fillXmls.length)}">${fillXmls.join('')}</fills>`,
|
|
216
|
+
`<borders count="${String(borderXmls.length)}">${borderXmls.join('')}</borders>`,
|
|
217
|
+
'<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>',
|
|
218
|
+
`<cellXfs count="${String(xfs.length)}">${xfs.join('')}</cellXfs>`,
|
|
219
|
+
'<cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>',
|
|
220
|
+
'</styleSheet>',
|
|
221
|
+
].join('');
|
|
222
|
+
return { styleIndexByKey, acceptsDirectStyleIndexes: false, stylesXml };
|
|
223
|
+
}
|
|
224
|
+
function styleIndexForCell(cell, registry) {
|
|
225
|
+
if (registry.acceptsDirectStyleIndexes &&
|
|
226
|
+
cell.styleIndex !== undefined &&
|
|
227
|
+
Number.isSafeInteger(cell.styleIndex) &&
|
|
228
|
+
cell.styleIndex >= 0) {
|
|
229
|
+
return cell.styleIndex;
|
|
230
|
+
}
|
|
231
|
+
const index = registry.styleIndexByKey.get(styleKey(createRegisteredStyle(cell.styleId, cell.numberFormat)));
|
|
232
|
+
return index && index > 0 ? index : undefined;
|
|
233
|
+
}
|
|
234
|
+
function cellValueXml(cell, formula) {
|
|
235
|
+
if (!formula && cell.sharedStringIndex !== undefined && Number.isSafeInteger(cell.sharedStringIndex) && cell.sharedStringIndex >= 0) {
|
|
236
|
+
return { type: 's', valueXml: `<v>${String(cell.sharedStringIndex)}</v>` };
|
|
237
|
+
}
|
|
238
|
+
if (!formula && cell.inlineStringXml !== undefined) {
|
|
239
|
+
return { type: 'inlineStr', valueXml: cell.inlineStringXml };
|
|
240
|
+
}
|
|
241
|
+
if (cell.error !== undefined) {
|
|
242
|
+
return { type: 'e', valueXml: `<v>${escapeXmlText(cell.error)}</v>` };
|
|
243
|
+
}
|
|
244
|
+
const value = cell.value;
|
|
245
|
+
if (value === undefined || value === null) {
|
|
246
|
+
return { type: '', valueXml: '' };
|
|
247
|
+
}
|
|
248
|
+
if (typeof value === 'number') {
|
|
249
|
+
return { type: '', valueXml: `<v>${escapeXmlText(String(value))}</v>` };
|
|
250
|
+
}
|
|
251
|
+
if (typeof value === 'boolean') {
|
|
252
|
+
return { type: 'b', valueXml: `<v>${value ? '1' : '0'}</v>` };
|
|
253
|
+
}
|
|
254
|
+
if (formula) {
|
|
255
|
+
return { type: 'str', valueXml: `<v>${escapeXmlText(value)}</v>` };
|
|
256
|
+
}
|
|
257
|
+
return { type: 'inlineStr', valueXml: `<is>${textElement('t', value)}</is>` };
|
|
258
|
+
}
|
|
259
|
+
function cellXml(cell, registry) {
|
|
260
|
+
const styleIndex = styleIndexForCell(cell, registry);
|
|
261
|
+
const formula = cell.formula?.replace(/^=/u, '');
|
|
262
|
+
const { type, valueXml } = cellValueXml(cell, formula);
|
|
263
|
+
const attributes = [
|
|
264
|
+
`r="${escapeXmlAttribute(cell.address)}"`,
|
|
265
|
+
styleIndex !== undefined ? `s="${String(styleIndex)}"` : null,
|
|
266
|
+
type ? `t="${type}"` : null,
|
|
267
|
+
].filter((entry) => Boolean(entry));
|
|
268
|
+
const formulaXml = formula ? `<f>${formulaText(formula)}</f>` : '';
|
|
269
|
+
const body = `${formulaXml}${valueXml}`;
|
|
270
|
+
return body ? `<c ${attributes.join(' ')}>${body}</c>` : `<c ${attributes.join(' ')}/>`;
|
|
271
|
+
}
|
|
272
|
+
function rowXml(rowIndex, cells, rowMetadata, registry) {
|
|
273
|
+
const attributes = [`r="${String(rowIndex + 1)}"`];
|
|
274
|
+
if (rowMetadata?.size !== undefined && Number.isFinite(rowMetadata.size) && rowMetadata.size > 0) {
|
|
275
|
+
attributes.push(`ht="${String(rowMetadata.size)}"`, 'customHeight="1"');
|
|
276
|
+
}
|
|
277
|
+
if (rowMetadata?.hidden === true) {
|
|
278
|
+
attributes.push('hidden="1"');
|
|
279
|
+
}
|
|
280
|
+
const body = cells.map((cell) => cellXml(cell, registry)).join('');
|
|
281
|
+
return body ? `<row ${attributes.join(' ')}>${body}</row>` : `<row ${attributes.join(' ')}/>`;
|
|
282
|
+
}
|
|
283
|
+
function worksheetDimension(sheet) {
|
|
284
|
+
if (sheet.dimension) {
|
|
285
|
+
return encodeCellRange(sheet.dimension);
|
|
286
|
+
}
|
|
287
|
+
let startRow = Number.POSITIVE_INFINITY;
|
|
288
|
+
let startCol = Number.POSITIVE_INFINITY;
|
|
289
|
+
let endRow = 0;
|
|
290
|
+
let endCol = 0;
|
|
291
|
+
const visit = (address) => {
|
|
292
|
+
startRow = Math.min(startRow, address.row);
|
|
293
|
+
startCol = Math.min(startCol, address.col);
|
|
294
|
+
endRow = Math.max(endRow, address.row);
|
|
295
|
+
endCol = Math.max(endCol, address.col);
|
|
296
|
+
};
|
|
297
|
+
for (const cell of sheet.cells) {
|
|
298
|
+
visit(cell);
|
|
299
|
+
}
|
|
300
|
+
for (const merge of sheet.merges ?? []) {
|
|
301
|
+
const range = encodeCellRangeAddress(merge.startAddress, merge.endAddress);
|
|
302
|
+
visit({ row: range.s.r, col: range.s.c });
|
|
303
|
+
visit({ row: range.e.r, col: range.e.c });
|
|
304
|
+
}
|
|
305
|
+
if (!Number.isFinite(startRow) || !Number.isFinite(startCol)) {
|
|
306
|
+
return 'A1';
|
|
307
|
+
}
|
|
308
|
+
return encodeCellRange({ s: { r: startRow, c: startCol }, e: { r: endRow, c: endCol } });
|
|
309
|
+
}
|
|
310
|
+
function encodeCellRangeAddress(startAddress, endAddress) {
|
|
311
|
+
const start = parseCellAddressFromA1(startAddress);
|
|
312
|
+
const end = parseCellAddressFromA1(endAddress);
|
|
313
|
+
return {
|
|
314
|
+
s: { r: Math.min(start.row, end.row), c: Math.min(start.col, end.col) },
|
|
315
|
+
e: { r: Math.max(start.row, end.row), c: Math.max(start.col, end.col) },
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
function parseCellAddressFromA1(address) {
|
|
319
|
+
const match = /^([A-Z]+)([1-9][0-9]*)$/iu.exec(address.replaceAll('$', ''));
|
|
320
|
+
if (!match) {
|
|
321
|
+
throw new Error(`Invalid XLSX cell address: ${address}`);
|
|
322
|
+
}
|
|
323
|
+
let col = 0;
|
|
324
|
+
for (const character of match[1].toUpperCase()) {
|
|
325
|
+
col = col * 26 + character.charCodeAt(0) - 64;
|
|
326
|
+
}
|
|
327
|
+
return { row: Number(match[2]) - 1, col: col - 1 };
|
|
328
|
+
}
|
|
329
|
+
function columnsXml(columns) {
|
|
330
|
+
if (!columns || columns.length === 0) {
|
|
331
|
+
return '';
|
|
332
|
+
}
|
|
333
|
+
const sorted = [...columns]
|
|
334
|
+
.filter((column) => Number.isSafeInteger(column.index) && column.index >= 0)
|
|
335
|
+
.toSorted((left, right) => left.index - right.index);
|
|
336
|
+
const groups = [];
|
|
337
|
+
let index = 0;
|
|
338
|
+
while (index < sorted.length) {
|
|
339
|
+
const first = sorted[index];
|
|
340
|
+
let last = first;
|
|
341
|
+
index += 1;
|
|
342
|
+
while (index < sorted.length &&
|
|
343
|
+
sorted[index].index === last.index + 1 &&
|
|
344
|
+
sorted[index].size === first.size &&
|
|
345
|
+
sorted[index].hidden === first.hidden) {
|
|
346
|
+
last = sorted[index];
|
|
347
|
+
index += 1;
|
|
348
|
+
}
|
|
349
|
+
const attributes = [`min="${String(first.index + 1)}"`, `max="${String(last.index + 1)}"`];
|
|
350
|
+
if (first.size !== undefined && Number.isFinite(first.size) && first.size > 0) {
|
|
351
|
+
attributes.push(`width="${String(Math.max(0.1, first.size / 6))}"`, 'customWidth="1"');
|
|
352
|
+
}
|
|
353
|
+
if (first.hidden === true) {
|
|
354
|
+
attributes.push('hidden="1"');
|
|
355
|
+
}
|
|
356
|
+
groups.push(`<col ${attributes.join(' ')}/>`);
|
|
357
|
+
}
|
|
358
|
+
return groups.length > 0 ? `<cols>${groups.join('')}</cols>` : '';
|
|
359
|
+
}
|
|
360
|
+
function sheetDataXml(sheet, registry) {
|
|
361
|
+
const cellsByRow = new Map();
|
|
362
|
+
for (const cell of sheet.cells) {
|
|
363
|
+
let row = cellsByRow.get(cell.row);
|
|
364
|
+
if (!row) {
|
|
365
|
+
row = [];
|
|
366
|
+
cellsByRow.set(cell.row, row);
|
|
367
|
+
}
|
|
368
|
+
row.push(cell);
|
|
369
|
+
}
|
|
370
|
+
for (const row of cellsByRow.values()) {
|
|
371
|
+
row.sort((left, right) => left.col - right.col);
|
|
372
|
+
}
|
|
373
|
+
const rowMetadataByIndex = new Map((sheet.rows ?? []).map((row) => [row.index, row]));
|
|
374
|
+
const rowIndexes = [...new Set([...cellsByRow.keys(), ...rowMetadataByIndex.keys()])].toSorted((left, right) => left - right);
|
|
375
|
+
return `<sheetData>${rowIndexes
|
|
376
|
+
.map((rowIndex) => rowXml(rowIndex, cellsByRow.get(rowIndex) ?? [], rowMetadataByIndex.get(rowIndex), registry))
|
|
377
|
+
.join('')}</sheetData>`;
|
|
378
|
+
}
|
|
379
|
+
function mergeCellsXml(merges) {
|
|
380
|
+
if (!merges || merges.length === 0) {
|
|
381
|
+
return '';
|
|
382
|
+
}
|
|
383
|
+
const entries = merges.map((merge) => `<mergeCell ref="${escapeXmlAttribute(`${merge.startAddress}:${merge.endAddress}`)}"/>`);
|
|
384
|
+
return `<mergeCells count="${String(entries.length)}">${entries.join('')}</mergeCells>`;
|
|
385
|
+
}
|
|
386
|
+
function autoFilterXml(autoFilters) {
|
|
387
|
+
const filter = autoFilters?.[0];
|
|
388
|
+
return filter ? `<autoFilter ref="${escapeXmlAttribute(`${filter.startAddress}:${filter.endAddress}`)}"/>` : '';
|
|
389
|
+
}
|
|
390
|
+
function validSimpleHyperlinks(hyperlinks) {
|
|
391
|
+
return (hyperlinks ?? []).filter((hyperlink) => hyperlink.address.trim().length > 0 && hyperlink.target.trim().length > 0);
|
|
392
|
+
}
|
|
393
|
+
function externalHyperlinkRelationshipId(index) {
|
|
394
|
+
return `rIdHyperlink${String(index + 1)}`;
|
|
395
|
+
}
|
|
396
|
+
function worksheetHyperlinksXml(hyperlinks) {
|
|
397
|
+
let externalIndex = 0;
|
|
398
|
+
const entries = validSimpleHyperlinks(hyperlinks).map((hyperlink) => {
|
|
399
|
+
const target = hyperlink.target.trim();
|
|
400
|
+
let targetAttribute;
|
|
401
|
+
if (target.startsWith('#')) {
|
|
402
|
+
targetAttribute = `location="${escapeXmlAttribute(target.slice(1))}"`;
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
targetAttribute = `r:id="${externalHyperlinkRelationshipId(externalIndex)}"`;
|
|
406
|
+
externalIndex += 1;
|
|
407
|
+
}
|
|
408
|
+
const attributes = [
|
|
409
|
+
`ref="${escapeXmlAttribute(hyperlink.address)}"`,
|
|
410
|
+
targetAttribute,
|
|
411
|
+
hyperlink.tooltip && hyperlink.tooltip.trim().length > 0 ? `tooltip="${escapeXmlAttribute(hyperlink.tooltip)}"` : null,
|
|
412
|
+
hyperlink.display && hyperlink.display.trim().length > 0 ? `display="${escapeXmlAttribute(hyperlink.display)}"` : null,
|
|
413
|
+
].filter((entry) => Boolean(entry));
|
|
414
|
+
return `<hyperlink ${attributes.join(' ')}/>`;
|
|
415
|
+
});
|
|
416
|
+
return entries.length > 0 ? `<hyperlinks>${entries.join('')}</hyperlinks>` : '';
|
|
417
|
+
}
|
|
418
|
+
function normalizedMacroCodeName(value) {
|
|
419
|
+
const trimmed = value?.trim();
|
|
420
|
+
return trimmed && trimmed.length > 0 ? trimmed : null;
|
|
421
|
+
}
|
|
422
|
+
function macroSheetCodeNameByName(macro) {
|
|
423
|
+
const output = new Map();
|
|
424
|
+
for (const entry of macro?.sheetCodeNames ?? []) {
|
|
425
|
+
const sheetName = entry.sheetName.trim();
|
|
426
|
+
const codeName = normalizedMacroCodeName(entry.codeName);
|
|
427
|
+
if (sheetName.length > 0 && codeName) {
|
|
428
|
+
output.set(sheetName, codeName);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return output;
|
|
432
|
+
}
|
|
433
|
+
function sheetPropertiesXml(sheetCodeName) {
|
|
434
|
+
const codeName = normalizedMacroCodeName(sheetCodeName);
|
|
435
|
+
return codeName ? `<sheetPr codeName="${escapeXmlAttribute(codeName)}"/>` : '';
|
|
436
|
+
}
|
|
437
|
+
function worksheetXml(sheet, registry, sheetCodeName) {
|
|
438
|
+
return [
|
|
439
|
+
xmlDeclaration(),
|
|
440
|
+
`<worksheet xmlns="${spreadsheetNs}" xmlns:r="${relationshipNs}">`,
|
|
441
|
+
sheetPropertiesXml(sheetCodeName),
|
|
442
|
+
`<dimension ref="${escapeXmlAttribute(worksheetDimension(sheet))}"/>`,
|
|
443
|
+
'<sheetViews><sheetView workbookViewId="0"/></sheetViews>',
|
|
444
|
+
'<sheetFormatPr defaultRowHeight="15"/>',
|
|
445
|
+
columnsXml(sheet.columns),
|
|
446
|
+
sheetDataXml(sheet, registry),
|
|
447
|
+
mergeCellsXml(sheet.merges),
|
|
448
|
+
autoFilterXml(sheet.autoFilters),
|
|
449
|
+
worksheetHyperlinksXml(sheet.hyperlinks),
|
|
450
|
+
'</worksheet>',
|
|
451
|
+
].join('');
|
|
452
|
+
}
|
|
453
|
+
function workbookXml(workbook) {
|
|
454
|
+
const sheetsXml = workbook.sheets
|
|
455
|
+
.map((sheet, index) => `<sheet name="${escapeXmlAttribute(sheet.name)}" sheetId="${String(index + 1)}" r:id="rId${String(index + 1)}"/>`)
|
|
456
|
+
.join('');
|
|
457
|
+
const definedNamesXml = definedNamesXmlForWorkbook(workbook.definedNames);
|
|
458
|
+
return [
|
|
459
|
+
xmlDeclaration(),
|
|
460
|
+
`<workbook xmlns="${spreadsheetNs}" xmlns:r="${relationshipNs}">`,
|
|
461
|
+
workbookPropertiesXml(workbook.macro),
|
|
462
|
+
`<sheets>${sheetsXml}</sheets>`,
|
|
463
|
+
definedNamesXml,
|
|
464
|
+
'</workbook>',
|
|
465
|
+
].join('');
|
|
466
|
+
}
|
|
467
|
+
function workbookPropertiesXml(macro) {
|
|
468
|
+
const codeName = normalizedMacroCodeName(macro?.workbookCodeName);
|
|
469
|
+
return codeName ? `<workbookPr codeName="${escapeXmlAttribute(codeName)}"/>` : '<workbookPr/>';
|
|
470
|
+
}
|
|
471
|
+
function definedNamesXmlForWorkbook(definedNames) {
|
|
472
|
+
if (!definedNames || definedNames.length === 0) {
|
|
473
|
+
return '';
|
|
474
|
+
}
|
|
475
|
+
return `<definedNames>${definedNames
|
|
476
|
+
.map((entry) => {
|
|
477
|
+
const localSheetId = entry.localSheetIndex !== undefined && Number.isSafeInteger(entry.localSheetIndex) && entry.localSheetIndex >= 0
|
|
478
|
+
? ` localSheetId="${String(entry.localSheetIndex)}"`
|
|
479
|
+
: '';
|
|
480
|
+
return `<definedName name="${escapeXmlAttribute(entry.name)}"${localSheetId}>${escapeXmlText(entry.formula.replace(/^=/u, ''))}</definedName>`;
|
|
481
|
+
})
|
|
482
|
+
.join('')}</definedNames>`;
|
|
483
|
+
}
|
|
484
|
+
function workbookRelationshipsXml(sheetCount, hasSharedStrings, hasMacro) {
|
|
485
|
+
const sheetRelationships = Array.from({ length: sheetCount }, (_entry, index) => `<Relationship Id="rId${String(index + 1)}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet${String(index + 1)}.xml"/>`).join('');
|
|
486
|
+
return [
|
|
487
|
+
xmlDeclaration(),
|
|
488
|
+
`<Relationships xmlns="${packageRelationshipNs}">`,
|
|
489
|
+
sheetRelationships,
|
|
490
|
+
`<Relationship Id="rId${String(sheetCount + 1)}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>`,
|
|
491
|
+
`<Relationship Id="rId${String(sheetCount + 2)}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/>`,
|
|
492
|
+
hasSharedStrings
|
|
493
|
+
? `<Relationship Id="rId${String(sheetCount + 3)}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>`
|
|
494
|
+
: '',
|
|
495
|
+
hasMacro
|
|
496
|
+
? `<Relationship Id="rId${String(sheetCount + (hasSharedStrings ? 4 : 3))}" Type="http://schemas.microsoft.com/office/2006/relationships/vbaProject" Target="vbaProject.bin"/>`
|
|
497
|
+
: '',
|
|
498
|
+
'</Relationships>',
|
|
499
|
+
].join('');
|
|
500
|
+
}
|
|
501
|
+
function rootRelationshipsXml() {
|
|
502
|
+
return [
|
|
503
|
+
xmlDeclaration(),
|
|
504
|
+
`<Relationships xmlns="${packageRelationshipNs}">`,
|
|
505
|
+
'<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>',
|
|
506
|
+
'<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>',
|
|
507
|
+
'<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>',
|
|
508
|
+
'</Relationships>',
|
|
509
|
+
].join('');
|
|
510
|
+
}
|
|
511
|
+
function worksheetRelationshipsXml(hyperlinks) {
|
|
512
|
+
const relationships = validSimpleHyperlinks(hyperlinks)
|
|
513
|
+
.filter((hyperlink) => !hyperlink.target.trim().startsWith('#'))
|
|
514
|
+
.map((hyperlink, index) => `<Relationship Id="${externalHyperlinkRelationshipId(index)}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" Target="${escapeXmlAttribute(hyperlink.target.trim())}" TargetMode="External"/>`);
|
|
515
|
+
return relationships.length > 0
|
|
516
|
+
? [xmlDeclaration(), `<Relationships xmlns="${packageRelationshipNs}">`, ...relationships, '</Relationships>'].join('')
|
|
517
|
+
: '';
|
|
518
|
+
}
|
|
519
|
+
function contentTypesXml(sheetCount, hasSharedStrings, hasMacro) {
|
|
520
|
+
const worksheets = Array.from({ length: sheetCount }, (_entry, index) => `<Override PartName="/xl/worksheets/sheet${String(index + 1)}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>`).join('');
|
|
521
|
+
const sharedStrings = hasSharedStrings
|
|
522
|
+
? '<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>'
|
|
523
|
+
: '';
|
|
524
|
+
return [
|
|
525
|
+
xmlDeclaration(),
|
|
526
|
+
`<Types xmlns="${contentTypesNs}">`,
|
|
527
|
+
'<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>',
|
|
528
|
+
'<Default Extension="xml" ContentType="application/xml"/>',
|
|
529
|
+
hasMacro ? '<Default Extension="bin" ContentType="application/vnd.ms-office.vbaProject"/>' : '',
|
|
530
|
+
`<Override PartName="/xl/workbook.xml" ContentType="${hasMacro
|
|
531
|
+
? 'application/vnd.ms-excel.sheet.macroEnabled.main+xml'
|
|
532
|
+
: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml'}"/>`,
|
|
533
|
+
'<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>',
|
|
534
|
+
`<Override PartName="/xl/theme/theme1.xml" ContentType="${themeContentType}"/>`,
|
|
535
|
+
sharedStrings,
|
|
536
|
+
'<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>',
|
|
537
|
+
'<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>',
|
|
538
|
+
worksheets,
|
|
539
|
+
'</Types>',
|
|
540
|
+
].join('');
|
|
541
|
+
}
|
|
542
|
+
function corePropertiesXml() {
|
|
543
|
+
return [
|
|
544
|
+
xmlDeclaration(),
|
|
545
|
+
'<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">',
|
|
546
|
+
'<dc:creator>Bilig</dc:creator>',
|
|
547
|
+
'<cp:lastModifiedBy>Bilig</cp:lastModifiedBy>',
|
|
548
|
+
'</cp:coreProperties>',
|
|
549
|
+
].join('');
|
|
550
|
+
}
|
|
551
|
+
function appPropertiesXml(sheetCount) {
|
|
552
|
+
return [
|
|
553
|
+
xmlDeclaration(),
|
|
554
|
+
'<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">',
|
|
555
|
+
'<Application>Bilig</Application>',
|
|
556
|
+
`<HeadingPairs><vt:vector size="2" baseType="variant"><vt:variant><vt:lpstr>Worksheets</vt:lpstr></vt:variant><vt:variant><vt:i4>${String(sheetCount)}</vt:i4></vt:variant></vt:vector></HeadingPairs>`,
|
|
557
|
+
'</Properties>',
|
|
558
|
+
].join('');
|
|
559
|
+
}
|
|
560
|
+
function themeXml() {
|
|
561
|
+
return [
|
|
562
|
+
xmlDeclaration(),
|
|
563
|
+
'<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Bilig Theme">',
|
|
564
|
+
'<a:themeElements>',
|
|
565
|
+
'<a:clrScheme name="Bilig">',
|
|
566
|
+
'<a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1>',
|
|
567
|
+
'<a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1>',
|
|
568
|
+
'<a:dk2><a:srgbClr val="44546A"/></a:dk2>',
|
|
569
|
+
'<a:lt2><a:srgbClr val="E7E6E6"/></a:lt2>',
|
|
570
|
+
'<a:accent1><a:srgbClr val="4472C4"/></a:accent1>',
|
|
571
|
+
'<a:accent2><a:srgbClr val="ED7D31"/></a:accent2>',
|
|
572
|
+
'<a:accent3><a:srgbClr val="A5A5A5"/></a:accent3>',
|
|
573
|
+
'<a:accent4><a:srgbClr val="FFC000"/></a:accent4>',
|
|
574
|
+
'<a:accent5><a:srgbClr val="5B9BD5"/></a:accent5>',
|
|
575
|
+
'<a:accent6><a:srgbClr val="70AD47"/></a:accent6>',
|
|
576
|
+
'<a:hlink><a:srgbClr val="0563C1"/></a:hlink>',
|
|
577
|
+
'<a:folHlink><a:srgbClr val="954F72"/></a:folHlink>',
|
|
578
|
+
'</a:clrScheme>',
|
|
579
|
+
'<a:fontScheme name="Aptos">',
|
|
580
|
+
'<a:majorFont><a:latin typeface="Aptos Display"/><a:ea typeface=""/><a:cs typeface=""/></a:majorFont>',
|
|
581
|
+
'<a:minorFont><a:latin typeface="Aptos"/><a:ea typeface=""/><a:cs typeface=""/></a:minorFont>',
|
|
582
|
+
'</a:fontScheme>',
|
|
583
|
+
'<a:fmtScheme name="Bilig"><a:fillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill></a:fillStyleLst><a:lnStyleLst><a:ln w="9525"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill></a:ln></a:lnStyleLst><a:effectStyleLst><a:effectStyle/></a:effectStyleLst><a:bgFillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill></a:bgFillStyleLst></a:fmtScheme>',
|
|
584
|
+
'</a:themeElements>',
|
|
585
|
+
'</a:theme>',
|
|
586
|
+
].join('');
|
|
587
|
+
}
|
|
588
|
+
export function writeSimpleXlsxWorkbook(workbook) {
|
|
589
|
+
if (workbook.sheets.length === 0) {
|
|
590
|
+
throw new Error('Cannot write an XLSX workbook without worksheets');
|
|
591
|
+
}
|
|
592
|
+
const registry = buildStyleRegistry(workbook);
|
|
593
|
+
const hasSharedStrings = workbook.sharedStringsXml !== undefined;
|
|
594
|
+
const hasMacro = workbook.macro !== undefined;
|
|
595
|
+
const sheetCodeNameByName = macroSheetCodeNameByName(workbook.macro);
|
|
596
|
+
const zip = {
|
|
597
|
+
'[Content_Types].xml': new TextEncoder().encode(contentTypesXml(workbook.sheets.length, hasSharedStrings, hasMacro)),
|
|
598
|
+
'_rels/.rels': new TextEncoder().encode(rootRelationshipsXml()),
|
|
599
|
+
'docProps/app.xml': new TextEncoder().encode(appPropertiesXml(workbook.sheets.length)),
|
|
600
|
+
'docProps/core.xml': new TextEncoder().encode(corePropertiesXml()),
|
|
601
|
+
'xl/workbook.xml': new TextEncoder().encode(workbookXml(workbook)),
|
|
602
|
+
'xl/_rels/workbook.xml.rels': new TextEncoder().encode(workbookRelationshipsXml(workbook.sheets.length, hasSharedStrings, hasMacro)),
|
|
603
|
+
'xl/styles.xml': new TextEncoder().encode(registry.stylesXml),
|
|
604
|
+
'xl/theme/theme1.xml': new TextEncoder().encode(themeXml()),
|
|
605
|
+
};
|
|
606
|
+
if (workbook.macro !== undefined) {
|
|
607
|
+
zip['xl/vbaProject.bin'] = new Uint8Array(workbook.macro.vbaProject);
|
|
608
|
+
}
|
|
609
|
+
if (workbook.sharedStringsXml !== undefined) {
|
|
610
|
+
zip['xl/sharedStrings.xml'] = new TextEncoder().encode(workbook.sharedStringsXml);
|
|
611
|
+
}
|
|
612
|
+
workbook.sheets.forEach((sheet, index) => {
|
|
613
|
+
zip[`xl/worksheets/sheet${String(index + 1)}.xml`] = new TextEncoder().encode(worksheetXml(sheet, registry, sheetCodeNameByName.get(sheet.name)));
|
|
614
|
+
const relationshipsXml = worksheetRelationshipsXml(sheet.hyperlinks);
|
|
615
|
+
if (relationshipsXml.length > 0) {
|
|
616
|
+
zip[`xl/worksheets/_rels/sheet${String(index + 1)}.xml.rels`] = new TextEncoder().encode(relationshipsXml);
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
return zipSourcePreservingEntries(zip, new Map(), { dosTime: simpleWorkbookZipDosTimeParts });
|
|
620
|
+
}
|
|
621
|
+
//# sourceMappingURL=simple-workbook-writer.js.map
|