@office-open/xlsx 0.6.4 → 0.6.6

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/dist/index.js ADDED
@@ -0,0 +1,1628 @@
1
+ import { AppProperties, BaseXmlComponent, ChartCollection, ChartSpace, Formatter, IgnoreIfEmptyXmlComponent, OoxmlMimeType, Relationships, buildCorePropertiesXml, compileMapping, createPacker, parseArchive, parseCorePropsElement, strFromU8, toJson, unzipSync, zipAndConvert } from "@office-open/core";
2
+ import { attr, attrNum, attrs, escapeXml, findChild, js2xml, selfCloseElement, textOf } from "@office-open/xml";
3
+ import { toUint8Array } from "undio";
4
+ //#region src/file/content-types.ts
5
+ /**
6
+ * Content Types module for XLSX packages.
7
+ *
8
+ * @module
9
+ */
10
+ const XLSX_MAIN = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
11
+ const XLSX_WORKSHEET = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml";
12
+ const XLSX_STYLES = "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml";
13
+ const XLSX_SHARED_STRINGS = "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml";
14
+ const XLSX_THEME = "application/vnd.openxmlformats-officedocument.theme+xml";
15
+ const XLSX_CHART = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml";
16
+ const STATIC_CHILDREN = [{ _attr: { xmlns: "http://schemas.openxmlformats.org/package/2006/content-types" } }, ...[
17
+ {
18
+ type: "Default",
19
+ contentType: "application/vnd.openxmlformats-package.relationships+xml",
20
+ key: "rels"
21
+ },
22
+ {
23
+ type: "Default",
24
+ contentType: "application/xml",
25
+ key: "xml"
26
+ },
27
+ {
28
+ type: "Default",
29
+ contentType: "image/png",
30
+ key: "png"
31
+ },
32
+ {
33
+ type: "Default",
34
+ contentType: "image/jpeg",
35
+ key: "jpeg"
36
+ },
37
+ {
38
+ type: "Override",
39
+ contentType: XLSX_MAIN,
40
+ key: "/xl/workbook.xml"
41
+ },
42
+ {
43
+ type: "Override",
44
+ contentType: "application/vnd.openxmlformats-package.core-properties+xml",
45
+ key: "/docProps/core.xml"
46
+ },
47
+ {
48
+ type: "Override",
49
+ contentType: "application/vnd.openxmlformats-officedocument.extended-properties+xml",
50
+ key: "/docProps/app.xml"
51
+ }
52
+ ].map((e) => {
53
+ if (e.type === "Default") return { Default: { _attr: {
54
+ ContentType: e.contentType,
55
+ Extension: e.key
56
+ } } };
57
+ return { Override: { _attr: {
58
+ ContentType: e.contentType,
59
+ PartName: e.key
60
+ } } };
61
+ })];
62
+ var ContentTypes = class extends BaseXmlComponent {
63
+ dynamicEntries = [];
64
+ constructor() {
65
+ super("Types");
66
+ }
67
+ addWorksheet(index) {
68
+ this.dynamicEntries.push({
69
+ type: "Override",
70
+ contentType: XLSX_WORKSHEET,
71
+ key: `/xl/worksheets/sheet${index}.xml`
72
+ });
73
+ }
74
+ addStyles() {
75
+ this.dynamicEntries.push({
76
+ type: "Override",
77
+ contentType: XLSX_STYLES,
78
+ key: "/xl/styles.xml"
79
+ });
80
+ }
81
+ addSharedStrings() {
82
+ this.dynamicEntries.push({
83
+ type: "Override",
84
+ contentType: XLSX_SHARED_STRINGS,
85
+ key: "/xl/sharedStrings.xml"
86
+ });
87
+ }
88
+ addTheme(index = 1) {
89
+ this.dynamicEntries.push({
90
+ type: "Override",
91
+ contentType: XLSX_THEME,
92
+ key: `/xl/theme/theme${index}.xml`
93
+ });
94
+ }
95
+ addChart(index) {
96
+ this.dynamicEntries.push({
97
+ type: "Override",
98
+ contentType: XLSX_CHART,
99
+ key: `/xl/charts/chart${index}.xml`
100
+ });
101
+ }
102
+ addDrawing(index) {
103
+ this.dynamicEntries.push({
104
+ type: "Override",
105
+ contentType: "application/vnd.openxmlformats-officedocument.drawing+xml",
106
+ key: `/xl/drawings/drawing${index}.xml`
107
+ });
108
+ }
109
+ prepForXml(_context) {
110
+ const children = [...STATIC_CHILDREN];
111
+ for (const e of this.dynamicEntries) if (e.type === "Default") children.push({ Default: { _attr: {
112
+ ContentType: e.contentType,
113
+ Extension: e.key
114
+ } } });
115
+ else children.push({ Override: { _attr: {
116
+ ContentType: e.contentType,
117
+ PartName: e.key
118
+ } } });
119
+ return { Types: children };
120
+ }
121
+ };
122
+ //#endregion
123
+ //#region src/file/core-properties.ts
124
+ /**
125
+ * Core Properties module for SpreadsheetML documents.
126
+ *
127
+ * @module
128
+ */
129
+ var CoreProperties = class extends BaseXmlComponent {
130
+ options;
131
+ constructor(options) {
132
+ super("cp:coreProperties");
133
+ this.options = options;
134
+ }
135
+ prepForXml(_context) {
136
+ return buildCorePropertiesXml(this.options);
137
+ }
138
+ };
139
+ //#endregion
140
+ //#region src/file/media/media.ts
141
+ var Media = class {
142
+ map = /* @__PURE__ */ new Map();
143
+ addImage(key, data) {
144
+ this.map.set(key, data);
145
+ }
146
+ get array() {
147
+ return [...this.map.values()];
148
+ }
149
+ };
150
+ //#endregion
151
+ //#region src/file/shared-strings.ts
152
+ /**
153
+ * Shared Strings Table — generates xl/sharedStrings.xml.
154
+ *
155
+ * XLSX stores repeated string values in a central table to reduce file size.
156
+ * Cells reference strings by index into this table.
157
+ *
158
+ * @module
159
+ */
160
+ var SharedStrings = class extends BaseXmlComponent {
161
+ strings = [];
162
+ indexMap = /* @__PURE__ */ new Map();
163
+ constructor() {
164
+ super("sst");
165
+ }
166
+ /**
167
+ * Register a string and return its index.
168
+ * Returns existing index if the string is already registered.
169
+ */
170
+ register(s) {
171
+ const existing = this.indexMap.get(s);
172
+ if (existing !== void 0) return existing;
173
+ const idx = this.strings.length;
174
+ this.strings.push(s);
175
+ this.indexMap.set(s, idx);
176
+ return idx;
177
+ }
178
+ get count() {
179
+ return this.strings.length;
180
+ }
181
+ /**
182
+ * Zero-allocation fast path: directly concatenate XML string.
183
+ * Bypasses the IXmlableObject intermediate tree entirely.
184
+ */
185
+ toXml(_context) {
186
+ const p = ["<sst xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"", ` count="${this.strings.length}" uniqueCount="${this.indexMap.size}">`];
187
+ for (const s of this.strings) p.push(`<si><t>${escapeXml(s)}</t></si>`);
188
+ p.push("</sst>");
189
+ return p.join("");
190
+ }
191
+ prepForXml(_context) {
192
+ const children = [{ _attr: {
193
+ xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
194
+ count: this.strings.length,
195
+ uniqueCount: this.indexMap.size
196
+ } }];
197
+ for (const s of this.strings) children.push({ si: [{ t: [s] }] });
198
+ return { sst: children };
199
+ }
200
+ };
201
+ //#endregion
202
+ //#region src/file/styles.ts
203
+ /**
204
+ * Styles component — generates xl/styles.xml.
205
+ *
206
+ * XLSX uses an index-based style system: cells reference style entries
207
+ * via the `s` attribute, which is an index into `cellXfs`.
208
+ *
209
+ * @module
210
+ */
211
+ function fontKey(f) {
212
+ return `b${f.bold ? 1 : 0}i${f.italic ? 1 : 0}u${f.underline ? 1 : 0}s${f.strike ? 1 : 0}z${f.size ?? 0}c${f.color ?? ""}n${f.fontName ?? ""}`;
213
+ }
214
+ function fillKey(f) {
215
+ return `t${f.type ?? ""}c${f.color ?? ""}p${f.patternType ?? ""}`;
216
+ }
217
+ function borderKey(b) {
218
+ const sk = (o) => `${o?.style ?? ""}_${o?.color ?? ""}`;
219
+ return `t${sk(b.top)}b${sk(b.bottom)}l${sk(b.left)}r${sk(b.right)}d${sk(b.diagonal)}`;
220
+ }
221
+ const BUILTIN_NUMFMTS = {
222
+ General: 0,
223
+ "0": 1,
224
+ "0.00": 2,
225
+ "#,##0": 3,
226
+ "#,##0.00": 4,
227
+ "0%": 9,
228
+ "0.00%": 10,
229
+ "0.00E+00": 11,
230
+ "mm-dd-yy": 14,
231
+ "d-mmm-yy": 15,
232
+ "d-mmm": 16,
233
+ "mmm-yy": 17,
234
+ "h:mm AM/PM": 18,
235
+ "h:mm:ss AM/PM": 19,
236
+ "h:mm": 20,
237
+ "h:mm:ss": 21,
238
+ "m/d/yy h:mm": 22,
239
+ "#,##0 ;(#,##0)": 37,
240
+ "#,##0 ;[Red](#,##0)": 38,
241
+ "#,##0.00;(#,##0.00)": 39,
242
+ "#,##0.00;[Red](#,##0.00)": 40,
243
+ "mm:ss": 45,
244
+ "[h]:mm:ss": 46,
245
+ "mmss.0": 47,
246
+ "##0.0E+0": 48,
247
+ "@": 49
248
+ };
249
+ var Styles = class extends BaseXmlComponent {
250
+ fonts = [{
251
+ size: 11,
252
+ fontName: "Calibri"
253
+ }];
254
+ fontKeys = /* @__PURE__ */ new Map();
255
+ fills = [{ patternType: "none" }, { patternType: "gray125" }];
256
+ fillKeys = /* @__PURE__ */ new Map();
257
+ borders = [{}];
258
+ borderKeys = /* @__PURE__ */ new Map();
259
+ customNumFmts = /* @__PURE__ */ new Map();
260
+ nextCustomNumFmtId = 164;
261
+ cellXfs = [{
262
+ fontId: 0,
263
+ fillId: 0,
264
+ borderId: 0,
265
+ numFmtId: 0
266
+ }];
267
+ cellXfKeys = /* @__PURE__ */ new Map();
268
+ constructor() {
269
+ super("styleSheet");
270
+ this.fontKeys.set(fontKey(this.fonts[0]), 0);
271
+ this.fillKeys.set(fillKey(this.fills[0]), 0);
272
+ this.fillKeys.set(fillKey(this.fills[1]), 1);
273
+ this.borderKeys.set(borderKey(this.borders[0]), 0);
274
+ this.cellXfKeys.set(this.cellXfKey(this.cellXfs[0]), 0);
275
+ }
276
+ /**
277
+ * Register a style and return its index (for the cell `s` attribute).
278
+ * Deduplicates across fonts, fills, borders, numFmts, and cellXfs.
279
+ */
280
+ register(opts) {
281
+ const xf = {
282
+ fontId: this.registerFont(opts.font),
283
+ fillId: this.registerFill(opts.fill),
284
+ borderId: this.registerBorder(opts.border),
285
+ numFmtId: this.registerNumFmt(opts.numFmt),
286
+ alignment: opts.alignment
287
+ };
288
+ const key = this.cellXfKey(xf);
289
+ const existing = this.cellXfKeys.get(key);
290
+ if (existing !== void 0) return existing;
291
+ const idx = this.cellXfs.length;
292
+ this.cellXfs.push(xf);
293
+ this.cellXfKeys.set(key, idx);
294
+ return idx;
295
+ }
296
+ registerFont(opts) {
297
+ if (!opts) return 0;
298
+ const key = fontKey(opts);
299
+ const existing = this.fontKeys.get(key);
300
+ if (existing !== void 0) return existing;
301
+ const idx = this.fonts.length;
302
+ this.fonts.push(opts);
303
+ this.fontKeys.set(key, idx);
304
+ return idx;
305
+ }
306
+ registerFill(opts) {
307
+ if (!opts) return 0;
308
+ const key = fillKey(opts);
309
+ const existing = this.fillKeys.get(key);
310
+ if (existing !== void 0) return existing;
311
+ const idx = this.fills.length;
312
+ this.fills.push(opts);
313
+ this.fillKeys.set(key, idx);
314
+ return idx;
315
+ }
316
+ registerBorder(opts) {
317
+ if (!opts) return 0;
318
+ const key = borderKey(opts);
319
+ const existing = this.borderKeys.get(key);
320
+ if (existing !== void 0) return existing;
321
+ const idx = this.borders.length;
322
+ this.borders.push(opts);
323
+ this.borderKeys.set(key, idx);
324
+ return idx;
325
+ }
326
+ registerNumFmt(fmt) {
327
+ if (!fmt) return 0;
328
+ const builtin = BUILTIN_NUMFMTS[fmt];
329
+ if (builtin !== void 0) return builtin;
330
+ const existing = this.customNumFmts.get(fmt);
331
+ if (existing !== void 0) return existing;
332
+ const id = this.nextCustomNumFmtId++;
333
+ this.customNumFmts.set(fmt, id);
334
+ return id;
335
+ }
336
+ cellXfKey(xf) {
337
+ const a = xf.alignment;
338
+ const ak = a ? `h${a.horizontal ?? ""}v${a.vertical ?? ""}w${a.wrapText ? 1 : 0}r${a.textRotation ?? ""}i${a.indent ?? ""}` : "";
339
+ return `${xf.fontId}|${xf.fillId}|${xf.borderId}|${xf.numFmtId}|${ak}`;
340
+ }
341
+ /**
342
+ * Zero-allocation fast path: directly concatenate XML string.
343
+ * Bypasses the IXmlableObject intermediate tree entirely.
344
+ */
345
+ toXml(_context) {
346
+ const p = ["<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">"];
347
+ if (this.customNumFmts.size > 0) {
348
+ p.push(`<numFmts count="${this.customNumFmts.size}">`);
349
+ for (const [fmt, id] of this.customNumFmts) p.push(`<numFmt numFmtId="${id}" formatCode="${escapeXml(fmt)}"/>`);
350
+ p.push("</numFmts>");
351
+ }
352
+ p.push(`<fonts count="${this.fonts.length}">`);
353
+ for (const f of this.fonts) p.push(`<font>${this.fontXmlStr(f)}</font>`);
354
+ p.push("</fonts>");
355
+ p.push(`<fills count="${this.fills.length}">`);
356
+ for (const f of this.fills) {
357
+ const patternAttrs = attrs({ patternType: f.patternType ?? "solid" });
358
+ const fgColor = f.color ? `<fgColor rgb="FF${f.color}"/>` : "";
359
+ p.push(`<fill><patternFill${patternAttrs}>${fgColor}</patternFill></fill>`);
360
+ }
361
+ p.push("</fills>");
362
+ p.push(`<borders count="${this.borders.length}">`);
363
+ for (const b of this.borders) p.push(`<border>${this.borderXmlStr(b)}</border>`);
364
+ p.push("</borders>");
365
+ p.push("<cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\"/></cellStyleXfs>");
366
+ p.push(`<cellXfs count="${this.cellXfs.length}">`);
367
+ for (const xf of this.cellXfs) {
368
+ const xAttrs = {
369
+ numFmtId: xf.numFmtId,
370
+ fontId: xf.fontId,
371
+ fillId: xf.fillId,
372
+ borderId: xf.borderId
373
+ };
374
+ if (xf.alignment) xAttrs.applyAlignment = 1;
375
+ if (xf.fontId > 0) xAttrs.applyFont = 1;
376
+ if (xf.fillId > 0) xAttrs.applyFill = 1;
377
+ if (xf.borderId > 0) xAttrs.applyBorder = 1;
378
+ const alignStr = xf.alignment ? this.alignmentXmlStr(xf.alignment) : "";
379
+ p.push(`<xf${attrs(xAttrs)}>${alignStr}</xf>`);
380
+ }
381
+ p.push("</cellXfs>");
382
+ p.push("<cellStyles count=\"1\"><cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\"/></cellStyles>");
383
+ p.push("</styleSheet>");
384
+ return p.join("");
385
+ }
386
+ fontXmlStr(f) {
387
+ const parts = [];
388
+ if (f.bold) parts.push("<b/>");
389
+ if (f.italic) parts.push("<i/>");
390
+ if (f.underline) parts.push("<u/>");
391
+ if (f.strike) parts.push("<strike/>");
392
+ if (f.size) parts.push(`<sz val="${f.size}"/>`);
393
+ if (f.color) parts.push(`<color rgb="FF${f.color}"/>`);
394
+ if (f.fontName) parts.push(`<name val="${escapeXml(f.fontName)}"/>`);
395
+ return parts.join("");
396
+ }
397
+ borderXmlStr(b) {
398
+ const parts = [];
399
+ for (const side of [
400
+ "left",
401
+ "right",
402
+ "top",
403
+ "bottom",
404
+ "diagonal"
405
+ ]) {
406
+ const opts = b[side];
407
+ if (opts && opts.style && opts.style !== "none") {
408
+ const colorStr = opts.color ? `<color rgb="FF${opts.color}"/>` : "";
409
+ parts.push(`<${side} style="${opts.style}">${colorStr}</${side}>`);
410
+ } else parts.push(`<${side}/>`);
411
+ }
412
+ return parts.join("");
413
+ }
414
+ alignmentXmlStr(a) {
415
+ const aAttrs = {};
416
+ if (a.horizontal) aAttrs.horizontal = a.horizontal;
417
+ if (a.vertical) aAttrs.vertical = a.vertical;
418
+ if (a.wrapText) aAttrs.wrapText = 1;
419
+ if (a.textRotation !== void 0) aAttrs.textRotation = a.textRotation;
420
+ if (a.indent !== void 0) aAttrs.indent = a.indent;
421
+ return `<alignment${attrs(aAttrs)}/>`;
422
+ }
423
+ prepForXml(_context) {
424
+ const children = [{ _attr: { xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main" } }];
425
+ if (this.customNumFmts.size > 0) {
426
+ const fmtElements = [{ _attr: { count: this.customNumFmts.size } }];
427
+ for (const [fmt, id] of this.customNumFmts) fmtElements.push({ numFmt: { _attr: {
428
+ numFmtId: id,
429
+ formatCode: fmt
430
+ } } });
431
+ children.push({ numFmts: fmtElements });
432
+ }
433
+ children.push(this.buildFonts());
434
+ children.push(this.buildFills());
435
+ children.push(this.buildBorders());
436
+ children.push({ cellStyleXfs: [{ _attr: { count: 1 } }, { xf: [{ _attr: {
437
+ numFmtId: 0,
438
+ fontId: 0,
439
+ fillId: 0,
440
+ borderId: 0
441
+ } }] }] });
442
+ children.push(this.buildCellXfs());
443
+ children.push({ cellStyles: [{ _attr: { count: 1 } }, { cellStyle: [{ _attr: {
444
+ name: "Normal",
445
+ xfId: 0,
446
+ builtinId: 0
447
+ } }] }] });
448
+ return { styleSheet: children };
449
+ }
450
+ buildFonts() {
451
+ const elements = [{ _attr: { count: this.fonts.length } }];
452
+ for (const f of this.fonts) elements.push({ font: this.fontXml(f) });
453
+ return { fonts: elements };
454
+ }
455
+ fontXml(f) {
456
+ const parts = [];
457
+ if (f.bold) parts.push({ b: [] });
458
+ if (f.italic) parts.push({ i: [] });
459
+ if (f.underline) parts.push({ u: [] });
460
+ if (f.strike) parts.push({ strike: [] });
461
+ if (f.size) parts.push({ sz: [{ _attr: { val: f.size } }] });
462
+ if (f.color) parts.push({ color: [{ _attr: { rgb: `FF${f.color}` } }] });
463
+ if (f.fontName) parts.push({ name: [{ _attr: { val: f.fontName } }] });
464
+ return parts;
465
+ }
466
+ buildFills() {
467
+ const elements = [{ _attr: { count: this.fills.length } }];
468
+ for (const f of this.fills) elements.push({ fill: [{ patternFill: [{ _attr: { patternType: f.patternType ?? "solid" } }, ...f.color ? [{ fgColor: [{ _attr: { rgb: `FF${f.color}` } }] }] : []] }] });
469
+ return { fills: elements };
470
+ }
471
+ buildBorders() {
472
+ const elements = [{ _attr: { count: this.borders.length } }];
473
+ for (const b of this.borders) elements.push({ border: this.borderXml(b) });
474
+ return { borders: elements };
475
+ }
476
+ borderXml(b) {
477
+ const parts = [];
478
+ for (const side of [
479
+ "left",
480
+ "right",
481
+ "top",
482
+ "bottom",
483
+ "diagonal"
484
+ ]) {
485
+ const opts = b[side];
486
+ if (opts && opts.style && opts.style !== "none") {
487
+ const children = [{ _attr: { style: opts.style } }];
488
+ if (opts.color) children.push({ color: [{ _attr: { rgb: `FF${opts.color}` } }] });
489
+ parts.push({ [side]: children });
490
+ } else parts.push({ [side]: [] });
491
+ }
492
+ return parts;
493
+ }
494
+ buildCellXfs() {
495
+ const elements = [{ _attr: { count: this.cellXfs.length } }];
496
+ for (const xf of this.cellXfs) {
497
+ const attrs = {
498
+ numFmtId: xf.numFmtId,
499
+ fontId: xf.fontId,
500
+ fillId: xf.fillId,
501
+ borderId: xf.borderId
502
+ };
503
+ if (xf.alignment) attrs.applyAlignment = 1;
504
+ if (xf.fontId > 0) attrs.applyFont = 1;
505
+ if (xf.fillId > 0) attrs.applyFill = 1;
506
+ if (xf.borderId > 0) attrs.applyBorder = 1;
507
+ const children = [{ _attr: attrs }];
508
+ if (xf.alignment) children.push(this.alignmentXml(xf.alignment));
509
+ elements.push({ xf: children });
510
+ }
511
+ return { cellXfs: elements };
512
+ }
513
+ alignmentXml(a) {
514
+ const attrs = {};
515
+ if (a.horizontal) attrs.horizontal = a.horizontal;
516
+ if (a.vertical) attrs.vertical = a.vertical;
517
+ if (a.wrapText) attrs.wrapText = 1;
518
+ if (a.textRotation !== void 0) attrs.textRotation = a.textRotation;
519
+ if (a.indent !== void 0) attrs.indent = a.indent;
520
+ return { alignment: [{ _attr: attrs }] };
521
+ }
522
+ };
523
+ //#endregion
524
+ //#region src/file/theme.ts
525
+ /**
526
+ * Default theme for XLSX files — matches Microsoft Office's output structure.
527
+ * Produces xl/theme/theme1.xml that Excel accepts without repair warnings.
528
+ *
529
+ * The theme XML is completely static — identical for every XLSX file.
530
+ * Pre-serialized as a string constant to avoid building the IXmlableObject
531
+ * tree and re-serializing on every compile.
532
+ *
533
+ * @module
534
+ */
535
+ const THEME_XML = "<a:theme xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" name=\"Office Theme\"><a:themeElements><a:clrScheme name=\"Office\"><a:dk1><a:sysClr val=\"windowText\" lastClr=\"000000\"/></a:dk1><a:lt1><a:sysClr val=\"window\" lastClr=\"FFFFFF\"/></a:lt1><a:dk2><a:srgbClr val=\"44546A\"/></a:dk2><a:lt2><a:srgbClr val=\"E7E6E6\"/></a:lt2><a:accent1><a:srgbClr val=\"5B9BD5\"/></a:accent1><a:accent2><a:srgbClr val=\"ED7D31\"/></a:accent2><a:accent3><a:srgbClr val=\"A5A5A5\"/></a:accent3><a:accent4><a:srgbClr val=\"FFC000\"/></a:accent4><a:accent5><a:srgbClr val=\"4472C4\"/></a:accent5><a:accent6><a:srgbClr val=\"70AD47\"/></a:accent6><a:hlink><a:srgbClr val=\"0563C1\"/></a:hlink><a:folHlink><a:srgbClr val=\"954F72\"/></a:folHlink></a:clrScheme><a:fontScheme name=\"Office\"><a:majorFont><a:latin typeface=\"Calibri Light\" panose=\"020F0302020204030204\"/><a:ea typeface=\"\"/><a:cs typeface=\"\"/></a:majorFont><a:minorFont><a:latin typeface=\"Calibri\" panose=\"020F0502020204030204\"/><a:ea typeface=\"\"/><a:cs typeface=\"\"/></a:minorFont></a:fontScheme><a:fmtScheme name=\"Office\"><a:fillStyleLst><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:gradFill rotWithShape=\"1\"><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"110000\"/><a:satMod val=\"105000\"/><a:tint val=\"67000\"/></a:schemeClr></a:gs><a:gs pos=\"50000\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"105000\"/><a:satMod val=\"103000\"/><a:tint val=\"73000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"105000\"/><a:satMod val=\"109000\"/><a:tint val=\"81000\"/></a:schemeClr></a:gs></a:gsLst><a:lin ang=\"5400000\" scaled=\"0\"/></a:gradFill><a:gradFill rotWithShape=\"1\"><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"102000\"/><a:satMod val=\"103000\"/><a:tint val=\"94000\"/></a:schemeClr></a:gs><a:gs pos=\"50000\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"100000\"/><a:satMod val=\"110000\"/><a:shade val=\"100000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"99000\"/><a:satMod val=\"120000\"/><a:shade val=\"78000\"/></a:schemeClr></a:gs></a:gsLst><a:lin ang=\"5400000\" scaled=\"0\"/></a:gradFill></a:fillStyleLst><a:lnStyleLst><a:ln w=\"6350\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:prstDash val=\"solid\"/><a:miter lim=\"800000\"/></a:ln><a:ln w=\"12700\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:prstDash val=\"solid\"/><a:miter lim=\"800000\"/></a:ln><a:ln w=\"19050\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:prstDash val=\"solid\"/><a:miter lim=\"800000\"/></a:ln></a:lnStyleLst><a:effectStyleLst><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad=\"57150\" dist=\"19050\" dir=\"5400000\" algn=\"ctr\" rotWithShape=\"0\"><a:srgbClr val=\"000000\"><a:alpha val=\"63000\"/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle></a:effectStyleLst><a:bgFillStyleLst><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:solidFill><a:schemeClr val=\"phClr\"><a:tint val=\"95000\"/><a:satMod val=\"170000\"/></a:schemeClr></a:solidFill><a:gradFill rotWithShape=\"1\"><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"102000\"/><a:satMod val=\"150000\"/><a:tint val=\"93000\"/><a:shade val=\"98000\"/></a:schemeClr></a:gs><a:gs pos=\"50000\"><a:schemeClr val=\"phClr\"><a:lumMod val=\"103000\"/><a:satMod val=\"130000\"/><a:tint val=\"98000\"/><a:shade val=\"90000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:satMod val=\"120000\"/><a:shade val=\"63000\"/></a:schemeClr></a:gs></a:gsLst><a:lin ang=\"5400000\" scaled=\"0\"/></a:gradFill></a:bgFillStyleLst></a:fmtScheme></a:themeElements><a:objectDefaults/><a:extraClrSchemeLst/></a:theme>";
536
+ var DefaultTheme = class extends BaseXmlComponent {
537
+ constructor() {
538
+ super("a:theme");
539
+ }
540
+ /** Return pre-cached static theme XML — zero allocation. */
541
+ toXml(_context) {
542
+ return THEME_XML;
543
+ }
544
+ prepForXml(_context) {
545
+ return { "a:theme": [{ _attr: {
546
+ "xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
547
+ name: "Office Theme"
548
+ } }] };
549
+ }
550
+ };
551
+ //#endregion
552
+ //#region src/file/workbook.ts
553
+ /**
554
+ * Workbook component — generates xl/workbook.xml.
555
+ *
556
+ * @module
557
+ */
558
+ var WorkbookXml = class extends BaseXmlComponent {
559
+ sheets;
560
+ constructor(sheets) {
561
+ super("workbook");
562
+ this.sheets = sheets;
563
+ }
564
+ prepForXml(_context) {
565
+ const sheetElements = [];
566
+ for (const s of this.sheets) {
567
+ const attrs = {
568
+ name: s.name,
569
+ sheetId: String(s.sheetId),
570
+ "r:id": s.rId
571
+ };
572
+ if (s.state && s.state !== "visible") attrs.state = s.state;
573
+ sheetElements.push({ sheet: { _attr: attrs } });
574
+ }
575
+ return { workbook: [{ _attr: {
576
+ xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
577
+ "xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
578
+ } }, { sheets: sheetElements }] };
579
+ }
580
+ };
581
+ //#endregion
582
+ //#region src/file/worksheet.ts
583
+ /**
584
+ * Worksheet component — generates xl/worksheets/sheet{n}.xml.
585
+ *
586
+ * @module
587
+ */
588
+ var Worksheet = class extends IgnoreIfEmptyXmlComponent {
589
+ rows;
590
+ columns;
591
+ mergeCells;
592
+ freezePanes;
593
+ autoFilter;
594
+ images;
595
+ chartOptions;
596
+ dataValidations;
597
+ conditionalFormats;
598
+ constructor(options) {
599
+ super("worksheet");
600
+ this.rows = options.children ?? [];
601
+ this.columns = options.columns ?? [];
602
+ this.mergeCells = options.mergeCells ?? [];
603
+ this.freezePanes = options.freezePanes;
604
+ this.autoFilter = options.autoFilter;
605
+ this.images = options.images ?? [];
606
+ this.chartOptions = options.charts ?? [];
607
+ this.dataValidations = options.dataValidations ?? [];
608
+ this.conditionalFormats = options.conditionalFormats ?? [];
609
+ }
610
+ get imageOptions() {
611
+ return this.images;
612
+ }
613
+ get charts() {
614
+ return this.chartOptions;
615
+ }
616
+ prepForXml(context) {
617
+ const fileData = context.fileData;
618
+ const sharedStrings = fileData?.sharedStrings;
619
+ const styles = fileData?.styles;
620
+ const children = [{ _attr: {
621
+ xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
622
+ "xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
623
+ } }];
624
+ if (this.freezePanes) {
625
+ const fp = this.freezePanes;
626
+ const ySplit = fp.row ? fp.row : 0;
627
+ const xSplit = fp.col ? fp.col : 0;
628
+ const topRow = fp.row ? fp.row + 1 : 1;
629
+ const leftCol = fp.col ? fp.col + 1 : 1;
630
+ const attr = {
631
+ ySplit,
632
+ xSplit,
633
+ topLeftCell: this.defaultCellRef(topRow, leftCol),
634
+ activePane: ySplit > 0 && xSplit > 0 ? "bottomRight" : ySplit > 0 ? "bottomLeft" : "topRight",
635
+ state: "frozen"
636
+ };
637
+ children.push({ sheetViews: [{ sheetView: [{ _attr: {
638
+ tabSelected: 1,
639
+ workbookViewId: 0
640
+ } }, { pane: { _attr: attr } }] }] });
641
+ }
642
+ if (this.columns.length > 0) {
643
+ const colElements = [];
644
+ for (const col of this.columns) {
645
+ const colAttrs = {
646
+ min: col.min,
647
+ max: col.max
648
+ };
649
+ if (col.width !== void 0) {
650
+ colAttrs.width = col.width;
651
+ colAttrs.customWidth = 1;
652
+ }
653
+ if (col.hidden) colAttrs.hidden = 1;
654
+ colElements.push({ col: { _attr: colAttrs } });
655
+ }
656
+ children.push({ cols: colElements });
657
+ }
658
+ const sheetDataChildren = [];
659
+ for (let i = 0; i < this.rows.length; i++) {
660
+ const rowOpts = this.rows[i];
661
+ const rowNumber = rowOpts.rowNumber ?? i + 1;
662
+ const rowAttrs = { r: rowNumber };
663
+ if (rowOpts.height !== void 0) {
664
+ rowAttrs.ht = rowOpts.height;
665
+ rowAttrs.customHeight = 1;
666
+ }
667
+ if (rowOpts.hidden) rowAttrs.hidden = 1;
668
+ const cellElements = [];
669
+ if (rowOpts.cells) for (let j = 0; j < rowOpts.cells.length; j++) {
670
+ const cell = rowOpts.cells[j];
671
+ const ref = cell.reference ?? this.defaultCellRef(rowNumber, j + 1);
672
+ const cellObj = this.buildCell(ref, cell, sharedStrings, styles);
673
+ if (cellObj) cellElements.push(cellObj);
674
+ }
675
+ sheetDataChildren.push({ row: [{ _attr: rowAttrs }, ...cellElements] });
676
+ }
677
+ children.push({ sheetData: sheetDataChildren });
678
+ if (this.autoFilter) children.push({ autoFilter: { _attr: { ref: this.autoFilter } } });
679
+ if (this.mergeCells.length > 0) {
680
+ const mergeElements = [{ _attr: { count: this.mergeCells.length } }];
681
+ for (const mc of this.mergeCells) {
682
+ const fromRef = this.defaultCellRef(mc.from.row, mc.from.col);
683
+ const toRef = this.defaultCellRef(mc.to.row, mc.to.col);
684
+ mergeElements.push({ mergeCell: { _attr: { ref: `${fromRef}:${toRef}` } } });
685
+ }
686
+ children.push({ mergeCells: mergeElements });
687
+ }
688
+ if (this.conditionalFormats.length > 0) for (const cf of this.conditionalFormats) {
689
+ const rules = [];
690
+ for (let ri = 0; ri < cf.rules.length; ri++) {
691
+ const rule = cf.rules[ri];
692
+ const ruleAttrs = {
693
+ type: rule.type,
694
+ priority: rule.priority ?? ri + 1
695
+ };
696
+ if (rule.operator) ruleAttrs.operator = rule.operator;
697
+ if (rule.dxfId !== void 0) ruleAttrs.dxfId = rule.dxfId;
698
+ const ruleChildren = [{ _attr: ruleAttrs }];
699
+ if (rule.formulas) for (const f of rule.formulas) ruleChildren.push({ formula: [f] });
700
+ rules.push({ cfRule: ruleChildren });
701
+ }
702
+ children.push({ conditionalFormatting: [{ _attr: { sqref: cf.sqref } }, ...rules] });
703
+ }
704
+ if (this.dataValidations.length > 0) {
705
+ const dvElements = [{ _attr: { count: this.dataValidations.length } }];
706
+ for (const dv of this.dataValidations) {
707
+ const dvAttrs = { sqref: dv.sqref };
708
+ if (dv.type && dv.type !== "none") dvAttrs.type = dv.type;
709
+ if (dv.operator) dvAttrs.operator = dv.operator;
710
+ if (dv.allowBlank) dvAttrs.allowBlank = 1;
711
+ if (dv.showErrorMessage) dvAttrs.showErrorMessage = 1;
712
+ if (dv.showInputMessage) dvAttrs.showInputMessage = 1;
713
+ if (dv.errorTitle) dvAttrs.errorTitle = dv.errorTitle;
714
+ if (dv.error) dvAttrs.error = dv.error;
715
+ if (dv.promptTitle) dvAttrs.promptTitle = dv.promptTitle;
716
+ if (dv.prompt) dvAttrs.prompt = dv.prompt;
717
+ const dvChildren = [{ _attr: dvAttrs }];
718
+ if (dv.formula1 !== void 0) dvChildren.push({ formula1: [dv.formula1] });
719
+ if (dv.formula2 !== void 0) dvChildren.push({ formula2: [dv.formula2] });
720
+ dvElements.push({ dataValidation: dvChildren });
721
+ }
722
+ children.push({ dataValidations: dvElements });
723
+ }
724
+ return { worksheet: children };
725
+ }
726
+ /**
727
+ * Zero-allocation fast path: directly concatenate XML string.
728
+ * Bypasses the IXmlableObject intermediate tree entirely.
729
+ */
730
+ toXml(context) {
731
+ const fileData = context.fileData;
732
+ const sharedStrings = fileData?.sharedStrings;
733
+ const styles = fileData?.styles;
734
+ const p = ["<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">"];
735
+ if (this.freezePanes) {
736
+ const fp = this.freezePanes;
737
+ const ySplit = fp.row ? fp.row : 0;
738
+ const xSplit = fp.col ? fp.col : 0;
739
+ const topRow = fp.row ? fp.row + 1 : 1;
740
+ const leftCol = fp.col ? fp.col + 1 : 1;
741
+ const topLeftCell = this.defaultCellRef(topRow, leftCol);
742
+ const activePane = ySplit > 0 && xSplit > 0 ? "bottomRight" : ySplit > 0 ? "bottomLeft" : "topRight";
743
+ p.push("<sheetViews><sheetView tabSelected=\"1\" workbookViewId=\"0\">", `<pane ySplit="${ySplit}" xSplit="${xSplit}" topLeftCell="${topLeftCell}" activePane="${activePane}" state="frozen"/>`, "</sheetView></sheetViews>");
744
+ }
745
+ if (this.columns.length > 0) {
746
+ p.push("<cols>");
747
+ for (const col of this.columns) {
748
+ const colAttrs = {
749
+ min: col.min,
750
+ max: col.max
751
+ };
752
+ if (col.width !== void 0) {
753
+ colAttrs.width = col.width;
754
+ colAttrs.customWidth = 1;
755
+ }
756
+ if (col.hidden) colAttrs.hidden = 1;
757
+ p.push(selfCloseElement("col", attrs(colAttrs)));
758
+ }
759
+ p.push("</cols>");
760
+ }
761
+ p.push("<sheetData>");
762
+ for (let i = 0; i < this.rows.length; i++) {
763
+ const rowOpts = this.rows[i];
764
+ const rowNumber = rowOpts.rowNumber ?? i + 1;
765
+ const rowAttrs = { r: rowNumber };
766
+ if (rowOpts.height !== void 0) {
767
+ rowAttrs.ht = rowOpts.height;
768
+ rowAttrs.customHeight = 1;
769
+ }
770
+ if (rowOpts.hidden) rowAttrs.hidden = 1;
771
+ if (rowOpts.cells) {
772
+ const rowParts = [];
773
+ for (let j = 0; j < rowOpts.cells.length; j++) {
774
+ const cell = rowOpts.cells[j];
775
+ const ref = cell.reference ?? this.defaultCellRef(rowNumber, j + 1);
776
+ const cellStr = this.buildCellString(ref, cell, sharedStrings, styles);
777
+ if (cellStr) rowParts.push(cellStr);
778
+ }
779
+ p.push(`<row${attrs(rowAttrs)}>`, ...rowParts, "</row>");
780
+ } else p.push(`<row${attrs(rowAttrs)}></row>`);
781
+ }
782
+ p.push("</sheetData>");
783
+ if (this.autoFilter) p.push(selfCloseElement("autoFilter", attrs({ ref: this.autoFilter })));
784
+ if (this.mergeCells.length > 0) {
785
+ p.push(`<mergeCells count="${this.mergeCells.length}">`);
786
+ for (const mc of this.mergeCells) {
787
+ const fromRef = this.defaultCellRef(mc.from.row, mc.from.col);
788
+ const toRef = this.defaultCellRef(mc.to.row, mc.to.col);
789
+ p.push(selfCloseElement("mergeCell", attrs({ ref: `${fromRef}:${toRef}` })));
790
+ }
791
+ p.push("</mergeCells>");
792
+ }
793
+ if (this.conditionalFormats.length > 0) for (const cf of this.conditionalFormats) {
794
+ p.push(`<conditionalFormatting sqref="${cf.sqref}">`);
795
+ for (let ri = 0; ri < cf.rules.length; ri++) {
796
+ const rule = cf.rules[ri];
797
+ const ruleAttrs = {
798
+ type: rule.type,
799
+ priority: rule.priority ?? ri + 1
800
+ };
801
+ if (rule.operator) ruleAttrs.operator = rule.operator;
802
+ if (rule.dxfId !== void 0) ruleAttrs.dxfId = rule.dxfId;
803
+ if (rule.formulas && rule.formulas.length > 0) {
804
+ const formulaParts = rule.formulas.map((f) => `<formula>${escapeXml(f)}</formula>`);
805
+ p.push(`<cfRule${attrs(ruleAttrs)}>`, ...formulaParts, "</cfRule>");
806
+ } else p.push(selfCloseElement("cfRule", attrs(ruleAttrs)));
807
+ }
808
+ p.push("</conditionalFormatting>");
809
+ }
810
+ if (this.dataValidations.length > 0) {
811
+ p.push(`<dataValidations count="${this.dataValidations.length}">`);
812
+ for (const dv of this.dataValidations) {
813
+ const dvAttrs = { sqref: dv.sqref };
814
+ if (dv.type && dv.type !== "none") dvAttrs.type = dv.type;
815
+ if (dv.operator) dvAttrs.operator = dv.operator;
816
+ if (dv.allowBlank) dvAttrs.allowBlank = 1;
817
+ if (dv.showErrorMessage) dvAttrs.showErrorMessage = 1;
818
+ if (dv.showInputMessage) dvAttrs.showInputMessage = 1;
819
+ if (dv.errorTitle) dvAttrs.errorTitle = dv.errorTitle;
820
+ if (dv.error) dvAttrs.error = dv.error;
821
+ if (dv.promptTitle) dvAttrs.promptTitle = dv.promptTitle;
822
+ if (dv.prompt) dvAttrs.prompt = dv.prompt;
823
+ const inner = [];
824
+ if (dv.formula1 !== void 0) inner.push(`<formula1>${escapeXml(dv.formula1)}</formula1>`);
825
+ if (dv.formula2 !== void 0) inner.push(`<formula2>${escapeXml(dv.formula2)}</formula2>`);
826
+ if (inner.length > 0) p.push(`<dataValidation${attrs(dvAttrs)}>`, ...inner, "</dataValidation>");
827
+ else p.push(selfCloseElement("dataValidation", attrs(dvAttrs)));
828
+ }
829
+ p.push("</dataValidations>");
830
+ }
831
+ p.push("</worksheet>");
832
+ return p.join("");
833
+ }
834
+ /**
835
+ * Direct string serialization of a single cell — zero intermediate objects.
836
+ */
837
+ buildCellString(ref, cell, sharedStrings, styles) {
838
+ const cellAttrs = { r: ref };
839
+ if (cell.style !== void 0 && styles) cellAttrs.s = styles.register(cell.style);
840
+ else if (cell.styleIndex !== void 0) cellAttrs.s = cell.styleIndex;
841
+ const value = cell.value;
842
+ if (value === null || value === void 0) {
843
+ if (cell.styleIndex !== void 0) return selfCloseElement("c", attrs(cellAttrs));
844
+ return "";
845
+ }
846
+ if (typeof value === "string") {
847
+ if (sharedStrings) {
848
+ cellAttrs.t = "s";
849
+ const idx = sharedStrings.register(value);
850
+ return `<c${attrs(cellAttrs)}><v>${idx}</v></c>`;
851
+ }
852
+ cellAttrs.t = "inlineStr";
853
+ return `<c${attrs(cellAttrs)}><is><t>${escapeXml(value)}</t></is></c>`;
854
+ }
855
+ if (typeof value === "number") return `<c${attrs(cellAttrs)}><v>${value}</v></c>`;
856
+ if (typeof value === "boolean") {
857
+ cellAttrs.t = "b";
858
+ return `<c${attrs(cellAttrs)}><v>${value ? 1 : 0}</v></c>`;
859
+ }
860
+ if (value instanceof Date) {
861
+ const serial = this.dateToSerialNumber(value);
862
+ return `<c${attrs(cellAttrs)}><v>${serial}</v></c>`;
863
+ }
864
+ return "";
865
+ }
866
+ defaultCellRef(row, col) {
867
+ return this.columnToLetter(col) + row;
868
+ }
869
+ columnToLetter(col) {
870
+ let result = "";
871
+ let n = col;
872
+ while (n > 0) {
873
+ const remainder = (n - 1) % 26;
874
+ result = String.fromCharCode(65 + remainder) + result;
875
+ n = Math.floor((n - 1) / 26);
876
+ }
877
+ return result;
878
+ }
879
+ buildCell(ref, cell, sharedStrings, styles) {
880
+ const attrs = { r: ref };
881
+ if (cell.style !== void 0 && styles) attrs.s = styles.register(cell.style);
882
+ else if (cell.styleIndex !== void 0) attrs.s = cell.styleIndex;
883
+ const value = cell.value;
884
+ if (value === null || value === void 0) {
885
+ if (cell.styleIndex !== void 0) return { c: [{ _attr: attrs }] };
886
+ return;
887
+ }
888
+ if (typeof value === "string") {
889
+ if (sharedStrings) {
890
+ attrs.t = "s";
891
+ const idx = sharedStrings.register(value);
892
+ return { c: [{ _attr: attrs }, { v: [idx] }] };
893
+ }
894
+ attrs.t = "inlineStr";
895
+ return { c: [{ _attr: attrs }, { is: [{ t: [value] }] }] };
896
+ }
897
+ if (typeof value === "number") return { c: [{ _attr: attrs }, { v: [value] }] };
898
+ if (typeof value === "boolean") {
899
+ attrs.t = "b";
900
+ return { c: [{ _attr: attrs }, { v: [value ? 1 : 0] }] };
901
+ }
902
+ if (value instanceof Date) {
903
+ const serial = this.dateToSerialNumber(value);
904
+ return { c: [{ _attr: attrs }, { v: [serial] }] };
905
+ }
906
+ }
907
+ dateToSerialNumber(date) {
908
+ const epoch = new Date(1899, 11, 30);
909
+ return (date.getTime() - epoch.getTime()) / 864e5;
910
+ }
911
+ };
912
+ //#endregion
913
+ //#region src/file/file.ts
914
+ /**
915
+ * File class (exported as Workbook) — the top-level container for XLSX documents.
916
+ *
917
+ * @module
918
+ */
919
+ var File = class {
920
+ worksheetOptions;
921
+ corePropsOptions;
922
+ _coreProperties;
923
+ _appProperties;
924
+ _contentTypes;
925
+ _styles;
926
+ _theme;
927
+ _workbookXml;
928
+ _worksheets;
929
+ _sharedStrings;
930
+ _media;
931
+ _fileRels;
932
+ _workbookRels;
933
+ _charts;
934
+ constructor(options) {
935
+ this.worksheetOptions = options.worksheets ?? [];
936
+ this.corePropsOptions = options;
937
+ }
938
+ get coreProperties() {
939
+ return this._coreProperties ??= new CoreProperties(this.corePropsOptions);
940
+ }
941
+ get appProperties() {
942
+ return this._appProperties ??= new AppProperties();
943
+ }
944
+ get contentTypes() {
945
+ if (!this._contentTypes) {
946
+ this._contentTypes = new ContentTypes();
947
+ for (let i = 0; i < this.worksheetOptions.length; i++) this._contentTypes.addWorksheet(i + 1);
948
+ this._contentTypes.addStyles();
949
+ this._contentTypes.addSharedStrings();
950
+ this._contentTypes.addTheme();
951
+ }
952
+ return this._contentTypes;
953
+ }
954
+ get styles() {
955
+ return this._styles ??= new Styles();
956
+ }
957
+ get theme() {
958
+ return this._theme ??= new DefaultTheme();
959
+ }
960
+ get workbookXml() {
961
+ if (!this._workbookXml) {
962
+ const sheets = this.worksheetOptions.map((ws, i) => ({
963
+ name: ws.name ?? `Sheet${i + 1}`,
964
+ sheetId: i + 1,
965
+ rId: `rId${i + 1}`
966
+ }));
967
+ this._workbookXml = new WorkbookXml(sheets);
968
+ }
969
+ return this._workbookXml;
970
+ }
971
+ get sharedStrings() {
972
+ return this._sharedStrings ??= new SharedStrings();
973
+ }
974
+ get media() {
975
+ return this._media ??= new Media();
976
+ }
977
+ get charts() {
978
+ return this._charts ??= new ChartCollection();
979
+ }
980
+ get worksheets() {
981
+ if (!this._worksheets) this._worksheets = this.worksheetOptions.map((ws) => new Worksheet(ws));
982
+ return this._worksheets;
983
+ }
984
+ get fileRelationships() {
985
+ if (!this._fileRels) {
986
+ this._fileRels = new Relationships();
987
+ this._fileRels.addRelationship(1, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument", "xl/workbook.xml");
988
+ this._fileRels.addRelationship(2, "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties", "docProps/core.xml");
989
+ this._fileRels.addRelationship(3, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties", "docProps/app.xml");
990
+ }
991
+ return this._fileRels;
992
+ }
993
+ get workbookRelationships() {
994
+ if (!this._workbookRels) {
995
+ this._workbookRels = new Relationships();
996
+ let rid = 1;
997
+ for (let i = 0; i < this.worksheetOptions.length; i++) this._workbookRels.addRelationship(rid++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet", `worksheets/sheet${i + 1}.xml`);
998
+ this._workbookRels.addRelationship(rid++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", "styles.xml");
999
+ this._workbookRels.addRelationship(rid++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme", "theme/theme1.xml");
1000
+ this._workbookRels.addRelationship(rid++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings", "sharedStrings.xml");
1001
+ }
1002
+ return this._workbookRels;
1003
+ }
1004
+ };
1005
+ //#endregion
1006
+ //#region src/file/drawing/drawing.ts
1007
+ /**
1008
+ * XLSX Drawing component — generates xl/drawings/drawing{n}.xml.
1009
+ *
1010
+ * Uses the spreadsheetDrawing namespace (default, no prefix) for anchoring
1011
+ * images and charts to worksheet cells.
1012
+ *
1013
+ * @module
1014
+ */
1015
+ const XDR_NS = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing";
1016
+ const A_NS = "http://schemas.openxmlformats.org/drawingml/2006/main";
1017
+ const R_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
1018
+ const C_URI = "http://schemas.openxmlformats.org/drawingml/2006/chart";
1019
+ var Drawing = class extends BaseXmlComponent {
1020
+ images;
1021
+ charts;
1022
+ constructor(images, charts = []) {
1023
+ super("wsDr");
1024
+ this.images = images;
1025
+ this.charts = charts;
1026
+ }
1027
+ prepForXml(_context) {
1028
+ const children = [{ _attr: {
1029
+ xmlns: XDR_NS,
1030
+ "xmlns:a": A_NS,
1031
+ "xmlns:r": R_NS
1032
+ } }];
1033
+ let nextId = 1;
1034
+ for (const img of this.images) children.push(this.buildImageAnchor(img, nextId++));
1035
+ for (const chart of this.charts) children.push(this.buildChartAnchor(chart, nextId++));
1036
+ return { wsDr: children };
1037
+ }
1038
+ buildFromAnchor(col, row, colOffset, rowOffset) {
1039
+ return { from: [
1040
+ { col: [col - 1] },
1041
+ { colOff: [colOffset ?? 0] },
1042
+ { row: [row - 1] },
1043
+ { rowOff: [rowOffset ?? 0] }
1044
+ ] };
1045
+ }
1046
+ buildToAnchor(col, row) {
1047
+ return { to: [
1048
+ { col: [col] },
1049
+ { colOff: [0] },
1050
+ { row: [row] },
1051
+ { rowOff: [0] }
1052
+ ] };
1053
+ }
1054
+ buildImageAnchor(img, id) {
1055
+ return { twoCellAnchor: [
1056
+ { _attr: { editAs: "oneCell" } },
1057
+ this.buildFromAnchor(img.col, img.row, img.colOffset, img.rowOffset),
1058
+ this.buildToAnchor(img.col, img.row),
1059
+ { pic: [
1060
+ { nvPicPr: [{ cNvPr: { _attr: {
1061
+ id,
1062
+ name: `Picture ${id}`
1063
+ } } }, { cNvPicPr: [{ _attr: { preferRelativeResize: 1 } }] }] },
1064
+ { blipFill: [{ "a:blip": { _attr: { "r:embed": img.rId } } }, { "a:stretch": [{ "a:fillRect": [] }] }] },
1065
+ { spPr: [{ "a:xfrm": [{ "a:off": { _attr: {
1066
+ x: 0,
1067
+ y: 0
1068
+ } } }, { "a:ext": { _attr: {
1069
+ cx: 4e5,
1070
+ cy: 3e5
1071
+ } } }] }, { "a:prstGeom": [{ _attr: { prst: "rect" } }, { "a:avLst": [] }] }] }
1072
+ ] },
1073
+ { clientData: [] }
1074
+ ] };
1075
+ }
1076
+ buildChartAnchor(chart, id) {
1077
+ return { twoCellAnchor: [
1078
+ { _attr: { editAs: "oneCell" } },
1079
+ this.buildFromAnchor(chart.col, chart.row, chart.colOffset, chart.rowOffset),
1080
+ this.buildToAnchor(chart.col + 8, chart.row + 15),
1081
+ { graphicFrame: [
1082
+ { nvGraphicFramePr: [{ cNvPr: { _attr: {
1083
+ id,
1084
+ name: `Chart ${id}`
1085
+ } } }, { cNvGraphicFramePr: [{ "a:graphicFrameLocks": { _attr: { noGrp: 1 } } }] }] },
1086
+ { xfrm: [{ "a:off": { _attr: {
1087
+ x: 0,
1088
+ y: 0
1089
+ } } }, { "a:ext": { _attr: {
1090
+ cx: 0,
1091
+ cy: 0
1092
+ } } }] },
1093
+ { "a:graphic": [{ "a:graphicData": [{ _attr: { uri: C_URI } }, { "c:chart": { _attr: {
1094
+ "xmlns:c": "http://schemas.openxmlformats.org/drawingml/2006/chart",
1095
+ "xmlns:r": R_NS,
1096
+ "r:id": chart.rId
1097
+ } } }] }] }
1098
+ ] },
1099
+ { clientData: [] }
1100
+ ] };
1101
+ }
1102
+ };
1103
+ //#endregion
1104
+ //#region src/export/packer/next-compiler.ts
1105
+ /**
1106
+ * XLSX Compiler — compiles a File object into a Zippable structure.
1107
+ *
1108
+ * @module
1109
+ */
1110
+ var Compiler = class {
1111
+ formatter = new Formatter();
1112
+ compile(file, overrides = []) {
1113
+ const context = {
1114
+ fileData: file,
1115
+ stack: []
1116
+ };
1117
+ const f = this.formatter;
1118
+ const mapping = {};
1119
+ const fmt = (component, declaration) => f.formatToXml(component, context, declaration);
1120
+ mapping["Properties"] = {
1121
+ data: fmt(file.coreProperties, true),
1122
+ path: "docProps/core.xml"
1123
+ };
1124
+ mapping["AppProperties"] = {
1125
+ data: fmt(file.appProperties, true),
1126
+ path: "docProps/app.xml"
1127
+ };
1128
+ mapping["FileRelationships"] = {
1129
+ data: fmt(file.fileRelationships),
1130
+ path: "_rels/.rels"
1131
+ };
1132
+ mapping["Workbook"] = {
1133
+ data: fmt(file.workbookXml, true),
1134
+ path: "xl/workbook.xml"
1135
+ };
1136
+ mapping["WorkbookRelationships"] = {
1137
+ data: fmt(file.workbookRelationships),
1138
+ path: "xl/_rels/workbook.xml.rels"
1139
+ };
1140
+ const worksheets = file.worksheets;
1141
+ let globalMediaIdx = 0;
1142
+ let globalChartIdx = 0;
1143
+ for (let i = 0; i < worksheets.length; i++) {
1144
+ const ws = worksheets[i];
1145
+ const imgOpts = ws.imageOptions;
1146
+ const chartOpts = ws.charts;
1147
+ let sheetXml = fmt(ws, true);
1148
+ if (imgOpts.length > 0 || chartOpts.length > 0) {
1149
+ const drawingImages = [];
1150
+ const drawingCharts = [];
1151
+ const drawingRels = new Relationships();
1152
+ let rid = 1;
1153
+ for (const img of imgOpts) {
1154
+ const mediaKey = `image_${globalMediaIdx}`;
1155
+ const ext = img.type === "jpeg" || img.type === "jpg" ? "jpeg" : "png";
1156
+ file.media.addImage(mediaKey, {
1157
+ fileName: `image${globalMediaIdx + 1}.${ext}`,
1158
+ type: ext,
1159
+ data: img.data,
1160
+ width: 0,
1161
+ height: 0
1162
+ });
1163
+ drawingRels.addRelationship(rid, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", `../media/image${globalMediaIdx + 1}.${ext}`);
1164
+ drawingImages.push({
1165
+ col: img.col,
1166
+ row: img.row,
1167
+ rId: `rId${rid}`
1168
+ });
1169
+ rid++;
1170
+ globalMediaIdx++;
1171
+ }
1172
+ for (const chart of chartOpts) {
1173
+ const chartKey = `chart_${globalChartIdx}`;
1174
+ file.charts.addChart(chartKey, {
1175
+ key: chartKey,
1176
+ chartSpace: new ChartSpace(chart)
1177
+ });
1178
+ drawingRels.addRelationship(rid, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", `../charts/chart${globalChartIdx + 1}.xml`);
1179
+ drawingCharts.push({
1180
+ col: chart.col,
1181
+ row: chart.row,
1182
+ rId: `rId${rid}`
1183
+ });
1184
+ rid++;
1185
+ globalChartIdx++;
1186
+ }
1187
+ const drawing = new Drawing(drawingImages, drawingCharts);
1188
+ const drawingIdx = i + 1;
1189
+ mapping[`Drawing${i}`] = {
1190
+ data: fmt(drawing, true),
1191
+ path: `xl/drawings/drawing${drawingIdx}.xml`
1192
+ };
1193
+ mapping[`DrawingRels${i}`] = {
1194
+ data: fmt(drawingRels),
1195
+ path: `xl/drawings/_rels/drawing${drawingIdx}.xml.rels`
1196
+ };
1197
+ sheetXml = sheetXml.slice(0, -12) + `<drawing r:id="rId${rid}"/></worksheet>`;
1198
+ const wsRels = new Relationships();
1199
+ wsRels.addRelationship(rid, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing", `../drawings/drawing${drawingIdx}.xml`);
1200
+ mapping[`WorksheetRels${i}`] = {
1201
+ data: fmt(wsRels),
1202
+ path: `xl/worksheets/_rels/sheet${i + 1}.xml.rels`
1203
+ };
1204
+ file.contentTypes.addDrawing(drawingIdx);
1205
+ }
1206
+ mapping[`Worksheet${i}`] = {
1207
+ data: sheetXml,
1208
+ path: `xl/worksheets/sheet${i + 1}.xml`
1209
+ };
1210
+ }
1211
+ const sharedStrings = file.sharedStrings;
1212
+ if (sharedStrings.count > 0) mapping["SharedStrings"] = {
1213
+ data: fmt(sharedStrings, true),
1214
+ path: "xl/sharedStrings.xml"
1215
+ };
1216
+ mapping["Styles"] = {
1217
+ data: fmt(file.styles, true),
1218
+ path: "xl/styles.xml"
1219
+ };
1220
+ mapping["Theme"] = {
1221
+ data: fmt(file.theme, true),
1222
+ path: "xl/theme/theme1.xml"
1223
+ };
1224
+ for (let i = 0; i < file.charts.array.length; i++) {
1225
+ const chartData = file.charts.array[i];
1226
+ mapping[`Chart${i}`] = {
1227
+ data: fmt(chartData.chartSpace, true),
1228
+ path: `xl/charts/chart${i + 1}.xml`
1229
+ };
1230
+ file.contentTypes.addChart(i + 1);
1231
+ }
1232
+ mapping["ContentTypes"] = {
1233
+ data: fmt(file.contentTypes),
1234
+ path: "[Content_Types].xml"
1235
+ };
1236
+ return compileMapping(mapping, overrides, file.media.array.map((img) => ({
1237
+ data: img.data,
1238
+ path: `xl/media/${img.fileName}`
1239
+ })));
1240
+ }
1241
+ };
1242
+ //#endregion
1243
+ //#region src/export/packer/packer.ts
1244
+ /**
1245
+ * Packer module — export API for XLSX files.
1246
+ *
1247
+ * @module
1248
+ */
1249
+ const compiler = new Compiler();
1250
+ const Packer = createPacker({
1251
+ compile: (file, overrides) => compiler.compile(file, overrides),
1252
+ mimeType: OoxmlMimeType.XLSX
1253
+ });
1254
+ //#endregion
1255
+ //#region src/util/index.ts
1256
+ /**
1257
+ * Convert a 1-based column number to Excel column letter(s).
1258
+ * 1 → "A", 26 → "Z", 27 → "AA", 28 → "AB"
1259
+ */
1260
+ function columnToLetter(col) {
1261
+ let result = "";
1262
+ let n = col;
1263
+ while (n > 0) {
1264
+ const remainder = (n - 1) % 26;
1265
+ result = String.fromCharCode(65 + remainder) + result;
1266
+ n = Math.floor((n - 1) / 26);
1267
+ }
1268
+ return result;
1269
+ }
1270
+ /**
1271
+ * Convert Excel column letter(s) to a 1-based column number.
1272
+ * "A" → 1, "Z" → 26, "AA" → 27
1273
+ */
1274
+ function letterToColumn(s) {
1275
+ let result = 0;
1276
+ for (let i = 0; i < s.length; i++) result = result * 26 + (s.charCodeAt(i) - 64);
1277
+ return result;
1278
+ }
1279
+ /**
1280
+ * Convert a JavaScript Date to an Excel serial number.
1281
+ * Excel epoch: January 1, 1900 = 1 (with the 1900 leap year bug).
1282
+ */
1283
+ function dateToSerialNumber(date) {
1284
+ const epoch = new Date(1899, 11, 30);
1285
+ return (date.getTime() - epoch.getTime()) / 864e5;
1286
+ }
1287
+ //#endregion
1288
+ //#region src/parse.ts
1289
+ /**
1290
+ * XLSX parsing — parse .xlsx files into structured data.
1291
+ *
1292
+ * @module
1293
+ */
1294
+ function sortByNumber(paths) {
1295
+ return paths.sort((a, b) => {
1296
+ return parseInt(a.match(/(\d+)/)?.[1] ?? "0", 10) - parseInt(b.match(/(\d+)/)?.[1] ?? "0", 10);
1297
+ });
1298
+ }
1299
+ /**
1300
+ * Parse raw .xlsx data into a low-level XlsxDocument.
1301
+ */
1302
+ function parseXlsx(data) {
1303
+ const doc = parseArchive(toUint8Array(data));
1304
+ const workbook = doc.get("xl/workbook.xml");
1305
+ const styles = doc.get("xl/styles.xml");
1306
+ const sharedStrings = doc.get("xl/sharedStrings.xml");
1307
+ const worksheets = [];
1308
+ const charts = [];
1309
+ const drawings = [];
1310
+ const media = [];
1311
+ const wbRels = doc.get("xl/_rels/workbook.xml.rels");
1312
+ if (wbRels) for (const child of wbRels.elements ?? []) {
1313
+ if (child.name !== "Relationship") continue;
1314
+ const type = attr(child, "Type") ?? "";
1315
+ const target = attr(child, "Target") ?? "";
1316
+ if (!target) continue;
1317
+ if (type.includes("/worksheet")) worksheets.push(target.startsWith("/") ? target.slice(1) : `xl/${target}`);
1318
+ }
1319
+ sortByNumber(worksheets);
1320
+ drawings.push(...doc.keys("xl/drawings/").filter((k) => k.endsWith(".xml")));
1321
+ charts.push(...doc.keys("xl/charts/").filter((k) => k.endsWith(".xml")));
1322
+ media.push(...doc.keys("xl/media/"));
1323
+ sortByNumber(drawings);
1324
+ sortByNumber(charts);
1325
+ let coreProps;
1326
+ let appProps;
1327
+ const rootRels = doc.get("_rels/.rels");
1328
+ if (rootRels) for (const child of rootRels.elements ?? []) {
1329
+ if (child.name !== "Relationship") continue;
1330
+ const type = attr(child, "Type") ?? "";
1331
+ const target = attr(child, "Target") ?? "";
1332
+ if (type.includes("/core-properties")) coreProps = target;
1333
+ else if (type.includes("/extended-properties")) appProps = target;
1334
+ }
1335
+ return {
1336
+ doc,
1337
+ workbook,
1338
+ worksheets,
1339
+ styles,
1340
+ sharedStrings,
1341
+ partRefs: {
1342
+ worksheets,
1343
+ charts,
1344
+ media,
1345
+ drawings
1346
+ },
1347
+ coreProps,
1348
+ appProps
1349
+ };
1350
+ }
1351
+ function parseSharedStrings(el) {
1352
+ if (!el) return [];
1353
+ const strings = [];
1354
+ for (const si of el.elements ?? []) {
1355
+ if (si.name !== "si") continue;
1356
+ const t = findChild(si, "t");
1357
+ if (t) strings.push(textOf(t) ?? "");
1358
+ else {
1359
+ const parts = [];
1360
+ for (const r of si.elements ?? []) {
1361
+ if (r.name !== "r") continue;
1362
+ const rt = findChild(r, "t");
1363
+ if (rt) parts.push(textOf(rt) ?? "");
1364
+ }
1365
+ strings.push(parts.join(""));
1366
+ }
1367
+ }
1368
+ return strings;
1369
+ }
1370
+ function colFromRef(ref) {
1371
+ const match = ref.match(/^([A-Z]+)/);
1372
+ return match ? letterToColumn(match[1]) : 1;
1373
+ }
1374
+ function rowFromRef(ref) {
1375
+ const match = ref.match(/(\d+)$/);
1376
+ return match ? parseInt(match[1], 10) : 1;
1377
+ }
1378
+ function parseWorksheetElement(wsEl, strings) {
1379
+ const opts = {};
1380
+ const colsEl = findChild(wsEl, "cols") ?? findChildByLocalName(wsEl, "cols");
1381
+ if (colsEl) {
1382
+ const columns = [];
1383
+ for (const col of colsEl.elements ?? []) {
1384
+ if (localName$1(col) !== "col") continue;
1385
+ const min = attrNum(col, "min");
1386
+ const max = attrNum(col, "max");
1387
+ if (min === void 0 || max === void 0) continue;
1388
+ const colOpts = {
1389
+ min,
1390
+ max
1391
+ };
1392
+ const width = attrNum(col, "width");
1393
+ if (width !== void 0) colOpts.width = width;
1394
+ if (attr(col, "hidden") === "1") colOpts.hidden = true;
1395
+ columns.push(colOpts);
1396
+ }
1397
+ if (columns.length > 0) opts.columns = columns;
1398
+ }
1399
+ const sheetViews = findChildByLocalName(wsEl, "sheetViews");
1400
+ if (sheetViews) {
1401
+ const sheetView = findChildByLocalName(sheetViews, "sheetView");
1402
+ if (sheetView) {
1403
+ const pane = findChildByLocalName(sheetView, "pane");
1404
+ if (pane) {
1405
+ if (attr(pane, "state") === "frozen") {
1406
+ const freezePanes = {};
1407
+ const ySplit = attrNum(pane, "ySplit");
1408
+ const xSplit = attrNum(pane, "xSplit");
1409
+ if (ySplit && ySplit > 0) freezePanes.row = ySplit;
1410
+ if (xSplit && xSplit > 0) freezePanes.col = xSplit;
1411
+ if (Object.keys(freezePanes).length > 0) opts.freezePanes = freezePanes;
1412
+ }
1413
+ }
1414
+ }
1415
+ }
1416
+ const sheetData = findChildByLocalName(wsEl, "sheetData");
1417
+ const rows = [];
1418
+ if (sheetData) for (const rowEl of sheetData.elements ?? []) {
1419
+ if (localName$1(rowEl) !== "row") continue;
1420
+ const rowNumber = attrNum(rowEl, "r");
1421
+ const rowOpts = {};
1422
+ if (rowNumber !== void 0) rowOpts.rowNumber = rowNumber;
1423
+ const ht = attrNum(rowEl, "ht");
1424
+ if (ht !== void 0) rowOpts.height = ht;
1425
+ if (attr(rowEl, "hidden") === "1") rowOpts.hidden = true;
1426
+ const cells = [];
1427
+ for (const cellEl of rowEl.elements ?? []) {
1428
+ if (localName$1(cellEl) !== "c") continue;
1429
+ const ref = attr(cellEl, "r");
1430
+ const type = attr(cellEl, "t");
1431
+ const cellOpts = {};
1432
+ if (ref) cellOpts.reference = ref;
1433
+ const styleIdx = attrNum(cellEl, "s");
1434
+ if (styleIdx !== void 0) cellOpts.styleIndex = styleIdx;
1435
+ const vEl = findChildByLocalName(cellEl, "v");
1436
+ const isEl = findChildByLocalName(cellEl, "is");
1437
+ if (type === "s" && vEl) cellOpts.value = strings[parseInt(textOf(vEl) ?? "", 10)] ?? "";
1438
+ else if (type === "b" && vEl) cellOpts.value = textOf(vEl) === "1";
1439
+ else if (type === "inlineStr" && isEl) cellOpts.value = textOf(findChildByLocalName(isEl, "t")) ?? "";
1440
+ else if (vEl) {
1441
+ const raw = textOf(vEl) ?? "";
1442
+ const num = Number(raw);
1443
+ cellOpts.value = isNaN(num) ? raw : num;
1444
+ }
1445
+ cells.push(cellOpts);
1446
+ }
1447
+ rowOpts.cells = cells;
1448
+ rows.push(rowOpts);
1449
+ }
1450
+ opts.children = rows;
1451
+ const mergeCellsEl = findChildByLocalName(wsEl, "mergeCells");
1452
+ if (mergeCellsEl) {
1453
+ const mergeCells = [];
1454
+ for (const mc of mergeCellsEl.elements ?? []) {
1455
+ if (localName$1(mc) !== "mergeCell") continue;
1456
+ const ref = attr(mc, "ref");
1457
+ if (!ref) continue;
1458
+ const parts = ref.split(":");
1459
+ if (parts.length === 2) mergeCells.push({
1460
+ from: {
1461
+ row: rowFromRef(parts[0]),
1462
+ col: colFromRef(parts[0])
1463
+ },
1464
+ to: {
1465
+ row: rowFromRef(parts[1]),
1466
+ col: colFromRef(parts[1])
1467
+ }
1468
+ });
1469
+ }
1470
+ if (mergeCells.length > 0) opts.mergeCells = mergeCells;
1471
+ }
1472
+ const autoFilterEl = findChildByLocalName(wsEl, "autoFilter");
1473
+ if (autoFilterEl) {
1474
+ const ref = attr(autoFilterEl, "ref");
1475
+ if (ref) opts.autoFilter = ref;
1476
+ }
1477
+ return opts;
1478
+ }
1479
+ function localName$1(el) {
1480
+ const name = el.name ?? "";
1481
+ const colonIdx = name.indexOf(":");
1482
+ return colonIdx >= 0 ? name.slice(colonIdx + 1) : name;
1483
+ }
1484
+ function findChildByLocalName(parent, name) {
1485
+ return (parent.elements ?? []).find((el) => localName$1(el) === name);
1486
+ }
1487
+ /**
1488
+ * Parse a .xlsx file and convert it into WorkbookOptions.
1489
+ *
1490
+ * The returned options can be passed to `new Workbook(parsed)`.
1491
+ */
1492
+ function parseWorkbook(data) {
1493
+ const xlsx = parseXlsx(data);
1494
+ const opts = {};
1495
+ if (xlsx.coreProps) {
1496
+ const corePropsEl = xlsx.doc.get(xlsx.coreProps);
1497
+ if (corePropsEl) {
1498
+ const cp = parseCorePropsElement(corePropsEl);
1499
+ if (cp.title) opts.title = cp.title;
1500
+ if (cp.subject) opts.subject = cp.subject;
1501
+ if (cp.creator) opts.creator = cp.creator;
1502
+ if (cp.keywords) opts.keywords = cp.keywords;
1503
+ if (cp.description) opts.description = cp.description;
1504
+ if (cp.lastModifiedBy) opts.lastModifiedBy = cp.lastModifiedBy;
1505
+ if (cp.revision) opts.revision = parseInt(cp.revision, 10);
1506
+ }
1507
+ }
1508
+ const strings = parseSharedStrings(xlsx.sharedStrings);
1509
+ const sheetNames = [];
1510
+ if (xlsx.workbook) {
1511
+ const sheetsEl = findChildByLocalName(xlsx.workbook, "sheets");
1512
+ if (sheetsEl) for (const s of sheetsEl.elements ?? []) {
1513
+ if (localName$1(s) !== "sheet") continue;
1514
+ sheetNames.push(attr(s, "name") ?? "");
1515
+ }
1516
+ }
1517
+ const worksheets = [];
1518
+ for (let i = 0; i < xlsx.worksheets.length; i++) {
1519
+ const wsPath = xlsx.worksheets[i];
1520
+ const wsEl = xlsx.doc.get(wsPath);
1521
+ if (!wsEl) continue;
1522
+ const wsOpts = parseWorksheetElement(wsEl, strings);
1523
+ if (sheetNames[i]) wsOpts.name = sheetNames[i];
1524
+ worksheets.push(wsOpts);
1525
+ }
1526
+ opts.worksheets = worksheets;
1527
+ return opts;
1528
+ }
1529
+ //#endregion
1530
+ //#region src/patcher.ts
1531
+ /**
1532
+ * XLSX patching — replace placeholders in existing .xlsx files.
1533
+ *
1534
+ * Unlike DOCX/PPTX (paragraph-based), XLSX patching targets cell values:
1535
+ * - Replaces placeholders in the shared strings table (most common)
1536
+ * - Replaces placeholders in inline strings within worksheet cells
1537
+ *
1538
+ * @module
1539
+ */
1540
+ /** Reusable TextEncoder (stateless, safe to share). */
1541
+ const encoder = new TextEncoder();
1542
+ const PatchType = { CELL: "cell" };
1543
+ /**
1544
+ * Patch an existing .xlsx workbook by replacing placeholder text in cells.
1545
+ *
1546
+ * Placeholders are matched in shared strings and inline strings.
1547
+ * For string replacements, the shared string value is updated in-place.
1548
+ * For non-string replacements, the cell type and value are updated.
1549
+ */
1550
+ const patchWorkbook = async ({ outputType, data, patches, placeholderDelimiters = {
1551
+ start: "{{",
1552
+ end: "}}"
1553
+ } }) => {
1554
+ const zipContent = unzipSync(toUint8Array(data));
1555
+ const xmlMap = /* @__PURE__ */ new Map();
1556
+ const binaryMap = /* @__PURE__ */ new Map();
1557
+ for (const [key, value] of Object.entries(zipContent)) if (key.endsWith(".xml") || key.endsWith(".rels")) xmlMap.set(key, toJson(strFromU8(value)));
1558
+ else binaryMap.set(key, value);
1559
+ const { start, end } = placeholderDelimiters;
1560
+ const patchMap = /* @__PURE__ */ new Map();
1561
+ for (const [key, patch] of Object.entries(patches)) patchMap.set(`${start}${key}${end}`, patch);
1562
+ const sst = xmlMap.get("xl/sharedStrings.xml");
1563
+ if (sst) patchSharedStrings(sst, patchMap);
1564
+ const worksheetKeys = Object.keys(zipContent).filter((k) => k.startsWith("xl/worksheets/sheet") && k.endsWith(".xml"));
1565
+ for (const wsKey of worksheetKeys) {
1566
+ const ws = xmlMap.get(wsKey);
1567
+ if (ws) patchWorksheetInlineStrings(ws, patchMap);
1568
+ }
1569
+ const files = {};
1570
+ for (const [key, value] of xmlMap) files[key] = encoder.encode(js2xml(value));
1571
+ for (const [key, value] of binaryMap) files[key] = value;
1572
+ return await zipAndConvert(files, outputType, OoxmlMimeType.XLSX);
1573
+ };
1574
+ function patchSharedStrings(sst, patchMap) {
1575
+ const root = sst.name ? sst : sst.elements?.[0];
1576
+ if (!root) return;
1577
+ for (const si of root.elements ?? []) {
1578
+ if (si.name !== "si") continue;
1579
+ const t = findLocalChild(si, "t");
1580
+ if (t) patchTextElement(t, patchMap);
1581
+ else for (const r of si.elements ?? []) {
1582
+ if (r.name !== "r") continue;
1583
+ const rt = findLocalChild(r, "t");
1584
+ if (rt) patchTextElement(rt, patchMap);
1585
+ }
1586
+ }
1587
+ }
1588
+ function patchWorksheetInlineStrings(ws, patchMap) {
1589
+ const root = ws.name ? ws : ws.elements?.[0];
1590
+ if (!root) return;
1591
+ const sheetData = findLocalChild(root, "sheetData");
1592
+ if (!sheetData) return;
1593
+ for (const row of sheetData.elements ?? []) {
1594
+ if (localName(row) !== "row") continue;
1595
+ for (const cell of row.elements ?? []) {
1596
+ if (localName(cell) !== "c") continue;
1597
+ const isEl = findLocalChild(cell, "is");
1598
+ if (isEl) {
1599
+ const t = findLocalChild(isEl, "t");
1600
+ if (t) patchTextElement(t, patchMap);
1601
+ }
1602
+ }
1603
+ }
1604
+ }
1605
+ function patchTextElement(tEl, patchMap) {
1606
+ const text = tEl.elements?.[0]?.text;
1607
+ if (typeof text !== "string") return;
1608
+ for (const [placeholder, patch] of patchMap) if (text.includes(placeholder)) {
1609
+ const newValue = String(patch.value);
1610
+ const replaced = text.replace(placeholder, newValue);
1611
+ if (tEl.elements) tEl.elements[0] = {
1612
+ ...tEl.elements[0],
1613
+ text: replaced
1614
+ };
1615
+ }
1616
+ }
1617
+ function localName(el) {
1618
+ const name = el.name ?? "";
1619
+ const colonIdx = name.indexOf(":");
1620
+ return colonIdx >= 0 ? name.slice(colonIdx + 1) : name;
1621
+ }
1622
+ function findLocalChild(parent, name) {
1623
+ return (parent.elements ?? []).find((el) => localName(el) === name);
1624
+ }
1625
+ //#endregion
1626
+ export { File, File as Workbook, Packer, PatchType, SharedStrings, Styles, columnToLetter, dateToSerialNumber, letterToColumn, parseWorkbook, parseXlsx, patchWorkbook };
1627
+
1628
+ //# sourceMappingURL=index.js.map