@cj-tech-master/excelts 1.5.0 → 1.6.1

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.
Files changed (45) hide show
  1. package/dist/browser/excelts.iife.js +1057 -201
  2. package/dist/browser/excelts.iife.js.map +1 -1
  3. package/dist/browser/excelts.iife.min.js +63 -33
  4. package/dist/cjs/doc/column.js +7 -3
  5. package/dist/cjs/doc/pivot-table.js +149 -61
  6. package/dist/cjs/doc/workbook.js +3 -1
  7. package/dist/cjs/doc/worksheet.js +0 -2
  8. package/dist/cjs/stream/xlsx/worksheet-writer.js +1 -1
  9. package/dist/cjs/utils/unzip/zip-parser.js +2 -5
  10. package/dist/cjs/xlsx/xform/book/workbook-xform.js +3 -0
  11. package/dist/cjs/xlsx/xform/core/content-types-xform.js +19 -14
  12. package/dist/cjs/xlsx/xform/pivot-table/cache-field-xform.js +135 -0
  13. package/dist/cjs/xlsx/xform/pivot-table/cache-field.js +7 -4
  14. package/dist/cjs/xlsx/xform/pivot-table/pivot-cache-definition-xform.js +135 -13
  15. package/dist/cjs/xlsx/xform/pivot-table/pivot-cache-records-xform.js +193 -45
  16. package/dist/cjs/xlsx/xform/pivot-table/pivot-table-xform.js +390 -39
  17. package/dist/cjs/xlsx/xform/sheet/cell-xform.js +6 -0
  18. package/dist/cjs/xlsx/xform/sheet/worksheet-xform.js +14 -3
  19. package/dist/cjs/xlsx/xlsx.js +261 -38
  20. package/dist/esm/doc/column.js +7 -3
  21. package/dist/esm/doc/pivot-table.js +150 -62
  22. package/dist/esm/doc/workbook.js +3 -1
  23. package/dist/esm/doc/worksheet.js +0 -2
  24. package/dist/esm/stream/xlsx/worksheet-writer.js +1 -1
  25. package/dist/esm/utils/unzip/zip-parser.js +2 -5
  26. package/dist/esm/xlsx/xform/book/workbook-xform.js +3 -0
  27. package/dist/esm/xlsx/xform/core/content-types-xform.js +19 -14
  28. package/dist/esm/xlsx/xform/pivot-table/cache-field-xform.js +132 -0
  29. package/dist/esm/xlsx/xform/pivot-table/cache-field.js +7 -4
  30. package/dist/esm/xlsx/xform/pivot-table/pivot-cache-definition-xform.js +135 -13
  31. package/dist/esm/xlsx/xform/pivot-table/pivot-cache-records-xform.js +193 -45
  32. package/dist/esm/xlsx/xform/pivot-table/pivot-table-xform.js +390 -39
  33. package/dist/esm/xlsx/xform/sheet/cell-xform.js +6 -0
  34. package/dist/esm/xlsx/xform/sheet/worksheet-xform.js +14 -3
  35. package/dist/esm/xlsx/xlsx.js +261 -38
  36. package/dist/types/doc/column.d.ts +13 -6
  37. package/dist/types/doc/pivot-table.d.ts +135 -9
  38. package/dist/types/doc/workbook.d.ts +2 -0
  39. package/dist/types/index.d.ts +1 -0
  40. package/dist/types/xlsx/xform/pivot-table/cache-field-xform.d.ts +42 -0
  41. package/dist/types/xlsx/xform/pivot-table/pivot-cache-definition-xform.d.ts +45 -6
  42. package/dist/types/xlsx/xform/pivot-table/pivot-cache-records-xform.d.ts +52 -5
  43. package/dist/types/xlsx/xform/pivot-table/pivot-table-xform.d.ts +98 -5
  44. package/dist/types/xlsx/xlsx.d.ts +27 -0
  45. package/package.json +17 -17
