@devmm/puredocs-excel 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +2595 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1016 -0
- package/dist/index.d.ts +1016 -0
- package/dist/index.js +2544 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2595 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fflate = require('fflate');
|
|
4
|
+
|
|
5
|
+
var __typeError = (msg) => {
|
|
6
|
+
throw TypeError(msg);
|
|
7
|
+
};
|
|
8
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
9
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
10
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
11
|
+
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
|
|
12
|
+
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
13
|
+
|
|
14
|
+
// src/io/xml-parser.ts
|
|
15
|
+
function domElementToXml(el) {
|
|
16
|
+
const attributes = {};
|
|
17
|
+
for (let i = 0; i < el.attributes.length; i++) {
|
|
18
|
+
const attr = el.attributes[i];
|
|
19
|
+
attributes[attr.name] = attr.value;
|
|
20
|
+
}
|
|
21
|
+
const children = [];
|
|
22
|
+
for (let i = 0; i < el.children.length; i++) {
|
|
23
|
+
children.push(domElementToXml(el.children[i]));
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
tagName: el.tagName,
|
|
27
|
+
attributes,
|
|
28
|
+
children,
|
|
29
|
+
textContent: el.textContent ?? ""
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function parseDom(xmlString) {
|
|
33
|
+
const parser = new DOMParser();
|
|
34
|
+
const doc = parser.parseFromString(xmlString, "application/xml");
|
|
35
|
+
const parseError = doc.querySelector("parsererror");
|
|
36
|
+
if (parseError) {
|
|
37
|
+
throw new Error(`XML parse error: ${parseError.textContent}`);
|
|
38
|
+
}
|
|
39
|
+
if (!doc.documentElement) {
|
|
40
|
+
throw new Error("XML parse error: no document element.");
|
|
41
|
+
}
|
|
42
|
+
return domElementToXml(doc.documentElement);
|
|
43
|
+
}
|
|
44
|
+
function parseMinimal(xmlString) {
|
|
45
|
+
const stack = [];
|
|
46
|
+
let pos = 0;
|
|
47
|
+
let root;
|
|
48
|
+
function skipUntil(ch) {
|
|
49
|
+
while (pos < xmlString.length && xmlString[pos] !== ch) pos++;
|
|
50
|
+
}
|
|
51
|
+
function parseAttributes(raw) {
|
|
52
|
+
const attrs = {};
|
|
53
|
+
const re = /(\S+?)\s*=\s*["']([^"']*)["']/g;
|
|
54
|
+
let m;
|
|
55
|
+
while ((m = re.exec(raw)) !== null) {
|
|
56
|
+
attrs[m[1]] = m[2].replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&");
|
|
57
|
+
}
|
|
58
|
+
return attrs;
|
|
59
|
+
}
|
|
60
|
+
while (pos < xmlString.length) {
|
|
61
|
+
if (xmlString[pos] === "<") {
|
|
62
|
+
pos++;
|
|
63
|
+
if (xmlString[pos] === "?") {
|
|
64
|
+
skipUntil(">");
|
|
65
|
+
pos++;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (xmlString[pos] === "!") {
|
|
69
|
+
if (xmlString.startsWith("![CDATA[", pos)) {
|
|
70
|
+
const cdataStart = pos + "![CDATA[".length;
|
|
71
|
+
const cdataEnd = xmlString.indexOf("]]>", cdataStart);
|
|
72
|
+
const end = cdataEnd === -1 ? xmlString.length : cdataEnd;
|
|
73
|
+
const cdata = xmlString.slice(cdataStart, end);
|
|
74
|
+
if (stack.length > 0) {
|
|
75
|
+
stack[stack.length - 1].textContent += cdata;
|
|
76
|
+
}
|
|
77
|
+
pos = cdataEnd === -1 ? xmlString.length : cdataEnd + 3;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
skipUntil(">");
|
|
81
|
+
pos++;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const isClose = xmlString[pos] === "/";
|
|
85
|
+
if (isClose) pos++;
|
|
86
|
+
const tagStart = pos;
|
|
87
|
+
skipUntil(">");
|
|
88
|
+
const tagContent = xmlString.slice(tagStart, pos).trim();
|
|
89
|
+
pos++;
|
|
90
|
+
const isSelfClose = tagContent.endsWith("/");
|
|
91
|
+
const raw = isSelfClose ? tagContent.slice(0, -1).trim() : tagContent;
|
|
92
|
+
const spaceIdx = raw.search(/\s/);
|
|
93
|
+
const tagName = spaceIdx === -1 ? raw : raw.slice(0, spaceIdx);
|
|
94
|
+
const attrRaw = spaceIdx === -1 ? "" : raw.slice(spaceIdx);
|
|
95
|
+
const attributes = parseAttributes(attrRaw);
|
|
96
|
+
if (isClose) {
|
|
97
|
+
stack.pop();
|
|
98
|
+
} else {
|
|
99
|
+
const el = { tagName, attributes, children: [], textContent: "" };
|
|
100
|
+
if (stack.length > 0) {
|
|
101
|
+
stack[stack.length - 1].children.push(el);
|
|
102
|
+
} else {
|
|
103
|
+
root = el;
|
|
104
|
+
}
|
|
105
|
+
if (!isSelfClose) stack.push(el);
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
const textStart = pos;
|
|
109
|
+
skipUntil("<");
|
|
110
|
+
const text = xmlString.slice(textStart, pos).replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&");
|
|
111
|
+
if (stack.length > 0 && text.trim()) {
|
|
112
|
+
stack[stack.length - 1].textContent += text;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!root) throw new Error("XML parse error: empty document.");
|
|
117
|
+
return root;
|
|
118
|
+
}
|
|
119
|
+
function parseXml(xmlString) {
|
|
120
|
+
if (typeof DOMParser !== "undefined") {
|
|
121
|
+
return parseDom(xmlString);
|
|
122
|
+
}
|
|
123
|
+
return parseMinimal(xmlString);
|
|
124
|
+
}
|
|
125
|
+
function decodeUtf8(bytes) {
|
|
126
|
+
if (typeof TextDecoder !== "undefined") {
|
|
127
|
+
return new TextDecoder("utf-8").decode(bytes);
|
|
128
|
+
}
|
|
129
|
+
return Buffer.from(bytes).toString("utf-8");
|
|
130
|
+
}
|
|
131
|
+
function encodeUtf8(str) {
|
|
132
|
+
if (typeof TextEncoder !== "undefined") {
|
|
133
|
+
return new TextEncoder().encode(str);
|
|
134
|
+
}
|
|
135
|
+
return Buffer.from(str, "utf-8");
|
|
136
|
+
}
|
|
137
|
+
function getElementsByTagName(root, localName) {
|
|
138
|
+
const results = [];
|
|
139
|
+
const lname = localName.toLowerCase();
|
|
140
|
+
function walk(el) {
|
|
141
|
+
const tag = el.tagName.toLowerCase();
|
|
142
|
+
if (tag === lname || tag.endsWith(`:${lname}`)) {
|
|
143
|
+
results.push(el);
|
|
144
|
+
}
|
|
145
|
+
for (const child of el.children) walk(child);
|
|
146
|
+
}
|
|
147
|
+
walk(root);
|
|
148
|
+
return results;
|
|
149
|
+
}
|
|
150
|
+
function getAttr(el, name) {
|
|
151
|
+
if (name in el.attributes) return el.attributes[name];
|
|
152
|
+
const local = name.includes(":") ? name.split(":").pop() : name;
|
|
153
|
+
for (const [key, val] of Object.entries(el.attributes)) {
|
|
154
|
+
if (key === local || key.endsWith(`:${local}`)) return val;
|
|
155
|
+
}
|
|
156
|
+
return void 0;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/io/zip-reader.ts
|
|
160
|
+
function unzipXlsx(buffer) {
|
|
161
|
+
const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
|
162
|
+
let raw;
|
|
163
|
+
try {
|
|
164
|
+
raw = fflate.unzipSync(bytes);
|
|
165
|
+
} catch (err) {
|
|
166
|
+
throw new Error(
|
|
167
|
+
`Failed to unzip xlsx: ${err instanceof Error ? err.message : String(err)}`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
const entries = /* @__PURE__ */ new Map();
|
|
171
|
+
for (const [path, data] of Object.entries(raw)) {
|
|
172
|
+
entries.set(path.replace(/\\/g, "/"), data);
|
|
173
|
+
}
|
|
174
|
+
return entries;
|
|
175
|
+
}
|
|
176
|
+
function readXmlEntry(entries, path) {
|
|
177
|
+
const bytes = entries.get(path);
|
|
178
|
+
if (!bytes) return void 0;
|
|
179
|
+
return decodeUtf8(bytes);
|
|
180
|
+
}
|
|
181
|
+
function requireXmlEntry(entries, path) {
|
|
182
|
+
const text = readXmlEntry(entries, path);
|
|
183
|
+
if (text === void 0) {
|
|
184
|
+
throw new Error(`Required xlsx entry not found: "${path}".`);
|
|
185
|
+
}
|
|
186
|
+
return text;
|
|
187
|
+
}
|
|
188
|
+
function listEntries(entries, prefix) {
|
|
189
|
+
const results = [];
|
|
190
|
+
for (const key of entries.keys()) {
|
|
191
|
+
if (key.startsWith(prefix)) results.push(key);
|
|
192
|
+
}
|
|
193
|
+
return results.sort();
|
|
194
|
+
}
|
|
195
|
+
function zipXlsx(entries) {
|
|
196
|
+
const zippable = {};
|
|
197
|
+
for (const [path, content] of entries) {
|
|
198
|
+
const bytes = typeof content === "string" ? encodeUtf8(content) : content;
|
|
199
|
+
zippable[path] = [bytes, { level: 6 }];
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
return fflate.zipSync(zippable);
|
|
203
|
+
} catch (err) {
|
|
204
|
+
throw new Error(
|
|
205
|
+
`Failed to create xlsx: ${err instanceof Error ? err.message : String(err)}`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function setXmlEntry(entries, path, xml2) {
|
|
210
|
+
entries.set(path, xml2);
|
|
211
|
+
}
|
|
212
|
+
function setBinaryEntry(entries, path, bytes) {
|
|
213
|
+
entries.set(path, bytes);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/io/xml-builder.ts
|
|
217
|
+
function escapeXml(value) {
|
|
218
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
219
|
+
}
|
|
220
|
+
function attrsToString(attrs) {
|
|
221
|
+
let result = "";
|
|
222
|
+
for (const [key, val] of Object.entries(attrs)) {
|
|
223
|
+
if (val === void 0 || val === null) continue;
|
|
224
|
+
result += ` ${key}="${escapeXml(String(val))}"`;
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
var XmlBuilder = class {
|
|
229
|
+
constructor() {
|
|
230
|
+
this.parts = [];
|
|
231
|
+
}
|
|
232
|
+
/** Appends the XML declaration header. */
|
|
233
|
+
xmlDeclaration() {
|
|
234
|
+
this.parts.push('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>');
|
|
235
|
+
return this;
|
|
236
|
+
}
|
|
237
|
+
/** Opens a tag with optional attributes. */
|
|
238
|
+
open(tag, attrs) {
|
|
239
|
+
this.parts.push(`<${tag}${attrsToString(attrs ?? {})}>`);
|
|
240
|
+
return this;
|
|
241
|
+
}
|
|
242
|
+
/** Closes a tag. */
|
|
243
|
+
close(tag) {
|
|
244
|
+
this.parts.push(`</${tag}>`);
|
|
245
|
+
return this;
|
|
246
|
+
}
|
|
247
|
+
/** Writes a self-closing tag. */
|
|
248
|
+
self(tag, attrs) {
|
|
249
|
+
this.parts.push(`<${tag}${attrsToString(attrs ?? {})} />`);
|
|
250
|
+
return this;
|
|
251
|
+
}
|
|
252
|
+
/** Writes a tag with text content. */
|
|
253
|
+
text(tag, content, attrs) {
|
|
254
|
+
this.parts.push(`<${tag}${attrsToString(attrs ?? {})}>${escapeXml(content)}</${tag}>`);
|
|
255
|
+
return this;
|
|
256
|
+
}
|
|
257
|
+
/** Writes raw (pre-escaped) XML — use with caution. */
|
|
258
|
+
raw(xml2) {
|
|
259
|
+
this.parts.push(xml2);
|
|
260
|
+
return this;
|
|
261
|
+
}
|
|
262
|
+
/** Returns the complete XML string. */
|
|
263
|
+
toString() {
|
|
264
|
+
return this.parts.join("");
|
|
265
|
+
}
|
|
266
|
+
/** Returns UTF-8 encoded bytes. */
|
|
267
|
+
toBytes() {
|
|
268
|
+
const str = this.toString();
|
|
269
|
+
if (typeof TextEncoder !== "undefined") {
|
|
270
|
+
return new TextEncoder().encode(str);
|
|
271
|
+
}
|
|
272
|
+
return Buffer.from(str, "utf-8");
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
function xml() {
|
|
276
|
+
return new XmlBuilder();
|
|
277
|
+
}
|
|
278
|
+
var NS = {
|
|
279
|
+
// SpreadsheetML
|
|
280
|
+
spreadsheetml: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
|
|
281
|
+
// Relationships
|
|
282
|
+
relationships: "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
|
283
|
+
relationshipsPackage: "http://schemas.openxmlformats.org/package/2006/relationships",
|
|
284
|
+
// Drawing
|
|
285
|
+
drawingml: "http://schemas.openxmlformats.org/drawingml/2006/main",
|
|
286
|
+
spreadsheetDrawing: "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing",
|
|
287
|
+
// Content types
|
|
288
|
+
contentTypes: "http://schemas.openxmlformats.org/package/2006/content-types",
|
|
289
|
+
// Core properties
|
|
290
|
+
coreProperties: "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"
|
|
291
|
+
};
|
|
292
|
+
var REL_TYPES = {
|
|
293
|
+
officeDocument: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
|
|
294
|
+
worksheet: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
|
|
295
|
+
sharedStrings: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings",
|
|
296
|
+
styles: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",
|
|
297
|
+
chart: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart",
|
|
298
|
+
drawing: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing",
|
|
299
|
+
hyperlink: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
|
|
300
|
+
};
|
|
301
|
+
var CONTENT_TYPES = {
|
|
302
|
+
workbook: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
|
|
303
|
+
worksheet: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
|
|
304
|
+
sharedStrings: "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
|
|
305
|
+
styles: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
|
|
306
|
+
drawing: "application/vnd.openxmlformats-officedocument.drawing+xml",
|
|
307
|
+
chart: "application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
|
|
308
|
+
relationships: "application/vnd.openxmlformats-package.relationships+xml",
|
|
309
|
+
coreProperties: "application/vnd.openxmlformats-package.core-properties+xml"
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// src/io/ooxml-templates.ts
|
|
313
|
+
function buildContentTypes(sheetCount, extraOverrides = []) {
|
|
314
|
+
const overrides = Array.from(
|
|
315
|
+
{ length: sheetCount },
|
|
316
|
+
(_, i) => ` <Override PartName="/xl/worksheets/sheet${i + 1}.xml" ContentType="${CONTENT_TYPES.worksheet}"/>`
|
|
317
|
+
);
|
|
318
|
+
for (const { partName, contentType } of extraOverrides) {
|
|
319
|
+
overrides.push(` <Override PartName="${partName}" ContentType="${contentType}"/>`);
|
|
320
|
+
}
|
|
321
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
322
|
+
<Types xmlns="${"http://schemas.openxmlformats.org/package/2006/content-types"}">
|
|
323
|
+
<Default Extension="rels" ContentType="${CONTENT_TYPES.relationships}"/>
|
|
324
|
+
<Default Extension="xml" ContentType="application/xml"/>
|
|
325
|
+
<Override PartName="/xl/workbook.xml" ContentType="${CONTENT_TYPES.workbook}"/>
|
|
326
|
+
<Override PartName="/xl/styles.xml" ContentType="${CONTENT_TYPES.styles}"/>
|
|
327
|
+
<Override PartName="/xl/sharedStrings.xml" ContentType="${CONTENT_TYPES.sharedStrings}"/>
|
|
328
|
+
${overrides.join("\n")}
|
|
329
|
+
</Types>`;
|
|
330
|
+
}
|
|
331
|
+
var ROOT_RELS = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
332
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
333
|
+
<Relationship Id="rId1" Type="${REL_TYPES.officeDocument}" Target="xl/workbook.xml"/>
|
|
334
|
+
</Relationships>`;
|
|
335
|
+
function buildWorkbookRels(sheetCount) {
|
|
336
|
+
const sheetRels = Array.from(
|
|
337
|
+
{ length: sheetCount },
|
|
338
|
+
(_, i) => ` <Relationship Id="rId${i + 1}" Type="${REL_TYPES.worksheet}" Target="worksheets/sheet${i + 1}.xml"/>`
|
|
339
|
+
).join("\n");
|
|
340
|
+
const stylesId = sheetCount + 1;
|
|
341
|
+
const sharedId = sheetCount + 2;
|
|
342
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
343
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
344
|
+
${sheetRels}
|
|
345
|
+
<Relationship Id="rId${stylesId}" Type="${REL_TYPES.styles}" Target="styles.xml"/>
|
|
346
|
+
<Relationship Id="rId${sharedId}" Type="${REL_TYPES.sharedStrings}" Target="sharedStrings.xml"/>
|
|
347
|
+
</Relationships>`;
|
|
348
|
+
}
|
|
349
|
+
function buildWorkbookXml(sheets) {
|
|
350
|
+
const sheetElems = sheets.map(({ name, sheetId, relationshipId, state }) => {
|
|
351
|
+
const stateAttr = state && state !== "visible" ? ` state="${state}"` : "";
|
|
352
|
+
return ` <sheet name="${escapeAttr(name)}" sheetId="${sheetId}" r:id="${relationshipId}"${stateAttr}/>`;
|
|
353
|
+
}).join("\n");
|
|
354
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
355
|
+
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
356
|
+
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
357
|
+
<fileVersion appName="xl" lastEdited="7" lowestEdited="7" rupBuild="22228"/>
|
|
358
|
+
<workbookPr defaultThemeVersion="124226"/>
|
|
359
|
+
<bookViews>
|
|
360
|
+
<workbookView xWindow="240" yWindow="105" windowWidth="14805" windowHeight="8010"/>
|
|
361
|
+
</bookViews>
|
|
362
|
+
<sheets>
|
|
363
|
+
${sheetElems}
|
|
364
|
+
</sheets>
|
|
365
|
+
<calcPr calcId="191028" fullCalcOnLoad="1"/>
|
|
366
|
+
</workbook>`;
|
|
367
|
+
}
|
|
368
|
+
var EMPTY_WORKSHEET_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
369
|
+
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
370
|
+
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
371
|
+
<sheetData/>
|
|
372
|
+
</worksheet>`;
|
|
373
|
+
function escapeAttr(s) {
|
|
374
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// src/io/drawing-part.ts
|
|
378
|
+
var WORKSHEET_DRAWING_REL_ID = "rId1";
|
|
379
|
+
function buildDrawingXml(anchorsXml) {
|
|
380
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
381
|
+
<xdr:wsDr xmlns:xdr="${NS.spreadsheetDrawing}" xmlns:a="${NS.drawingml}">${anchorsXml}</xdr:wsDr>`;
|
|
382
|
+
}
|
|
383
|
+
function buildRelsXml(relationships) {
|
|
384
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
385
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
386
|
+
${relationships.join("\n")}
|
|
387
|
+
</Relationships>`;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// src/model/shared-string-manager.ts
|
|
391
|
+
var _stringToIndex, _indexToString;
|
|
392
|
+
var SharedStringManager = class {
|
|
393
|
+
constructor() {
|
|
394
|
+
/** Forward map: string value → index */
|
|
395
|
+
__privateAdd(this, _stringToIndex, /* @__PURE__ */ new Map());
|
|
396
|
+
/** Reverse map: index → string value */
|
|
397
|
+
__privateAdd(this, _indexToString, []);
|
|
398
|
+
}
|
|
399
|
+
// ── Public API ─────────────────────────────────────────────────────────────
|
|
400
|
+
/** Total number of unique strings. */
|
|
401
|
+
get count() {
|
|
402
|
+
return __privateGet(this, _indexToString).length;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Adds a string to the table (if not already present) and returns its index.
|
|
406
|
+
* O(1) average case.
|
|
407
|
+
*/
|
|
408
|
+
addOrGet(value) {
|
|
409
|
+
const existing = __privateGet(this, _stringToIndex).get(value);
|
|
410
|
+
if (existing !== void 0) return existing;
|
|
411
|
+
const idx = __privateGet(this, _indexToString).length;
|
|
412
|
+
__privateGet(this, _indexToString).push(value);
|
|
413
|
+
__privateGet(this, _stringToIndex).set(value, idx);
|
|
414
|
+
return idx;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Returns the string at the given index.
|
|
418
|
+
* Throws if index is out of range.
|
|
419
|
+
*/
|
|
420
|
+
getString(index) {
|
|
421
|
+
const s = __privateGet(this, _indexToString)[index];
|
|
422
|
+
if (s === void 0) {
|
|
423
|
+
throw new RangeError(
|
|
424
|
+
`Shared string index ${index} out of range [0, ${__privateGet(this, _indexToString).length - 1}].`
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
return s;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Returns the string at index, or undefined if not found.
|
|
431
|
+
* Safe alternative to getString().
|
|
432
|
+
*/
|
|
433
|
+
tryGetString(index) {
|
|
434
|
+
return __privateGet(this, _indexToString)[index];
|
|
435
|
+
}
|
|
436
|
+
/** Returns true if the string is already in the table. */
|
|
437
|
+
has(value) {
|
|
438
|
+
return __privateGet(this, _stringToIndex).has(value);
|
|
439
|
+
}
|
|
440
|
+
// ── XML serialisation ──────────────────────────────────────────────────────
|
|
441
|
+
/**
|
|
442
|
+
* Builds the xl/sharedStrings.xml string.
|
|
443
|
+
*/
|
|
444
|
+
buildXml() {
|
|
445
|
+
const count = __privateGet(this, _indexToString).length;
|
|
446
|
+
const items = __privateGet(this, _indexToString).map((s) => {
|
|
447
|
+
const preserveSpace = s.startsWith(" ") || s.endsWith(" ") ? ' xml:space="preserve"' : "";
|
|
448
|
+
return `<si><t${preserveSpace}>${escContent(s)}</t></si>`;
|
|
449
|
+
}).join("");
|
|
450
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
451
|
+
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="${count}" uniqueCount="${count}">
|
|
452
|
+
${items}
|
|
453
|
+
</sst>`;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Parses an existing xl/sharedStrings.xml and loads strings into the table.
|
|
457
|
+
*/
|
|
458
|
+
loadFromXml(xml2) {
|
|
459
|
+
__privateGet(this, _stringToIndex).clear();
|
|
460
|
+
__privateGet(this, _indexToString).length = 0;
|
|
461
|
+
const root = parseXml(xml2);
|
|
462
|
+
for (const si of getElementsByTagName(root, "si")) {
|
|
463
|
+
const tNodes = getElementsByTagName(si, "t");
|
|
464
|
+
const text = tNodes.map((t) => t.textContent).join("");
|
|
465
|
+
this.addOrGet(text);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
_stringToIndex = new WeakMap();
|
|
470
|
+
_indexToString = new WeakMap();
|
|
471
|
+
function escContent(s) {
|
|
472
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// src/style/excel-color.ts
|
|
476
|
+
var _ExcelColor = class _ExcelColor {
|
|
477
|
+
constructor(opts) {
|
|
478
|
+
this.hex = opts.hex;
|
|
479
|
+
this.theme = opts.theme;
|
|
480
|
+
this.tint = opts.tint;
|
|
481
|
+
this.indexed = opts.indexed;
|
|
482
|
+
}
|
|
483
|
+
// ── Factory methods ────────────────────────────────────────────────────────
|
|
484
|
+
/**
|
|
485
|
+
* Creates a color from a hex string.
|
|
486
|
+
* Accepts "#RGB", "#RRGGBB", "RRGGBB", or "AARRGGBB" formats.
|
|
487
|
+
*/
|
|
488
|
+
static fromHex(hex) {
|
|
489
|
+
if (!hex) throw new Error("Hex color cannot be empty.");
|
|
490
|
+
let h = hex.startsWith("#") ? hex.slice(1) : hex;
|
|
491
|
+
if (h.length === 3) {
|
|
492
|
+
h = `FF${h[0]}${h[0]}${h[1]}${h[1]}${h[2]}${h[2]}`;
|
|
493
|
+
} else if (h.length === 6) {
|
|
494
|
+
h = `FF${h}`;
|
|
495
|
+
} else if (h.length !== 8) {
|
|
496
|
+
throw new Error(
|
|
497
|
+
`Invalid hex color "${hex}". Expected 3, 6, or 8 hex characters (with optional # prefix).`
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
const upper = h.toUpperCase();
|
|
501
|
+
if (!/^[0-9A-F]{8}$/.test(upper)) {
|
|
502
|
+
throw new Error(`Invalid hex color "${hex}": contains non-hex characters.`);
|
|
503
|
+
}
|
|
504
|
+
return new _ExcelColor({ hex: upper });
|
|
505
|
+
}
|
|
506
|
+
/** Creates a color from RGB values (0–255). Alpha is set to 255 (opaque). */
|
|
507
|
+
static fromRgb(red, green, blue) {
|
|
508
|
+
return new _ExcelColor({
|
|
509
|
+
hex: `FF${byteHex(red)}${byteHex(green)}${byteHex(blue)}`
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
/** Creates a color from ARGB values (0–255). */
|
|
513
|
+
static fromArgb(alpha, red, green, blue) {
|
|
514
|
+
return new _ExcelColor({
|
|
515
|
+
hex: `${byteHex(alpha)}${byteHex(red)}${byteHex(green)}${byteHex(blue)}`
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
/** Creates a theme color with optional tint value (-1.0 to 1.0). */
|
|
519
|
+
static fromTheme(themeIndex, tint = 0) {
|
|
520
|
+
return new _ExcelColor({
|
|
521
|
+
theme: themeIndex,
|
|
522
|
+
tint: tint !== 0 ? tint : void 0
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
/** Creates an indexed color. */
|
|
526
|
+
static fromIndexed(index) {
|
|
527
|
+
return new _ExcelColor({ indexed: index });
|
|
528
|
+
}
|
|
529
|
+
// ── Serialisation ─────────────────────────────────────────────────────────
|
|
530
|
+
/** Returns XML attribute key-value pairs for embedding in OOXML elements. */
|
|
531
|
+
toXmlAttrs() {
|
|
532
|
+
if (this.hex !== void 0) return { rgb: this.hex };
|
|
533
|
+
if (this.theme !== void 0) {
|
|
534
|
+
const attrs = { theme: this.theme };
|
|
535
|
+
if (this.tint !== void 0) attrs.tint = this.tint;
|
|
536
|
+
return attrs;
|
|
537
|
+
}
|
|
538
|
+
if (this.indexed !== void 0) return { indexed: this.indexed };
|
|
539
|
+
return {};
|
|
540
|
+
}
|
|
541
|
+
/** Builds an XML color element string for use inside other elements. */
|
|
542
|
+
toXmlElement(tagName) {
|
|
543
|
+
const attrs = this.toXmlAttrs();
|
|
544
|
+
const parts = [];
|
|
545
|
+
if (attrs.rgb !== void 0) parts.push(`rgb="${attrs.rgb}"`);
|
|
546
|
+
if (attrs.theme !== void 0) parts.push(`theme="${attrs.theme}"`);
|
|
547
|
+
if (attrs.tint !== void 0) parts.push(`tint="${attrs.tint}"`);
|
|
548
|
+
if (attrs.indexed !== void 0) parts.push(`indexed="${attrs.indexed}"`);
|
|
549
|
+
return `<${tagName} ${parts.join(" ")}/>`;
|
|
550
|
+
}
|
|
551
|
+
/** Parses a color from OOXML XML attributes. Returns undefined if no color data. */
|
|
552
|
+
static fromXmlAttrs(attrs) {
|
|
553
|
+
const rgb = attrs["rgb"];
|
|
554
|
+
if (rgb) return _ExcelColor.fromHex(rgb);
|
|
555
|
+
const themeStr = attrs["theme"];
|
|
556
|
+
if (themeStr !== void 0) {
|
|
557
|
+
const tintStr = attrs["tint"];
|
|
558
|
+
return _ExcelColor.fromTheme(parseInt(themeStr, 10), tintStr ? parseFloat(tintStr) : 0);
|
|
559
|
+
}
|
|
560
|
+
const indexedStr = attrs["indexed"];
|
|
561
|
+
if (indexedStr !== void 0) return _ExcelColor.fromIndexed(parseInt(indexedStr, 10));
|
|
562
|
+
return void 0;
|
|
563
|
+
}
|
|
564
|
+
toString() {
|
|
565
|
+
if (this.hex !== void 0) return `#${this.hex}`;
|
|
566
|
+
if (this.theme !== void 0) return `Theme(${this.theme}${this.tint ? `,${this.tint}` : ""})`;
|
|
567
|
+
if (this.indexed !== void 0) return `Indexed(${this.indexed})`;
|
|
568
|
+
return "None";
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
// ── Predefined colors (camelCase, per TypeScript convention) ─────────────
|
|
572
|
+
_ExcelColor.black = _ExcelColor.fromHex("FF000000");
|
|
573
|
+
_ExcelColor.white = _ExcelColor.fromHex("FFFFFFFF");
|
|
574
|
+
_ExcelColor.red = _ExcelColor.fromHex("FFFF0000");
|
|
575
|
+
_ExcelColor.green = _ExcelColor.fromHex("FF00FF00");
|
|
576
|
+
_ExcelColor.blue = _ExcelColor.fromHex("FF0000FF");
|
|
577
|
+
_ExcelColor.yellow = _ExcelColor.fromHex("FFFFFF00");
|
|
578
|
+
_ExcelColor.magenta = _ExcelColor.fromHex("FFFF00FF");
|
|
579
|
+
_ExcelColor.cyan = _ExcelColor.fromHex("FF00FFFF");
|
|
580
|
+
_ExcelColor.orange = _ExcelColor.fromHex("FFFF8C00");
|
|
581
|
+
_ExcelColor.purple = _ExcelColor.fromHex("FF800080");
|
|
582
|
+
_ExcelColor.darkRed = _ExcelColor.fromHex("FF8B0000");
|
|
583
|
+
_ExcelColor.darkGreen = _ExcelColor.fromHex("FF006400");
|
|
584
|
+
_ExcelColor.darkBlue = _ExcelColor.fromHex("FF00008B");
|
|
585
|
+
_ExcelColor.lightGray = _ExcelColor.fromHex("FFD3D3D3");
|
|
586
|
+
_ExcelColor.darkGray = _ExcelColor.fromHex("FFA9A9A9");
|
|
587
|
+
_ExcelColor.gray = _ExcelColor.fromHex("FF808080");
|
|
588
|
+
_ExcelColor.lightBlue = _ExcelColor.fromHex("FFADD8E6");
|
|
589
|
+
_ExcelColor.lightGreen = _ExcelColor.fromHex("FF90EE90");
|
|
590
|
+
_ExcelColor.lightYellow = _ExcelColor.fromHex("FFFFFFED");
|
|
591
|
+
_ExcelColor.lightPink = _ExcelColor.fromHex("FFFFB6C1");
|
|
592
|
+
_ExcelColor.transparent = _ExcelColor.fromArgb(0, 0, 0, 0);
|
|
593
|
+
var ExcelColor = _ExcelColor;
|
|
594
|
+
function byteHex(n) {
|
|
595
|
+
return Math.max(0, Math.min(255, Math.round(n))).toString(16).padStart(2, "0").toUpperCase();
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// src/style/excel-font.ts
|
|
599
|
+
var ExcelUnderline = /* @__PURE__ */ ((ExcelUnderline2) => {
|
|
600
|
+
ExcelUnderline2["None"] = "none";
|
|
601
|
+
ExcelUnderline2["Single"] = "single";
|
|
602
|
+
ExcelUnderline2["Double"] = "double";
|
|
603
|
+
ExcelUnderline2["SingleAccounting"] = "singleAccounting";
|
|
604
|
+
ExcelUnderline2["DoubleAccounting"] = "doubleAccounting";
|
|
605
|
+
return ExcelUnderline2;
|
|
606
|
+
})(ExcelUnderline || {});
|
|
607
|
+
var ExcelVerticalAlignRun = /* @__PURE__ */ ((ExcelVerticalAlignRun3) => {
|
|
608
|
+
ExcelVerticalAlignRun3["Baseline"] = "baseline";
|
|
609
|
+
ExcelVerticalAlignRun3["Superscript"] = "superscript";
|
|
610
|
+
ExcelVerticalAlignRun3["Subscript"] = "subscript";
|
|
611
|
+
return ExcelVerticalAlignRun3;
|
|
612
|
+
})(ExcelVerticalAlignRun || {});
|
|
613
|
+
var ExcelFont = class _ExcelFont {
|
|
614
|
+
constructor(opts = {}) {
|
|
615
|
+
Object.assign(this, opts);
|
|
616
|
+
}
|
|
617
|
+
// ── Serialisation ─────────────────────────────────────────────────────────
|
|
618
|
+
toXml() {
|
|
619
|
+
const parts = [];
|
|
620
|
+
if (this.bold) parts.push("<b/>");
|
|
621
|
+
if (this.italic) parts.push("<i/>");
|
|
622
|
+
if (this.strikethrough) parts.push("<strike/>");
|
|
623
|
+
if (this.underline && this.underline !== "none" /* None */) {
|
|
624
|
+
parts.push(`<u val="${this.underline}"/>`);
|
|
625
|
+
}
|
|
626
|
+
if (this.verticalAlign && this.verticalAlign !== "baseline" /* Baseline */) {
|
|
627
|
+
parts.push(`<vertAlign val="${this.verticalAlign}"/>`);
|
|
628
|
+
}
|
|
629
|
+
parts.push(`<sz val="${this.size ?? 11}"/>`);
|
|
630
|
+
if (this.color) {
|
|
631
|
+
parts.push(this.color.toXmlElement("color"));
|
|
632
|
+
} else {
|
|
633
|
+
parts.push('<color theme="1"/>');
|
|
634
|
+
}
|
|
635
|
+
parts.push(`<name val="${this.name ?? "Calibri"}"/>`);
|
|
636
|
+
return `<font>${parts.join("")}</font>`;
|
|
637
|
+
}
|
|
638
|
+
/** Parses font from parsed XML child elements. */
|
|
639
|
+
static fromXmlChildren(children) {
|
|
640
|
+
const font = new _ExcelFont();
|
|
641
|
+
for (const el of children) {
|
|
642
|
+
const tag = el.tagName.replace(/^.*:/, "");
|
|
643
|
+
switch (tag) {
|
|
644
|
+
case "b":
|
|
645
|
+
font.bold = true;
|
|
646
|
+
break;
|
|
647
|
+
case "i":
|
|
648
|
+
font.italic = true;
|
|
649
|
+
break;
|
|
650
|
+
case "strike":
|
|
651
|
+
font.strikethrough = true;
|
|
652
|
+
break;
|
|
653
|
+
case "sz":
|
|
654
|
+
font.size = parseFloat(el.attributes["val"] ?? "11");
|
|
655
|
+
break;
|
|
656
|
+
case "name":
|
|
657
|
+
font.name = el.attributes["val"];
|
|
658
|
+
break;
|
|
659
|
+
case "u": {
|
|
660
|
+
const val = el.attributes["val"] ?? "single";
|
|
661
|
+
font.underline = Object.values(ExcelUnderline).includes(val) ? val : "single" /* Single */;
|
|
662
|
+
break;
|
|
663
|
+
}
|
|
664
|
+
case "vertAlign": {
|
|
665
|
+
const val = el.attributes["val"] ?? "baseline";
|
|
666
|
+
font.verticalAlign = Object.values(ExcelVerticalAlignRun).includes(val) ? val : "baseline" /* Baseline */;
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
case "color":
|
|
670
|
+
font.color = ExcelColor.fromXmlAttrs(el.attributes);
|
|
671
|
+
break;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return font;
|
|
675
|
+
}
|
|
676
|
+
/** Builds a canonical cache key for deduplication in StyleManager. */
|
|
677
|
+
cacheKey() {
|
|
678
|
+
return [
|
|
679
|
+
`n:${this.name ?? "Calibri"}`,
|
|
680
|
+
`s:${this.size ?? 11}`,
|
|
681
|
+
`b:${this.bold ?? false}`,
|
|
682
|
+
`i:${this.italic ?? false}`,
|
|
683
|
+
`u:${this.underline ?? "none" /* None */}`,
|
|
684
|
+
`st:${this.strikethrough ?? false}`,
|
|
685
|
+
`va:${this.verticalAlign ?? "baseline" /* Baseline */}`,
|
|
686
|
+
`c:${this.color?.toString() ?? "null"}`
|
|
687
|
+
].join("|");
|
|
688
|
+
}
|
|
689
|
+
clone() {
|
|
690
|
+
return new _ExcelFont({
|
|
691
|
+
name: this.name,
|
|
692
|
+
size: this.size,
|
|
693
|
+
bold: this.bold,
|
|
694
|
+
italic: this.italic,
|
|
695
|
+
underline: this.underline,
|
|
696
|
+
strikethrough: this.strikethrough,
|
|
697
|
+
color: this.color,
|
|
698
|
+
verticalAlign: this.verticalAlign
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
|
|
703
|
+
// src/style/excel-fill.ts
|
|
704
|
+
var ExcelPatternType = /* @__PURE__ */ ((ExcelPatternType3) => {
|
|
705
|
+
ExcelPatternType3["None"] = "none";
|
|
706
|
+
ExcelPatternType3["Solid"] = "solid";
|
|
707
|
+
ExcelPatternType3["DarkGray"] = "darkGray";
|
|
708
|
+
ExcelPatternType3["MediumGray"] = "mediumGray";
|
|
709
|
+
ExcelPatternType3["LightGray"] = "lightGray";
|
|
710
|
+
ExcelPatternType3["Gray125"] = "gray125";
|
|
711
|
+
ExcelPatternType3["Gray0625"] = "gray0625";
|
|
712
|
+
ExcelPatternType3["DarkHorizontal"] = "darkHorizontal";
|
|
713
|
+
ExcelPatternType3["DarkVertical"] = "darkVertical";
|
|
714
|
+
ExcelPatternType3["DarkDown"] = "darkDown";
|
|
715
|
+
ExcelPatternType3["DarkUp"] = "darkUp";
|
|
716
|
+
ExcelPatternType3["DarkGrid"] = "darkGrid";
|
|
717
|
+
ExcelPatternType3["DarkTrellis"] = "darkTrellis";
|
|
718
|
+
ExcelPatternType3["LightHorizontal"] = "lightHorizontal";
|
|
719
|
+
ExcelPatternType3["LightVertical"] = "lightVertical";
|
|
720
|
+
ExcelPatternType3["LightDown"] = "lightDown";
|
|
721
|
+
ExcelPatternType3["LightUp"] = "lightUp";
|
|
722
|
+
ExcelPatternType3["LightGrid"] = "lightGrid";
|
|
723
|
+
ExcelPatternType3["LightTrellis"] = "lightTrellis";
|
|
724
|
+
return ExcelPatternType3;
|
|
725
|
+
})(ExcelPatternType || {});
|
|
726
|
+
var _ExcelFill = class _ExcelFill {
|
|
727
|
+
constructor(patternType = "none" /* None */, foregroundColor, backgroundColor) {
|
|
728
|
+
this.patternType = patternType;
|
|
729
|
+
this.foregroundColor = foregroundColor;
|
|
730
|
+
this.backgroundColor = backgroundColor;
|
|
731
|
+
}
|
|
732
|
+
// ── Factory methods ────────────────────────────────────────────────────────
|
|
733
|
+
/**
|
|
734
|
+
* Creates a solid fill with the given color.
|
|
735
|
+
* Excel requires the magic indexed(64) background color for solid fills.
|
|
736
|
+
*/
|
|
737
|
+
static solid(color) {
|
|
738
|
+
return new _ExcelFill(
|
|
739
|
+
"solid" /* Solid */,
|
|
740
|
+
color,
|
|
741
|
+
ExcelColor.fromIndexed(64)
|
|
742
|
+
// required by Excel spec
|
|
743
|
+
);
|
|
744
|
+
}
|
|
745
|
+
/** Creates a pattern fill. */
|
|
746
|
+
static pattern(pattern, foreground, background) {
|
|
747
|
+
return new _ExcelFill(pattern, foreground, background);
|
|
748
|
+
}
|
|
749
|
+
// ── Serialisation ─────────────────────────────────────────────────────────
|
|
750
|
+
toXml() {
|
|
751
|
+
let inner = `<patternFill patternType="${this.patternType}">`;
|
|
752
|
+
if (this.foregroundColor) {
|
|
753
|
+
const attrs = this.foregroundColor.toXmlAttrs();
|
|
754
|
+
const parts = [];
|
|
755
|
+
if (attrs.rgb) parts.push(`rgb="${attrs.rgb}"`);
|
|
756
|
+
if (attrs.theme !== void 0) parts.push(`theme="${attrs.theme}"`);
|
|
757
|
+
if (attrs.tint !== void 0) parts.push(`tint="${attrs.tint}"`);
|
|
758
|
+
if (attrs.indexed !== void 0) parts.push(`indexed="${attrs.indexed}"`);
|
|
759
|
+
inner += `<fgColor ${parts.join(" ")}/>`;
|
|
760
|
+
}
|
|
761
|
+
if (this.backgroundColor) {
|
|
762
|
+
const attrs = this.backgroundColor.toXmlAttrs();
|
|
763
|
+
const parts = [];
|
|
764
|
+
if (attrs.rgb) parts.push(`rgb="${attrs.rgb}"`);
|
|
765
|
+
if (attrs.theme !== void 0) parts.push(`theme="${attrs.theme}"`);
|
|
766
|
+
if (attrs.tint !== void 0) parts.push(`tint="${attrs.tint}"`);
|
|
767
|
+
if (attrs.indexed !== void 0) parts.push(`indexed="${attrs.indexed}"`);
|
|
768
|
+
inner += `<bgColor ${parts.join(" ")}/>`;
|
|
769
|
+
}
|
|
770
|
+
inner += "</patternFill>";
|
|
771
|
+
return `<fill>${inner}</fill>`;
|
|
772
|
+
}
|
|
773
|
+
static fromXmlChildren(children) {
|
|
774
|
+
const fill = new _ExcelFill();
|
|
775
|
+
for (const el of children) {
|
|
776
|
+
const tag = el.tagName.replace(/^.*:/, "");
|
|
777
|
+
if (tag === "patternFill") {
|
|
778
|
+
const pt = el.attributes["patternType"];
|
|
779
|
+
if (pt && Object.values(ExcelPatternType).includes(pt)) {
|
|
780
|
+
fill.patternType = pt;
|
|
781
|
+
}
|
|
782
|
+
for (const child of el.children) {
|
|
783
|
+
const ctag = child.tagName.replace(/^.*:/, "");
|
|
784
|
+
const color = ExcelColor.fromXmlAttrs(child.attributes);
|
|
785
|
+
if (ctag === "fgColor" && color) fill.foregroundColor = color;
|
|
786
|
+
if (ctag === "bgColor" && color) fill.backgroundColor = color;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
return fill;
|
|
791
|
+
}
|
|
792
|
+
cacheKey() {
|
|
793
|
+
return [
|
|
794
|
+
`p:${this.patternType}`,
|
|
795
|
+
`fg:${this.foregroundColor?.toString() ?? "null"}`,
|
|
796
|
+
`bg:${this.backgroundColor?.toString() ?? "null"}`
|
|
797
|
+
].join("|");
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
/** No fill (default). */
|
|
801
|
+
_ExcelFill.none = new _ExcelFill("none" /* None */);
|
|
802
|
+
var ExcelFill = _ExcelFill;
|
|
803
|
+
|
|
804
|
+
// src/style/excel-border.ts
|
|
805
|
+
var ExcelBorderStyle = /* @__PURE__ */ ((ExcelBorderStyle3) => {
|
|
806
|
+
ExcelBorderStyle3["None"] = "none";
|
|
807
|
+
ExcelBorderStyle3["Thin"] = "thin";
|
|
808
|
+
ExcelBorderStyle3["Medium"] = "medium";
|
|
809
|
+
ExcelBorderStyle3["Thick"] = "thick";
|
|
810
|
+
ExcelBorderStyle3["Dashed"] = "dashed";
|
|
811
|
+
ExcelBorderStyle3["Dotted"] = "dotted";
|
|
812
|
+
ExcelBorderStyle3["Double"] = "double";
|
|
813
|
+
ExcelBorderStyle3["Hair"] = "hair";
|
|
814
|
+
ExcelBorderStyle3["MediumDashed"] = "mediumDashed";
|
|
815
|
+
ExcelBorderStyle3["DashDot"] = "dashDot";
|
|
816
|
+
ExcelBorderStyle3["MediumDashDot"] = "mediumDashDot";
|
|
817
|
+
ExcelBorderStyle3["DashDotDot"] = "dashDotDot";
|
|
818
|
+
ExcelBorderStyle3["MediumDashDotDot"] = "mediumDashDotDot";
|
|
819
|
+
ExcelBorderStyle3["SlantDashDot"] = "slantDashDot";
|
|
820
|
+
return ExcelBorderStyle3;
|
|
821
|
+
})(ExcelBorderStyle || {});
|
|
822
|
+
var ExcelBorderEdge = class _ExcelBorderEdge {
|
|
823
|
+
constructor(style = "none" /* None */, color) {
|
|
824
|
+
this.style = style;
|
|
825
|
+
this.color = color;
|
|
826
|
+
}
|
|
827
|
+
toXml(tag) {
|
|
828
|
+
if (this.style === "none" /* None */) return `<${tag}/>`;
|
|
829
|
+
let inner = "";
|
|
830
|
+
if (this.color) inner = this.color.toXmlElement("color");
|
|
831
|
+
return `<${tag} style="${this.style}">${inner}</${tag}>`;
|
|
832
|
+
}
|
|
833
|
+
static fromXmlElement(el) {
|
|
834
|
+
const styleStr = el.attributes["style"] ?? "none";
|
|
835
|
+
const style = Object.values(ExcelBorderStyle).includes(styleStr) ? styleStr : "none" /* None */;
|
|
836
|
+
let color;
|
|
837
|
+
for (const child of el.children) {
|
|
838
|
+
const tag = child.tagName.replace(/^.*:/, "");
|
|
839
|
+
if (tag === "color") {
|
|
840
|
+
color = ExcelColor.fromXmlAttrs(child.attributes) ?? void 0;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
return new _ExcelBorderEdge(style, color);
|
|
844
|
+
}
|
|
845
|
+
cacheKey() {
|
|
846
|
+
return `${this.style}:${this.color?.toString() ?? "null"}`;
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
var _ExcelBorder = class _ExcelBorder {
|
|
850
|
+
constructor() {
|
|
851
|
+
this.left = new ExcelBorderEdge();
|
|
852
|
+
this.right = new ExcelBorderEdge();
|
|
853
|
+
this.top = new ExcelBorderEdge();
|
|
854
|
+
this.bottom = new ExcelBorderEdge();
|
|
855
|
+
this.diagonal = new ExcelBorderEdge();
|
|
856
|
+
this.diagonalDown = false;
|
|
857
|
+
this.diagonalUp = false;
|
|
858
|
+
}
|
|
859
|
+
// ── Factory methods ────────────────────────────────────────────────────────
|
|
860
|
+
/** Sets all four sides to the same style and color. */
|
|
861
|
+
static box(style, color) {
|
|
862
|
+
const b = new _ExcelBorder();
|
|
863
|
+
b.left = new ExcelBorderEdge(style, color);
|
|
864
|
+
b.right = new ExcelBorderEdge(style, color);
|
|
865
|
+
b.top = new ExcelBorderEdge(style, color);
|
|
866
|
+
b.bottom = new ExcelBorderEdge(style, color);
|
|
867
|
+
return b;
|
|
868
|
+
}
|
|
869
|
+
static bottomOnly(style, color) {
|
|
870
|
+
const b = new _ExcelBorder();
|
|
871
|
+
b.bottom = new ExcelBorderEdge(style, color);
|
|
872
|
+
return b;
|
|
873
|
+
}
|
|
874
|
+
static topOnly(style, color) {
|
|
875
|
+
const b = new _ExcelBorder();
|
|
876
|
+
b.top = new ExcelBorderEdge(style, color);
|
|
877
|
+
return b;
|
|
878
|
+
}
|
|
879
|
+
static leftOnly(style, color) {
|
|
880
|
+
const b = new _ExcelBorder();
|
|
881
|
+
b.left = new ExcelBorderEdge(style, color);
|
|
882
|
+
return b;
|
|
883
|
+
}
|
|
884
|
+
static rightOnly(style, color) {
|
|
885
|
+
const b = new _ExcelBorder();
|
|
886
|
+
b.right = new ExcelBorderEdge(style, color);
|
|
887
|
+
return b;
|
|
888
|
+
}
|
|
889
|
+
// ── Serialisation ─────────────────────────────────────────────────────────
|
|
890
|
+
toXml() {
|
|
891
|
+
const dd = this.diagonalDown ? ' diagonalDown="1"' : "";
|
|
892
|
+
const du = this.diagonalUp ? ' diagonalUp="1"' : "";
|
|
893
|
+
return `<border${dd}${du}>${this.left.toXml("left")}${this.right.toXml("right")}${this.top.toXml("top")}${this.bottom.toXml("bottom")}${this.diagonal.toXml("diagonal")}</border>`;
|
|
894
|
+
}
|
|
895
|
+
static fromXmlChildren(children, borderAttrs) {
|
|
896
|
+
const b = new _ExcelBorder();
|
|
897
|
+
b.diagonalDown = borderAttrs["diagonalDown"] === "1";
|
|
898
|
+
b.diagonalUp = borderAttrs["diagonalUp"] === "1";
|
|
899
|
+
for (const el of children) {
|
|
900
|
+
const tag = el.tagName.replace(/^.*:/, "");
|
|
901
|
+
const edge = ExcelBorderEdge.fromXmlElement(el);
|
|
902
|
+
switch (tag) {
|
|
903
|
+
case "left":
|
|
904
|
+
b.left = edge;
|
|
905
|
+
break;
|
|
906
|
+
case "right":
|
|
907
|
+
b.right = edge;
|
|
908
|
+
break;
|
|
909
|
+
case "top":
|
|
910
|
+
b.top = edge;
|
|
911
|
+
break;
|
|
912
|
+
case "bottom":
|
|
913
|
+
b.bottom = edge;
|
|
914
|
+
break;
|
|
915
|
+
case "diagonal":
|
|
916
|
+
b.diagonal = edge;
|
|
917
|
+
break;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
return b;
|
|
921
|
+
}
|
|
922
|
+
cacheKey() {
|
|
923
|
+
return [
|
|
924
|
+
`l:${this.left.cacheKey()}`,
|
|
925
|
+
`r:${this.right.cacheKey()}`,
|
|
926
|
+
`t:${this.top.cacheKey()}`,
|
|
927
|
+
`b:${this.bottom.cacheKey()}`,
|
|
928
|
+
`d:${this.diagonal.cacheKey()}`,
|
|
929
|
+
`dd:${this.diagonalDown}`,
|
|
930
|
+
`du:${this.diagonalUp}`
|
|
931
|
+
].join("|");
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
_ExcelBorder.none = new _ExcelBorder();
|
|
935
|
+
var ExcelBorder = _ExcelBorder;
|
|
936
|
+
|
|
937
|
+
// src/style/excel-alignment.ts
|
|
938
|
+
var ExcelHorizontalAlignment = /* @__PURE__ */ ((ExcelHorizontalAlignment3) => {
|
|
939
|
+
ExcelHorizontalAlignment3["General"] = "general";
|
|
940
|
+
ExcelHorizontalAlignment3["Left"] = "left";
|
|
941
|
+
ExcelHorizontalAlignment3["Center"] = "center";
|
|
942
|
+
ExcelHorizontalAlignment3["Right"] = "right";
|
|
943
|
+
ExcelHorizontalAlignment3["Fill"] = "fill";
|
|
944
|
+
ExcelHorizontalAlignment3["Justify"] = "justify";
|
|
945
|
+
ExcelHorizontalAlignment3["CenterContinuous"] = "centerContinuous";
|
|
946
|
+
ExcelHorizontalAlignment3["Distributed"] = "distributed";
|
|
947
|
+
return ExcelHorizontalAlignment3;
|
|
948
|
+
})(ExcelHorizontalAlignment || {});
|
|
949
|
+
var ExcelVerticalAlignment = /* @__PURE__ */ ((ExcelVerticalAlignment3) => {
|
|
950
|
+
ExcelVerticalAlignment3["Top"] = "top";
|
|
951
|
+
ExcelVerticalAlignment3["Center"] = "center";
|
|
952
|
+
ExcelVerticalAlignment3["Bottom"] = "bottom";
|
|
953
|
+
ExcelVerticalAlignment3["Justify"] = "justify";
|
|
954
|
+
ExcelVerticalAlignment3["Distributed"] = "distributed";
|
|
955
|
+
return ExcelVerticalAlignment3;
|
|
956
|
+
})(ExcelVerticalAlignment || {});
|
|
957
|
+
var ExcelReadingOrder = /* @__PURE__ */ ((ExcelReadingOrder2) => {
|
|
958
|
+
ExcelReadingOrder2[ExcelReadingOrder2["ContextDependent"] = 0] = "ContextDependent";
|
|
959
|
+
ExcelReadingOrder2[ExcelReadingOrder2["LeftToRight"] = 1] = "LeftToRight";
|
|
960
|
+
ExcelReadingOrder2[ExcelReadingOrder2["RightToLeft"] = 2] = "RightToLeft";
|
|
961
|
+
return ExcelReadingOrder2;
|
|
962
|
+
})(ExcelReadingOrder || {});
|
|
963
|
+
var ExcelAlignment = class _ExcelAlignment {
|
|
964
|
+
toXml() {
|
|
965
|
+
const parts = [];
|
|
966
|
+
if (this.horizontal) parts.push(`horizontal="${this.horizontal}"`);
|
|
967
|
+
if (this.vertical) parts.push(`vertical="${this.vertical}"`);
|
|
968
|
+
if (this.wrapText) parts.push('wrapText="1"');
|
|
969
|
+
if (this.shrinkToFit) parts.push('shrinkToFit="1"');
|
|
970
|
+
if (this.textRotation !== void 0) parts.push(`textRotation="${this.textRotation}"`);
|
|
971
|
+
if (this.indent !== void 0) parts.push(`indent="${this.indent}"`);
|
|
972
|
+
if (this.readingOrder !== void 0) parts.push(`readingOrder="${this.readingOrder}"`);
|
|
973
|
+
if (parts.length === 0) return "";
|
|
974
|
+
return `<alignment ${parts.join(" ")}/>`;
|
|
975
|
+
}
|
|
976
|
+
static fromXmlAttrs(attrs) {
|
|
977
|
+
const a = new _ExcelAlignment();
|
|
978
|
+
const h = attrs["horizontal"];
|
|
979
|
+
const v = attrs["vertical"];
|
|
980
|
+
if (h && Object.values(ExcelHorizontalAlignment).includes(h)) {
|
|
981
|
+
a.horizontal = h;
|
|
982
|
+
}
|
|
983
|
+
if (v && Object.values(ExcelVerticalAlignment).includes(v)) {
|
|
984
|
+
a.vertical = v;
|
|
985
|
+
}
|
|
986
|
+
if (attrs["wrapText"] === "1" || attrs["wrapText"] === "true") a.wrapText = true;
|
|
987
|
+
if (attrs["shrinkToFit"] === "1" || attrs["shrinkToFit"] === "true") a.shrinkToFit = true;
|
|
988
|
+
if (attrs["textRotation"] !== void 0) a.textRotation = parseInt(attrs["textRotation"], 10);
|
|
989
|
+
if (attrs["indent"] !== void 0) a.indent = parseInt(attrs["indent"], 10);
|
|
990
|
+
if (attrs["readingOrder"] !== void 0) a.readingOrder = parseInt(attrs["readingOrder"], 10);
|
|
991
|
+
return a;
|
|
992
|
+
}
|
|
993
|
+
cacheKey() {
|
|
994
|
+
return [
|
|
995
|
+
`h:${this.horizontal ?? ""}`,
|
|
996
|
+
`v:${this.vertical ?? ""}`,
|
|
997
|
+
`w:${this.wrapText ?? false}`,
|
|
998
|
+
`s:${this.shrinkToFit ?? false}`,
|
|
999
|
+
`r:${this.textRotation ?? 0}`,
|
|
1000
|
+
`i:${this.indent ?? 0}`,
|
|
1001
|
+
`ro:${this.readingOrder ?? 0}`
|
|
1002
|
+
].join("|");
|
|
1003
|
+
}
|
|
1004
|
+
};
|
|
1005
|
+
|
|
1006
|
+
// src/style/excel-number-format.ts
|
|
1007
|
+
var BUILT_IN_FORMAT_CODES = {
|
|
1008
|
+
0: "General",
|
|
1009
|
+
1: "0",
|
|
1010
|
+
2: "0.00",
|
|
1011
|
+
3: "#,##0",
|
|
1012
|
+
4: "#,##0.00",
|
|
1013
|
+
5: "$#,##0_);($#,##0)",
|
|
1014
|
+
6: "$#,##0_);[Red]($#,##0)",
|
|
1015
|
+
7: "$#,##0.00_);($#,##0.00)",
|
|
1016
|
+
8: "$#,##0.00_);[Red]($#,##0.00)",
|
|
1017
|
+
9: "0%",
|
|
1018
|
+
10: "0.00%",
|
|
1019
|
+
11: "0.00E+00",
|
|
1020
|
+
12: "# ?/?",
|
|
1021
|
+
13: "# ??/??",
|
|
1022
|
+
14: "mm-dd-yy",
|
|
1023
|
+
15: "d-mmm-yy",
|
|
1024
|
+
16: "d-mmm",
|
|
1025
|
+
17: "mmm-yy",
|
|
1026
|
+
18: "h:mm AM/PM",
|
|
1027
|
+
19: "h:mm:ss AM/PM",
|
|
1028
|
+
20: "h:mm",
|
|
1029
|
+
21: "h:mm:ss",
|
|
1030
|
+
22: "m/d/yy h:mm",
|
|
1031
|
+
37: "#,##0 ;(#,##0)",
|
|
1032
|
+
38: "#,##0 ;[Red](#,##0)",
|
|
1033
|
+
39: "#,##0.00;(#,##0.00)",
|
|
1034
|
+
40: "#,##0.00;[Red](#,##0.00)",
|
|
1035
|
+
45: "mm:ss",
|
|
1036
|
+
46: "[h]:mm:ss",
|
|
1037
|
+
47: "mmss.0",
|
|
1038
|
+
48: "##0.0E+0",
|
|
1039
|
+
49: "@"
|
|
1040
|
+
};
|
|
1041
|
+
var CODE_TO_BUILT_IN_ID = new Map(
|
|
1042
|
+
Object.entries(BUILT_IN_FORMAT_CODES).map(([id, code]) => [code, Number(id)])
|
|
1043
|
+
);
|
|
1044
|
+
var _ExcelNumberFormat = class _ExcelNumberFormat {
|
|
1045
|
+
constructor(formatCode, formatId) {
|
|
1046
|
+
this.formatCode = formatCode;
|
|
1047
|
+
this.formatId = formatId;
|
|
1048
|
+
}
|
|
1049
|
+
// ── Factory methods ────────────────────────────────────────────────────────
|
|
1050
|
+
/** Creates a number format from a custom format code string. */
|
|
1051
|
+
static custom(formatCode) {
|
|
1052
|
+
if (!formatCode) throw new Error("Format code cannot be empty.");
|
|
1053
|
+
const builtInId = CODE_TO_BUILT_IN_ID.get(formatCode);
|
|
1054
|
+
if (builtInId !== void 0) {
|
|
1055
|
+
return new _ExcelNumberFormat(formatCode, builtInId);
|
|
1056
|
+
}
|
|
1057
|
+
return new _ExcelNumberFormat(formatCode, 0);
|
|
1058
|
+
}
|
|
1059
|
+
/** Creates from format ID and optional custom formats map. */
|
|
1060
|
+
static fromFormatId(formatId, customFormats) {
|
|
1061
|
+
if (customFormats && formatId >= 164) {
|
|
1062
|
+
const code2 = customFormats.get(formatId);
|
|
1063
|
+
if (code2) return new _ExcelNumberFormat(code2, formatId);
|
|
1064
|
+
}
|
|
1065
|
+
const code = BUILT_IN_FORMAT_CODES[formatId] ?? "General";
|
|
1066
|
+
return new _ExcelNumberFormat(code, formatId);
|
|
1067
|
+
}
|
|
1068
|
+
/** Returns true if this format code represents a date/time value. */
|
|
1069
|
+
isDateFormat() {
|
|
1070
|
+
const id = this.formatId;
|
|
1071
|
+
if (id >= 14 && id <= 22 || id >= 45 && id <= 47) return true;
|
|
1072
|
+
const lower = this.formatCode.toLowerCase();
|
|
1073
|
+
return lower.includes("y") || lower.includes("d") || lower.includes("m") && !lower.startsWith("mm:") && !lower.startsWith("[") || lower.includes("h") && !lower.startsWith("[h]");
|
|
1074
|
+
}
|
|
1075
|
+
toString() {
|
|
1076
|
+
return this.formatCode;
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
// ── Predefined formats (camelCase, per TypeScript convention) ─────────────
|
|
1080
|
+
_ExcelNumberFormat.general = new _ExcelNumberFormat("General", 0);
|
|
1081
|
+
_ExcelNumberFormat.integer = new _ExcelNumberFormat("0", 1);
|
|
1082
|
+
_ExcelNumberFormat.decimal2 = new _ExcelNumberFormat("0.00", 2);
|
|
1083
|
+
_ExcelNumberFormat.thousandsSeparator = new _ExcelNumberFormat("#,##0", 3);
|
|
1084
|
+
_ExcelNumberFormat.thousandsDecimal2 = new _ExcelNumberFormat("#,##0.00", 4);
|
|
1085
|
+
_ExcelNumberFormat.percentage = new _ExcelNumberFormat("0%", 9);
|
|
1086
|
+
_ExcelNumberFormat.percentageDecimal2 = new _ExcelNumberFormat("0.00%", 10);
|
|
1087
|
+
_ExcelNumberFormat.scientific = new _ExcelNumberFormat("0.00E+00", 11);
|
|
1088
|
+
_ExcelNumberFormat.fraction = new _ExcelNumberFormat("# ?/?", 12);
|
|
1089
|
+
_ExcelNumberFormat.fractionTwoDigits = new _ExcelNumberFormat("# ??/??", 13);
|
|
1090
|
+
_ExcelNumberFormat.shortDate = new _ExcelNumberFormat("mm-dd-yy", 14);
|
|
1091
|
+
_ExcelNumberFormat.longDate = new _ExcelNumberFormat("d-mmm-yy", 15);
|
|
1092
|
+
_ExcelNumberFormat.dayMonth = new _ExcelNumberFormat("d-mmm", 16);
|
|
1093
|
+
_ExcelNumberFormat.monthYear = new _ExcelNumberFormat("mmm-yy", 17);
|
|
1094
|
+
_ExcelNumberFormat.time12h = new _ExcelNumberFormat("h:mm AM/PM", 18);
|
|
1095
|
+
_ExcelNumberFormat.time12hSeconds = new _ExcelNumberFormat("h:mm:ss AM/PM", 19);
|
|
1096
|
+
_ExcelNumberFormat.time24h = new _ExcelNumberFormat("h:mm", 20);
|
|
1097
|
+
_ExcelNumberFormat.time24hSeconds = new _ExcelNumberFormat("h:mm:ss", 21);
|
|
1098
|
+
_ExcelNumberFormat.dateTime = new _ExcelNumberFormat("m/d/yy h:mm", 22);
|
|
1099
|
+
_ExcelNumberFormat.accounting = new _ExcelNumberFormat("#,##0 ;(#,##0)", 37);
|
|
1100
|
+
_ExcelNumberFormat.accountingRed = new _ExcelNumberFormat("#,##0 ;[Red](#,##0)", 38);
|
|
1101
|
+
_ExcelNumberFormat.accountingDecimal2 = new _ExcelNumberFormat("#,##0.00;(#,##0.00)", 39);
|
|
1102
|
+
_ExcelNumberFormat.text = new _ExcelNumberFormat("@", 49);
|
|
1103
|
+
_ExcelNumberFormat.currency = _ExcelNumberFormat.custom("$#,##0.00");
|
|
1104
|
+
_ExcelNumberFormat.currencyNoDecimal = _ExcelNumberFormat.custom("$#,##0");
|
|
1105
|
+
_ExcelNumberFormat.isoDate = _ExcelNumberFormat.custom("yyyy-mm-dd");
|
|
1106
|
+
_ExcelNumberFormat.isoDateTime = _ExcelNumberFormat.custom("yyyy-mm-dd hh:mm:ss");
|
|
1107
|
+
_ExcelNumberFormat.phoneNumber = _ExcelNumberFormat.custom("[<=9999999]###-####;(###) ###-####");
|
|
1108
|
+
_ExcelNumberFormat.zipCode = _ExcelNumberFormat.custom("00000");
|
|
1109
|
+
var ExcelNumberFormat = _ExcelNumberFormat;
|
|
1110
|
+
|
|
1111
|
+
// src/style/cell-style.ts
|
|
1112
|
+
var _CellStyle_instances, ensureFont_fn, ensureBorder_fn, ensureAlignment_fn;
|
|
1113
|
+
var _CellStyle = class _CellStyle {
|
|
1114
|
+
constructor() {
|
|
1115
|
+
__privateAdd(this, _CellStyle_instances);
|
|
1116
|
+
}
|
|
1117
|
+
// ── Font fluent API ────────────────────────────────────────────────────────
|
|
1118
|
+
setFontName(name) {
|
|
1119
|
+
__privateMethod(this, _CellStyle_instances, ensureFont_fn).call(this).name = name;
|
|
1120
|
+
return this;
|
|
1121
|
+
}
|
|
1122
|
+
setFontSize(size) {
|
|
1123
|
+
__privateMethod(this, _CellStyle_instances, ensureFont_fn).call(this).size = size;
|
|
1124
|
+
return this;
|
|
1125
|
+
}
|
|
1126
|
+
setBold(bold = true) {
|
|
1127
|
+
__privateMethod(this, _CellStyle_instances, ensureFont_fn).call(this).bold = bold;
|
|
1128
|
+
return this;
|
|
1129
|
+
}
|
|
1130
|
+
setItalic(italic = true) {
|
|
1131
|
+
__privateMethod(this, _CellStyle_instances, ensureFont_fn).call(this).italic = italic;
|
|
1132
|
+
return this;
|
|
1133
|
+
}
|
|
1134
|
+
setUnderline(underline = "single" /* Single */) {
|
|
1135
|
+
__privateMethod(this, _CellStyle_instances, ensureFont_fn).call(this).underline = underline;
|
|
1136
|
+
return this;
|
|
1137
|
+
}
|
|
1138
|
+
setStrikethrough(strikethrough = true) {
|
|
1139
|
+
__privateMethod(this, _CellStyle_instances, ensureFont_fn).call(this).strikethrough = strikethrough;
|
|
1140
|
+
return this;
|
|
1141
|
+
}
|
|
1142
|
+
setFontColor(colorOrHex) {
|
|
1143
|
+
__privateMethod(this, _CellStyle_instances, ensureFont_fn).call(this).color = typeof colorOrHex === "string" ? ExcelColor.fromHex(colorOrHex) : colorOrHex;
|
|
1144
|
+
return this;
|
|
1145
|
+
}
|
|
1146
|
+
setVerticalAlign(align) {
|
|
1147
|
+
__privateMethod(this, _CellStyle_instances, ensureFont_fn).call(this).verticalAlign = align;
|
|
1148
|
+
return this;
|
|
1149
|
+
}
|
|
1150
|
+
setBackgroundColor(colorOrHex) {
|
|
1151
|
+
const color = typeof colorOrHex === "string" ? ExcelColor.fromHex(colorOrHex) : colorOrHex;
|
|
1152
|
+
this.fill = ExcelFill.solid(color);
|
|
1153
|
+
return this;
|
|
1154
|
+
}
|
|
1155
|
+
setPatternFill(pattern, foreground, background) {
|
|
1156
|
+
this.fill = ExcelFill.pattern(pattern, foreground, background);
|
|
1157
|
+
return this;
|
|
1158
|
+
}
|
|
1159
|
+
// ── Border fluent API ──────────────────────────────────────────────────────
|
|
1160
|
+
setAllBorders(style, color) {
|
|
1161
|
+
this.border = ExcelBorder.box(style, color);
|
|
1162
|
+
return this;
|
|
1163
|
+
}
|
|
1164
|
+
setBorder(border) {
|
|
1165
|
+
this.border = border;
|
|
1166
|
+
return this;
|
|
1167
|
+
}
|
|
1168
|
+
setLeftBorder(style, color) {
|
|
1169
|
+
__privateMethod(this, _CellStyle_instances, ensureBorder_fn).call(this).left = new ExcelBorderEdge(style, color);
|
|
1170
|
+
return this;
|
|
1171
|
+
}
|
|
1172
|
+
setRightBorder(style, color) {
|
|
1173
|
+
__privateMethod(this, _CellStyle_instances, ensureBorder_fn).call(this).right = new ExcelBorderEdge(style, color);
|
|
1174
|
+
return this;
|
|
1175
|
+
}
|
|
1176
|
+
setTopBorder(style, color) {
|
|
1177
|
+
__privateMethod(this, _CellStyle_instances, ensureBorder_fn).call(this).top = new ExcelBorderEdge(style, color);
|
|
1178
|
+
return this;
|
|
1179
|
+
}
|
|
1180
|
+
setBottomBorder(style, color) {
|
|
1181
|
+
__privateMethod(this, _CellStyle_instances, ensureBorder_fn).call(this).bottom = new ExcelBorderEdge(style, color);
|
|
1182
|
+
return this;
|
|
1183
|
+
}
|
|
1184
|
+
// ── Alignment fluent API ───────────────────────────────────────────────────
|
|
1185
|
+
setHorizontalAlignment(alignment) {
|
|
1186
|
+
__privateMethod(this, _CellStyle_instances, ensureAlignment_fn).call(this).horizontal = alignment;
|
|
1187
|
+
return this;
|
|
1188
|
+
}
|
|
1189
|
+
setVerticalAlignment(alignment) {
|
|
1190
|
+
__privateMethod(this, _CellStyle_instances, ensureAlignment_fn).call(this).vertical = alignment;
|
|
1191
|
+
return this;
|
|
1192
|
+
}
|
|
1193
|
+
setWrapText(wrap = true) {
|
|
1194
|
+
__privateMethod(this, _CellStyle_instances, ensureAlignment_fn).call(this).wrapText = wrap;
|
|
1195
|
+
return this;
|
|
1196
|
+
}
|
|
1197
|
+
setShrinkToFit(shrink = true) {
|
|
1198
|
+
__privateMethod(this, _CellStyle_instances, ensureAlignment_fn).call(this).shrinkToFit = shrink;
|
|
1199
|
+
return this;
|
|
1200
|
+
}
|
|
1201
|
+
setTextRotation(degrees) {
|
|
1202
|
+
__privateMethod(this, _CellStyle_instances, ensureAlignment_fn).call(this).textRotation = degrees;
|
|
1203
|
+
return this;
|
|
1204
|
+
}
|
|
1205
|
+
setIndent(indent) {
|
|
1206
|
+
__privateMethod(this, _CellStyle_instances, ensureAlignment_fn).call(this).indent = indent;
|
|
1207
|
+
return this;
|
|
1208
|
+
}
|
|
1209
|
+
setNumberFormat(formatOrCode) {
|
|
1210
|
+
this.numberFormat = typeof formatOrCode === "string" ? ExcelNumberFormat.custom(formatOrCode) : formatOrCode;
|
|
1211
|
+
return this;
|
|
1212
|
+
}
|
|
1213
|
+
// ── Protection fluent API ──────────────────────────────────────────────────
|
|
1214
|
+
setLocked(locked = true) {
|
|
1215
|
+
this.isLocked = locked;
|
|
1216
|
+
return this;
|
|
1217
|
+
}
|
|
1218
|
+
setFormulaHidden(hidden = true) {
|
|
1219
|
+
this.isHidden = hidden;
|
|
1220
|
+
return this;
|
|
1221
|
+
}
|
|
1222
|
+
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
1223
|
+
/** Creates a deep copy of this style. */
|
|
1224
|
+
clone() {
|
|
1225
|
+
const s = new _CellStyle();
|
|
1226
|
+
if (this.font) s.font = this.font.clone();
|
|
1227
|
+
s.fill = this.fill;
|
|
1228
|
+
s.border = this.border;
|
|
1229
|
+
s.alignment = this.alignment ? Object.assign(new ExcelAlignment(), this.alignment) : void 0;
|
|
1230
|
+
s.numberFormat = this.numberFormat;
|
|
1231
|
+
s.isLocked = this.isLocked;
|
|
1232
|
+
s.isHidden = this.isHidden;
|
|
1233
|
+
return s;
|
|
1234
|
+
}
|
|
1235
|
+
};
|
|
1236
|
+
_CellStyle_instances = new WeakSet();
|
|
1237
|
+
ensureFont_fn = function() {
|
|
1238
|
+
if (!this.font) this.font = new ExcelFont();
|
|
1239
|
+
return this.font;
|
|
1240
|
+
};
|
|
1241
|
+
ensureBorder_fn = function() {
|
|
1242
|
+
if (!this.border) this.border = new ExcelBorder();
|
|
1243
|
+
return this.border;
|
|
1244
|
+
};
|
|
1245
|
+
ensureAlignment_fn = function() {
|
|
1246
|
+
if (!this.alignment) this.alignment = new ExcelAlignment();
|
|
1247
|
+
return this.alignment;
|
|
1248
|
+
};
|
|
1249
|
+
var CellStyle = _CellStyle;
|
|
1250
|
+
|
|
1251
|
+
// src/style/style-manager.ts
|
|
1252
|
+
var _StyleManager_instances, initDefaults_fn, getOrCreateFont_fn, getOrCreateFill_fn, getOrCreateBorder_fn, getOrCreateNumFmt_fn, cellFormatKey_fn, cfToXml_fn;
|
|
1253
|
+
var StyleManager = class {
|
|
1254
|
+
constructor() {
|
|
1255
|
+
__privateAdd(this, _StyleManager_instances);
|
|
1256
|
+
// Index arrays — position = index
|
|
1257
|
+
this.fonts = [];
|
|
1258
|
+
this.fills = [];
|
|
1259
|
+
this.borders = [];
|
|
1260
|
+
this.numFmts = [];
|
|
1261
|
+
this.cellXfs = [];
|
|
1262
|
+
// Dedup caches: key → index
|
|
1263
|
+
this.fontCache = /* @__PURE__ */ new Map();
|
|
1264
|
+
this.fillCache = /* @__PURE__ */ new Map();
|
|
1265
|
+
this.borderCache = /* @__PURE__ */ new Map();
|
|
1266
|
+
this.numFmtCache = /* @__PURE__ */ new Map();
|
|
1267
|
+
// code → id
|
|
1268
|
+
this.cellXfCache = /* @__PURE__ */ new Map();
|
|
1269
|
+
this.nextCustomNumFmtId = 164;
|
|
1270
|
+
this.isDirty = false;
|
|
1271
|
+
__privateMethod(this, _StyleManager_instances, initDefaults_fn).call(this);
|
|
1272
|
+
}
|
|
1273
|
+
// ── Public API ─────────────────────────────────────────────────────────────
|
|
1274
|
+
/**
|
|
1275
|
+
* Returns the cellXf index for the given CellStyle.
|
|
1276
|
+
* Creates new font/fill/border entries as needed (with deduplication).
|
|
1277
|
+
*/
|
|
1278
|
+
getOrCreateCellFormatIndex(style) {
|
|
1279
|
+
const fontId = style.font ? __privateMethod(this, _StyleManager_instances, getOrCreateFont_fn).call(this, style.font) : 0;
|
|
1280
|
+
const fillId = style.fill ? __privateMethod(this, _StyleManager_instances, getOrCreateFill_fn).call(this, style.fill) : 0;
|
|
1281
|
+
const borderId = style.border ? __privateMethod(this, _StyleManager_instances, getOrCreateBorder_fn).call(this, style.border) : 0;
|
|
1282
|
+
const numFmtId = style.numberFormat ? __privateMethod(this, _StyleManager_instances, getOrCreateNumFmt_fn).call(this, style.numberFormat) : 0;
|
|
1283
|
+
const cf = {
|
|
1284
|
+
fontId,
|
|
1285
|
+
fillId,
|
|
1286
|
+
borderId,
|
|
1287
|
+
numFmtId,
|
|
1288
|
+
applyFont: style.font != null,
|
|
1289
|
+
applyFill: style.fill != null,
|
|
1290
|
+
applyBorder: style.border != null,
|
|
1291
|
+
applyNumFmt: style.numberFormat != null,
|
|
1292
|
+
alignment: style.alignment,
|
|
1293
|
+
applyAlign: style.alignment != null,
|
|
1294
|
+
isLocked: style.isLocked,
|
|
1295
|
+
isHidden: style.isHidden,
|
|
1296
|
+
applyProt: style.isLocked != null || style.isHidden != null
|
|
1297
|
+
};
|
|
1298
|
+
const key = __privateMethod(this, _StyleManager_instances, cellFormatKey_fn).call(this, cf);
|
|
1299
|
+
const existing = this.cellXfCache.get(key);
|
|
1300
|
+
if (existing !== void 0) return existing;
|
|
1301
|
+
const idx = this.cellXfs.length;
|
|
1302
|
+
this.cellXfs.push(cf);
|
|
1303
|
+
this.cellXfCache.set(key, idx);
|
|
1304
|
+
this.isDirty = true;
|
|
1305
|
+
return idx;
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* Reconstructs a CellStyle from a cellXf index.
|
|
1309
|
+
* Used by Cell.style getter.
|
|
1310
|
+
*/
|
|
1311
|
+
getCellStyle(styleIndex) {
|
|
1312
|
+
const cf = this.cellXfs[styleIndex];
|
|
1313
|
+
if (!cf) return new CellStyle();
|
|
1314
|
+
const s = new CellStyle();
|
|
1315
|
+
const fontEntry = this.fonts[cf.fontId];
|
|
1316
|
+
if (fontEntry && cf.applyFont) s.font = fontEntry.font;
|
|
1317
|
+
const fillEntry = this.fills[cf.fillId];
|
|
1318
|
+
if (fillEntry && cf.applyFill) s.fill = fillEntry.fill;
|
|
1319
|
+
const borderEntry = this.borders[cf.borderId];
|
|
1320
|
+
if (borderEntry && cf.applyBorder) s.border = borderEntry.border;
|
|
1321
|
+
if (cf.applyNumFmt) {
|
|
1322
|
+
const customMap = new Map(
|
|
1323
|
+
this.numFmts.map((n) => [n.id, n.code])
|
|
1324
|
+
);
|
|
1325
|
+
s.numberFormat = ExcelNumberFormat.fromFormatId(cf.numFmtId, customMap);
|
|
1326
|
+
}
|
|
1327
|
+
if (cf.alignment && cf.applyAlign) s.alignment = cf.alignment;
|
|
1328
|
+
if (cf.applyProt) {
|
|
1329
|
+
s.isLocked = cf.isLocked;
|
|
1330
|
+
s.isHidden = cf.isHidden;
|
|
1331
|
+
}
|
|
1332
|
+
return s;
|
|
1333
|
+
}
|
|
1334
|
+
// ── XML serialisation ──────────────────────────────────────────────────────
|
|
1335
|
+
/** Builds the complete xl/styles.xml string. */
|
|
1336
|
+
buildStylesXml() {
|
|
1337
|
+
const numFmtsXml = this.numFmts.length > 0 ? `<numFmts count="${this.numFmts.length}">${this.numFmts.map((n) => `<numFmt numFmtId="${n.id}" formatCode="${escAttr(n.code)}"/>`).join("")}</numFmts>` : "";
|
|
1338
|
+
const fontsXml = `<fonts count="${this.fonts.length}">${this.fonts.map((f) => f.font.toXml()).join("")}</fonts>`;
|
|
1339
|
+
const fillsXml = `<fills count="${this.fills.length}">${this.fills.map((f) => f.fill.toXml()).join("")}</fills>`;
|
|
1340
|
+
const bordersXml = `<borders count="${this.borders.length}">${this.borders.map((b) => b.border.toXml()).join("")}</borders>`;
|
|
1341
|
+
const cellXfsXml = `<cellXfs count="${this.cellXfs.length}">${this.cellXfs.map((cf) => __privateMethod(this, _StyleManager_instances, cfToXml_fn).call(this, cf)).join("")}</cellXfs>`;
|
|
1342
|
+
this.isDirty = false;
|
|
1343
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1344
|
+
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
|
1345
|
+
${numFmtsXml}${fontsXml}${fillsXml}${bordersXml}
|
|
1346
|
+
<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>
|
|
1347
|
+
${cellXfsXml}
|
|
1348
|
+
</styleSheet>`;
|
|
1349
|
+
}
|
|
1350
|
+
/** Loads an existing styles.xml, rebuilding all caches. */
|
|
1351
|
+
loadFromXml(stylesXml) {
|
|
1352
|
+
this.fonts = [];
|
|
1353
|
+
this.fills = [];
|
|
1354
|
+
this.borders = [];
|
|
1355
|
+
this.numFmts = [];
|
|
1356
|
+
this.cellXfs = [];
|
|
1357
|
+
this.fontCache.clear();
|
|
1358
|
+
this.fillCache.clear();
|
|
1359
|
+
this.borderCache.clear();
|
|
1360
|
+
this.numFmtCache.clear();
|
|
1361
|
+
this.cellXfCache.clear();
|
|
1362
|
+
this.nextCustomNumFmtId = 164;
|
|
1363
|
+
const root = parseXml(stylesXml);
|
|
1364
|
+
for (const el of getElementsByTagName(root, "numFmt")) {
|
|
1365
|
+
const id = parseInt(getAttr(el, "numFmtId") ?? "0", 10);
|
|
1366
|
+
const code = getAttr(el, "formatCode") ?? "";
|
|
1367
|
+
this.numFmts.push({ id, code });
|
|
1368
|
+
this.numFmtCache.set(code, id);
|
|
1369
|
+
if (id >= this.nextCustomNumFmtId) this.nextCustomNumFmtId = id + 1;
|
|
1370
|
+
}
|
|
1371
|
+
for (const el of getElementsByTagName(root, "fonts")) {
|
|
1372
|
+
for (const fontEl of el.children) {
|
|
1373
|
+
const font = ExcelFont.fromXmlChildren(fontEl.children);
|
|
1374
|
+
const key = font.cacheKey();
|
|
1375
|
+
this.fonts.push({ font, key });
|
|
1376
|
+
this.fontCache.set(key, this.fonts.length - 1);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
for (const el of getElementsByTagName(root, "fills")) {
|
|
1380
|
+
for (const fillEl of el.children) {
|
|
1381
|
+
const fill = ExcelFill.fromXmlChildren(fillEl.children);
|
|
1382
|
+
const key = fill.cacheKey();
|
|
1383
|
+
this.fills.push({ fill, key });
|
|
1384
|
+
this.fillCache.set(key, this.fills.length - 1);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
for (const el of getElementsByTagName(root, "borders")) {
|
|
1388
|
+
for (const borderEl of el.children) {
|
|
1389
|
+
const border = ExcelBorder.fromXmlChildren(
|
|
1390
|
+
borderEl.children,
|
|
1391
|
+
borderEl.attributes
|
|
1392
|
+
);
|
|
1393
|
+
const key = border.cacheKey();
|
|
1394
|
+
this.borders.push({ border, key });
|
|
1395
|
+
this.borderCache.set(key, this.borders.length - 1);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
for (const el of getElementsByTagName(root, "cellXfs")) {
|
|
1399
|
+
for (const xfEl of el.children) {
|
|
1400
|
+
const cf = {
|
|
1401
|
+
fontId: parseInt(getAttr(xfEl, "fontId") ?? "0", 10),
|
|
1402
|
+
fillId: parseInt(getAttr(xfEl, "fillId") ?? "0", 10),
|
|
1403
|
+
borderId: parseInt(getAttr(xfEl, "borderId") ?? "0", 10),
|
|
1404
|
+
numFmtId: parseInt(getAttr(xfEl, "numFmtId") ?? "0", 10),
|
|
1405
|
+
applyFont: getAttr(xfEl, "applyFont") === "1",
|
|
1406
|
+
applyFill: getAttr(xfEl, "applyFill") === "1",
|
|
1407
|
+
applyBorder: getAttr(xfEl, "applyBorder") === "1",
|
|
1408
|
+
applyNumFmt: getAttr(xfEl, "applyNumberFormat") === "1",
|
|
1409
|
+
applyAlign: getAttr(xfEl, "applyAlignment") === "1",
|
|
1410
|
+
applyProt: getAttr(xfEl, "applyProtection") === "1"
|
|
1411
|
+
};
|
|
1412
|
+
const alignEl = xfEl.children.find((c) => c.tagName.replace(/^.*:/, "") === "alignment");
|
|
1413
|
+
if (alignEl) cf.alignment = ExcelAlignment.fromXmlAttrs(alignEl.attributes);
|
|
1414
|
+
const key = __privateMethod(this, _StyleManager_instances, cellFormatKey_fn).call(this, cf);
|
|
1415
|
+
this.cellXfs.push(cf);
|
|
1416
|
+
this.cellXfCache.set(key, this.cellXfs.length - 1);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
if (this.fonts.length === 0) __privateMethod(this, _StyleManager_instances, initDefaults_fn).call(this);
|
|
1420
|
+
if (this.cellXfs.length === 0) __privateMethod(this, _StyleManager_instances, initDefaults_fn).call(this);
|
|
1421
|
+
}
|
|
1422
|
+
};
|
|
1423
|
+
_StyleManager_instances = new WeakSet();
|
|
1424
|
+
// ── Private helpers ────────────────────────────────────────────────────────
|
|
1425
|
+
initDefaults_fn = function() {
|
|
1426
|
+
const defaultFont = new ExcelFont({ name: "Calibri", size: 11 });
|
|
1427
|
+
const fontKey = defaultFont.cacheKey();
|
|
1428
|
+
this.fonts = [{ font: defaultFont, key: fontKey }];
|
|
1429
|
+
this.fontCache.set(fontKey, 0);
|
|
1430
|
+
const noneFill = new ExcelFill("none" /* None */);
|
|
1431
|
+
const grayFill = new ExcelFill("gray125" /* Gray125 */);
|
|
1432
|
+
this.fills = [
|
|
1433
|
+
{ fill: noneFill, key: noneFill.cacheKey() },
|
|
1434
|
+
{ fill: grayFill, key: grayFill.cacheKey() }
|
|
1435
|
+
];
|
|
1436
|
+
this.fillCache.set(noneFill.cacheKey(), 0);
|
|
1437
|
+
this.fillCache.set(grayFill.cacheKey(), 1);
|
|
1438
|
+
const defaultBorder = new ExcelBorder();
|
|
1439
|
+
const borderKey = defaultBorder.cacheKey();
|
|
1440
|
+
this.borders = [{ border: defaultBorder, key: borderKey }];
|
|
1441
|
+
this.borderCache.set(borderKey, 0);
|
|
1442
|
+
const defaultCf = {
|
|
1443
|
+
fontId: 0,
|
|
1444
|
+
fillId: 0,
|
|
1445
|
+
borderId: 0,
|
|
1446
|
+
numFmtId: 0,
|
|
1447
|
+
applyFont: false,
|
|
1448
|
+
applyFill: false,
|
|
1449
|
+
applyBorder: false,
|
|
1450
|
+
applyNumFmt: false,
|
|
1451
|
+
applyAlign: false,
|
|
1452
|
+
applyProt: false
|
|
1453
|
+
};
|
|
1454
|
+
const cfKey = __privateMethod(this, _StyleManager_instances, cellFormatKey_fn).call(this, defaultCf);
|
|
1455
|
+
this.cellXfs = [defaultCf];
|
|
1456
|
+
this.cellXfCache.set(cfKey, 0);
|
|
1457
|
+
};
|
|
1458
|
+
getOrCreateFont_fn = function(font) {
|
|
1459
|
+
const key = font.cacheKey();
|
|
1460
|
+
const existing = this.fontCache.get(key);
|
|
1461
|
+
if (existing !== void 0) return existing;
|
|
1462
|
+
const idx = this.fonts.length;
|
|
1463
|
+
this.fonts.push({ font, key });
|
|
1464
|
+
this.fontCache.set(key, idx);
|
|
1465
|
+
this.isDirty = true;
|
|
1466
|
+
return idx;
|
|
1467
|
+
};
|
|
1468
|
+
getOrCreateFill_fn = function(fill) {
|
|
1469
|
+
const key = fill.cacheKey();
|
|
1470
|
+
const existing = this.fillCache.get(key);
|
|
1471
|
+
if (existing !== void 0) return existing;
|
|
1472
|
+
const idx = this.fills.length;
|
|
1473
|
+
this.fills.push({ fill, key });
|
|
1474
|
+
this.fillCache.set(key, idx);
|
|
1475
|
+
this.isDirty = true;
|
|
1476
|
+
return idx;
|
|
1477
|
+
};
|
|
1478
|
+
getOrCreateBorder_fn = function(border) {
|
|
1479
|
+
const key = border.cacheKey();
|
|
1480
|
+
const existing = this.borderCache.get(key);
|
|
1481
|
+
if (existing !== void 0) return existing;
|
|
1482
|
+
const idx = this.borders.length;
|
|
1483
|
+
this.borders.push({ border, key });
|
|
1484
|
+
this.borderCache.set(key, idx);
|
|
1485
|
+
this.isDirty = true;
|
|
1486
|
+
return idx;
|
|
1487
|
+
};
|
|
1488
|
+
getOrCreateNumFmt_fn = function(fmt) {
|
|
1489
|
+
if (fmt.formatId > 0 && fmt.formatId < 164) return fmt.formatId;
|
|
1490
|
+
if (fmt.formatCode === "General") return 0;
|
|
1491
|
+
const existing = this.numFmtCache.get(fmt.formatCode);
|
|
1492
|
+
if (existing !== void 0) return existing;
|
|
1493
|
+
const id = this.nextCustomNumFmtId++;
|
|
1494
|
+
this.numFmts.push({ id, code: fmt.formatCode });
|
|
1495
|
+
this.numFmtCache.set(fmt.formatCode, id);
|
|
1496
|
+
this.isDirty = true;
|
|
1497
|
+
return id;
|
|
1498
|
+
};
|
|
1499
|
+
cellFormatKey_fn = function(cf) {
|
|
1500
|
+
return [
|
|
1501
|
+
cf.fontId,
|
|
1502
|
+
cf.fillId,
|
|
1503
|
+
cf.borderId,
|
|
1504
|
+
cf.numFmtId,
|
|
1505
|
+
cf.applyFont,
|
|
1506
|
+
cf.applyFill,
|
|
1507
|
+
cf.applyBorder,
|
|
1508
|
+
cf.applyNumFmt,
|
|
1509
|
+
cf.applyAlign,
|
|
1510
|
+
cf.applyProt,
|
|
1511
|
+
cf.alignment?.cacheKey() ?? "",
|
|
1512
|
+
cf.isLocked ?? "",
|
|
1513
|
+
cf.isHidden ?? ""
|
|
1514
|
+
].join("|");
|
|
1515
|
+
};
|
|
1516
|
+
cfToXml_fn = function(cf) {
|
|
1517
|
+
const attrs = [
|
|
1518
|
+
`numFmtId="${cf.numFmtId}"`,
|
|
1519
|
+
`fontId="${cf.fontId}"`,
|
|
1520
|
+
`fillId="${cf.fillId}"`,
|
|
1521
|
+
`borderId="${cf.borderId}"`,
|
|
1522
|
+
`xfId="0"`,
|
|
1523
|
+
cf.applyFont ? 'applyFont="1"' : "",
|
|
1524
|
+
cf.applyFill ? 'applyFill="1"' : "",
|
|
1525
|
+
cf.applyBorder ? 'applyBorder="1"' : "",
|
|
1526
|
+
cf.applyNumFmt ? 'applyNumberFormat="1"' : "",
|
|
1527
|
+
cf.applyAlign ? 'applyAlignment="1"' : "",
|
|
1528
|
+
cf.applyProt ? 'applyProtection="1"' : ""
|
|
1529
|
+
].filter(Boolean).join(" ");
|
|
1530
|
+
const alignXml = cf.alignment?.toXml() ?? "";
|
|
1531
|
+
const protXml = cf.applyProt ? `<protection${cf.isLocked !== void 0 ? ` locked="${cf.isLocked ? "1" : "0"}"` : ""}${cf.isHidden !== void 0 ? ` hidden="${cf.isHidden ? "1" : "0"}"` : ""}/>` : "";
|
|
1532
|
+
const inner = alignXml + protXml;
|
|
1533
|
+
return inner ? `<xf ${attrs}>${inner}</xf>` : `<xf ${attrs}/>`;
|
|
1534
|
+
};
|
|
1535
|
+
function escAttr(s) {
|
|
1536
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
// src/model/cell-reference.ts
|
|
1540
|
+
function parseCellRef(cellReference) {
|
|
1541
|
+
if (!cellReference) {
|
|
1542
|
+
throw new Error("Cell reference cannot be null or empty.");
|
|
1543
|
+
}
|
|
1544
|
+
const ref = cellReference.replace(/\$/g, "").toUpperCase();
|
|
1545
|
+
let i = 0;
|
|
1546
|
+
let column = 0;
|
|
1547
|
+
while (i < ref.length && ref.charCodeAt(i) >= 65 && ref.charCodeAt(i) <= 90) {
|
|
1548
|
+
column = column * 26 + (ref.charCodeAt(i) - 64);
|
|
1549
|
+
i++;
|
|
1550
|
+
}
|
|
1551
|
+
if (column === 0) {
|
|
1552
|
+
throw new Error(`Invalid cell reference: "${cellReference}" \u2014 no column letters found.`);
|
|
1553
|
+
}
|
|
1554
|
+
const rowStr = ref.slice(i);
|
|
1555
|
+
const row = parseInt(rowStr, 10);
|
|
1556
|
+
if (isNaN(row) || row < 1 || rowStr === "") {
|
|
1557
|
+
throw new Error(`Invalid cell reference: "${cellReference}" \u2014 no valid row number found.`);
|
|
1558
|
+
}
|
|
1559
|
+
return { row, column };
|
|
1560
|
+
}
|
|
1561
|
+
function cellRefFromRowCol(row, column) {
|
|
1562
|
+
if (row < 1) throw new RangeError(`Row must be >= 1, got ${row}.`);
|
|
1563
|
+
if (column < 1) throw new RangeError(`Column must be >= 1, got ${column}.`);
|
|
1564
|
+
return `${columnLetter(column)}${row}`;
|
|
1565
|
+
}
|
|
1566
|
+
function columnLetter(column) {
|
|
1567
|
+
if (column < 1) throw new RangeError(`Column must be >= 1, got ${column}.`);
|
|
1568
|
+
let result = "";
|
|
1569
|
+
let col = column;
|
|
1570
|
+
while (col > 0) {
|
|
1571
|
+
const remainder = (col - 1) % 26;
|
|
1572
|
+
result = String.fromCharCode(65 + remainder) + result;
|
|
1573
|
+
col = Math.floor((col - remainder) / 26);
|
|
1574
|
+
}
|
|
1575
|
+
return result;
|
|
1576
|
+
}
|
|
1577
|
+
function columnNumber(letters) {
|
|
1578
|
+
if (!letters) throw new Error("Column letter cannot be empty.");
|
|
1579
|
+
const upper = letters.toUpperCase();
|
|
1580
|
+
let col = 0;
|
|
1581
|
+
for (let i = 0; i < upper.length; i++) {
|
|
1582
|
+
const code = upper.charCodeAt(i);
|
|
1583
|
+
if (code < 65 || code > 90) {
|
|
1584
|
+
throw new Error(`Invalid column letter: "${letters}".`);
|
|
1585
|
+
}
|
|
1586
|
+
col = col * 26 + (code - 64);
|
|
1587
|
+
}
|
|
1588
|
+
return col;
|
|
1589
|
+
}
|
|
1590
|
+
function parseRangeRef(rangeReference) {
|
|
1591
|
+
const parts = rangeReference.split(":");
|
|
1592
|
+
if (parts.length !== 2) {
|
|
1593
|
+
throw new Error(`Invalid range reference: "${rangeReference}" \u2014 expected "A1:B10" format.`);
|
|
1594
|
+
}
|
|
1595
|
+
const start = parseCellRef(parts[0]);
|
|
1596
|
+
const end = parseCellRef(parts[1]);
|
|
1597
|
+
if (start.row > end.row || start.column > end.column) {
|
|
1598
|
+
throw new Error(
|
|
1599
|
+
`Invalid range reference: "${rangeReference}" \u2014 start must be top-left of end.`
|
|
1600
|
+
);
|
|
1601
|
+
}
|
|
1602
|
+
return {
|
|
1603
|
+
startRow: start.row,
|
|
1604
|
+
startColumn: start.column,
|
|
1605
|
+
endRow: end.row,
|
|
1606
|
+
endColumn: end.column
|
|
1607
|
+
};
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
// src/model/oa-date.ts
|
|
1611
|
+
var OA_EPOCH_MS = Date.UTC(1899, 11, 30, 0, 0, 0, 0);
|
|
1612
|
+
var MS_PER_DAY = 864e5;
|
|
1613
|
+
function toOADate(date) {
|
|
1614
|
+
const utcMs = Date.UTC(
|
|
1615
|
+
date.getFullYear(),
|
|
1616
|
+
date.getMonth(),
|
|
1617
|
+
date.getDate(),
|
|
1618
|
+
date.getHours(),
|
|
1619
|
+
date.getMinutes(),
|
|
1620
|
+
date.getSeconds(),
|
|
1621
|
+
date.getMilliseconds()
|
|
1622
|
+
);
|
|
1623
|
+
return (utcMs - OA_EPOCH_MS) / MS_PER_DAY;
|
|
1624
|
+
}
|
|
1625
|
+
function fromOADate(oaDate) {
|
|
1626
|
+
const ms = OA_EPOCH_MS + oaDate * MS_PER_DAY;
|
|
1627
|
+
const d = new Date(ms);
|
|
1628
|
+
return new Date(
|
|
1629
|
+
d.getUTCFullYear(),
|
|
1630
|
+
d.getUTCMonth(),
|
|
1631
|
+
d.getUTCDate(),
|
|
1632
|
+
d.getUTCHours(),
|
|
1633
|
+
d.getUTCMinutes(),
|
|
1634
|
+
d.getUTCSeconds(),
|
|
1635
|
+
d.getUTCMilliseconds()
|
|
1636
|
+
);
|
|
1637
|
+
}
|
|
1638
|
+
var DATE_FORMAT_IDS = /* @__PURE__ */ new Set([14, 15, 16, 17, 18, 19, 20, 21, 22, 45, 46, 47]);
|
|
1639
|
+
function isDateFormatId(formatId) {
|
|
1640
|
+
return DATE_FORMAT_IDS.has(formatId);
|
|
1641
|
+
}
|
|
1642
|
+
function isDateFormatCode(formatCode) {
|
|
1643
|
+
const lower = formatCode.toLowerCase();
|
|
1644
|
+
return lower.includes("y") || lower.includes("d") || lower.includes("m") && !lower.includes("mm:") || // m = month unless part of mm:ss
|
|
1645
|
+
lower.includes("h") || lower.includes("am") || lower.includes("pm");
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
// src/model/cell.ts
|
|
1649
|
+
var _data, _sharedStrings, _styles, _Cell_instances, isDateStyle_fn;
|
|
1650
|
+
var Cell = class {
|
|
1651
|
+
/** @internal */
|
|
1652
|
+
constructor(data, sharedStrings, styles) {
|
|
1653
|
+
__privateAdd(this, _Cell_instances);
|
|
1654
|
+
__privateAdd(this, _data);
|
|
1655
|
+
__privateAdd(this, _sharedStrings);
|
|
1656
|
+
__privateAdd(this, _styles);
|
|
1657
|
+
__privateSet(this, _data, data);
|
|
1658
|
+
__privateSet(this, _sharedStrings, sharedStrings);
|
|
1659
|
+
__privateSet(this, _styles, styles);
|
|
1660
|
+
}
|
|
1661
|
+
// ── Identity ───────────────────────────────────────────────────────────────
|
|
1662
|
+
/** Cell reference string e.g. "A1". */
|
|
1663
|
+
get reference() {
|
|
1664
|
+
return __privateGet(this, _data).reference;
|
|
1665
|
+
}
|
|
1666
|
+
/** 1-based row index. */
|
|
1667
|
+
get row() {
|
|
1668
|
+
return parseCellRef(__privateGet(this, _data).reference).row;
|
|
1669
|
+
}
|
|
1670
|
+
/** 1-based column index. */
|
|
1671
|
+
get column() {
|
|
1672
|
+
return parseCellRef(__privateGet(this, _data).reference).column;
|
|
1673
|
+
}
|
|
1674
|
+
setValue(value) {
|
|
1675
|
+
__privateGet(this, _data).formula = void 0;
|
|
1676
|
+
if (value === null || value === void 0) {
|
|
1677
|
+
__privateGet(this, _data).dataType = void 0;
|
|
1678
|
+
__privateGet(this, _data).rawValue = void 0;
|
|
1679
|
+
return this;
|
|
1680
|
+
}
|
|
1681
|
+
if (typeof value === "string") {
|
|
1682
|
+
const idx = __privateGet(this, _sharedStrings).addOrGet(value);
|
|
1683
|
+
__privateGet(this, _data).dataType = "s";
|
|
1684
|
+
__privateGet(this, _data).rawValue = String(idx);
|
|
1685
|
+
return this;
|
|
1686
|
+
}
|
|
1687
|
+
if (typeof value === "boolean") {
|
|
1688
|
+
__privateGet(this, _data).dataType = "b";
|
|
1689
|
+
__privateGet(this, _data).rawValue = value ? "1" : "0";
|
|
1690
|
+
return this;
|
|
1691
|
+
}
|
|
1692
|
+
if (value instanceof Date) {
|
|
1693
|
+
__privateGet(this, _data).dataType = "n";
|
|
1694
|
+
__privateGet(this, _data).rawValue = String(toOADate(value));
|
|
1695
|
+
if (__privateGet(this, _data).styleIndex === 0) {
|
|
1696
|
+
const style = new CellStyle();
|
|
1697
|
+
style.setNumberFormat(ExcelNumberFormat.shortDate);
|
|
1698
|
+
__privateGet(this, _data).styleIndex = __privateGet(this, _styles).getOrCreateCellFormatIndex(style);
|
|
1699
|
+
}
|
|
1700
|
+
return this;
|
|
1701
|
+
}
|
|
1702
|
+
__privateGet(this, _data).dataType = "n";
|
|
1703
|
+
__privateGet(this, _data).rawValue = String(value);
|
|
1704
|
+
return this;
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
* Gets the typed cell value.
|
|
1708
|
+
* Returns string | number | boolean | Date | null.
|
|
1709
|
+
* Date detection is based on the cell's number format.
|
|
1710
|
+
*/
|
|
1711
|
+
getValue() {
|
|
1712
|
+
if (__privateGet(this, _data).rawValue === void 0 || __privateGet(this, _data).rawValue === "") return null;
|
|
1713
|
+
switch (__privateGet(this, _data).dataType) {
|
|
1714
|
+
case "s": {
|
|
1715
|
+
const idx = parseInt(__privateGet(this, _data).rawValue, 10);
|
|
1716
|
+
return __privateGet(this, _sharedStrings).tryGetString(idx) ?? __privateGet(this, _data).rawValue;
|
|
1717
|
+
}
|
|
1718
|
+
case "b":
|
|
1719
|
+
return __privateGet(this, _data).rawValue === "1";
|
|
1720
|
+
case "str":
|
|
1721
|
+
return __privateGet(this, _data).rawValue;
|
|
1722
|
+
default: {
|
|
1723
|
+
const num = parseFloat(__privateGet(this, _data).rawValue);
|
|
1724
|
+
if (isNaN(num)) return __privateGet(this, _data).rawValue;
|
|
1725
|
+
if (__privateMethod(this, _Cell_instances, isDateStyle_fn).call(this)) {
|
|
1726
|
+
try {
|
|
1727
|
+
return fromOADate(num);
|
|
1728
|
+
} catch {
|
|
1729
|
+
return num;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
return num;
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
/**
|
|
1737
|
+
* Returns the display text of the cell value (always a string).
|
|
1738
|
+
*/
|
|
1739
|
+
getText() {
|
|
1740
|
+
const val = this.getValue();
|
|
1741
|
+
if (val === null) return "";
|
|
1742
|
+
if (val instanceof Date) return val.toLocaleDateString();
|
|
1743
|
+
return String(val);
|
|
1744
|
+
}
|
|
1745
|
+
// ── Formula API ────────────────────────────────────────────────────────────
|
|
1746
|
+
/**
|
|
1747
|
+
* Sets a formula. The leading '=' is optional.
|
|
1748
|
+
* Clears any cached value.
|
|
1749
|
+
*/
|
|
1750
|
+
setFormula(formula) {
|
|
1751
|
+
if (!formula) throw new Error("Formula cannot be empty.");
|
|
1752
|
+
__privateGet(this, _data).formula = formula.startsWith("=") ? formula.slice(1) : formula;
|
|
1753
|
+
__privateGet(this, _data).rawValue = void 0;
|
|
1754
|
+
__privateGet(this, _data).dataType = void 0;
|
|
1755
|
+
return this;
|
|
1756
|
+
}
|
|
1757
|
+
/** Returns the formula text (without leading '='), or null if no formula. */
|
|
1758
|
+
getFormula() {
|
|
1759
|
+
return __privateGet(this, _data).formula ?? null;
|
|
1760
|
+
}
|
|
1761
|
+
/** True if this cell contains a formula. */
|
|
1762
|
+
get hasFormula() {
|
|
1763
|
+
return __privateGet(this, _data).formula !== void 0 && __privateGet(this, _data).formula !== "";
|
|
1764
|
+
}
|
|
1765
|
+
// ── Style API ──────────────────────────────────────────────────────────────
|
|
1766
|
+
/** Gets the current CellStyle. Returns a new CellStyle if no style is set. */
|
|
1767
|
+
get style() {
|
|
1768
|
+
return __privateGet(this, _styles).getCellStyle(__privateGet(this, _data).styleIndex);
|
|
1769
|
+
}
|
|
1770
|
+
/** Replaces the entire cell style. */
|
|
1771
|
+
set style(value) {
|
|
1772
|
+
__privateGet(this, _data).styleIndex = __privateGet(this, _styles).getOrCreateCellFormatIndex(value);
|
|
1773
|
+
}
|
|
1774
|
+
/**
|
|
1775
|
+
* Applies style changes via a callback on the current style.
|
|
1776
|
+
* Returns this for chaining.
|
|
1777
|
+
*
|
|
1778
|
+
* @example
|
|
1779
|
+
* cell.applyStyle(s => s.setBold(true).setFontColor(ExcelColor.red))
|
|
1780
|
+
*/
|
|
1781
|
+
applyStyle(action) {
|
|
1782
|
+
const s = __privateGet(this, _styles).getCellStyle(__privateGet(this, _data).styleIndex).clone();
|
|
1783
|
+
action(s);
|
|
1784
|
+
__privateGet(this, _data).styleIndex = __privateGet(this, _styles).getOrCreateCellFormatIndex(s);
|
|
1785
|
+
return this;
|
|
1786
|
+
}
|
|
1787
|
+
// Convenience style shortcuts (mirror Cell.cs methods)
|
|
1788
|
+
setBold(bold = true) {
|
|
1789
|
+
return this.applyStyle((s) => s.setBold(bold));
|
|
1790
|
+
}
|
|
1791
|
+
setItalic(italic = true) {
|
|
1792
|
+
return this.applyStyle((s) => s.setItalic(italic));
|
|
1793
|
+
}
|
|
1794
|
+
setFontSize(size) {
|
|
1795
|
+
return this.applyStyle((s) => s.setFontSize(size));
|
|
1796
|
+
}
|
|
1797
|
+
setFontColor(color) {
|
|
1798
|
+
return this.applyStyle((s) => s.setFontColor(color));
|
|
1799
|
+
}
|
|
1800
|
+
setFontName(name) {
|
|
1801
|
+
return this.applyStyle((s) => s.setFontName(name));
|
|
1802
|
+
}
|
|
1803
|
+
setBackgroundColor(color) {
|
|
1804
|
+
return this.applyStyle((s) => s.setBackgroundColor(color));
|
|
1805
|
+
}
|
|
1806
|
+
setWrapText(wrap = true) {
|
|
1807
|
+
return this.applyStyle((s) => s.setWrapText(wrap));
|
|
1808
|
+
}
|
|
1809
|
+
setHorizontalAlignment(a) {
|
|
1810
|
+
return this.applyStyle((s) => s.setHorizontalAlignment(a));
|
|
1811
|
+
}
|
|
1812
|
+
setVerticalAlignment(a) {
|
|
1813
|
+
return this.applyStyle((s) => s.setVerticalAlignment(a));
|
|
1814
|
+
}
|
|
1815
|
+
setAllBorders(style, color) {
|
|
1816
|
+
return this.applyStyle((s) => s.setAllBorders(style, color));
|
|
1817
|
+
}
|
|
1818
|
+
setNumberFormat(formatOrCode) {
|
|
1819
|
+
return this.applyStyle((s) => s.setNumberFormat(formatOrCode));
|
|
1820
|
+
}
|
|
1821
|
+
// ── Clear ──────────────────────────────────────────────────────────────────
|
|
1822
|
+
/** Clears the cell value and formula, preserving style. */
|
|
1823
|
+
clear() {
|
|
1824
|
+
__privateGet(this, _data).rawValue = void 0;
|
|
1825
|
+
__privateGet(this, _data).dataType = void 0;
|
|
1826
|
+
__privateGet(this, _data).formula = void 0;
|
|
1827
|
+
}
|
|
1828
|
+
/** Clears the cell value, formula, AND style. */
|
|
1829
|
+
clearAll() {
|
|
1830
|
+
this.clear();
|
|
1831
|
+
__privateGet(this, _data).styleIndex = 0;
|
|
1832
|
+
}
|
|
1833
|
+
// ── XML serialisation ──────────────────────────────────────────────────────
|
|
1834
|
+
/** @internal Builds the <c> XML element string for this cell. */
|
|
1835
|
+
toXml() {
|
|
1836
|
+
const ref = __privateGet(this, _data).reference;
|
|
1837
|
+
const style = __privateGet(this, _data).styleIndex > 0 ? ` s="${__privateGet(this, _data).styleIndex}"` : "";
|
|
1838
|
+
const type = __privateGet(this, _data).dataType ? ` t="${__privateGet(this, _data).dataType}"` : "";
|
|
1839
|
+
const formulaXml = __privateGet(this, _data).formula ? `<f>${escXml(__privateGet(this, _data).formula)}</f>` : "";
|
|
1840
|
+
const valueXml = __privateGet(this, _data).rawValue !== void 0 && __privateGet(this, _data).rawValue !== "" ? `<v>${escXml(__privateGet(this, _data).rawValue)}</v>` : "";
|
|
1841
|
+
if (!formulaXml && !valueXml && __privateGet(this, _data).styleIndex === 0) return "";
|
|
1842
|
+
return `<c r="${ref}"${style}${type}>${formulaXml}${valueXml}</c>`;
|
|
1843
|
+
}
|
|
1844
|
+
/** @internal Parses a <c> XML element into CellData. */
|
|
1845
|
+
static fromXmlElement(el, ref) {
|
|
1846
|
+
const dataType = el.attributes["t"] ?? void 0;
|
|
1847
|
+
const styleIndex = parseInt(el.attributes["s"] ?? "0", 10);
|
|
1848
|
+
let rawValue;
|
|
1849
|
+
let formula;
|
|
1850
|
+
for (const child of el.children) {
|
|
1851
|
+
const tag = child.tagName.replace(/^.*:/, "");
|
|
1852
|
+
if (tag === "v") rawValue = child.textContent;
|
|
1853
|
+
if (tag === "f") formula = child.textContent;
|
|
1854
|
+
}
|
|
1855
|
+
return { reference: ref, dataType, rawValue, formula, styleIndex };
|
|
1856
|
+
}
|
|
1857
|
+
};
|
|
1858
|
+
_data = new WeakMap();
|
|
1859
|
+
_sharedStrings = new WeakMap();
|
|
1860
|
+
_styles = new WeakMap();
|
|
1861
|
+
_Cell_instances = new WeakSet();
|
|
1862
|
+
// ── Private helpers ────────────────────────────────────────────────────────
|
|
1863
|
+
isDateStyle_fn = function() {
|
|
1864
|
+
const style = __privateGet(this, _styles).getCellStyle(__privateGet(this, _data).styleIndex);
|
|
1865
|
+
if (!style.numberFormat) return false;
|
|
1866
|
+
if (isDateFormatId(style.numberFormat.formatId)) return true;
|
|
1867
|
+
return isDateFormatCode(style.numberFormat.formatCode);
|
|
1868
|
+
};
|
|
1869
|
+
function escXml(s) {
|
|
1870
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
// src/model/range.ts
|
|
1874
|
+
var _sheet, _startRow, _startColumn, _endRow, _endColumn, _address, _Range_instances, forEach_fn;
|
|
1875
|
+
var Range = class {
|
|
1876
|
+
constructor(sheet, rangeReference) {
|
|
1877
|
+
__privateAdd(this, _Range_instances);
|
|
1878
|
+
__privateAdd(this, _sheet);
|
|
1879
|
+
__privateAdd(this, _startRow);
|
|
1880
|
+
__privateAdd(this, _startColumn);
|
|
1881
|
+
__privateAdd(this, _endRow);
|
|
1882
|
+
__privateAdd(this, _endColumn);
|
|
1883
|
+
__privateAdd(this, _address);
|
|
1884
|
+
__privateSet(this, _sheet, sheet);
|
|
1885
|
+
__privateSet(this, _address, rangeReference.toUpperCase());
|
|
1886
|
+
const { startRow, startColumn, endRow, endColumn } = parseRangeRef(rangeReference);
|
|
1887
|
+
__privateSet(this, _startRow, startRow);
|
|
1888
|
+
__privateSet(this, _startColumn, startColumn);
|
|
1889
|
+
__privateSet(this, _endRow, endRow);
|
|
1890
|
+
__privateSet(this, _endColumn, endColumn);
|
|
1891
|
+
}
|
|
1892
|
+
/** The range address e.g. "A1:B10". */
|
|
1893
|
+
get address() {
|
|
1894
|
+
return __privateGet(this, _address);
|
|
1895
|
+
}
|
|
1896
|
+
/** Number of rows in the range. */
|
|
1897
|
+
get rowCount() {
|
|
1898
|
+
return __privateGet(this, _endRow) - __privateGet(this, _startRow) + 1;
|
|
1899
|
+
}
|
|
1900
|
+
/** Number of columns in the range. */
|
|
1901
|
+
get columnCount() {
|
|
1902
|
+
return __privateGet(this, _endColumn) - __privateGet(this, _startColumn) + 1;
|
|
1903
|
+
}
|
|
1904
|
+
// ── Value bulk operations ──────────────────────────────────────────────────
|
|
1905
|
+
/**
|
|
1906
|
+
* Sets values from a 2D array.
|
|
1907
|
+
* Values that exceed the range boundary are silently ignored.
|
|
1908
|
+
*/
|
|
1909
|
+
setValues(values) {
|
|
1910
|
+
for (let r = 0; r < values.length && __privateGet(this, _startRow) + r <= __privateGet(this, _endRow); r++) {
|
|
1911
|
+
const rowValues = values[r];
|
|
1912
|
+
for (let c = 0; c < rowValues.length && __privateGet(this, _startColumn) + c <= __privateGet(this, _endColumn); c++) {
|
|
1913
|
+
const cell = __privateGet(this, _sheet).getCell(__privateGet(this, _startRow) + r, __privateGet(this, _startColumn) + c);
|
|
1914
|
+
const val = rowValues[c];
|
|
1915
|
+
cell.setValue(val);
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
/**
|
|
1920
|
+
* Gets all cell values as a 2D array (row-major order).
|
|
1921
|
+
*/
|
|
1922
|
+
getValues() {
|
|
1923
|
+
const result = [];
|
|
1924
|
+
for (let r = 0; r < this.rowCount; r++) {
|
|
1925
|
+
const row = [];
|
|
1926
|
+
for (let c = 0; c < this.columnCount; c++) {
|
|
1927
|
+
const cell = __privateGet(this, _sheet).tryGetCell(__privateGet(this, _startRow) + r, __privateGet(this, _startColumn) + c);
|
|
1928
|
+
row.push(cell ? cell.getValue() : null);
|
|
1929
|
+
}
|
|
1930
|
+
result.push(row);
|
|
1931
|
+
}
|
|
1932
|
+
return result;
|
|
1933
|
+
}
|
|
1934
|
+
/** Clears all cells in the range (values only, preserves style). */
|
|
1935
|
+
clear() {
|
|
1936
|
+
__privateMethod(this, _Range_instances, forEach_fn).call(this, (cell) => cell.clear());
|
|
1937
|
+
}
|
|
1938
|
+
/** Auto-fits all columns in the range. */
|
|
1939
|
+
autoFit() {
|
|
1940
|
+
for (let col = __privateGet(this, _startColumn); col <= __privateGet(this, _endColumn); col++) {
|
|
1941
|
+
__privateGet(this, _sheet).autoFitColumn(col);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
// ── Style bulk operations ──────────────────────────────────────────────────
|
|
1945
|
+
/** Applies a CellStyle to all cells in the range. Returns this for chaining. */
|
|
1946
|
+
setStyle(style) {
|
|
1947
|
+
__privateMethod(this, _Range_instances, forEach_fn).call(this, (cell) => {
|
|
1948
|
+
cell.style = style;
|
|
1949
|
+
});
|
|
1950
|
+
return this;
|
|
1951
|
+
}
|
|
1952
|
+
/**
|
|
1953
|
+
* Applies style changes to all cells in the range.
|
|
1954
|
+
* @example range.applyStyle(s => s.setBold(true).setBackgroundColor(ExcelColor.lightGray))
|
|
1955
|
+
*/
|
|
1956
|
+
applyStyle(action) {
|
|
1957
|
+
__privateMethod(this, _Range_instances, forEach_fn).call(this, (cell) => cell.applyStyle(action));
|
|
1958
|
+
return this;
|
|
1959
|
+
}
|
|
1960
|
+
setBold(bold = true) {
|
|
1961
|
+
__privateMethod(this, _Range_instances, forEach_fn).call(this, (cell) => cell.setBold(bold));
|
|
1962
|
+
return this;
|
|
1963
|
+
}
|
|
1964
|
+
setFontSize(size) {
|
|
1965
|
+
__privateMethod(this, _Range_instances, forEach_fn).call(this, (cell) => cell.setFontSize(size));
|
|
1966
|
+
return this;
|
|
1967
|
+
}
|
|
1968
|
+
setFontColor(color) {
|
|
1969
|
+
__privateMethod(this, _Range_instances, forEach_fn).call(this, (cell) => cell.setFontColor(color));
|
|
1970
|
+
return this;
|
|
1971
|
+
}
|
|
1972
|
+
setFontName(name) {
|
|
1973
|
+
__privateMethod(this, _Range_instances, forEach_fn).call(this, (cell) => cell.setFontName(name));
|
|
1974
|
+
return this;
|
|
1975
|
+
}
|
|
1976
|
+
setBackgroundColor(color) {
|
|
1977
|
+
__privateMethod(this, _Range_instances, forEach_fn).call(this, (cell) => cell.setBackgroundColor(color));
|
|
1978
|
+
return this;
|
|
1979
|
+
}
|
|
1980
|
+
setAllBorders(style, color) {
|
|
1981
|
+
__privateMethod(this, _Range_instances, forEach_fn).call(this, (cell) => cell.setAllBorders(style, color));
|
|
1982
|
+
return this;
|
|
1983
|
+
}
|
|
1984
|
+
setHorizontalAlignment(alignment) {
|
|
1985
|
+
__privateMethod(this, _Range_instances, forEach_fn).call(this, (cell) => cell.setHorizontalAlignment(alignment));
|
|
1986
|
+
return this;
|
|
1987
|
+
}
|
|
1988
|
+
setVerticalAlignment(alignment) {
|
|
1989
|
+
__privateMethod(this, _Range_instances, forEach_fn).call(this, (cell) => cell.setVerticalAlignment(alignment));
|
|
1990
|
+
return this;
|
|
1991
|
+
}
|
|
1992
|
+
setWrapText(wrap = true) {
|
|
1993
|
+
__privateMethod(this, _Range_instances, forEach_fn).call(this, (cell) => cell.setWrapText(wrap));
|
|
1994
|
+
return this;
|
|
1995
|
+
}
|
|
1996
|
+
setNumberFormat(formatOrCode) {
|
|
1997
|
+
__privateMethod(this, _Range_instances, forEach_fn).call(this, (cell) => cell.setNumberFormat(formatOrCode));
|
|
1998
|
+
return this;
|
|
1999
|
+
}
|
|
2000
|
+
};
|
|
2001
|
+
_sheet = new WeakMap();
|
|
2002
|
+
_startRow = new WeakMap();
|
|
2003
|
+
_startColumn = new WeakMap();
|
|
2004
|
+
_endRow = new WeakMap();
|
|
2005
|
+
_endColumn = new WeakMap();
|
|
2006
|
+
_address = new WeakMap();
|
|
2007
|
+
_Range_instances = new WeakSet();
|
|
2008
|
+
// ── Private helper ─────────────────────────────────────────────────────────
|
|
2009
|
+
forEach_fn = function(action) {
|
|
2010
|
+
for (let r = __privateGet(this, _startRow); r <= __privateGet(this, _endRow); r++) {
|
|
2011
|
+
for (let c = __privateGet(this, _startColumn); c <= __privateGet(this, _endColumn); c++) {
|
|
2012
|
+
action(__privateGet(this, _sheet).getCell(r, c));
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
};
|
|
2016
|
+
|
|
2017
|
+
// src/model/worksheet.ts
|
|
2018
|
+
var _sharedStrings2, _styles2, _name, _rows, _cols, _mergeCells, _pane, _autoFilter, _dataValidations, _visibility, _drawings, _Worksheet_instances, buildColsXml_fn, buildSheetDataXml_fn, buildMergeCellsXml_fn, buildDataValidationsXml_fn, buildSheetViewXml_fn, getOrCreateRow_fn;
|
|
2019
|
+
var Worksheet = class {
|
|
2020
|
+
/** @internal */
|
|
2021
|
+
constructor(name, sharedStrings, styles) {
|
|
2022
|
+
__privateAdd(this, _Worksheet_instances);
|
|
2023
|
+
__privateAdd(this, _sharedStrings2);
|
|
2024
|
+
__privateAdd(this, _styles2);
|
|
2025
|
+
__privateAdd(this, _name);
|
|
2026
|
+
__privateAdd(this, _rows, /* @__PURE__ */ new Map());
|
|
2027
|
+
__privateAdd(this, _cols, []);
|
|
2028
|
+
__privateAdd(this, _mergeCells, []);
|
|
2029
|
+
__privateAdd(this, _pane);
|
|
2030
|
+
__privateAdd(this, _autoFilter);
|
|
2031
|
+
__privateAdd(this, _dataValidations, []);
|
|
2032
|
+
__privateAdd(this, _visibility, "visible");
|
|
2033
|
+
__privateAdd(this, _drawings, []);
|
|
2034
|
+
__privateSet(this, _name, name);
|
|
2035
|
+
__privateSet(this, _sharedStrings2, sharedStrings);
|
|
2036
|
+
__privateSet(this, _styles2, styles);
|
|
2037
|
+
}
|
|
2038
|
+
// ── Identity ───────────────────────────────────────────────────────────────
|
|
2039
|
+
get name() {
|
|
2040
|
+
return __privateGet(this, _name);
|
|
2041
|
+
}
|
|
2042
|
+
set name(value) {
|
|
2043
|
+
if (!value) throw new Error("Worksheet name cannot be empty.");
|
|
2044
|
+
__privateSet(this, _name, value);
|
|
2045
|
+
}
|
|
2046
|
+
getCell(refOrRow, column) {
|
|
2047
|
+
const ref = typeof refOrRow === "string" ? refOrRow.replace(/\$/g, "").toUpperCase() : cellRefFromRowCol(refOrRow, column);
|
|
2048
|
+
const { row } = parseCellRef(ref);
|
|
2049
|
+
const rowData = __privateMethod(this, _Worksheet_instances, getOrCreateRow_fn).call(this, row);
|
|
2050
|
+
let cellData = rowData.cells.get(ref);
|
|
2051
|
+
if (!cellData) {
|
|
2052
|
+
cellData = { reference: ref, styleIndex: 0 };
|
|
2053
|
+
rowData.cells.set(ref, cellData);
|
|
2054
|
+
}
|
|
2055
|
+
return new Cell(cellData, __privateGet(this, _sharedStrings2), __privateGet(this, _styles2));
|
|
2056
|
+
}
|
|
2057
|
+
tryGetCell(refOrRow, column) {
|
|
2058
|
+
const ref = typeof refOrRow === "string" ? refOrRow.replace(/\$/g, "").toUpperCase() : cellRefFromRowCol(refOrRow, column);
|
|
2059
|
+
const { row } = parseCellRef(ref);
|
|
2060
|
+
const rowData = __privateGet(this, _rows).get(row);
|
|
2061
|
+
if (!rowData) return null;
|
|
2062
|
+
const cellData = rowData.cells.get(ref);
|
|
2063
|
+
if (!cellData) return null;
|
|
2064
|
+
return new Cell(cellData, __privateGet(this, _sharedStrings2), __privateGet(this, _styles2));
|
|
2065
|
+
}
|
|
2066
|
+
cell(refOrRow, column) {
|
|
2067
|
+
return typeof refOrRow === "string" ? this.getCell(refOrRow) : this.getCell(refOrRow, column);
|
|
2068
|
+
}
|
|
2069
|
+
/** Gets a Range object for bulk operations. */
|
|
2070
|
+
getRange(rangeReference) {
|
|
2071
|
+
if (!rangeReference) throw new Error("Range reference cannot be empty.");
|
|
2072
|
+
return new Range(this, rangeReference);
|
|
2073
|
+
}
|
|
2074
|
+
/** Gets the raw value of a cell (for formula evaluation). */
|
|
2075
|
+
getCellValue(reference) {
|
|
2076
|
+
return this.tryGetCell(reference)?.getValue() ?? null;
|
|
2077
|
+
}
|
|
2078
|
+
/**
|
|
2079
|
+
* Returns the 1-based extent of populated cells (largest row and column that
|
|
2080
|
+
* contain data). Returns zeros for an empty sheet. Useful for snapshotting a
|
|
2081
|
+
* sheet into a dense 2D array.
|
|
2082
|
+
*/
|
|
2083
|
+
get usedBounds() {
|
|
2084
|
+
let rowCount = 0;
|
|
2085
|
+
let columnCount = 0;
|
|
2086
|
+
for (const row of __privateGet(this, _rows).values()) {
|
|
2087
|
+
if (row.cells.size === 0) continue;
|
|
2088
|
+
if (row.rowIndex > rowCount) rowCount = row.rowIndex;
|
|
2089
|
+
for (const ref of row.cells.keys()) {
|
|
2090
|
+
const col = parseCellRef(ref).column;
|
|
2091
|
+
if (col > columnCount) columnCount = col;
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
return { rowCount, columnCount };
|
|
2095
|
+
}
|
|
2096
|
+
// ── Layout ─────────────────────────────────────────────────────────────────
|
|
2097
|
+
/** Sets the width of a column (1-based index). */
|
|
2098
|
+
setColumnWidth(columnIndex, width) {
|
|
2099
|
+
if (columnIndex < 1) throw new RangeError("Column index must be >= 1.");
|
|
2100
|
+
if (width <= 0) throw new RangeError("Width must be > 0.");
|
|
2101
|
+
__privateSet(this, _cols, __privateGet(this, _cols).filter((c) => !(c.min <= columnIndex && c.max >= columnIndex)));
|
|
2102
|
+
__privateGet(this, _cols).push({ min: columnIndex, max: columnIndex, width, customWidth: true });
|
|
2103
|
+
__privateGet(this, _cols).sort((a, b) => a.min - b.min);
|
|
2104
|
+
}
|
|
2105
|
+
/** Auto-fits column width based on content (approximate). */
|
|
2106
|
+
autoFitColumn(columnIndex) {
|
|
2107
|
+
if (columnIndex < 1) throw new RangeError("Column index must be >= 1.");
|
|
2108
|
+
let maxLen = 8;
|
|
2109
|
+
for (const row of __privateGet(this, _rows).values()) {
|
|
2110
|
+
const ref = cellRefFromRowCol(row.rowIndex, columnIndex);
|
|
2111
|
+
const cellData = row.cells.get(ref);
|
|
2112
|
+
if (cellData) {
|
|
2113
|
+
const cell = new Cell(cellData, __privateGet(this, _sharedStrings2), __privateGet(this, _styles2));
|
|
2114
|
+
const textLen = cell.getText().length;
|
|
2115
|
+
if (textLen > maxLen) maxLen = textLen;
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
this.setColumnWidth(columnIndex, Math.min(maxLen * 1.2 + 2, 255));
|
|
2119
|
+
}
|
|
2120
|
+
/** Sets the height of a row (1-based index). */
|
|
2121
|
+
setRowHeight(rowIndex, height) {
|
|
2122
|
+
if (rowIndex < 1) throw new RangeError("Row index must be >= 1.");
|
|
2123
|
+
if (height <= 0) throw new RangeError("Height must be > 0.");
|
|
2124
|
+
const row = __privateMethod(this, _Worksheet_instances, getOrCreateRow_fn).call(this, rowIndex);
|
|
2125
|
+
row.height = height;
|
|
2126
|
+
row.customHeight = true;
|
|
2127
|
+
}
|
|
2128
|
+
/** Merges cells in the given range (e.g. "A1:B2"). */
|
|
2129
|
+
mergeCells(rangeReference) {
|
|
2130
|
+
if (!rangeReference) throw new Error("Range reference cannot be empty.");
|
|
2131
|
+
__privateGet(this, _mergeCells).push({ ref: rangeReference });
|
|
2132
|
+
}
|
|
2133
|
+
/** Removes a merge for the given range reference. */
|
|
2134
|
+
unmergeCells(rangeReference) {
|
|
2135
|
+
__privateSet(this, _mergeCells, __privateGet(this, _mergeCells).filter((m) => m.ref !== rangeReference));
|
|
2136
|
+
}
|
|
2137
|
+
/**
|
|
2138
|
+
* Freezes rows and/or columns.
|
|
2139
|
+
* @param row Number of rows to freeze (0 = none)
|
|
2140
|
+
* @param column Number of columns to freeze (0 = none)
|
|
2141
|
+
*/
|
|
2142
|
+
freezePanes(row, column) {
|
|
2143
|
+
if (row < 0) throw new RangeError("Row must be >= 0.");
|
|
2144
|
+
if (column < 0) throw new RangeError("Column must be >= 0.");
|
|
2145
|
+
__privateSet(this, _pane, row === 0 && column === 0 ? void 0 : { row, column });
|
|
2146
|
+
}
|
|
2147
|
+
/** Sets auto-filter on the given range. */
|
|
2148
|
+
setAutoFilter(rangeReference) {
|
|
2149
|
+
__privateSet(this, _autoFilter, { ref: rangeReference });
|
|
2150
|
+
}
|
|
2151
|
+
/**
|
|
2152
|
+
* Adds a dropdown data validation to a cell range.
|
|
2153
|
+
* @param cellRange Range to apply (e.g. "F2:F1000")
|
|
2154
|
+
* @param listFormula Formula for the dropdown list (e.g. "'Sheet2'!$A$1:$A$10")
|
|
2155
|
+
*/
|
|
2156
|
+
addDropdownValidation(cellRange, listFormula) {
|
|
2157
|
+
__privateGet(this, _dataValidations).push({ sqref: cellRange, formula: listFormula });
|
|
2158
|
+
}
|
|
2159
|
+
/** Sets the visibility state of this worksheet. */
|
|
2160
|
+
setVisibility(state) {
|
|
2161
|
+
__privateSet(this, _visibility, state);
|
|
2162
|
+
}
|
|
2163
|
+
get visibility() {
|
|
2164
|
+
return __privateGet(this, _visibility);
|
|
2165
|
+
}
|
|
2166
|
+
// ── Drawings (charts, images …) ──────────────────────────────────────────────
|
|
2167
|
+
/**
|
|
2168
|
+
* Attaches a drawing provider (e.g. a chart) to this worksheet.
|
|
2169
|
+
* Satellite packages such as `@devmm/puredocs-excel-charts` call this; the core
|
|
2170
|
+
* save pipeline turns registered providers into valid OOXML drawing/chart parts.
|
|
2171
|
+
*/
|
|
2172
|
+
addDrawingProvider(provider) {
|
|
2173
|
+
__privateGet(this, _drawings).push(provider);
|
|
2174
|
+
}
|
|
2175
|
+
/** True when this worksheet has at least one drawing to serialise. */
|
|
2176
|
+
get hasDrawings() {
|
|
2177
|
+
return __privateGet(this, _drawings).length > 0;
|
|
2178
|
+
}
|
|
2179
|
+
/** @internal — drawing providers, consumed by the save pipeline. */
|
|
2180
|
+
get drawingProviders() {
|
|
2181
|
+
return __privateGet(this, _drawings);
|
|
2182
|
+
}
|
|
2183
|
+
// ── XML serialisation ──────────────────────────────────────────────────────
|
|
2184
|
+
/** Builds the xl/worksheets/sheetN.xml string. */
|
|
2185
|
+
buildXml() {
|
|
2186
|
+
const colsXml = __privateMethod(this, _Worksheet_instances, buildColsXml_fn).call(this);
|
|
2187
|
+
const sheetDataXml = __privateMethod(this, _Worksheet_instances, buildSheetDataXml_fn).call(this);
|
|
2188
|
+
const mergeXml = __privateMethod(this, _Worksheet_instances, buildMergeCellsXml_fn).call(this);
|
|
2189
|
+
const filterXml = __privateGet(this, _autoFilter) ? `<autoFilter ref="${__privateGet(this, _autoFilter).ref}"/>` : "";
|
|
2190
|
+
const validXml = __privateMethod(this, _Worksheet_instances, buildDataValidationsXml_fn).call(this);
|
|
2191
|
+
const sheetViewXml = __privateMethod(this, _Worksheet_instances, buildSheetViewXml_fn).call(this);
|
|
2192
|
+
const drawingXml = this.hasDrawings ? `<drawing r:id="${WORKSHEET_DRAWING_REL_ID}"/>` : "";
|
|
2193
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
2194
|
+
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
2195
|
+
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
2196
|
+
<sheetViews>${sheetViewXml}</sheetViews>
|
|
2197
|
+
${colsXml}${sheetDataXml}${filterXml}${mergeXml}${validXml}${drawingXml}
|
|
2198
|
+
</worksheet>`;
|
|
2199
|
+
}
|
|
2200
|
+
/** Parses xl/worksheets/sheetN.xml and loads cells into memory. */
|
|
2201
|
+
loadFromXml(xml2) {
|
|
2202
|
+
__privateGet(this, _rows).clear();
|
|
2203
|
+
__privateSet(this, _cols, []);
|
|
2204
|
+
__privateSet(this, _mergeCells, []);
|
|
2205
|
+
__privateSet(this, _pane, void 0);
|
|
2206
|
+
__privateSet(this, _autoFilter, void 0);
|
|
2207
|
+
__privateSet(this, _dataValidations, []);
|
|
2208
|
+
const root = parseXml(xml2);
|
|
2209
|
+
for (const colEl of getElementsByTagName(root, "col")) {
|
|
2210
|
+
__privateGet(this, _cols).push({
|
|
2211
|
+
min: parseInt(getAttr(colEl, "min") ?? "1", 10),
|
|
2212
|
+
max: parseInt(getAttr(colEl, "max") ?? "1", 10),
|
|
2213
|
+
width: parseFloat(getAttr(colEl, "width") ?? "8"),
|
|
2214
|
+
customWidth: getAttr(colEl, "customWidth") === "1",
|
|
2215
|
+
hidden: getAttr(colEl, "hidden") === "1"
|
|
2216
|
+
});
|
|
2217
|
+
}
|
|
2218
|
+
for (const rowEl of getElementsByTagName(root, "row")) {
|
|
2219
|
+
const rowIndex = parseInt(getAttr(rowEl, "r") ?? "0", 10);
|
|
2220
|
+
if (rowIndex < 1) continue;
|
|
2221
|
+
const rowData = { rowIndex, cells: /* @__PURE__ */ new Map() };
|
|
2222
|
+
const ht = getAttr(rowEl, "ht");
|
|
2223
|
+
if (ht) {
|
|
2224
|
+
rowData.height = parseFloat(ht);
|
|
2225
|
+
rowData.customHeight = true;
|
|
2226
|
+
}
|
|
2227
|
+
for (const cellEl of rowEl.children) {
|
|
2228
|
+
const tag = cellEl.tagName.replace(/^.*:/, "");
|
|
2229
|
+
if (tag !== "c") continue;
|
|
2230
|
+
const ref = getAttr(cellEl, "r");
|
|
2231
|
+
if (!ref) continue;
|
|
2232
|
+
const cellData = Cell.fromXmlElement(
|
|
2233
|
+
{ attributes: cellEl.attributes, children: cellEl.children },
|
|
2234
|
+
ref.toUpperCase()
|
|
2235
|
+
);
|
|
2236
|
+
rowData.cells.set(ref.toUpperCase(), cellData);
|
|
2237
|
+
}
|
|
2238
|
+
__privateGet(this, _rows).set(rowIndex, rowData);
|
|
2239
|
+
}
|
|
2240
|
+
for (const mcEl of getElementsByTagName(root, "mergeCell")) {
|
|
2241
|
+
const ref = getAttr(mcEl, "ref");
|
|
2242
|
+
if (ref) __privateGet(this, _mergeCells).push({ ref });
|
|
2243
|
+
}
|
|
2244
|
+
const afEls = getElementsByTagName(root, "autoFilter");
|
|
2245
|
+
if (afEls.length > 0) {
|
|
2246
|
+
const ref = getAttr(afEls[0], "ref");
|
|
2247
|
+
if (ref) __privateSet(this, _autoFilter, { ref });
|
|
2248
|
+
}
|
|
2249
|
+
for (const paneEl of getElementsByTagName(root, "pane")) {
|
|
2250
|
+
const state = getAttr(paneEl, "state");
|
|
2251
|
+
if (state === "frozen" || state === "frozenSplit") {
|
|
2252
|
+
__privateSet(this, _pane, {
|
|
2253
|
+
row: parseInt(getAttr(paneEl, "ySplit") ?? "0", 10),
|
|
2254
|
+
column: parseInt(getAttr(paneEl, "xSplit") ?? "0", 10)
|
|
2255
|
+
});
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
for (const dvEl of getElementsByTagName(root, "dataValidation")) {
|
|
2259
|
+
const sqref = getAttr(dvEl, "sqref") ?? "";
|
|
2260
|
+
const f1Els = getElementsByTagName(dvEl, "formula1");
|
|
2261
|
+
const formula = f1Els[0]?.textContent ?? "";
|
|
2262
|
+
if (sqref && formula) __privateGet(this, _dataValidations).push({ sqref, formula });
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
};
|
|
2266
|
+
_sharedStrings2 = new WeakMap();
|
|
2267
|
+
_styles2 = new WeakMap();
|
|
2268
|
+
_name = new WeakMap();
|
|
2269
|
+
_rows = new WeakMap();
|
|
2270
|
+
_cols = new WeakMap();
|
|
2271
|
+
_mergeCells = new WeakMap();
|
|
2272
|
+
_pane = new WeakMap();
|
|
2273
|
+
_autoFilter = new WeakMap();
|
|
2274
|
+
_dataValidations = new WeakMap();
|
|
2275
|
+
_visibility = new WeakMap();
|
|
2276
|
+
_drawings = new WeakMap();
|
|
2277
|
+
_Worksheet_instances = new WeakSet();
|
|
2278
|
+
// ── Private XML builders ───────────────────────────────────────────────────
|
|
2279
|
+
buildColsXml_fn = function() {
|
|
2280
|
+
if (__privateGet(this, _cols).length === 0) return "";
|
|
2281
|
+
const inner = __privateGet(this, _cols).map((c) => {
|
|
2282
|
+
const hidden = c.hidden ? ' hidden="1"' : "";
|
|
2283
|
+
return `<col min="${c.min}" max="${c.max}" width="${c.width.toFixed(2)}" customWidth="${c.customWidth ? 1 : 0}"${hidden}/>`;
|
|
2284
|
+
}).join("");
|
|
2285
|
+
return `<cols>${inner}</cols>`;
|
|
2286
|
+
};
|
|
2287
|
+
buildSheetDataXml_fn = function() {
|
|
2288
|
+
const sortedRows = [...__privateGet(this, _rows).values()].sort((a, b) => a.rowIndex - b.rowIndex);
|
|
2289
|
+
if (sortedRows.length === 0) return "<sheetData/>";
|
|
2290
|
+
const rowsXml = sortedRows.map((row) => {
|
|
2291
|
+
const ht = row.height !== void 0 && row.customHeight ? ` ht="${row.height}" customHeight="1"` : "";
|
|
2292
|
+
const sortedCells = [...row.cells.values()].sort((a, b) => {
|
|
2293
|
+
const ra = parseCellRef(a.reference);
|
|
2294
|
+
const rb = parseCellRef(b.reference);
|
|
2295
|
+
return ra.column - rb.column;
|
|
2296
|
+
});
|
|
2297
|
+
const cellsXml = sortedCells.map((cd) => new Cell(cd, __privateGet(this, _sharedStrings2), __privateGet(this, _styles2)).toXml()).filter(Boolean).join("");
|
|
2298
|
+
if (!cellsXml && !ht) return "";
|
|
2299
|
+
return `<row r="${row.rowIndex}"${ht}>${cellsXml}</row>`;
|
|
2300
|
+
}).filter(Boolean).join("");
|
|
2301
|
+
return `<sheetData>${rowsXml}</sheetData>`;
|
|
2302
|
+
};
|
|
2303
|
+
buildMergeCellsXml_fn = function() {
|
|
2304
|
+
if (__privateGet(this, _mergeCells).length === 0) return "";
|
|
2305
|
+
const inner = __privateGet(this, _mergeCells).map((m) => `<mergeCell ref="${m.ref}"/>`).join("");
|
|
2306
|
+
return `<mergeCells count="${__privateGet(this, _mergeCells).length}">${inner}</mergeCells>`;
|
|
2307
|
+
};
|
|
2308
|
+
buildDataValidationsXml_fn = function() {
|
|
2309
|
+
if (__privateGet(this, _dataValidations).length === 0) return "";
|
|
2310
|
+
const inner = __privateGet(this, _dataValidations).map(
|
|
2311
|
+
(dv) => `<dataValidation type="list" allowBlank="1" showInputMessage="1" showErrorMessage="1" sqref="${dv.sqref}"><formula1>${escXml2(dv.formula)}</formula1></dataValidation>`
|
|
2312
|
+
).join("");
|
|
2313
|
+
return `<dataValidations count="${__privateGet(this, _dataValidations).length}">${inner}</dataValidations>`;
|
|
2314
|
+
};
|
|
2315
|
+
buildSheetViewXml_fn = function() {
|
|
2316
|
+
if (!__privateGet(this, _pane)) return '<sheetView workbookViewId="0"/>';
|
|
2317
|
+
const { row, column } = __privateGet(this, _pane);
|
|
2318
|
+
const topLeftRow = row > 0 ? row + 1 : 1;
|
|
2319
|
+
const topLeftCol = column > 0 ? column + 1 : 1;
|
|
2320
|
+
const topLeft = cellRefFromRowCol(topLeftRow, topLeftCol);
|
|
2321
|
+
const activePane = row > 0 && column > 0 ? "bottomRight" : row > 0 ? "bottomLeft" : "topRight";
|
|
2322
|
+
const xSplit = column > 0 ? ` xSplit="${column}"` : "";
|
|
2323
|
+
const ySplit = row > 0 ? ` ySplit="${row}"` : "";
|
|
2324
|
+
return `<sheetView workbookViewId="0"><pane${xSplit}${ySplit} topLeftCell="${topLeft}" activePane="${activePane}" state="frozen"/></sheetView>`;
|
|
2325
|
+
};
|
|
2326
|
+
getOrCreateRow_fn = function(rowIndex) {
|
|
2327
|
+
let row = __privateGet(this, _rows).get(rowIndex);
|
|
2328
|
+
if (!row) {
|
|
2329
|
+
row = { rowIndex, cells: /* @__PURE__ */ new Map() };
|
|
2330
|
+
__privateGet(this, _rows).set(rowIndex, row);
|
|
2331
|
+
}
|
|
2332
|
+
return row;
|
|
2333
|
+
};
|
|
2334
|
+
function escXml2(s) {
|
|
2335
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
// src/model/workbook.ts
|
|
2339
|
+
var _sharedStrings3, _styles3, _sheets, _closed, _Workbook_instances, assertOpen_fn, buildZipEntries_fn;
|
|
2340
|
+
var _Workbook = class _Workbook {
|
|
2341
|
+
constructor(sharedStrings, styles) {
|
|
2342
|
+
__privateAdd(this, _Workbook_instances);
|
|
2343
|
+
__privateAdd(this, _sharedStrings3);
|
|
2344
|
+
__privateAdd(this, _styles3);
|
|
2345
|
+
__privateAdd(this, _sheets, []);
|
|
2346
|
+
__privateAdd(this, _closed, false);
|
|
2347
|
+
__privateSet(this, _sharedStrings3, sharedStrings);
|
|
2348
|
+
__privateSet(this, _styles3, styles);
|
|
2349
|
+
}
|
|
2350
|
+
// ── Factory methods ────────────────────────────────────────────────────────
|
|
2351
|
+
/**
|
|
2352
|
+
* Creates a new empty workbook.
|
|
2353
|
+
* Mirrors Workbook.Create() in C#.
|
|
2354
|
+
*/
|
|
2355
|
+
static create() {
|
|
2356
|
+
const ss = new SharedStringManager();
|
|
2357
|
+
const sm = new StyleManager();
|
|
2358
|
+
return new _Workbook(ss, sm);
|
|
2359
|
+
}
|
|
2360
|
+
/**
|
|
2361
|
+
* Opens an existing workbook from a binary buffer (ArrayBuffer or Uint8Array).
|
|
2362
|
+
* Works in both browser and Node.js.
|
|
2363
|
+
* Mirrors Workbook.Open(stream) in C#.
|
|
2364
|
+
*/
|
|
2365
|
+
static fromBuffer(buffer) {
|
|
2366
|
+
const entries = unzipXlsx(buffer);
|
|
2367
|
+
const ss = new SharedStringManager();
|
|
2368
|
+
const sm = new StyleManager();
|
|
2369
|
+
const wb = new _Workbook(ss, sm);
|
|
2370
|
+
const ssXml = readXmlEntry(entries, "xl/sharedStrings.xml");
|
|
2371
|
+
if (ssXml) ss.loadFromXml(ssXml);
|
|
2372
|
+
const stylesXml = readXmlEntry(entries, "xl/styles.xml");
|
|
2373
|
+
if (stylesXml) sm.loadFromXml(stylesXml);
|
|
2374
|
+
const wbXml = requireXmlEntry(entries, "xl/workbook.xml");
|
|
2375
|
+
const wbRoot = parseXml(wbXml);
|
|
2376
|
+
for (const sheetEl of getElementsByTagName(wbRoot, "sheet")) {
|
|
2377
|
+
const name = getAttr(sheetEl, "name") ?? "Sheet";
|
|
2378
|
+
const sheetId = parseInt(getAttr(sheetEl, "sheetId") ?? "1", 10);
|
|
2379
|
+
const relId = getAttr(sheetEl, "r:id") ?? getAttr(sheetEl, "id") ?? `rId${sheetId}`;
|
|
2380
|
+
const state = getAttr(sheetEl, "state");
|
|
2381
|
+
const relXml = readXmlEntry(entries, "xl/_rels/workbook.xml.rels") ?? "";
|
|
2382
|
+
const wsPath = resolveWorksheetPath(relXml, relId);
|
|
2383
|
+
const wsXml = wsPath ? readXmlEntry(entries, wsPath) ?? EMPTY_WORKSHEET_XML : EMPTY_WORKSHEET_XML;
|
|
2384
|
+
const ws = new Worksheet(name, ss, sm);
|
|
2385
|
+
if (state) ws.setVisibility(state);
|
|
2386
|
+
ws.loadFromXml(wsXml);
|
|
2387
|
+
__privateGet(wb, _sheets).push({ worksheet: ws, sheetId, relId });
|
|
2388
|
+
}
|
|
2389
|
+
return wb;
|
|
2390
|
+
}
|
|
2391
|
+
/**
|
|
2392
|
+
* Opens an existing workbook from a file path (Node.js only).
|
|
2393
|
+
* Mirrors Workbook.Open(filePath) in C#.
|
|
2394
|
+
*/
|
|
2395
|
+
static async fromFile(filePath) {
|
|
2396
|
+
const fs = await import('fs/promises');
|
|
2397
|
+
const buffer = await fs.readFile(filePath);
|
|
2398
|
+
return _Workbook.fromBuffer(buffer);
|
|
2399
|
+
}
|
|
2400
|
+
// ── Worksheet management ───────────────────────────────────────────────────
|
|
2401
|
+
/**
|
|
2402
|
+
* Collection of worksheets (read-only array view).
|
|
2403
|
+
* Access by index: workbook.worksheets[0]
|
|
2404
|
+
* Access by name: workbook.worksheets.find(s => s.name === 'Sheet1')
|
|
2405
|
+
*/
|
|
2406
|
+
get worksheets() {
|
|
2407
|
+
return __privateGet(this, _sheets).map((e) => e.worksheet);
|
|
2408
|
+
}
|
|
2409
|
+
/**
|
|
2410
|
+
* Adds a new worksheet with the given name and returns it.
|
|
2411
|
+
* Mirrors workbook.AddWorksheet(name) in C#.
|
|
2412
|
+
*/
|
|
2413
|
+
addWorksheet(name) {
|
|
2414
|
+
__privateMethod(this, _Workbook_instances, assertOpen_fn).call(this);
|
|
2415
|
+
if (!name) throw new Error("Worksheet name cannot be empty.");
|
|
2416
|
+
if (__privateGet(this, _sheets).some((e) => e.worksheet.name === name)) {
|
|
2417
|
+
throw new Error(`Worksheet "${name}" already exists.`);
|
|
2418
|
+
}
|
|
2419
|
+
const sheetId = __privateGet(this, _sheets).length + 1;
|
|
2420
|
+
const relId = `rId${sheetId}`;
|
|
2421
|
+
const ws = new Worksheet(name, __privateGet(this, _sharedStrings3), __privateGet(this, _styles3));
|
|
2422
|
+
__privateGet(this, _sheets).push({ worksheet: ws, sheetId, relId });
|
|
2423
|
+
return ws;
|
|
2424
|
+
}
|
|
2425
|
+
/**
|
|
2426
|
+
* Returns a worksheet by name. Throws if not found.
|
|
2427
|
+
*/
|
|
2428
|
+
getWorksheet(name) {
|
|
2429
|
+
const entry = __privateGet(this, _sheets).find((e) => e.worksheet.name === name);
|
|
2430
|
+
if (!entry) throw new Error(`Worksheet "${name}" not found.`);
|
|
2431
|
+
return entry.worksheet;
|
|
2432
|
+
}
|
|
2433
|
+
// ── Serialisation ──────────────────────────────────────────────────────────
|
|
2434
|
+
/**
|
|
2435
|
+
* Serialises the workbook to a Uint8Array (xlsx binary).
|
|
2436
|
+
* Mirrors workbook.SaveAs(stream) in C#.
|
|
2437
|
+
* Works in browser and Node.js.
|
|
2438
|
+
*/
|
|
2439
|
+
saveAsBuffer() {
|
|
2440
|
+
__privateMethod(this, _Workbook_instances, assertOpen_fn).call(this);
|
|
2441
|
+
const entries = __privateMethod(this, _Workbook_instances, buildZipEntries_fn).call(this);
|
|
2442
|
+
return zipXlsx(entries);
|
|
2443
|
+
}
|
|
2444
|
+
/**
|
|
2445
|
+
* Saves the workbook to a file (Node.js only).
|
|
2446
|
+
* Mirrors workbook.SaveAs(filePath) in C#.
|
|
2447
|
+
*/
|
|
2448
|
+
async saveToFile(filePath) {
|
|
2449
|
+
__privateMethod(this, _Workbook_instances, assertOpen_fn).call(this);
|
|
2450
|
+
const buffer = this.saveAsBuffer();
|
|
2451
|
+
const fs = await import('fs/promises');
|
|
2452
|
+
const path = await import('path');
|
|
2453
|
+
const dir = path.dirname(filePath);
|
|
2454
|
+
await fs.mkdir(dir, { recursive: true });
|
|
2455
|
+
await fs.writeFile(filePath, buffer);
|
|
2456
|
+
}
|
|
2457
|
+
// ── Lifecycle ──────────────────────────────────────────────────────────────
|
|
2458
|
+
/** Releases resources. The workbook should not be used after this call. */
|
|
2459
|
+
close() {
|
|
2460
|
+
__privateSet(this, _closed, true);
|
|
2461
|
+
}
|
|
2462
|
+
/** Symbol.dispose support for `using` keyword (TypeScript 5.2+). */
|
|
2463
|
+
[Symbol.dispose]() {
|
|
2464
|
+
this.close();
|
|
2465
|
+
}
|
|
2466
|
+
};
|
|
2467
|
+
_sharedStrings3 = new WeakMap();
|
|
2468
|
+
_styles3 = new WeakMap();
|
|
2469
|
+
_sheets = new WeakMap();
|
|
2470
|
+
_closed = new WeakMap();
|
|
2471
|
+
_Workbook_instances = new WeakSet();
|
|
2472
|
+
// ── Private helpers ────────────────────────────────────────────────────────
|
|
2473
|
+
assertOpen_fn = function() {
|
|
2474
|
+
if (__privateGet(this, _closed)) throw new Error("Workbook has been closed.");
|
|
2475
|
+
};
|
|
2476
|
+
buildZipEntries_fn = function() {
|
|
2477
|
+
const entries = /* @__PURE__ */ new Map();
|
|
2478
|
+
const sheetCount = __privateGet(this, _sheets).length;
|
|
2479
|
+
entries.set("_rels/.rels", ROOT_RELS);
|
|
2480
|
+
const sheetMetas = __privateGet(this, _sheets).map((e) => ({
|
|
2481
|
+
name: e.worksheet.name,
|
|
2482
|
+
sheetId: e.sheetId,
|
|
2483
|
+
relationshipId: e.relId,
|
|
2484
|
+
state: e.worksheet.visibility !== "visible" ? e.worksheet.visibility : void 0
|
|
2485
|
+
}));
|
|
2486
|
+
entries.set("xl/workbook.xml", buildWorkbookXml(sheetMetas));
|
|
2487
|
+
entries.set("xl/_rels/workbook.xml.rels", buildWorkbookRels(sheetCount));
|
|
2488
|
+
entries.set("xl/styles.xml", __privateGet(this, _styles3).buildStylesXml());
|
|
2489
|
+
entries.set("xl/sharedStrings.xml", __privateGet(this, _sharedStrings3).buildXml());
|
|
2490
|
+
for (let i = 0; i < __privateGet(this, _sheets).length; i++) {
|
|
2491
|
+
entries.set(`xl/worksheets/sheet${i + 1}.xml`, __privateGet(this, _sheets)[i].worksheet.buildXml());
|
|
2492
|
+
}
|
|
2493
|
+
const extraOverrides = [];
|
|
2494
|
+
let drawingCounter = 0;
|
|
2495
|
+
let partCounter = 0;
|
|
2496
|
+
for (let i = 0; i < __privateGet(this, _sheets).length; i++) {
|
|
2497
|
+
const ws = __privateGet(this, _sheets)[i].worksheet;
|
|
2498
|
+
if (!ws.hasDrawings) continue;
|
|
2499
|
+
drawingCounter++;
|
|
2500
|
+
const drawingPath = `xl/drawings/drawing${drawingCounter}.xml`;
|
|
2501
|
+
const anchors = [];
|
|
2502
|
+
const drawingRels = [];
|
|
2503
|
+
ws.drawingProviders.forEach((provider, idx) => {
|
|
2504
|
+
const relId = `rId${idx + 1}`;
|
|
2505
|
+
anchors.push(provider.buildAnchorXml(relId));
|
|
2506
|
+
partCounter++;
|
|
2507
|
+
const part = provider.buildPart(partCounter);
|
|
2508
|
+
entries.set(part.path, part.content);
|
|
2509
|
+
extraOverrides.push({ partName: `/${part.path}`, contentType: part.contentType });
|
|
2510
|
+
const target = `../${part.path.slice("xl/".length)}`;
|
|
2511
|
+
drawingRels.push(
|
|
2512
|
+
` <Relationship Id="${relId}" Type="${part.relType}" Target="${target}"/>`
|
|
2513
|
+
);
|
|
2514
|
+
});
|
|
2515
|
+
entries.set(drawingPath, buildDrawingXml(anchors.join("")));
|
|
2516
|
+
entries.set(`xl/drawings/_rels/drawing${drawingCounter}.xml.rels`, buildRelsXml(drawingRels));
|
|
2517
|
+
extraOverrides.push({ partName: `/${drawingPath}`, contentType: CONTENT_TYPES.drawing });
|
|
2518
|
+
entries.set(
|
|
2519
|
+
`xl/worksheets/_rels/sheet${i + 1}.xml.rels`,
|
|
2520
|
+
buildRelsXml([
|
|
2521
|
+
` <Relationship Id="${WORKSHEET_DRAWING_REL_ID}" Type="${REL_TYPES.drawing}" Target="../drawings/drawing${drawingCounter}.xml"/>`
|
|
2522
|
+
])
|
|
2523
|
+
);
|
|
2524
|
+
}
|
|
2525
|
+
entries.set("[Content_Types].xml", buildContentTypes(sheetCount, extraOverrides));
|
|
2526
|
+
return entries;
|
|
2527
|
+
};
|
|
2528
|
+
var Workbook = _Workbook;
|
|
2529
|
+
function resolveWorksheetPath(relsXml, relId) {
|
|
2530
|
+
if (!relsXml) return void 0;
|
|
2531
|
+
try {
|
|
2532
|
+
const root = parseXml(relsXml);
|
|
2533
|
+
for (const el of getElementsByTagName(root, "Relationship")) {
|
|
2534
|
+
if (getAttr(el, "Id") === relId) {
|
|
2535
|
+
const target = getAttr(el, "Target") ?? "";
|
|
2536
|
+
return target.startsWith("xl/") ? target : `xl/${target}`;
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
} catch {
|
|
2540
|
+
}
|
|
2541
|
+
return void 0;
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
exports.CONTENT_TYPES = CONTENT_TYPES;
|
|
2545
|
+
exports.Cell = Cell;
|
|
2546
|
+
exports.CellStyle = CellStyle;
|
|
2547
|
+
exports.ExcelAlignment = ExcelAlignment;
|
|
2548
|
+
exports.ExcelBorder = ExcelBorder;
|
|
2549
|
+
exports.ExcelBorderEdge = ExcelBorderEdge;
|
|
2550
|
+
exports.ExcelBorderStyle = ExcelBorderStyle;
|
|
2551
|
+
exports.ExcelColor = ExcelColor;
|
|
2552
|
+
exports.ExcelFill = ExcelFill;
|
|
2553
|
+
exports.ExcelFont = ExcelFont;
|
|
2554
|
+
exports.ExcelHorizontalAlignment = ExcelHorizontalAlignment;
|
|
2555
|
+
exports.ExcelNumberFormat = ExcelNumberFormat;
|
|
2556
|
+
exports.ExcelPatternType = ExcelPatternType;
|
|
2557
|
+
exports.ExcelReadingOrder = ExcelReadingOrder;
|
|
2558
|
+
exports.ExcelUnderline = ExcelUnderline;
|
|
2559
|
+
exports.ExcelVerticalAlignRun = ExcelVerticalAlignRun;
|
|
2560
|
+
exports.ExcelVerticalAlignment = ExcelVerticalAlignment;
|
|
2561
|
+
exports.NS = NS;
|
|
2562
|
+
exports.REL_TYPES = REL_TYPES;
|
|
2563
|
+
exports.Range = Range;
|
|
2564
|
+
exports.StyleManager = StyleManager;
|
|
2565
|
+
exports.WORKSHEET_DRAWING_REL_ID = WORKSHEET_DRAWING_REL_ID;
|
|
2566
|
+
exports.Workbook = Workbook;
|
|
2567
|
+
exports.Worksheet = Worksheet;
|
|
2568
|
+
exports.XmlBuilder = XmlBuilder;
|
|
2569
|
+
exports.buildDrawingXml = buildDrawingXml;
|
|
2570
|
+
exports.buildRelsXml = buildRelsXml;
|
|
2571
|
+
exports.cellRefFromRowCol = cellRefFromRowCol;
|
|
2572
|
+
exports.columnLetter = columnLetter;
|
|
2573
|
+
exports.columnNumber = columnNumber;
|
|
2574
|
+
exports.decodeUtf8 = decodeUtf8;
|
|
2575
|
+
exports.encodeUtf8 = encodeUtf8;
|
|
2576
|
+
exports.escapeXml = escapeXml;
|
|
2577
|
+
exports.fromOADate = fromOADate;
|
|
2578
|
+
exports.getAttr = getAttr;
|
|
2579
|
+
exports.getElementsByTagName = getElementsByTagName;
|
|
2580
|
+
exports.isDateFormatCode = isDateFormatCode;
|
|
2581
|
+
exports.isDateFormatId = isDateFormatId;
|
|
2582
|
+
exports.listEntries = listEntries;
|
|
2583
|
+
exports.parseCellRef = parseCellRef;
|
|
2584
|
+
exports.parseRangeRef = parseRangeRef;
|
|
2585
|
+
exports.parseXml = parseXml;
|
|
2586
|
+
exports.readXmlEntry = readXmlEntry;
|
|
2587
|
+
exports.requireXmlEntry = requireXmlEntry;
|
|
2588
|
+
exports.setBinaryEntry = setBinaryEntry;
|
|
2589
|
+
exports.setXmlEntry = setXmlEntry;
|
|
2590
|
+
exports.toOADate = toOADate;
|
|
2591
|
+
exports.unzipXlsx = unzipXlsx;
|
|
2592
|
+
exports.xml = xml;
|
|
2593
|
+
exports.zipXlsx = zipXlsx;
|
|
2594
|
+
//# sourceMappingURL=index.cjs.map
|
|
2595
|
+
//# sourceMappingURL=index.cjs.map
|