han-excel-builder 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.
@@ -0,0 +1,1031 @@
1
+ import ExcelJS from "exceljs";
2
+ import saveAs from "file-saver";
3
+ class EventEmitter {
4
+ listeners = /* @__PURE__ */ new Map();
5
+ /**
6
+ * Add an event listener
7
+ */
8
+ on(type, listener, options = {}) {
9
+ if (!this.listeners.has(type)) {
10
+ this.listeners.set(type, []);
11
+ }
12
+ const registration = {
13
+ type,
14
+ listener,
15
+ options: {
16
+ once: false,
17
+ async: false,
18
+ priority: 0,
19
+ stopPropagation: false,
20
+ ...options
21
+ },
22
+ id: this.generateId(),
23
+ active: true,
24
+ timestamp: /* @__PURE__ */ new Date()
25
+ };
26
+ this.listeners.get(type).push(registration);
27
+ this.listeners.get(type).sort((a, b) => (b.options.priority || 0) - (a.options.priority || 0));
28
+ return registration.id;
29
+ }
30
+ /**
31
+ * Add a one-time event listener
32
+ */
33
+ once(type, listener, options = {}) {
34
+ return this.on(type, listener, { ...options, once: true });
35
+ }
36
+ /**
37
+ * Remove an event listener
38
+ */
39
+ off(type, listenerId) {
40
+ const listeners = this.listeners.get(type);
41
+ if (!listeners) {
42
+ return false;
43
+ }
44
+ const index = listeners.findIndex((reg) => reg.id === listenerId);
45
+ if (index === -1) {
46
+ return false;
47
+ }
48
+ listeners.splice(index, 1);
49
+ return true;
50
+ }
51
+ /**
52
+ * Remove all listeners for an event type
53
+ */
54
+ offAll(type) {
55
+ const listeners = this.listeners.get(type);
56
+ if (!listeners) {
57
+ return 0;
58
+ }
59
+ const count = listeners.length;
60
+ this.listeners.delete(type);
61
+ return count;
62
+ }
63
+ /**
64
+ * Emit an event
65
+ */
66
+ async emit(event) {
67
+ const type = event.type || "default";
68
+ const listeners = this.listeners.get(type);
69
+ if (!listeners || listeners.length === 0) {
70
+ return;
71
+ }
72
+ const activeListeners = listeners.filter((reg) => reg.active);
73
+ for (const registration of activeListeners) {
74
+ try {
75
+ if (registration.options.once) {
76
+ registration.active = false;
77
+ }
78
+ if (registration.options.async) {
79
+ await registration.listener(event);
80
+ } else {
81
+ registration.listener(event);
82
+ }
83
+ if (registration.options.stopPropagation) {
84
+ break;
85
+ }
86
+ } catch (error) {
87
+ console.error(`Error in event listener for ${type}:`, error);
88
+ }
89
+ }
90
+ this.cleanupInactiveListeners(type);
91
+ }
92
+ /**
93
+ * Emit an event synchronously
94
+ */
95
+ emitSync(event) {
96
+ const type = event.type || "default";
97
+ const listeners = this.listeners.get(type);
98
+ if (!listeners || listeners.length === 0) {
99
+ return;
100
+ }
101
+ const activeListeners = listeners.filter((reg) => reg.active);
102
+ for (const registration of activeListeners) {
103
+ try {
104
+ if (registration.options.once) {
105
+ registration.active = false;
106
+ }
107
+ registration.listener(event);
108
+ if (registration.options.stopPropagation) {
109
+ break;
110
+ }
111
+ } catch (error) {
112
+ console.error(`Error in event listener for ${type}:`, error);
113
+ }
114
+ }
115
+ this.cleanupInactiveListeners(type);
116
+ }
117
+ /**
118
+ * Clear all listeners
119
+ */
120
+ clear() {
121
+ this.listeners.clear();
122
+ }
123
+ /**
124
+ * Get listeners for an event type
125
+ */
126
+ getListeners(type) {
127
+ return this.listeners.get(type) || [];
128
+ }
129
+ /**
130
+ * Get listener count for an event type
131
+ */
132
+ getListenerCount(type) {
133
+ return this.listeners.get(type)?.length || 0;
134
+ }
135
+ /**
136
+ * Get all registered event types
137
+ */
138
+ getEventTypes() {
139
+ return Array.from(this.listeners.keys());
140
+ }
141
+ // Private methods
142
+ generateId() {
143
+ return Math.random().toString(36).substr(2, 9);
144
+ }
145
+ cleanupInactiveListeners(type) {
146
+ const listeners = this.listeners.get(type);
147
+ if (listeners) {
148
+ const activeListeners = listeners.filter((reg) => reg.active);
149
+ if (activeListeners.length !== listeners.length) {
150
+ this.listeners.set(type, activeListeners);
151
+ }
152
+ }
153
+ }
154
+ }
155
+ var CellType = /* @__PURE__ */ ((CellType2) => {
156
+ CellType2["STRING"] = "string";
157
+ CellType2["NUMBER"] = "number";
158
+ CellType2["BOOLEAN"] = "boolean";
159
+ CellType2["DATE"] = "date";
160
+ CellType2["PERCENTAGE"] = "percentage";
161
+ CellType2["CURRENCY"] = "currency";
162
+ CellType2["LINK"] = "link";
163
+ CellType2["FORMULA"] = "formula";
164
+ return CellType2;
165
+ })(CellType || {});
166
+ var NumberFormat = /* @__PURE__ */ ((NumberFormat2) => {
167
+ NumberFormat2["GENERAL"] = "General";
168
+ NumberFormat2["NUMBER"] = "#,##0";
169
+ NumberFormat2["NUMBER_DECIMALS"] = "#,##0.00";
170
+ NumberFormat2["CURRENCY"] = "$#,##0.00";
171
+ NumberFormat2["CURRENCY_INTEGER"] = "$#,##0";
172
+ NumberFormat2["PERCENTAGE"] = "0%";
173
+ NumberFormat2["PERCENTAGE_DECIMALS"] = "0.00%";
174
+ NumberFormat2["DATE"] = "dd/mm/yyyy";
175
+ NumberFormat2["DATE_TIME"] = "dd/mm/yyyy hh:mm";
176
+ NumberFormat2["TIME"] = "hh:mm:ss";
177
+ NumberFormat2["CUSTOM"] = "custom";
178
+ return NumberFormat2;
179
+ })(NumberFormat || {});
180
+ var HorizontalAlignment = /* @__PURE__ */ ((HorizontalAlignment2) => {
181
+ HorizontalAlignment2["LEFT"] = "left";
182
+ HorizontalAlignment2["CENTER"] = "center";
183
+ HorizontalAlignment2["RIGHT"] = "right";
184
+ HorizontalAlignment2["FILL"] = "fill";
185
+ HorizontalAlignment2["JUSTIFY"] = "justify";
186
+ HorizontalAlignment2["CENTER_CONTINUOUS"] = "centerContinuous";
187
+ HorizontalAlignment2["DISTRIBUTED"] = "distributed";
188
+ return HorizontalAlignment2;
189
+ })(HorizontalAlignment || {});
190
+ var VerticalAlignment = /* @__PURE__ */ ((VerticalAlignment2) => {
191
+ VerticalAlignment2["TOP"] = "top";
192
+ VerticalAlignment2["MIDDLE"] = "middle";
193
+ VerticalAlignment2["BOTTOM"] = "bottom";
194
+ VerticalAlignment2["DISTRIBUTED"] = "distributed";
195
+ VerticalAlignment2["JUSTIFY"] = "justify";
196
+ return VerticalAlignment2;
197
+ })(VerticalAlignment || {});
198
+ var BorderStyle = /* @__PURE__ */ ((BorderStyle2) => {
199
+ BorderStyle2["THIN"] = "thin";
200
+ BorderStyle2["MEDIUM"] = "medium";
201
+ BorderStyle2["THICK"] = "thick";
202
+ BorderStyle2["DOTTED"] = "dotted";
203
+ BorderStyle2["DASHED"] = "dashed";
204
+ BorderStyle2["DOUBLE"] = "double";
205
+ BorderStyle2["HAIR"] = "hair";
206
+ BorderStyle2["MEDIUM_DASHED"] = "mediumDashed";
207
+ BorderStyle2["DASH_DOT"] = "dashDot";
208
+ BorderStyle2["MEDIUM_DASH_DOT"] = "mediumDashDot";
209
+ BorderStyle2["DASH_DOT_DOT"] = "dashDotDot";
210
+ BorderStyle2["MEDIUM_DASH_DOT_DOT"] = "mediumDashDotDot";
211
+ BorderStyle2["SLANT_DASH_DOT"] = "slantDashDot";
212
+ return BorderStyle2;
213
+ })(BorderStyle || {});
214
+ var FontStyle = /* @__PURE__ */ ((FontStyle2) => {
215
+ FontStyle2["NORMAL"] = "normal";
216
+ FontStyle2["BOLD"] = "bold";
217
+ FontStyle2["ITALIC"] = "italic";
218
+ FontStyle2["BOLD_ITALIC"] = "bold italic";
219
+ return FontStyle2;
220
+ })(FontStyle || {});
221
+ var ErrorType = /* @__PURE__ */ ((ErrorType2) => {
222
+ ErrorType2["VALIDATION_ERROR"] = "VALIDATION_ERROR";
223
+ ErrorType2["BUILD_ERROR"] = "BUILD_ERROR";
224
+ ErrorType2["STYLE_ERROR"] = "STYLE_ERROR";
225
+ ErrorType2["WORKSHEET_ERROR"] = "WORKSHEET_ERROR";
226
+ ErrorType2["CELL_ERROR"] = "CELL_ERROR";
227
+ return ErrorType2;
228
+ })(ErrorType || {});
229
+ class Worksheet {
230
+ config;
231
+ tables = [];
232
+ currentRow = 1;
233
+ currentCol = 1;
234
+ headerPointers = /* @__PURE__ */ new Map();
235
+ isBuilt = false;
236
+ // Estructuras temporales para la tabla actual
237
+ headers = [];
238
+ subHeaders = [];
239
+ body = [];
240
+ footers = [];
241
+ constructor(config) {
242
+ this.config = config;
243
+ }
244
+ /**
245
+ * Agrega un header principal
246
+ */
247
+ addHeader(header) {
248
+ this.headers.push(header);
249
+ return this;
250
+ }
251
+ /**
252
+ * Agrega subheaders
253
+ */
254
+ addSubHeaders(subHeaders) {
255
+ this.subHeaders.push(...subHeaders);
256
+ return this;
257
+ }
258
+ /**
259
+ * Agrega una fila de datos (puede ser jerárquica con childrens)
260
+ */
261
+ addRow(row) {
262
+ if (Array.isArray(row)) {
263
+ this.body.push(...row);
264
+ } else {
265
+ this.body.push(row);
266
+ }
267
+ return this;
268
+ }
269
+ /**
270
+ * Agrega un footer o varios
271
+ */
272
+ addFooter(footer) {
273
+ if (Array.isArray(footer)) {
274
+ this.footers.push(...footer);
275
+ } else {
276
+ this.footers.push(footer);
277
+ }
278
+ return this;
279
+ }
280
+ /**
281
+ * Construye la hoja en el workbook de ExcelJS
282
+ */
283
+ async build(workbook, _options = {}) {
284
+ const ws = workbook.addWorksheet(this.config.name, {
285
+ properties: {
286
+ defaultRowHeight: this.config.defaultRowHeight || 20,
287
+ tabColor: this.config.tabColor
288
+ },
289
+ pageSetup: this.config.pageSetup
290
+ });
291
+ let rowPointer = 1;
292
+ if (this.headers.length > 0) {
293
+ this.headers.forEach((header) => {
294
+ ws.addRow([header.value]);
295
+ if (header.mergeCell) {
296
+ ws.mergeCells(rowPointer, 1, rowPointer, this.subHeaders.length || 1);
297
+ }
298
+ if (header.styles) {
299
+ ws.getRow(rowPointer).eachCell((cell) => {
300
+ cell.style = this.convertStyle(header.styles);
301
+ });
302
+ }
303
+ rowPointer++;
304
+ });
305
+ }
306
+ if (this.subHeaders.length > 0) {
307
+ const subHeaderValues = this.subHeaders.map((sh) => sh.value);
308
+ ws.addRow(subHeaderValues);
309
+ this.subHeaders.forEach((sh, idx) => {
310
+ if (sh.styles) {
311
+ ws.getRow(rowPointer).getCell(idx + 1).style = this.convertStyle(sh.styles);
312
+ }
313
+ });
314
+ rowPointer++;
315
+ }
316
+ for (const row of this.body) {
317
+ rowPointer = this.addDataRowRecursive(ws, rowPointer, row);
318
+ }
319
+ if (this.footers.length > 0) {
320
+ for (const footer of this.footers) {
321
+ ws.addRow([footer.value]);
322
+ if (footer.mergeCell && footer.mergeTo) {
323
+ ws.mergeCells(rowPointer, 1, rowPointer, footer.mergeTo);
324
+ }
325
+ if (footer.styles) {
326
+ ws.getRow(rowPointer).eachCell((cell) => {
327
+ cell.style = this.convertStyle(footer.styles);
328
+ });
329
+ }
330
+ rowPointer++;
331
+ }
332
+ }
333
+ this.isBuilt = true;
334
+ }
335
+ /**
336
+ * Valida la hoja
337
+ */
338
+ validate() {
339
+ if (!this.headers.length && !this.body.length) {
340
+ return {
341
+ success: false,
342
+ error: {
343
+ type: ErrorType.VALIDATION_ERROR,
344
+ message: "La hoja no tiene datos"
345
+ }
346
+ };
347
+ }
348
+ return { success: true, data: true };
349
+ }
350
+ /**
351
+ * Agrega una fila de datos y sus children recursivamente
352
+ * @returns el siguiente rowPointer disponible
353
+ */
354
+ addDataRowRecursive(ws, rowPointer, row, colPointer = 1) {
355
+ const excelRow = ws.getRow(rowPointer);
356
+ const cell = excelRow.getCell(colPointer);
357
+ cell.value = row.value;
358
+ if (row.styles) {
359
+ cell.style = this.convertStyle(row.styles);
360
+ }
361
+ if (row.numberFormat) {
362
+ cell.numFmt = row.numberFormat;
363
+ }
364
+ let maxRowPointer = rowPointer;
365
+ if (row.children && row.children.length > 0) {
366
+ let childRowPointer = rowPointer;
367
+ for (const child of row.children) {
368
+ childRowPointer++;
369
+ const usedRow = this.addDataRowRecursive(ws, childRowPointer, child, colPointer + 1);
370
+ if (usedRow > maxRowPointer)
371
+ maxRowPointer = usedRow;
372
+ }
373
+ }
374
+ return maxRowPointer;
375
+ }
376
+ /**
377
+ * Convierte el estilo personalizado a formato compatible con ExcelJS
378
+ */
379
+ convertStyle(style) {
380
+ if (!style)
381
+ return {};
382
+ const converted = {};
383
+ if (style.font) {
384
+ converted.font = {
385
+ name: style.font.family,
386
+ size: style.font.size,
387
+ bold: style.font.bold,
388
+ italic: style.font.italic,
389
+ underline: style.font.underline,
390
+ color: style.font.color
391
+ };
392
+ }
393
+ if (style.fill) {
394
+ converted.fill = {
395
+ type: style.fill.type,
396
+ pattern: style.fill.pattern,
397
+ fgColor: style.fill.fgColor,
398
+ bgColor: style.fill.bgColor
399
+ };
400
+ }
401
+ if (style.border) {
402
+ converted.border = {
403
+ top: style.border.top,
404
+ left: style.border.left,
405
+ bottom: style.border.bottom,
406
+ right: style.border.right
407
+ };
408
+ }
409
+ if (style.alignment) {
410
+ converted.alignment = {
411
+ horizontal: style.alignment.horizontal,
412
+ vertical: style.alignment.vertical,
413
+ wrapText: style.alignment.wrapText,
414
+ indent: style.alignment.indent
415
+ };
416
+ }
417
+ if (style.numFmt) {
418
+ converted.numFmt = style.numFmt;
419
+ }
420
+ return converted;
421
+ }
422
+ }
423
+ var BuilderEventType = /* @__PURE__ */ ((BuilderEventType2) => {
424
+ BuilderEventType2["WORKSHEET_ADDED"] = "worksheetAdded";
425
+ BuilderEventType2["WORKSHEET_REMOVED"] = "worksheetRemoved";
426
+ BuilderEventType2["WORKSHEET_UPDATED"] = "worksheetUpdated";
427
+ BuilderEventType2["BUILD_STARTED"] = "buildStarted";
428
+ BuilderEventType2["BUILD_PROGRESS"] = "buildProgress";
429
+ BuilderEventType2["BUILD_COMPLETED"] = "buildCompleted";
430
+ BuilderEventType2["BUILD_ERROR"] = "buildError";
431
+ BuilderEventType2["DOWNLOAD_STARTED"] = "downloadStarted";
432
+ BuilderEventType2["DOWNLOAD_PROGRESS"] = "downloadProgress";
433
+ BuilderEventType2["DOWNLOAD_COMPLETED"] = "downloadCompleted";
434
+ BuilderEventType2["DOWNLOAD_ERROR"] = "downloadError";
435
+ return BuilderEventType2;
436
+ })(BuilderEventType || {});
437
+ class ExcelBuilder {
438
+ config;
439
+ worksheets = /* @__PURE__ */ new Map();
440
+ currentWorksheet;
441
+ isBuilding = false;
442
+ stats;
443
+ eventEmitter;
444
+ constructor(config = {}) {
445
+ this.config = {
446
+ enableValidation: true,
447
+ enableEvents: true,
448
+ enablePerformanceMonitoring: false,
449
+ maxWorksheets: 255,
450
+ maxRowsPerWorksheet: 1048576,
451
+ maxColumnsPerWorksheet: 16384,
452
+ memoryLimit: 100 * 1024 * 1024,
453
+ // 100MB
454
+ ...config
455
+ };
456
+ this.stats = this.initializeStats();
457
+ this.eventEmitter = new EventEmitter();
458
+ }
459
+ /**
460
+ * Add a new worksheet to the workbook
461
+ */
462
+ addWorksheet(name, worksheetConfig = {}) {
463
+ if (this.worksheets.has(name)) {
464
+ throw new Error(`Worksheet "${name}" already exists`);
465
+ }
466
+ const config = {
467
+ name,
468
+ defaultRowHeight: 20,
469
+ defaultColWidth: 10,
470
+ ...this.config.defaultWorksheetConfig,
471
+ ...worksheetConfig
472
+ };
473
+ const worksheet = new Worksheet(config);
474
+ this.worksheets.set(name, worksheet);
475
+ this.currentWorksheet = worksheet;
476
+ this.emitEvent(BuilderEventType.WORKSHEET_ADDED, { worksheetName: name });
477
+ return worksheet;
478
+ }
479
+ /**
480
+ * Get a worksheet by name
481
+ */
482
+ getWorksheet(name) {
483
+ return this.worksheets.get(name);
484
+ }
485
+ /**
486
+ * Remove a worksheet by name
487
+ */
488
+ removeWorksheet(name) {
489
+ const worksheet = this.worksheets.get(name);
490
+ if (!worksheet) {
491
+ return false;
492
+ }
493
+ this.worksheets.delete(name);
494
+ if (this.currentWorksheet === worksheet) {
495
+ this.currentWorksheet = void 0;
496
+ }
497
+ this.emitEvent(BuilderEventType.WORKSHEET_REMOVED, { worksheetName: name });
498
+ return true;
499
+ }
500
+ /**
501
+ * Set the current worksheet
502
+ */
503
+ setCurrentWorksheet(name) {
504
+ const worksheet = this.worksheets.get(name);
505
+ if (!worksheet) {
506
+ return false;
507
+ }
508
+ this.currentWorksheet = worksheet;
509
+ return true;
510
+ }
511
+ /**
512
+ * Build the workbook and return as ArrayBuffer
513
+ */
514
+ async build(options = {}) {
515
+ if (this.isBuilding) {
516
+ return {
517
+ success: false,
518
+ error: {
519
+ type: ErrorType.BUILD_ERROR,
520
+ message: "Build already in progress",
521
+ stack: new Error().stack || ""
522
+ }
523
+ };
524
+ }
525
+ this.isBuilding = true;
526
+ const startTime = Date.now();
527
+ try {
528
+ this.emitEvent(BuilderEventType.BUILD_STARTED);
529
+ const workbook = new ExcelJS.Workbook();
530
+ if (this.config.metadata) {
531
+ workbook.creator = this.config.metadata.author || "Han Excel Builder";
532
+ workbook.lastModifiedBy = this.config.metadata.author || "Han Excel Builder";
533
+ workbook.created = this.config.metadata.created || /* @__PURE__ */ new Date();
534
+ workbook.modified = this.config.metadata.modified || /* @__PURE__ */ new Date();
535
+ if (this.config.metadata.title)
536
+ workbook.title = this.config.metadata.title;
537
+ if (this.config.metadata.subject)
538
+ workbook.subject = this.config.metadata.subject;
539
+ if (this.config.metadata.keywords)
540
+ workbook.keywords = this.config.metadata.keywords;
541
+ if (this.config.metadata.category)
542
+ workbook.category = this.config.metadata.category;
543
+ if (this.config.metadata.description)
544
+ workbook.description = this.config.metadata.description;
545
+ }
546
+ for (const worksheet of this.worksheets.values()) {
547
+ await worksheet.build(workbook, options);
548
+ }
549
+ const buffer = await workbook.xlsx.writeBuffer({
550
+ compression: options.compressionLevel || 6
551
+ });
552
+ const endTime = Date.now();
553
+ this.stats.buildTime = endTime - startTime;
554
+ this.stats.fileSize = buffer.byteLength;
555
+ const successResult = {
556
+ success: true,
557
+ data: buffer
558
+ };
559
+ this.emitEvent(BuilderEventType.BUILD_COMPLETED, {
560
+ buildTime: this.stats.buildTime,
561
+ fileSize: this.stats.fileSize
562
+ });
563
+ return successResult;
564
+ } catch (error) {
565
+ const errorResult = {
566
+ success: false,
567
+ error: {
568
+ type: ErrorType.BUILD_ERROR,
569
+ message: error instanceof Error ? error.message : "Unknown build error",
570
+ stack: error instanceof Error ? error.stack || "" : ""
571
+ }
572
+ };
573
+ this.emitEvent(BuilderEventType.BUILD_ERROR, { error: errorResult.error });
574
+ return errorResult;
575
+ } finally {
576
+ this.isBuilding = false;
577
+ }
578
+ }
579
+ /**
580
+ * Generate and download the file
581
+ */
582
+ async generateAndDownload(fileName, options = {}) {
583
+ const buildResult = await this.build(options);
584
+ if (!buildResult.success) {
585
+ return buildResult;
586
+ }
587
+ try {
588
+ this.emitEvent(BuilderEventType.DOWNLOAD_STARTED, { fileName });
589
+ const blob = new Blob([buildResult.data], {
590
+ type: options.mimeType || "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
591
+ });
592
+ saveAs(blob, fileName);
593
+ this.emitEvent(BuilderEventType.DOWNLOAD_COMPLETED, { fileName });
594
+ return { success: true, data: void 0 };
595
+ } catch (error) {
596
+ const errorResult = {
597
+ success: false,
598
+ error: {
599
+ type: ErrorType.BUILD_ERROR,
600
+ message: error instanceof Error ? error.message : "Download failed",
601
+ stack: error instanceof Error ? error.stack || "" : ""
602
+ }
603
+ };
604
+ this.emitEvent(BuilderEventType.DOWNLOAD_ERROR, { error: errorResult.error });
605
+ return errorResult;
606
+ }
607
+ }
608
+ /**
609
+ * Get workbook as buffer
610
+ */
611
+ async toBuffer(options = {}) {
612
+ return this.build(options);
613
+ }
614
+ /**
615
+ * Get workbook as blob
616
+ */
617
+ async toBlob(options = {}) {
618
+ const buildResult = await this.build(options);
619
+ if (!buildResult.success) {
620
+ return buildResult;
621
+ }
622
+ const blob = new Blob([buildResult.data], {
623
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
624
+ });
625
+ return { success: true, data: blob };
626
+ }
627
+ /**
628
+ * Validate the workbook
629
+ */
630
+ validate() {
631
+ const errors = [];
632
+ if (this.worksheets.size === 0) {
633
+ errors.push("No worksheets found");
634
+ }
635
+ for (const [name, worksheet] of this.worksheets.entries()) {
636
+ const worksheetValidation = worksheet.validate();
637
+ if (!worksheetValidation.success) {
638
+ errors.push(`Worksheet "${name}": ${worksheetValidation.error?.message}`);
639
+ }
640
+ }
641
+ if (errors.length > 0) {
642
+ return {
643
+ success: false,
644
+ error: {
645
+ type: ErrorType.VALIDATION_ERROR,
646
+ message: errors.join("; "),
647
+ stack: new Error().stack || ""
648
+ }
649
+ };
650
+ }
651
+ return { success: true, data: true };
652
+ }
653
+ /**
654
+ * Clear all worksheets
655
+ */
656
+ clear() {
657
+ this.worksheets.clear();
658
+ this.currentWorksheet = void 0;
659
+ }
660
+ /**
661
+ * Get workbook statistics
662
+ */
663
+ getStats() {
664
+ return { ...this.stats };
665
+ }
666
+ /**
667
+ * Event handling methods
668
+ */
669
+ on(eventType, listener) {
670
+ return this.eventEmitter.on(eventType, listener);
671
+ }
672
+ off(eventType, listenerId) {
673
+ return this.eventEmitter.off(eventType, listenerId);
674
+ }
675
+ removeAllListeners(eventType) {
676
+ if (eventType) {
677
+ this.eventEmitter.offAll(eventType);
678
+ } else {
679
+ this.eventEmitter.clear();
680
+ }
681
+ }
682
+ /**
683
+ * Private methods
684
+ */
685
+ emitEvent(type, data) {
686
+ const event = {
687
+ type,
688
+ data: data || {},
689
+ timestamp: /* @__PURE__ */ new Date()
690
+ };
691
+ this.eventEmitter.emitSync(event);
692
+ }
693
+ initializeStats() {
694
+ return {
695
+ totalWorksheets: 0,
696
+ totalCells: 0,
697
+ memoryUsage: 0,
698
+ buildTime: 0,
699
+ fileSize: 0,
700
+ stylesUsed: 0,
701
+ formulasUsed: 0,
702
+ conditionalFormatsUsed: 0,
703
+ performance: {
704
+ headersTime: 0,
705
+ dataTime: 0,
706
+ stylesTime: 0,
707
+ writeTime: 0
708
+ }
709
+ };
710
+ }
711
+ }
712
+ class StyleBuilder {
713
+ style = {};
714
+ /**
715
+ * Create a new StyleBuilder instance
716
+ */
717
+ static create() {
718
+ return new StyleBuilder();
719
+ }
720
+ /**
721
+ * Set font name
722
+ */
723
+ fontName(name) {
724
+ if (!this.style.font) {
725
+ this.style.font = {};
726
+ }
727
+ this.style.font.name = name;
728
+ return this;
729
+ }
730
+ /**
731
+ * Set font size
732
+ */
733
+ fontSize(size) {
734
+ if (!this.style.font) {
735
+ this.style.font = {};
736
+ }
737
+ this.style.font.size = size;
738
+ return this;
739
+ }
740
+ /**
741
+ * Set font style
742
+ */
743
+ fontStyle(style) {
744
+ if (!this.style.font) {
745
+ this.style.font = {};
746
+ }
747
+ this.style.font.style = style;
748
+ return this;
749
+ }
750
+ /**
751
+ * Set font color
752
+ */
753
+ fontColor(color) {
754
+ if (!this.style.font) {
755
+ this.style.font = {};
756
+ }
757
+ this.style.font.color = color;
758
+ return this;
759
+ }
760
+ /**
761
+ * Make font bold
762
+ */
763
+ fontBold() {
764
+ if (!this.style.font) {
765
+ this.style.font = {};
766
+ }
767
+ this.style.font.bold = true;
768
+ return this;
769
+ }
770
+ /**
771
+ * Make font italic
772
+ */
773
+ fontItalic() {
774
+ if (!this.style.font) {
775
+ this.style.font = {};
776
+ }
777
+ this.style.font.italic = true;
778
+ return this;
779
+ }
780
+ /**
781
+ * Make font underlined
782
+ */
783
+ fontUnderline() {
784
+ if (!this.style.font) {
785
+ this.style.font = {};
786
+ }
787
+ this.style.font.underline = true;
788
+ return this;
789
+ }
790
+ /**
791
+ * Set border on all sides
792
+ */
793
+ border(style, color) {
794
+ if (!this.style.border) {
795
+ this.style.border = {};
796
+ }
797
+ const border = { style };
798
+ if (color !== void 0) {
799
+ border.color = color;
800
+ }
801
+ this.style.border.top = border;
802
+ this.style.border.left = border;
803
+ this.style.border.bottom = border;
804
+ this.style.border.right = border;
805
+ return this;
806
+ }
807
+ /**
808
+ * Set top border
809
+ */
810
+ borderTop(style, color) {
811
+ if (!this.style.border) {
812
+ this.style.border = {};
813
+ }
814
+ const border = { style };
815
+ if (color !== void 0) {
816
+ border.color = color;
817
+ }
818
+ this.style.border.top = border;
819
+ return this;
820
+ }
821
+ /**
822
+ * Set left border
823
+ */
824
+ borderLeft(style, color) {
825
+ if (!this.style.border) {
826
+ this.style.border = {};
827
+ }
828
+ const border = { style };
829
+ if (color !== void 0) {
830
+ border.color = color;
831
+ }
832
+ this.style.border.left = border;
833
+ return this;
834
+ }
835
+ /**
836
+ * Set bottom border
837
+ */
838
+ borderBottom(style, color) {
839
+ if (!this.style.border) {
840
+ this.style.border = {};
841
+ }
842
+ const border = { style };
843
+ if (color !== void 0) {
844
+ border.color = color;
845
+ }
846
+ this.style.border.bottom = border;
847
+ return this;
848
+ }
849
+ /**
850
+ * Set right border
851
+ */
852
+ borderRight(style, color) {
853
+ if (!this.style.border) {
854
+ this.style.border = {};
855
+ }
856
+ const border = { style };
857
+ if (color !== void 0) {
858
+ border.color = color;
859
+ }
860
+ this.style.border.right = border;
861
+ return this;
862
+ }
863
+ /**
864
+ * Set background color
865
+ */
866
+ backgroundColor(color) {
867
+ if (!this.style.fill) {
868
+ this.style.fill = { type: "pattern" };
869
+ }
870
+ this.style.fill.backgroundColor = color;
871
+ this.style.fill.pattern = "solid";
872
+ return this;
873
+ }
874
+ /**
875
+ * Set horizontal alignment
876
+ */
877
+ horizontalAlign(alignment) {
878
+ if (!this.style.alignment) {
879
+ this.style.alignment = {};
880
+ }
881
+ this.style.alignment.horizontal = alignment;
882
+ return this;
883
+ }
884
+ /**
885
+ * Set vertical alignment
886
+ */
887
+ verticalAlign(alignment) {
888
+ if (!this.style.alignment) {
889
+ this.style.alignment = {};
890
+ }
891
+ this.style.alignment.vertical = alignment;
892
+ return this;
893
+ }
894
+ /**
895
+ * Center align text
896
+ */
897
+ centerAlign() {
898
+ if (!this.style.alignment) {
899
+ this.style.alignment = {};
900
+ }
901
+ this.style.alignment.horizontal = HorizontalAlignment.CENTER;
902
+ this.style.alignment.vertical = VerticalAlignment.MIDDLE;
903
+ return this;
904
+ }
905
+ /**
906
+ * Left align text
907
+ */
908
+ leftAlign() {
909
+ if (!this.style.alignment) {
910
+ this.style.alignment = {};
911
+ }
912
+ this.style.alignment.horizontal = HorizontalAlignment.LEFT;
913
+ return this;
914
+ }
915
+ /**
916
+ * Right align text
917
+ */
918
+ rightAlign() {
919
+ if (!this.style.alignment) {
920
+ this.style.alignment = {};
921
+ }
922
+ this.style.alignment.horizontal = HorizontalAlignment.RIGHT;
923
+ return this;
924
+ }
925
+ /**
926
+ * Wrap text
927
+ */
928
+ wrapText() {
929
+ if (!this.style.alignment) {
930
+ this.style.alignment = {};
931
+ }
932
+ this.style.alignment.wrapText = true;
933
+ return this;
934
+ }
935
+ /**
936
+ * Set number format
937
+ */
938
+ numberFormat(format) {
939
+ this.style.numberFormat = format;
940
+ return this;
941
+ }
942
+ /**
943
+ * Set striped rows
944
+ */
945
+ striped() {
946
+ this.style.striped = true;
947
+ return this;
948
+ }
949
+ /**
950
+ * Add conditional formatting
951
+ */
952
+ conditionalFormat(format) {
953
+ if (!this.style.conditionalFormats) {
954
+ this.style.conditionalFormats = [];
955
+ }
956
+ this.style.conditionalFormats.push(format);
957
+ return this;
958
+ }
959
+ /**
960
+ * Build the final style
961
+ */
962
+ build() {
963
+ return this.style;
964
+ }
965
+ /**
966
+ * Reset the builder
967
+ */
968
+ reset() {
969
+ this.style = {};
970
+ return this;
971
+ }
972
+ /**
973
+ * Clone the current style
974
+ */
975
+ clone() {
976
+ const cloned = new StyleBuilder();
977
+ cloned.style = JSON.parse(JSON.stringify(this.style));
978
+ return cloned;
979
+ }
980
+ }
981
+ var CellEventType = /* @__PURE__ */ ((CellEventType2) => {
982
+ CellEventType2["CREATED"] = "created";
983
+ CellEventType2["UPDATED"] = "updated";
984
+ CellEventType2["DELETED"] = "deleted";
985
+ CellEventType2["STYLED"] = "styled";
986
+ CellEventType2["VALIDATED"] = "validated";
987
+ return CellEventType2;
988
+ })(CellEventType || {});
989
+ var WorksheetEventType = /* @__PURE__ */ ((WorksheetEventType2) => {
990
+ WorksheetEventType2["CREATED"] = "created";
991
+ WorksheetEventType2["UPDATED"] = "updated";
992
+ WorksheetEventType2["DELETED"] = "deleted";
993
+ WorksheetEventType2["TABLE_ADDED"] = "tableAdded";
994
+ WorksheetEventType2["TABLE_REMOVED"] = "tableRemoved";
995
+ WorksheetEventType2["CELL_ADDED"] = "cellAdded";
996
+ WorksheetEventType2["CELL_UPDATED"] = "cellUpdated";
997
+ WorksheetEventType2["CELL_DELETED"] = "cellDeleted";
998
+ return WorksheetEventType2;
999
+ })(WorksheetEventType || {});
1000
+ var StylePreset = /* @__PURE__ */ ((StylePreset2) => {
1001
+ StylePreset2["HEADER"] = "header";
1002
+ StylePreset2["SUBHEADER"] = "subheader";
1003
+ StylePreset2["DATA"] = "data";
1004
+ StylePreset2["FOOTER"] = "footer";
1005
+ StylePreset2["TOTAL"] = "total";
1006
+ StylePreset2["HIGHLIGHT"] = "highlight";
1007
+ StylePreset2["WARNING"] = "warning";
1008
+ StylePreset2["ERROR"] = "error";
1009
+ StylePreset2["SUCCESS"] = "success";
1010
+ StylePreset2["INFO"] = "info";
1011
+ return StylePreset2;
1012
+ })(StylePreset || {});
1013
+ export {
1014
+ BorderStyle,
1015
+ BuilderEventType,
1016
+ CellEventType,
1017
+ CellType,
1018
+ ErrorType,
1019
+ EventEmitter,
1020
+ ExcelBuilder,
1021
+ FontStyle,
1022
+ HorizontalAlignment,
1023
+ NumberFormat,
1024
+ StyleBuilder,
1025
+ StylePreset,
1026
+ VerticalAlignment,
1027
+ Worksheet,
1028
+ WorksheetEventType,
1029
+ ExcelBuilder as default
1030
+ };
1031
+ //# sourceMappingURL=han-excel.es.js.map