@@ -111,6 +111,8 @@ class XLSX {
111
111
  Object.values(model.tables).forEach((table) => {
112
112
  tableXform.reconcile(table, tableOptions);
113
113
  });
114
+ // Reconcile pivot tables - link pivot tables to worksheets and cache data
115
+ this._reconcilePivotTables(model);
114
116
  const sheetOptions = {
115
117
  styles: model.styles,
116
118
  sharedStrings: model.sharedStrings,
@@ -120,7 +122,8 @@ class XLSX {
120
122
  drawings: model.drawings,
121
123
  comments: model.comments,
122
124
  tables: model.tables,
123
- vmlDrawings: model.vmlDrawings
125
+ vmlDrawings: model.vmlDrawings,
126
+ pivotTables: model.pivotTablesIndexed
124
127
  };
125
128
  model.worksheets.forEach((worksheet) => {
126
129
  worksheet.relationships = model.worksheetRels[worksheet.sheetNo];
@@ -138,6 +141,136 @@ class XLSX {
138
141
  delete model.drawings;
139
142
  delete model.drawingRels;
140
143
  delete model.vmlDrawings;
144
+ // Clean up raw pivot table data after reconciliation
145
+ delete model.pivotTableRels;
146
+ delete model.pivotCacheDefinitionRels;
147
+ }
148
+ /**
149
+ * Reconcile pivot tables by linking them to worksheets and their cache data.
150
+ * This builds a complete pivot table model ready for writing.
151
+ */
152
+ _reconcilePivotTables(model) {
153
+ // Skip if no pivot tables were loaded (object is empty or undefined)
154
+ const rawPivotTables = model.pivotTables || {};
155
+ if (typeof rawPivotTables !== "object" || Object.keys(rawPivotTables).length === 0) {
156
+ // Ensure pivotTables is an empty array (not an object)
157
+ model.pivotTables = [];
158
+ // Also create an empty indexed object for worksheet reconciliation
159
+ model.pivotTablesIndexed = {};
160
+ return;
161
+ }
162
+ // Build mapping from definition name to cacheId
163
+ const definitionToCacheId = this._buildDefinitionToCacheIdMap(model);
164
+ // Build a map of cache IDs to their definitions and records
165
+ const cacheMap = new Map();
166
+ // Process cache definitions
167
+ Object.entries(model.pivotCacheDefinitions || {}).forEach(([name, definition]) => {
168
+ // Get the cacheId from the mapping (derived from workbook.xml pivotCaches)
169
+ const cacheId = definitionToCacheId.get(name);
170
+ if (cacheId !== undefined) {
171
+ const recordsName = name.replace("Definition", "Records");
172
+ cacheMap.set(cacheId, {
173
+ definition,
174
+ records: model.pivotCacheRecords?.[recordsName],
175
+ definitionName: name
176
+ });
177
+ }
178
+ });
179
+ // Process pivot tables and link to worksheets
180
+ const loadedPivotTables = [];
181
+ // Create indexed object for worksheet reconciliation (keyed by relative path)
182
+ const pivotTablesIndexed = {};
183
+ Object.entries(rawPivotTables).forEach(([pivotName, pivotTable]) => {
184
+ const pt = pivotTable;
185
+ const tableNumber = this._extractTableNumber(pivotName);
186
+ // Get cache data for this pivot table
187
+ const cacheData = cacheMap.get(pt.cacheId);
188
+ // Build complete pivot table model
189
+ const completePivotTable = {
190
+ // Core model data
191
+ ...pt,
192
+ tableNumber,
193
+ // Link to cache data
194
+ cacheDefinition: cacheData?.definition,
195
+ cacheRecords: cacheData?.records,
196
+ // Reconstruct cacheFields from definition for compatibility
197
+ cacheFields: cacheData?.definition?.cacheFields || [],
198
+ // Determine rows, columns, values from parsed data
199
+ rows: pt.rowFields.filter(f => f >= 0),
200
+ columns: pt.colFields.filter(f => f >= 0 && f !== -2),
201
+ values: pt.dataFields.map(df => df.fld),
202
+ // Determine metric from dataFields
203
+ metric: this._determineMetric(pt.dataFields),
204
+ // Preserve formatting options
205
+ applyWidthHeightFormats: pt.applyWidthHeightFormats || "0"
206
+ };
207
+ loadedPivotTables.push(completePivotTable);
208
+ // Index by relative path for worksheet reconciliation
209
+ pivotTablesIndexed[`../pivotTables/${pivotName}.xml`] = completePivotTable;
210
+ });
211
+ // Sort by table number to maintain order
212
+ loadedPivotTables.sort((a, b) => a.tableNumber - b.tableNumber);
213
+ // Replace pivotTables object with the processed array
214
+ // This is what the Workbook model setter expects
215
+ model.pivotTables = loadedPivotTables;
216
+ // Also keep indexed version for worksheet reconciliation
217
+ model.pivotTablesIndexed = pivotTablesIndexed;
218
+ // Also keep as loadedPivotTables for backward compatibility
219
+ model.loadedPivotTables = loadedPivotTables;
220
+ }
221
+ /**
222
+ * Extract table number from pivot table name (e.g., "pivotTable1" -> 1)
223
+ */
224
+ _extractTableNumber(name) {
225
+ const match = name.match(/pivotTable(\d+)/);
226
+ return match ? parseInt(match[1], 10) : 1;
227
+ }
228
+ /**
229
+ * Build a mapping from rId to cacheId using pivotCaches from workbook.xml
230
+ * and workbookRels to determine which definition file corresponds to which cacheId
231
+ */
232
+ _buildCacheIdMap(model) {
233
+ const rIdToCacheId = new Map();
234
+ // pivotCaches from workbook.xml contains {cacheId, rId} mappings
235
+ const pivotCaches = model.pivotCaches || [];
236
+ for (const cache of pivotCaches) {
237
+ if (cache.cacheId && cache.rId) {
238
+ rIdToCacheId.set(cache.rId, parseInt(cache.cacheId, 10));
239
+ }
240
+ }
241
+ return rIdToCacheId;
242
+ }
243
+ /**
244
+ * Build a mapping from definition name to cacheId
245
+ */
246
+ _buildDefinitionToCacheIdMap(model) {
247
+ const definitionToCacheId = new Map();
248
+ const rIdToCacheId = this._buildCacheIdMap(model);
249
+ const workbookRels = model.workbookRels || [];
250
+ // Map workbook rels to get definitionNumber -> cacheId mapping
251
+ for (const rel of workbookRels) {
252
+ if (rel.Type === XLSX.RelType.PivotCacheDefinition && rel.Target) {
253
+ // Extract definition number from target (e.g., "pivotCache/pivotCacheDefinition1.xml" -> 1)
254
+ const match = rel.Target.match(/pivotCacheDefinition(\d+)\.xml/);
255
+ if (match) {
256
+ const defName = `pivotCacheDefinition${match[1]}`;
257
+ const cacheId = rIdToCacheId.get(rel.Id);
258
+ if (cacheId !== undefined) {
259
+ definitionToCacheId.set(defName, cacheId);
260
+ }
261
+ }
262
+ }
263
+ }
264
+ return definitionToCacheId;
265
+ }
266
+ /**
267
+ * Determine the aggregation metric from dataFields
268
+ */
269
+ _determineMetric(dataFields) {
270
+ if (dataFields.length > 0 && dataFields[0].subtotal === "count") {
271
+ return "count";
272
+ }
273
+ return "sum";
141
274
  }
142
275
  async _processWorksheetEntry(stream, model, sheetNo, options, path) {
143
276
  const xform = new worksheet_xform_js_1.WorkSheetXform(options);
@@ -240,6 +373,37 @@ class XLSX {
240
373
  stream.pipe(streamBuf);
241
374
  });
242
375
  }
376
+ async _processPivotTableEntry(stream, model, name) {
377
+ const xform = new pivot_table_xform_js_1.PivotTableXform();
378
+ const pivotTable = await xform.parseStream(stream);
379
+ if (pivotTable) {
380
+ model.pivotTables[name] = pivotTable;
381
+ }
382
+ }
383
+ async _processPivotTableRelsEntry(stream, model, name) {
384
+ const xform = new relationships_xform_js_1.RelationshipsXform();
385
+ const relationships = await xform.parseStream(stream);
386
+ model.pivotTableRels[name] = relationships;
387
+ }
388
+ async _processPivotCacheDefinitionEntry(stream, model, name) {
389
+ const xform = new pivot_cache_definition_xform_js_1.PivotCacheDefinitionXform();
390
+ const cacheDefinition = await xform.parseStream(stream);
391
+ if (cacheDefinition) {
392
+ model.pivotCacheDefinitions[name] = cacheDefinition;
393
+ }
394
+ }
395
+ async _processPivotCacheDefinitionRelsEntry(stream, model, name) {
396
+ const xform = new relationships_xform_js_1.RelationshipsXform();
397
+ const relationships = await xform.parseStream(stream);
398
+ model.pivotCacheDefinitionRels[name] = relationships;
399
+ }
400
+ async _processPivotCacheRecordsEntry(stream, model, name) {
401
+ const xform = new pivot_cache_records_xform_js_1.PivotCacheRecordsXform();
402
+ const cacheRecords = await xform.parseStream(stream);
403
+ if (cacheRecords) {
404
+ model.pivotCacheRecords[name] = cacheRecords;
405
+ }
406
+ }
243
407
  async read(stream, options) {
244
408
  // Use streaming unzip with fflate
245
409
  const allFiles = {};
@@ -349,7 +513,13 @@ class XLSX {
349
513
  drawingRels: {},
350
514
  comments: {},
351
515
  tables: {},
352
- vmlDrawings: {}
516
+ vmlDrawings: {},
517
+ // Pivot table storage for loaded files
518
+ pivotTables: {},
519
+ pivotTableRels: {},
520
+ pivotCacheDefinitions: {},
521
+ pivotCacheDefinitionRels: {},
522
+ pivotCacheRecords: {}
353
523
  };
354
524
  // Convert fflate format to JSZip-like structure for compatibility
355
525
  const entries = Object.keys(zipData).map(name => ({
@@ -397,6 +567,9 @@ class XLSX {
397
567
  model.views = workbook.views;
398
568
  model.properties = workbook.properties;
399
569
  model.calcProperties = workbook.calcProperties;
570
+ // pivotCaches contains the mapping from rId to cacheId
571
+ // needed for linking pivot tables to their cache data
572
+ model.pivotCaches = workbook.pivotCaches;
400
573
  break;
401
574
  }
402
575
  case "xl/sharedStrings.xml":
@@ -465,6 +638,33 @@ class XLSX {
465
638
  await this._processThemeEntry(stream, model, match[1]);
466
639
  break;
467
640
  }
641
+ // Pivot table files
642
+ match = entryName.match(/xl\/pivotTables\/(pivotTable\d+)[.]xml/);
643
+ if (match) {
644
+ await this._processPivotTableEntry(stream, model, match[1]);
645
+ break;
646
+ }
647
+ match = entryName.match(/xl\/pivotTables\/_rels\/(pivotTable\d+)[.]xml[.]rels/);
648
+ if (match) {
649
+ await this._processPivotTableRelsEntry(stream, model, match[1]);
650
+ break;
651
+ }
652
+ // Pivot cache files
653
+ match = entryName.match(/xl\/pivotCache\/(pivotCacheDefinition\d+)[.]xml/);
654
+ if (match) {
655
+ await this._processPivotCacheDefinitionEntry(stream, model, match[1]);
656
+ break;
657
+ }
658
+ match = entryName.match(/xl\/pivotCache\/_rels\/(pivotCacheDefinition\d+)[.]xml[.]rels/);
659
+ if (match) {
660
+ await this._processPivotCacheDefinitionRelsEntry(stream, model, match[1]);
661
+ break;
662
+ }
663
+ match = entryName.match(/xl\/pivotCache\/(pivotCacheRecords\d+)[.]xml/);
664
+ if (match) {
665
+ await this._processPivotCacheRecordsEntry(stream, model, match[1]);
666
+ break;
667
+ }
468
668
  }
469
669
  }
470
670
  }
@@ -521,21 +721,24 @@ class XLSX {
521
721
  Target: "sharedStrings.xml"
522
722
  });
523
723
  }
524
- if ((model.pivotTables || []).length) {
525
- const pivotTable = model.pivotTables[0];
724
+ // Add relationships for all pivot tables
725
+ (model.pivotTables || []).forEach((pivotTable) => {
526
726
  pivotTable.rId = `rId${count++}`;
527
727
  relationships.push({
528
728
  Id: pivotTable.rId,
529
729
  Type: XLSX.RelType.PivotCacheDefinition,
530
- Target: "pivotCache/pivotCacheDefinition1.xml"
730
+ Target: `pivotCache/pivotCacheDefinition${pivotTable.tableNumber}.xml`
531
731
  });
532
- }
533
- model.worksheets.forEach((worksheet) => {
732
+ });
733
+ model.worksheets.forEach((worksheet, index) => {
734
+ // Use sequential index (1-based) for file naming, not worksheet.id (sheetId)
735
+ // sheetId can be non-sequential (e.g., 1, 3, 5) which would create gaps in filenames
534
736
  worksheet.rId = `rId${count++}`;
737
+ worksheet.fileIndex = index + 1; // Store for use in addWorksheets and content types
535
738
  relationships.push({
536
739
  Id: worksheet.rId,
537
740
  Type: XLSX.RelType.Worksheet,
538
- Target: `worksheets/sheet${worksheet.id}.xml`
741
+ Target: `worksheets/sheet${worksheet.fileIndex}.xml`
539
742
  });
540
743
  });
541
744
  const xform = new relationships_xform_js_1.RelationshipsXform();
@@ -564,22 +767,24 @@ class XLSX {
564
767
  const commentsXform = new comments_xform_js_1.CommentsXform();
565
768
  const vmlNotesXform = new vml_notes_xform_js_1.VmlNotesXform();
566
769
  // write sheets
567
- model.worksheets.forEach((worksheet) => {
770
+ model.worksheets.forEach((worksheet, index) => {
771
+ // Use fileIndex if set by addWorkbookRels, otherwise use index + 1
772
+ const fileIndex = worksheet.fileIndex || index + 1;
568
773
  let xmlStream = new xml_stream_js_1.XmlStream();
569
774
  worksheetXform.render(xmlStream, worksheet);
570
- zip.append(xmlStream.xml, { name: `xl/worksheets/sheet${worksheet.id}.xml` });
775
+ zip.append(xmlStream.xml, { name: `xl/worksheets/sheet${fileIndex}.xml` });
571
776
  if (worksheet.rels && worksheet.rels.length) {
572
777
  xmlStream = new xml_stream_js_1.XmlStream();
573
778
  relationshipsXform.render(xmlStream, worksheet.rels);
574
- zip.append(xmlStream.xml, { name: `xl/worksheets/_rels/sheet${worksheet.id}.xml.rels` });
779
+ zip.append(xmlStream.xml, { name: `xl/worksheets/_rels/sheet${fileIndex}.xml.rels` });
575
780
  }
576
781
  if (worksheet.comments.length > 0) {
577
782
  xmlStream = new xml_stream_js_1.XmlStream();
578
783
  commentsXform.render(xmlStream, worksheet);
579
- zip.append(xmlStream.xml, { name: `xl/comments${worksheet.id}.xml` });
784
+ zip.append(xmlStream.xml, { name: `xl/comments${fileIndex}.xml` });
580
785
  xmlStream = new xml_stream_js_1.XmlStream();
581
786
  vmlNotesXform.render(xmlStream, worksheet);
582
- zip.append(xmlStream.xml, { name: `xl/drawings/vmlDrawing${worksheet.id}.vml` });
787
+ zip.append(xmlStream.xml, { name: `xl/drawings/vmlDrawing${fileIndex}.vml` });
583
788
  }
584
789
  });
585
790
  }
@@ -632,37 +837,55 @@ class XLSX {
632
837
  if (!model.pivotTables.length) {
633
838
  return;
634
839
  }
635
- const pivotTable = model.pivotTables[0];
636
840
  const pivotCacheRecordsXform = new pivot_cache_records_xform_js_1.PivotCacheRecordsXform();
637
841
  const pivotCacheDefinitionXform = new pivot_cache_definition_xform_js_1.PivotCacheDefinitionXform();
638
842
  const pivotTableXform = new pivot_table_xform_js_1.PivotTableXform();
639
843
  const relsXform = new relationships_xform_js_1.RelationshipsXform();
640
- // pivot cache records
641
- let xml = pivotCacheRecordsXform.toXml(pivotTable);
642
- zip.append(xml, { name: "xl/pivotCache/pivotCacheRecords1.xml" });
643
- // pivot cache definition
644
- xml = pivotCacheDefinitionXform.toXml(pivotTable);
645
- zip.append(xml, { name: "xl/pivotCache/pivotCacheDefinition1.xml" });
646
- // pivot cache definition rels
647
- xml = relsXform.toXml([
648
- {
649
- Id: "rId1",
650
- Type: XLSX.RelType.PivotCacheRecords,
651
- Target: "pivotCacheRecords1.xml"
844
+ // Generate files for each pivot table
845
+ model.pivotTables.forEach((pivotTable) => {
846
+ const n = pivotTable.tableNumber;
847
+ // For loaded pivot tables, use the stored cache data
848
+ // For new pivot tables, use the source data
849
+ const isLoaded = pivotTable.isLoaded;
850
+ if (isLoaded) {
851
+ // Loaded pivot table - use stored cache definition and records
852
+ if (pivotTable.cacheDefinition) {
853
+ const xml = pivotCacheDefinitionXform.toXml(pivotTable.cacheDefinition);
854
+ zip.append(xml, { name: `xl/pivotCache/pivotCacheDefinition${n}.xml` });
855
+ }
856
+ if (pivotTable.cacheRecords) {
857
+ const xml = pivotCacheRecordsXform.toXml(pivotTable.cacheRecords);
858
+ zip.append(xml, { name: `xl/pivotCache/pivotCacheRecords${n}.xml` });
859
+ }
652
860
  }
653
- ]);
654
- zip.append(xml, { name: "xl/pivotCache/_rels/pivotCacheDefinition1.xml.rels" });
655
- // pivot table
656
- xml = pivotTableXform.toXml(pivotTable);
657
- zip.append(xml, { name: "xl/pivotTables/pivotTable1.xml" });
658
- xml = relsXform.toXml([
659
- {
660
- Id: "rId1",
661
- Type: XLSX.RelType.PivotCacheDefinition,
662
- Target: "../pivotCache/pivotCacheDefinition1.xml"
861
+ else {
862
+ // New pivot table - generate from source
863
+ let xml = pivotCacheRecordsXform.toXml(pivotTable);
864
+ zip.append(xml, { name: `xl/pivotCache/pivotCacheRecords${n}.xml` });
865
+ xml = pivotCacheDefinitionXform.toXml(pivotTable);
866
+ zip.append(xml, { name: `xl/pivotCache/pivotCacheDefinition${n}.xml` });
663
867
  }
664
- ]);
665
- zip.append(xml, { name: "xl/pivotTables/_rels/pivotTable1.xml.rels" });
868
+ // pivot cache definition rels (same for both)
869
+ let xml = relsXform.toXml([
870
+ {
871
+ Id: "rId1",
872
+ Type: XLSX.RelType.PivotCacheRecords,
873
+ Target: `pivotCacheRecords${n}.xml`
874
+ }
875
+ ]);
876
+ zip.append(xml, { name: `xl/pivotCache/_rels/pivotCacheDefinition${n}.xml.rels` });
877
+ // pivot table
878
+ xml = pivotTableXform.toXml(pivotTable);
879
+ zip.append(xml, { name: `xl/pivotTables/pivotTable${n}.xml` });
880
+ xml = relsXform.toXml([
881
+ {
882
+ Id: "rId1",
883
+ Type: XLSX.RelType.PivotCacheDefinition,
884
+ Target: `../pivotCache/pivotCacheDefinition${n}.xml`
885
+ }
886
+ ]);
887
+ zip.append(xml, { name: `xl/pivotTables/_rels/pivotTable${n}.xml.rels` });
888
+ });
666
889
  }
667
890
  _finalize(zip) {
668
891
  return new Promise((resolve, reject) => {
@@ -64,6 +64,9 @@ class Column {
64
64
  this.outlineLevel = 0;
65
65
  }
66
66
  }
67
+ /**
68
+ * Get header values as an array (for multi-row header support)
69
+ */
67
70
  get headers() {
68
71
  if (Array.isArray(this._header)) {
69
72
  return this._header;
@@ -74,7 +77,8 @@ class Column {
74
77
  return [];
75
78
  }
76
79
  /**
77
- * Can be a string to set one row high header or an array to set multi-row high header
80
+ * Can be a single value or an array for multi-row headers.
81
+ * Supports any CellValue type including Date, number, string, etc.
78
82
  */
79
83
  get header() {
80
84
  return this._header;
@@ -82,8 +86,8 @@ class Column {
82
86
  set header(value) {
83
87
  if (value !== undefined) {
84
88
  this._header = value;
85
- this.headers.forEach((text, index) => {
86
- this._worksheet.getCell(index + 1, this.number).value = text;
89
+ this.headers.forEach((cellValue, index) => {
90
+ this._worksheet.getCell(index + 1, this.number).value = cellValue;
87
91
  });
88
92
  }
89
93
  else {