@js-ak/excel-toolbox 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/lib/template/template-fs.js +89 -10
- package/build/cjs/lib/template/template-memory.js +89 -22
- package/build/cjs/lib/template/utils/compare-columns.js +16 -0
- package/build/cjs/lib/template/utils/index.js +1 -0
- package/build/esm/lib/template/template-fs.js +89 -10
- package/build/esm/lib/template/template-memory.js +89 -22
- package/build/esm/lib/template/utils/compare-columns.js +13 -0
- package/build/esm/lib/template/utils/index.js +1 -0
- package/build/types/lib/template/template-fs.d.ts +14 -0
- package/build/types/lib/template/template-memory.d.ts +4 -2
- package/build/types/lib/template/utils/compare-columns.d.ts +8 -0
- package/build/types/lib/template/utils/index.d.ts +1 -0
- package/package.json +1 -1
@@ -92,6 +92,7 @@ class TemplateFs {
|
|
92
92
|
this.fileKeys = fileKeys;
|
93
93
|
this.destination = destination;
|
94
94
|
}
|
95
|
+
/** Private methods */
|
95
96
|
/**
|
96
97
|
* Removes the temporary directory created by this Template instance.
|
97
98
|
* @private
|
@@ -224,6 +225,20 @@ class TemplateFs {
|
|
224
225
|
const fullPath = path.join(this.destination, ...key.split("/"));
|
225
226
|
await fs.writeFile(fullPath, Buffer.isBuffer(content) ? content : Buffer.from(content));
|
226
227
|
}
|
228
|
+
/**
|
229
|
+
* Replaces placeholders in the given sheet with values from the replacements map.
|
230
|
+
*
|
231
|
+
* The function searches for placeholders in the format `${key}` within the sheet
|
232
|
+
* content, where `key` corresponds to a path in the replacements object.
|
233
|
+
* If a value is found for the key, it replaces the placeholder with the value.
|
234
|
+
* If no value is found, the original placeholder remains unchanged.
|
235
|
+
*
|
236
|
+
* @param sheetName - The name of the sheet to be replaced.
|
237
|
+
* @param replacements - An object where keys represent placeholder paths and values are the replacements.
|
238
|
+
* @returns A promise that resolves when the substitution is complete.
|
239
|
+
* @throws {Error} If the template instance has been destroyed.
|
240
|
+
* @experimental This API is experimental and might change in future versions.
|
241
|
+
*/
|
227
242
|
async #substitute(sheetName, replacements) {
|
228
243
|
const sharedStringsPath = this.#excelKeys.sharedStrings;
|
229
244
|
const sheetPath = await this.#getSheetPathByName(sheetName);
|
@@ -251,6 +266,54 @@ class TemplateFs {
|
|
251
266
|
await this.#set(sheetPath, sheetContent);
|
252
267
|
}
|
253
268
|
}
|
269
|
+
/**
|
270
|
+
* Removes sheets from the workbook.
|
271
|
+
*
|
272
|
+
* @param {Object} data - The data for sheet removal.
|
273
|
+
* @param {number[]} [data.sheetIndexes] - The 1-based indexes of the sheets to remove.
|
274
|
+
* @param {string[]} [data.sheetNames] - The names of the sheets to remove.
|
275
|
+
* @returns {void}
|
276
|
+
*
|
277
|
+
* @throws {Error} If the template instance has been destroyed.
|
278
|
+
* @throws {Error} If the sheet does not exist.
|
279
|
+
* @experimental This API is experimental and might change in future versions.
|
280
|
+
*/
|
281
|
+
async #removeSheets(data) {
|
282
|
+
const { sheetIndexes = [], sheetNames = [] } = data;
|
283
|
+
// first get index of sheets to remove
|
284
|
+
const sheetIndexesToRemove = new Set(sheetIndexes);
|
285
|
+
for (const sheetName of sheetNames) {
|
286
|
+
const sheetPath = await this.#getSheetPathByName(sheetName);
|
287
|
+
const sheetIndexMatch = sheetPath.match(/sheet(\d+)\.xml$/);
|
288
|
+
if (!sheetIndexMatch || !sheetIndexMatch[1]) {
|
289
|
+
throw new Error(`Sheet "${sheetName}" not found`);
|
290
|
+
}
|
291
|
+
const sheetIndex = parseInt(sheetIndexMatch[1], 10);
|
292
|
+
sheetIndexesToRemove.add(sheetIndex);
|
293
|
+
}
|
294
|
+
// Remove sheets by index
|
295
|
+
for (const sheetIndex of sheetIndexesToRemove.values()) {
|
296
|
+
const sheetPath = `xl/worksheets/sheet${sheetIndex}.xml`;
|
297
|
+
if (!this.fileKeys.has(sheetPath)) {
|
298
|
+
continue;
|
299
|
+
}
|
300
|
+
// remove sheet file
|
301
|
+
await fs.unlink(path.join(this.destination, ...sheetPath.split("/")));
|
302
|
+
this.fileKeys.delete(sheetPath);
|
303
|
+
// remove sheet from workbook
|
304
|
+
if (this.fileKeys.has(this.#excelKeys.workbook)) {
|
305
|
+
this.#set(this.#excelKeys.workbook, Buffer.from(Utils.Common.removeSheetFromWorkbook(this.#readFile(this.#excelKeys.workbook).toString(), sheetIndex)));
|
306
|
+
}
|
307
|
+
// remove sheet from workbook relations
|
308
|
+
if (this.fileKeys.has(this.#excelKeys.workbookRels)) {
|
309
|
+
this.#set(this.#excelKeys.workbookRels, Buffer.from(Utils.Common.removeSheetFromRels(this.#readFile(this.#excelKeys.workbookRels).toString(), sheetIndex)));
|
310
|
+
}
|
311
|
+
// remove sheet from content types
|
312
|
+
if (this.fileKeys.has(this.#excelKeys.contentTypes)) {
|
313
|
+
this.#set(this.#excelKeys.contentTypes, Buffer.from(Utils.Common.removeSheetFromContentTypes(this.#readFile(this.#excelKeys.contentTypes).toString(), sheetIndex)));
|
314
|
+
}
|
315
|
+
}
|
316
|
+
}
|
254
317
|
/**
|
255
318
|
* Validates the template by checking all required files exist.
|
256
319
|
*
|
@@ -270,6 +333,7 @@ class TemplateFs {
|
|
270
333
|
}
|
271
334
|
}
|
272
335
|
}
|
336
|
+
/** Public methods */
|
273
337
|
/**
|
274
338
|
* Copies a sheet from the template to a new name.
|
275
339
|
*
|
@@ -360,12 +424,12 @@ class TemplateFs {
|
|
360
424
|
* @param replacements - An object where keys represent placeholder paths and values are the replacements.
|
361
425
|
* @returns A promise that resolves when the substitution is complete.
|
362
426
|
*/
|
363
|
-
substitute(sheetName, replacements) {
|
427
|
+
async substitute(sheetName, replacements) {
|
364
428
|
this.#ensureNotProcessing();
|
365
429
|
this.#ensureNotDestroyed();
|
366
430
|
this.#isProcessing = true;
|
367
431
|
try {
|
368
|
-
|
432
|
+
await this.#substitute(sheetName, replacements);
|
369
433
|
}
|
370
434
|
finally {
|
371
435
|
this.#isProcessing = false;
|
@@ -527,7 +591,7 @@ class TemplateFs {
|
|
527
591
|
}
|
528
592
|
}
|
529
593
|
const { dimension: newDimension, rowNumber: actualRowNumber } = await Utils.writeRowsToStream(output, rows, maxRowNumber);
|
530
|
-
if (compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
594
|
+
if (Utils.compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
531
595
|
dimension.maxColumn = newDimension.maxColumn;
|
532
596
|
}
|
533
597
|
if (newDimension.maxRow > dimension.maxRow) {
|
@@ -574,7 +638,7 @@ class TemplateFs {
|
|
574
638
|
}
|
575
639
|
// new <row>
|
576
640
|
const { dimension: newDimension, rowNumber: actualRowNumber } = await Utils.writeRowsToStream(output, rows, maxRowNumber);
|
577
|
-
if (compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
641
|
+
if (Utils.compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
578
642
|
dimension.maxColumn = newDimension.maxColumn;
|
579
643
|
}
|
580
644
|
if (newDimension.maxRow > dimension.maxRow) {
|
@@ -607,7 +671,7 @@ class TemplateFs {
|
|
607
671
|
output.write("<sheetData>");
|
608
672
|
// Prepare the rows
|
609
673
|
const { dimension: newDimension } = await Utils.writeRowsToStream(output, rows, maxRowNumber);
|
610
|
-
if (compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
674
|
+
if (Utils.compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
611
675
|
dimension.maxColumn = newDimension.maxColumn;
|
612
676
|
}
|
613
677
|
if (newDimension.maxRow > dimension.maxRow) {
|
@@ -674,6 +738,25 @@ class TemplateFs {
|
|
674
738
|
this.#isProcessing = false;
|
675
739
|
}
|
676
740
|
}
|
741
|
+
/**
|
742
|
+
* Removes sheets from the workbook.
|
743
|
+
*
|
744
|
+
* @param {Object} data
|
745
|
+
* @param {number[]} [data.sheetIndexes] - The 1-based indexes of the sheets to remove.
|
746
|
+
* @param {string[]} [data.sheetNames] - The names of the sheets to remove.
|
747
|
+
* @returns {void}
|
748
|
+
*/
|
749
|
+
async removeSheets(data) {
|
750
|
+
this.#ensureNotProcessing();
|
751
|
+
this.#ensureNotDestroyed();
|
752
|
+
this.#isProcessing = true;
|
753
|
+
try {
|
754
|
+
await this.#removeSheets(data);
|
755
|
+
}
|
756
|
+
finally {
|
757
|
+
this.#isProcessing = false;
|
758
|
+
}
|
759
|
+
}
|
677
760
|
/**
|
678
761
|
* Saves the modified Excel template to a buffer.
|
679
762
|
*
|
@@ -762,6 +845,7 @@ class TemplateFs {
|
|
762
845
|
this.#isProcessing = false;
|
763
846
|
}
|
764
847
|
}
|
848
|
+
/** Static methods */
|
765
849
|
/**
|
766
850
|
* Creates a Template instance from an Excel file source.
|
767
851
|
* Removes any existing files in the destination directory.
|
@@ -800,8 +884,3 @@ class TemplateFs {
|
|
800
884
|
}
|
801
885
|
}
|
802
886
|
exports.TemplateFs = TemplateFs;
|
803
|
-
const compareColumns = (a, b) => {
|
804
|
-
if (a === b)
|
805
|
-
return 0;
|
806
|
-
return a.length === b.length ? (a < b ? -1 : 1) : (a.length < b.length ? -1 : 1);
|
807
|
-
};
|
@@ -76,6 +76,7 @@ class TemplateMemory {
|
|
76
76
|
constructor(files) {
|
77
77
|
this.files = files;
|
78
78
|
}
|
79
|
+
/** Private methods */
|
79
80
|
/**
|
80
81
|
* Ensures that this Template instance has not been destroyed.
|
81
82
|
* @private
|
@@ -335,28 +336,45 @@ class TemplateMemory {
|
|
335
336
|
* @throws {Error} If the sheet does not exist.
|
336
337
|
* @experimental This API is experimental and might change in future versions.
|
337
338
|
*/
|
338
|
-
#removeSheets(data) {
|
339
|
+
async #removeSheets(data) {
|
339
340
|
const { sheetIndexes = [], sheetNames = [] } = data;
|
340
|
-
|
341
|
+
// first get index of sheets to remove
|
342
|
+
const sheetIndexesToRemove = new Set(sheetIndexes);
|
343
|
+
for (const sheetName of sheetNames) {
|
344
|
+
const sheetPath = await this.#getSheetPathByName(sheetName);
|
345
|
+
const sheetIndexMatch = sheetPath.match(/sheet(\d+)\.xml$/);
|
346
|
+
if (!sheetIndexMatch || !sheetIndexMatch[1]) {
|
347
|
+
throw new Error(`Sheet "${sheetName}" not found`);
|
348
|
+
}
|
349
|
+
const sheetIndex = parseInt(sheetIndexMatch[1], 10);
|
350
|
+
sheetIndexesToRemove.add(sheetIndex);
|
351
|
+
}
|
352
|
+
// Remove sheets by index
|
353
|
+
for (const sheetIndex of sheetIndexesToRemove.values()) {
|
341
354
|
const sheetPath = `xl/worksheets/sheet${sheetIndex}.xml`;
|
342
355
|
if (!this.files[sheetPath]) {
|
343
356
|
continue;
|
344
357
|
}
|
358
|
+
// remove sheet file
|
345
359
|
delete this.files[sheetPath];
|
346
|
-
|
347
|
-
|
360
|
+
// remove sheet from workbook
|
361
|
+
const workbook = this.files[this.#excelKeys.workbook];
|
362
|
+
if (workbook) {
|
363
|
+
this.files[this.#excelKeys.workbook] = Buffer.from(Utils.Common.removeSheetFromWorkbook(workbook.toString(), sheetIndex));
|
348
364
|
}
|
349
|
-
|
350
|
-
|
365
|
+
// remove sheet from workbook relations
|
366
|
+
const workbookRels = this.files[this.#excelKeys.workbookRels];
|
367
|
+
if (workbookRels) {
|
368
|
+
this.files[this.#excelKeys.workbookRels] = Buffer.from(Utils.Common.removeSheetFromRels(workbookRels.toString(), sheetIndex));
|
351
369
|
}
|
352
|
-
|
353
|
-
|
370
|
+
// remove sheet from content types
|
371
|
+
const contentTypes = this.files[this.#excelKeys.contentTypes];
|
372
|
+
if (contentTypes) {
|
373
|
+
this.files[this.#excelKeys.contentTypes] = Buffer.from(Utils.Common.removeSheetFromContentTypes(contentTypes.toString(), sheetIndex));
|
354
374
|
}
|
355
375
|
}
|
356
|
-
for (const sheetName of sheetNames) {
|
357
|
-
Utils.Common.removeSheetByName(this.files, sheetName);
|
358
|
-
}
|
359
376
|
}
|
377
|
+
/** Public methods */
|
360
378
|
/**
|
361
379
|
* Copies a sheet from the template to a new name.
|
362
380
|
*
|
@@ -454,12 +472,12 @@ class TemplateMemory {
|
|
454
472
|
* @param replacements - An object where keys represent placeholder paths and values are the replacements.
|
455
473
|
* @returns A promise that resolves when the substitution is complete.
|
456
474
|
*/
|
457
|
-
substitute(sheetName, replacements) {
|
475
|
+
async substitute(sheetName, replacements) {
|
458
476
|
this.#ensureNotProcessing();
|
459
477
|
this.#ensureNotDestroyed();
|
460
478
|
this.#isProcessing = true;
|
461
479
|
try {
|
462
|
-
|
480
|
+
await this.#substitute(sheetName, replacements);
|
463
481
|
}
|
464
482
|
finally {
|
465
483
|
this.#isProcessing = false;
|
@@ -525,7 +543,7 @@ class TemplateMemory {
|
|
525
543
|
else {
|
526
544
|
updatedXml = sheetXml.replace(/<worksheet[^>]*>/, (match) => `${match}<sheetData>${rowsXml}</sheetData>`);
|
527
545
|
}
|
528
|
-
await this.#set(sheetPath, Buffer.from(updatedXml));
|
546
|
+
await this.#set(sheetPath, Buffer.from(Utils.updateDimension(updatedXml)));
|
529
547
|
}
|
530
548
|
finally {
|
531
549
|
this.#isProcessing = false;
|
@@ -558,6 +576,26 @@ class TemplateMemory {
|
|
558
576
|
const sheetXml = await this.#extractXmlFromSheet(sheetPath);
|
559
577
|
const output = new memory_write_stream_js_1.MemoryWriteStream();
|
560
578
|
let inserted = false;
|
579
|
+
const initialDimension = sheetXml.match(/<dimension\s+ref="[^"]*"/)?.[0] || "";
|
580
|
+
const dimension = {
|
581
|
+
maxColumn: "A",
|
582
|
+
maxRow: 1,
|
583
|
+
minColumn: "A",
|
584
|
+
minRow: 1,
|
585
|
+
};
|
586
|
+
if (initialDimension) {
|
587
|
+
const dimensionMatch = initialDimension.match(/<dimension\s+ref="([^"]*)"/);
|
588
|
+
if (dimensionMatch) {
|
589
|
+
const dimensionRef = dimensionMatch[1];
|
590
|
+
if (dimensionRef) {
|
591
|
+
const [min, max] = dimensionRef.split(":");
|
592
|
+
dimension.minColumn = min.slice(0, 1);
|
593
|
+
dimension.minRow = parseInt(min.slice(1));
|
594
|
+
dimension.maxColumn = max.slice(0, 1);
|
595
|
+
dimension.maxRow = parseInt(max.slice(1));
|
596
|
+
}
|
597
|
+
}
|
598
|
+
}
|
561
599
|
// --- Case 1: <sheetData>...</sheetData> on one line ---
|
562
600
|
const singleLineMatch = sheetXml.match(/(<sheetData[^>]*>)(.*)(<\/sheetData>)/);
|
563
601
|
if (!inserted && singleLineMatch) {
|
@@ -578,7 +616,13 @@ class TemplateMemory {
|
|
578
616
|
output.write(innerRows);
|
579
617
|
}
|
580
618
|
}
|
581
|
-
const { rowNumber: actualRowNumber } = await Utils.writeRowsToStream(output, rows, maxRowNumber);
|
619
|
+
const { dimension: newDimension, rowNumber: actualRowNumber } = await Utils.writeRowsToStream(output, rows, maxRowNumber);
|
620
|
+
if (Utils.compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
621
|
+
dimension.maxColumn = newDimension.maxColumn;
|
622
|
+
}
|
623
|
+
if (newDimension.maxRow > dimension.maxRow) {
|
624
|
+
dimension.maxRow = newDimension.maxRow;
|
625
|
+
}
|
582
626
|
if (innerRows) {
|
583
627
|
const filtered = Utils.getRowsAbove(innerRowsMap, actualRowNumber);
|
584
628
|
if (filtered)
|
@@ -595,7 +639,13 @@ class TemplateMemory {
|
|
595
639
|
const matchIndex = match.index;
|
596
640
|
output.write(sheetXml.slice(0, matchIndex));
|
597
641
|
output.write("<sheetData>");
|
598
|
-
await Utils.writeRowsToStream(output, rows, maxRowNumber);
|
642
|
+
const { dimension: newDimension } = await Utils.writeRowsToStream(output, rows, maxRowNumber);
|
643
|
+
if (Utils.compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
644
|
+
dimension.maxColumn = newDimension.maxColumn;
|
645
|
+
}
|
646
|
+
if (newDimension.maxRow > dimension.maxRow) {
|
647
|
+
dimension.maxRow = newDimension.maxRow;
|
648
|
+
}
|
599
649
|
output.write("</sheetData>");
|
600
650
|
output.write(sheetXml.slice(matchIndex + match[0].length));
|
601
651
|
inserted = true;
|
@@ -626,7 +676,13 @@ class TemplateMemory {
|
|
626
676
|
output.write(innerRows);
|
627
677
|
}
|
628
678
|
}
|
629
|
-
const { rowNumber: actualRowNumber } = await Utils.writeRowsToStream(output, rows, Utils.getMaxRowNumber(innerRows));
|
679
|
+
const { dimension: newDimension, rowNumber: actualRowNumber } = await Utils.writeRowsToStream(output, rows, Utils.getMaxRowNumber(innerRows));
|
680
|
+
if (Utils.compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
681
|
+
dimension.maxColumn = newDimension.maxColumn;
|
682
|
+
}
|
683
|
+
if (newDimension.maxRow > dimension.maxRow) {
|
684
|
+
dimension.maxRow = newDimension.maxRow;
|
685
|
+
}
|
630
686
|
if (innerRows) {
|
631
687
|
const filtered = Utils.getRowsAbove(innerRowsMap, actualRowNumber);
|
632
688
|
if (filtered)
|
@@ -638,8 +694,18 @@ class TemplateMemory {
|
|
638
694
|
}
|
639
695
|
if (!inserted)
|
640
696
|
throw new Error("Failed to locate <sheetData> for insertion");
|
697
|
+
let result = output.toBuffer();
|
698
|
+
// update dimension
|
699
|
+
{
|
700
|
+
const target = initialDimension;
|
701
|
+
const refRange = `${dimension.minColumn}${dimension.minRow}:${dimension.maxColumn}${dimension.maxRow}`;
|
702
|
+
const replacement = `<dimension ref="${refRange}"`;
|
703
|
+
if (target) {
|
704
|
+
result = Buffer.from(result.toString().replace(target, replacement));
|
705
|
+
}
|
706
|
+
}
|
641
707
|
// Save the buffer to the sheet
|
642
|
-
this.files[sheetPath] =
|
708
|
+
this.files[sheetPath] = result;
|
643
709
|
}
|
644
710
|
finally {
|
645
711
|
this.#isProcessing = false;
|
@@ -702,12 +768,12 @@ class TemplateMemory {
|
|
702
768
|
* @param {number} [data.gap=0] - The number of empty rows to insert between each added section.
|
703
769
|
* @returns {void}
|
704
770
|
*/
|
705
|
-
mergeSheets(data) {
|
771
|
+
async mergeSheets(data) {
|
706
772
|
this.#ensureNotProcessing();
|
707
773
|
this.#ensureNotDestroyed();
|
708
774
|
this.#isProcessing = true;
|
709
775
|
try {
|
710
|
-
this.#mergeSheets(data);
|
776
|
+
await this.#mergeSheets(data);
|
711
777
|
}
|
712
778
|
finally {
|
713
779
|
this.#isProcessing = false;
|
@@ -721,17 +787,18 @@ class TemplateMemory {
|
|
721
787
|
* @param {string[]} [data.sheetNames] - The names of the sheets to remove.
|
722
788
|
* @returns {void}
|
723
789
|
*/
|
724
|
-
removeSheets(data) {
|
790
|
+
async removeSheets(data) {
|
725
791
|
this.#ensureNotProcessing();
|
726
792
|
this.#ensureNotDestroyed();
|
727
793
|
this.#isProcessing = true;
|
728
794
|
try {
|
729
|
-
this.#removeSheets(data);
|
795
|
+
await this.#removeSheets(data);
|
730
796
|
}
|
731
797
|
finally {
|
732
798
|
this.#isProcessing = false;
|
733
799
|
}
|
734
800
|
}
|
801
|
+
/** Static methods */
|
735
802
|
/**
|
736
803
|
* Creates a Template instance from an Excel file source.
|
737
804
|
*
|
@@ -0,0 +1,16 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.compareColumns = compareColumns;
|
4
|
+
/**
|
5
|
+
* Compares two column strings and returns a number indicating their relative order.
|
6
|
+
*
|
7
|
+
* @param a - The first column string to compare.
|
8
|
+
* @param b - The second column string to compare.
|
9
|
+
* @returns 0 if the columns are equal, -1 if the first column is less than the second, or 1 if the first column is greater than the second.
|
10
|
+
*/
|
11
|
+
function compareColumns(a, b) {
|
12
|
+
if (a === b) {
|
13
|
+
return 0;
|
14
|
+
}
|
15
|
+
return a.length === b.length ? (a < b ? -1 : 1) : (a.length < b.length ? -1 : 1);
|
16
|
+
}
|
@@ -43,6 +43,7 @@ __exportStar(require("./check-row.js"), exports);
|
|
43
43
|
__exportStar(require("./check-rows.js"), exports);
|
44
44
|
__exportStar(require("./check-start-row.js"), exports);
|
45
45
|
__exportStar(require("./column-index-to-letter.js"), exports);
|
46
|
+
__exportStar(require("./compare-columns.js"), exports);
|
46
47
|
__exportStar(require("./escape-xml.js"), exports);
|
47
48
|
__exportStar(require("./extract-xml-declaration.js"), exports);
|
48
49
|
__exportStar(require("./get-by-path.js"), exports);
|
@@ -53,6 +53,7 @@ export class TemplateFs {
|
|
53
53
|
this.fileKeys = fileKeys;
|
54
54
|
this.destination = destination;
|
55
55
|
}
|
56
|
+
/** Private methods */
|
56
57
|
/**
|
57
58
|
* Removes the temporary directory created by this Template instance.
|
58
59
|
* @private
|
@@ -185,6 +186,20 @@ export class TemplateFs {
|
|
185
186
|
const fullPath = path.join(this.destination, ...key.split("/"));
|
186
187
|
await fs.writeFile(fullPath, Buffer.isBuffer(content) ? content : Buffer.from(content));
|
187
188
|
}
|
189
|
+
/**
|
190
|
+
* Replaces placeholders in the given sheet with values from the replacements map.
|
191
|
+
*
|
192
|
+
* The function searches for placeholders in the format `${key}` within the sheet
|
193
|
+
* content, where `key` corresponds to a path in the replacements object.
|
194
|
+
* If a value is found for the key, it replaces the placeholder with the value.
|
195
|
+
* If no value is found, the original placeholder remains unchanged.
|
196
|
+
*
|
197
|
+
* @param sheetName - The name of the sheet to be replaced.
|
198
|
+
* @param replacements - An object where keys represent placeholder paths and values are the replacements.
|
199
|
+
* @returns A promise that resolves when the substitution is complete.
|
200
|
+
* @throws {Error} If the template instance has been destroyed.
|
201
|
+
* @experimental This API is experimental and might change in future versions.
|
202
|
+
*/
|
188
203
|
async #substitute(sheetName, replacements) {
|
189
204
|
const sharedStringsPath = this.#excelKeys.sharedStrings;
|
190
205
|
const sheetPath = await this.#getSheetPathByName(sheetName);
|
@@ -212,6 +227,54 @@ export class TemplateFs {
|
|
212
227
|
await this.#set(sheetPath, sheetContent);
|
213
228
|
}
|
214
229
|
}
|
230
|
+
/**
|
231
|
+
* Removes sheets from the workbook.
|
232
|
+
*
|
233
|
+
* @param {Object} data - The data for sheet removal.
|
234
|
+
* @param {number[]} [data.sheetIndexes] - The 1-based indexes of the sheets to remove.
|
235
|
+
* @param {string[]} [data.sheetNames] - The names of the sheets to remove.
|
236
|
+
* @returns {void}
|
237
|
+
*
|
238
|
+
* @throws {Error} If the template instance has been destroyed.
|
239
|
+
* @throws {Error} If the sheet does not exist.
|
240
|
+
* @experimental This API is experimental and might change in future versions.
|
241
|
+
*/
|
242
|
+
async #removeSheets(data) {
|
243
|
+
const { sheetIndexes = [], sheetNames = [] } = data;
|
244
|
+
// first get index of sheets to remove
|
245
|
+
const sheetIndexesToRemove = new Set(sheetIndexes);
|
246
|
+
for (const sheetName of sheetNames) {
|
247
|
+
const sheetPath = await this.#getSheetPathByName(sheetName);
|
248
|
+
const sheetIndexMatch = sheetPath.match(/sheet(\d+)\.xml$/);
|
249
|
+
if (!sheetIndexMatch || !sheetIndexMatch[1]) {
|
250
|
+
throw new Error(`Sheet "${sheetName}" not found`);
|
251
|
+
}
|
252
|
+
const sheetIndex = parseInt(sheetIndexMatch[1], 10);
|
253
|
+
sheetIndexesToRemove.add(sheetIndex);
|
254
|
+
}
|
255
|
+
// Remove sheets by index
|
256
|
+
for (const sheetIndex of sheetIndexesToRemove.values()) {
|
257
|
+
const sheetPath = `xl/worksheets/sheet${sheetIndex}.xml`;
|
258
|
+
if (!this.fileKeys.has(sheetPath)) {
|
259
|
+
continue;
|
260
|
+
}
|
261
|
+
// remove sheet file
|
262
|
+
await fs.unlink(path.join(this.destination, ...sheetPath.split("/")));
|
263
|
+
this.fileKeys.delete(sheetPath);
|
264
|
+
// remove sheet from workbook
|
265
|
+
if (this.fileKeys.has(this.#excelKeys.workbook)) {
|
266
|
+
this.#set(this.#excelKeys.workbook, Buffer.from(Utils.Common.removeSheetFromWorkbook(this.#readFile(this.#excelKeys.workbook).toString(), sheetIndex)));
|
267
|
+
}
|
268
|
+
// remove sheet from workbook relations
|
269
|
+
if (this.fileKeys.has(this.#excelKeys.workbookRels)) {
|
270
|
+
this.#set(this.#excelKeys.workbookRels, Buffer.from(Utils.Common.removeSheetFromRels(this.#readFile(this.#excelKeys.workbookRels).toString(), sheetIndex)));
|
271
|
+
}
|
272
|
+
// remove sheet from content types
|
273
|
+
if (this.fileKeys.has(this.#excelKeys.contentTypes)) {
|
274
|
+
this.#set(this.#excelKeys.contentTypes, Buffer.from(Utils.Common.removeSheetFromContentTypes(this.#readFile(this.#excelKeys.contentTypes).toString(), sheetIndex)));
|
275
|
+
}
|
276
|
+
}
|
277
|
+
}
|
215
278
|
/**
|
216
279
|
* Validates the template by checking all required files exist.
|
217
280
|
*
|
@@ -231,6 +294,7 @@ export class TemplateFs {
|
|
231
294
|
}
|
232
295
|
}
|
233
296
|
}
|
297
|
+
/** Public methods */
|
234
298
|
/**
|
235
299
|
* Copies a sheet from the template to a new name.
|
236
300
|
*
|
@@ -321,12 +385,12 @@ export class TemplateFs {
|
|
321
385
|
* @param replacements - An object where keys represent placeholder paths and values are the replacements.
|
322
386
|
* @returns A promise that resolves when the substitution is complete.
|
323
387
|
*/
|
324
|
-
substitute(sheetName, replacements) {
|
388
|
+
async substitute(sheetName, replacements) {
|
325
389
|
this.#ensureNotProcessing();
|
326
390
|
this.#ensureNotDestroyed();
|
327
391
|
this.#isProcessing = true;
|
328
392
|
try {
|
329
|
-
|
393
|
+
await this.#substitute(sheetName, replacements);
|
330
394
|
}
|
331
395
|
finally {
|
332
396
|
this.#isProcessing = false;
|
@@ -488,7 +552,7 @@ export class TemplateFs {
|
|
488
552
|
}
|
489
553
|
}
|
490
554
|
const { dimension: newDimension, rowNumber: actualRowNumber } = await Utils.writeRowsToStream(output, rows, maxRowNumber);
|
491
|
-
if (compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
555
|
+
if (Utils.compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
492
556
|
dimension.maxColumn = newDimension.maxColumn;
|
493
557
|
}
|
494
558
|
if (newDimension.maxRow > dimension.maxRow) {
|
@@ -535,7 +599,7 @@ export class TemplateFs {
|
|
535
599
|
}
|
536
600
|
// new <row>
|
537
601
|
const { dimension: newDimension, rowNumber: actualRowNumber } = await Utils.writeRowsToStream(output, rows, maxRowNumber);
|
538
|
-
if (compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
602
|
+
if (Utils.compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
539
603
|
dimension.maxColumn = newDimension.maxColumn;
|
540
604
|
}
|
541
605
|
if (newDimension.maxRow > dimension.maxRow) {
|
@@ -568,7 +632,7 @@ export class TemplateFs {
|
|
568
632
|
output.write("<sheetData>");
|
569
633
|
// Prepare the rows
|
570
634
|
const { dimension: newDimension } = await Utils.writeRowsToStream(output, rows, maxRowNumber);
|
571
|
-
if (compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
635
|
+
if (Utils.compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
572
636
|
dimension.maxColumn = newDimension.maxColumn;
|
573
637
|
}
|
574
638
|
if (newDimension.maxRow > dimension.maxRow) {
|
@@ -635,6 +699,25 @@ export class TemplateFs {
|
|
635
699
|
this.#isProcessing = false;
|
636
700
|
}
|
637
701
|
}
|
702
|
+
/**
|
703
|
+
* Removes sheets from the workbook.
|
704
|
+
*
|
705
|
+
* @param {Object} data
|
706
|
+
* @param {number[]} [data.sheetIndexes] - The 1-based indexes of the sheets to remove.
|
707
|
+
* @param {string[]} [data.sheetNames] - The names of the sheets to remove.
|
708
|
+
* @returns {void}
|
709
|
+
*/
|
710
|
+
async removeSheets(data) {
|
711
|
+
this.#ensureNotProcessing();
|
712
|
+
this.#ensureNotDestroyed();
|
713
|
+
this.#isProcessing = true;
|
714
|
+
try {
|
715
|
+
await this.#removeSheets(data);
|
716
|
+
}
|
717
|
+
finally {
|
718
|
+
this.#isProcessing = false;
|
719
|
+
}
|
720
|
+
}
|
638
721
|
/**
|
639
722
|
* Saves the modified Excel template to a buffer.
|
640
723
|
*
|
@@ -723,6 +806,7 @@ export class TemplateFs {
|
|
723
806
|
this.#isProcessing = false;
|
724
807
|
}
|
725
808
|
}
|
809
|
+
/** Static methods */
|
726
810
|
/**
|
727
811
|
* Creates a Template instance from an Excel file source.
|
728
812
|
* Removes any existing files in the destination directory.
|
@@ -760,8 +844,3 @@ export class TemplateFs {
|
|
760
844
|
return new TemplateFs(new Set(Object.keys(files)), destinationWithUuid);
|
761
845
|
}
|
762
846
|
}
|
763
|
-
const compareColumns = (a, b) => {
|
764
|
-
if (a === b)
|
765
|
-
return 0;
|
766
|
-
return a.length === b.length ? (a < b ? -1 : 1) : (a.length < b.length ? -1 : 1);
|
767
|
-
};
|
@@ -40,6 +40,7 @@ export class TemplateMemory {
|
|
40
40
|
constructor(files) {
|
41
41
|
this.files = files;
|
42
42
|
}
|
43
|
+
/** Private methods */
|
43
44
|
/**
|
44
45
|
* Ensures that this Template instance has not been destroyed.
|
45
46
|
* @private
|
@@ -299,28 +300,45 @@ export class TemplateMemory {
|
|
299
300
|
* @throws {Error} If the sheet does not exist.
|
300
301
|
* @experimental This API is experimental and might change in future versions.
|
301
302
|
*/
|
302
|
-
#removeSheets(data) {
|
303
|
+
async #removeSheets(data) {
|
303
304
|
const { sheetIndexes = [], sheetNames = [] } = data;
|
304
|
-
|
305
|
+
// first get index of sheets to remove
|
306
|
+
const sheetIndexesToRemove = new Set(sheetIndexes);
|
307
|
+
for (const sheetName of sheetNames) {
|
308
|
+
const sheetPath = await this.#getSheetPathByName(sheetName);
|
309
|
+
const sheetIndexMatch = sheetPath.match(/sheet(\d+)\.xml$/);
|
310
|
+
if (!sheetIndexMatch || !sheetIndexMatch[1]) {
|
311
|
+
throw new Error(`Sheet "${sheetName}" not found`);
|
312
|
+
}
|
313
|
+
const sheetIndex = parseInt(sheetIndexMatch[1], 10);
|
314
|
+
sheetIndexesToRemove.add(sheetIndex);
|
315
|
+
}
|
316
|
+
// Remove sheets by index
|
317
|
+
for (const sheetIndex of sheetIndexesToRemove.values()) {
|
305
318
|
const sheetPath = `xl/worksheets/sheet${sheetIndex}.xml`;
|
306
319
|
if (!this.files[sheetPath]) {
|
307
320
|
continue;
|
308
321
|
}
|
322
|
+
// remove sheet file
|
309
323
|
delete this.files[sheetPath];
|
310
|
-
|
311
|
-
|
324
|
+
// remove sheet from workbook
|
325
|
+
const workbook = this.files[this.#excelKeys.workbook];
|
326
|
+
if (workbook) {
|
327
|
+
this.files[this.#excelKeys.workbook] = Buffer.from(Utils.Common.removeSheetFromWorkbook(workbook.toString(), sheetIndex));
|
312
328
|
}
|
313
|
-
|
314
|
-
|
329
|
+
// remove sheet from workbook relations
|
330
|
+
const workbookRels = this.files[this.#excelKeys.workbookRels];
|
331
|
+
if (workbookRels) {
|
332
|
+
this.files[this.#excelKeys.workbookRels] = Buffer.from(Utils.Common.removeSheetFromRels(workbookRels.toString(), sheetIndex));
|
315
333
|
}
|
316
|
-
|
317
|
-
|
334
|
+
// remove sheet from content types
|
335
|
+
const contentTypes = this.files[this.#excelKeys.contentTypes];
|
336
|
+
if (contentTypes) {
|
337
|
+
this.files[this.#excelKeys.contentTypes] = Buffer.from(Utils.Common.removeSheetFromContentTypes(contentTypes.toString(), sheetIndex));
|
318
338
|
}
|
319
339
|
}
|
320
|
-
for (const sheetName of sheetNames) {
|
321
|
-
Utils.Common.removeSheetByName(this.files, sheetName);
|
322
|
-
}
|
323
340
|
}
|
341
|
+
/** Public methods */
|
324
342
|
/**
|
325
343
|
* Copies a sheet from the template to a new name.
|
326
344
|
*
|
@@ -418,12 +436,12 @@ export class TemplateMemory {
|
|
418
436
|
* @param replacements - An object where keys represent placeholder paths and values are the replacements.
|
419
437
|
* @returns A promise that resolves when the substitution is complete.
|
420
438
|
*/
|
421
|
-
substitute(sheetName, replacements) {
|
439
|
+
async substitute(sheetName, replacements) {
|
422
440
|
this.#ensureNotProcessing();
|
423
441
|
this.#ensureNotDestroyed();
|
424
442
|
this.#isProcessing = true;
|
425
443
|
try {
|
426
|
-
|
444
|
+
await this.#substitute(sheetName, replacements);
|
427
445
|
}
|
428
446
|
finally {
|
429
447
|
this.#isProcessing = false;
|
@@ -489,7 +507,7 @@ export class TemplateMemory {
|
|
489
507
|
else {
|
490
508
|
updatedXml = sheetXml.replace(/<worksheet[^>]*>/, (match) => `${match}<sheetData>${rowsXml}</sheetData>`);
|
491
509
|
}
|
492
|
-
await this.#set(sheetPath, Buffer.from(updatedXml));
|
510
|
+
await this.#set(sheetPath, Buffer.from(Utils.updateDimension(updatedXml)));
|
493
511
|
}
|
494
512
|
finally {
|
495
513
|
this.#isProcessing = false;
|
@@ -522,6 +540,26 @@ export class TemplateMemory {
|
|
522
540
|
const sheetXml = await this.#extractXmlFromSheet(sheetPath);
|
523
541
|
const output = new MemoryWriteStream();
|
524
542
|
let inserted = false;
|
543
|
+
const initialDimension = sheetXml.match(/<dimension\s+ref="[^"]*"/)?.[0] || "";
|
544
|
+
const dimension = {
|
545
|
+
maxColumn: "A",
|
546
|
+
maxRow: 1,
|
547
|
+
minColumn: "A",
|
548
|
+
minRow: 1,
|
549
|
+
};
|
550
|
+
if (initialDimension) {
|
551
|
+
const dimensionMatch = initialDimension.match(/<dimension\s+ref="([^"]*)"/);
|
552
|
+
if (dimensionMatch) {
|
553
|
+
const dimensionRef = dimensionMatch[1];
|
554
|
+
if (dimensionRef) {
|
555
|
+
const [min, max] = dimensionRef.split(":");
|
556
|
+
dimension.minColumn = min.slice(0, 1);
|
557
|
+
dimension.minRow = parseInt(min.slice(1));
|
558
|
+
dimension.maxColumn = max.slice(0, 1);
|
559
|
+
dimension.maxRow = parseInt(max.slice(1));
|
560
|
+
}
|
561
|
+
}
|
562
|
+
}
|
525
563
|
// --- Case 1: <sheetData>...</sheetData> on one line ---
|
526
564
|
const singleLineMatch = sheetXml.match(/(<sheetData[^>]*>)(.*)(<\/sheetData>)/);
|
527
565
|
if (!inserted && singleLineMatch) {
|
@@ -542,7 +580,13 @@ export class TemplateMemory {
|
|
542
580
|
output.write(innerRows);
|
543
581
|
}
|
544
582
|
}
|
545
|
-
const { rowNumber: actualRowNumber } = await Utils.writeRowsToStream(output, rows, maxRowNumber);
|
583
|
+
const { dimension: newDimension, rowNumber: actualRowNumber } = await Utils.writeRowsToStream(output, rows, maxRowNumber);
|
584
|
+
if (Utils.compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
585
|
+
dimension.maxColumn = newDimension.maxColumn;
|
586
|
+
}
|
587
|
+
if (newDimension.maxRow > dimension.maxRow) {
|
588
|
+
dimension.maxRow = newDimension.maxRow;
|
589
|
+
}
|
546
590
|
if (innerRows) {
|
547
591
|
const filtered = Utils.getRowsAbove(innerRowsMap, actualRowNumber);
|
548
592
|
if (filtered)
|
@@ -559,7 +603,13 @@ export class TemplateMemory {
|
|
559
603
|
const matchIndex = match.index;
|
560
604
|
output.write(sheetXml.slice(0, matchIndex));
|
561
605
|
output.write("<sheetData>");
|
562
|
-
await Utils.writeRowsToStream(output, rows, maxRowNumber);
|
606
|
+
const { dimension: newDimension } = await Utils.writeRowsToStream(output, rows, maxRowNumber);
|
607
|
+
if (Utils.compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
608
|
+
dimension.maxColumn = newDimension.maxColumn;
|
609
|
+
}
|
610
|
+
if (newDimension.maxRow > dimension.maxRow) {
|
611
|
+
dimension.maxRow = newDimension.maxRow;
|
612
|
+
}
|
563
613
|
output.write("</sheetData>");
|
564
614
|
output.write(sheetXml.slice(matchIndex + match[0].length));
|
565
615
|
inserted = true;
|
@@ -590,7 +640,13 @@ export class TemplateMemory {
|
|
590
640
|
output.write(innerRows);
|
591
641
|
}
|
592
642
|
}
|
593
|
-
const { rowNumber: actualRowNumber } = await Utils.writeRowsToStream(output, rows, Utils.getMaxRowNumber(innerRows));
|
643
|
+
const { dimension: newDimension, rowNumber: actualRowNumber } = await Utils.writeRowsToStream(output, rows, Utils.getMaxRowNumber(innerRows));
|
644
|
+
if (Utils.compareColumns(newDimension.maxColumn, dimension.maxColumn) > 0) {
|
645
|
+
dimension.maxColumn = newDimension.maxColumn;
|
646
|
+
}
|
647
|
+
if (newDimension.maxRow > dimension.maxRow) {
|
648
|
+
dimension.maxRow = newDimension.maxRow;
|
649
|
+
}
|
594
650
|
if (innerRows) {
|
595
651
|
const filtered = Utils.getRowsAbove(innerRowsMap, actualRowNumber);
|
596
652
|
if (filtered)
|
@@ -602,8 +658,18 @@ export class TemplateMemory {
|
|
602
658
|
}
|
603
659
|
if (!inserted)
|
604
660
|
throw new Error("Failed to locate <sheetData> for insertion");
|
661
|
+
let result = output.toBuffer();
|
662
|
+
// update dimension
|
663
|
+
{
|
664
|
+
const target = initialDimension;
|
665
|
+
const refRange = `${dimension.minColumn}${dimension.minRow}:${dimension.maxColumn}${dimension.maxRow}`;
|
666
|
+
const replacement = `<dimension ref="${refRange}"`;
|
667
|
+
if (target) {
|
668
|
+
result = Buffer.from(result.toString().replace(target, replacement));
|
669
|
+
}
|
670
|
+
}
|
605
671
|
// Save the buffer to the sheet
|
606
|
-
this.files[sheetPath] =
|
672
|
+
this.files[sheetPath] = result;
|
607
673
|
}
|
608
674
|
finally {
|
609
675
|
this.#isProcessing = false;
|
@@ -666,12 +732,12 @@ export class TemplateMemory {
|
|
666
732
|
* @param {number} [data.gap=0] - The number of empty rows to insert between each added section.
|
667
733
|
* @returns {void}
|
668
734
|
*/
|
669
|
-
mergeSheets(data) {
|
735
|
+
async mergeSheets(data) {
|
670
736
|
this.#ensureNotProcessing();
|
671
737
|
this.#ensureNotDestroyed();
|
672
738
|
this.#isProcessing = true;
|
673
739
|
try {
|
674
|
-
this.#mergeSheets(data);
|
740
|
+
await this.#mergeSheets(data);
|
675
741
|
}
|
676
742
|
finally {
|
677
743
|
this.#isProcessing = false;
|
@@ -685,17 +751,18 @@ export class TemplateMemory {
|
|
685
751
|
* @param {string[]} [data.sheetNames] - The names of the sheets to remove.
|
686
752
|
* @returns {void}
|
687
753
|
*/
|
688
|
-
removeSheets(data) {
|
754
|
+
async removeSheets(data) {
|
689
755
|
this.#ensureNotProcessing();
|
690
756
|
this.#ensureNotDestroyed();
|
691
757
|
this.#isProcessing = true;
|
692
758
|
try {
|
693
|
-
this.#removeSheets(data);
|
759
|
+
await this.#removeSheets(data);
|
694
760
|
}
|
695
761
|
finally {
|
696
762
|
this.#isProcessing = false;
|
697
763
|
}
|
698
764
|
}
|
765
|
+
/** Static methods */
|
699
766
|
/**
|
700
767
|
* Creates a Template instance from an Excel file source.
|
701
768
|
*
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/**
|
2
|
+
* Compares two column strings and returns a number indicating their relative order.
|
3
|
+
*
|
4
|
+
* @param a - The first column string to compare.
|
5
|
+
* @param b - The second column string to compare.
|
6
|
+
* @returns 0 if the columns are equal, -1 if the first column is less than the second, or 1 if the first column is greater than the second.
|
7
|
+
*/
|
8
|
+
export function compareColumns(a, b) {
|
9
|
+
if (a === b) {
|
10
|
+
return 0;
|
11
|
+
}
|
12
|
+
return a.length === b.length ? (a < b ? -1 : 1) : (a.length < b.length ? -1 : 1);
|
13
|
+
}
|
@@ -4,6 +4,7 @@ export * from "./check-row.js";
|
|
4
4
|
export * from "./check-rows.js";
|
5
5
|
export * from "./check-start-row.js";
|
6
6
|
export * from "./column-index-to-letter.js";
|
7
|
+
export * from "./compare-columns.js";
|
7
8
|
export * from "./escape-xml.js";
|
8
9
|
export * from "./extract-xml-declaration.js";
|
9
10
|
export * from "./get-by-path.js";
|
@@ -29,6 +29,7 @@ export declare class TemplateFs {
|
|
29
29
|
* @experimental This API is experimental and might change in future versions.
|
30
30
|
*/
|
31
31
|
constructor(fileKeys: Set<string>, destination: string);
|
32
|
+
/** Public methods */
|
32
33
|
/**
|
33
34
|
* Copies a sheet from the template to a new name.
|
34
35
|
*
|
@@ -91,6 +92,18 @@ export declare class TemplateFs {
|
|
91
92
|
startRowNumber?: number;
|
92
93
|
rows: AsyncIterable<unknown[]>;
|
93
94
|
}): Promise<void>;
|
95
|
+
/**
|
96
|
+
* Removes sheets from the workbook.
|
97
|
+
*
|
98
|
+
* @param {Object} data
|
99
|
+
* @param {number[]} [data.sheetIndexes] - The 1-based indexes of the sheets to remove.
|
100
|
+
* @param {string[]} [data.sheetNames] - The names of the sheets to remove.
|
101
|
+
* @returns {void}
|
102
|
+
*/
|
103
|
+
removeSheets(data: {
|
104
|
+
sheetNames?: string[];
|
105
|
+
sheetIndexes?: number[];
|
106
|
+
}): Promise<void>;
|
94
107
|
/**
|
95
108
|
* Saves the modified Excel template to a buffer.
|
96
109
|
*
|
@@ -128,6 +141,7 @@ export declare class TemplateFs {
|
|
128
141
|
* @experimental This API is experimental and might change in future versions.
|
129
142
|
*/
|
130
143
|
validate(): Promise<void>;
|
144
|
+
/** Static methods */
|
131
145
|
/**
|
132
146
|
* Creates a Template instance from an Excel file source.
|
133
147
|
* Removes any existing files in the destination directory.
|
@@ -19,6 +19,7 @@ export declare class TemplateMemory {
|
|
19
19
|
* @experimental This API is experimental and might change in future versions.
|
20
20
|
*/
|
21
21
|
constructor(files: Record<string, Buffer>);
|
22
|
+
/** Public methods */
|
22
23
|
/**
|
23
24
|
* Copies a sheet from the template to a new name.
|
24
25
|
*
|
@@ -118,7 +119,7 @@ export declare class TemplateMemory {
|
|
118
119
|
baseSheetIndex?: number;
|
119
120
|
baseSheetName?: string;
|
120
121
|
gap?: number;
|
121
|
-
}): void
|
122
|
+
}): Promise<void>;
|
122
123
|
/**
|
123
124
|
* Removes sheets from the workbook.
|
124
125
|
*
|
@@ -130,7 +131,8 @@ export declare class TemplateMemory {
|
|
130
131
|
removeSheets(data: {
|
131
132
|
sheetNames?: string[];
|
132
133
|
sheetIndexes?: number[];
|
133
|
-
}): void
|
134
|
+
}): Promise<void>;
|
135
|
+
/** Static methods */
|
134
136
|
/**
|
135
137
|
* Creates a Template instance from an Excel file source.
|
136
138
|
*
|
@@ -0,0 +1,8 @@
|
|
1
|
+
/**
|
2
|
+
* Compares two column strings and returns a number indicating their relative order.
|
3
|
+
*
|
4
|
+
* @param a - The first column string to compare.
|
5
|
+
* @param b - The second column string to compare.
|
6
|
+
* @returns 0 if the columns are equal, -1 if the first column is less than the second, or 1 if the first column is greater than the second.
|
7
|
+
*/
|
8
|
+
export declare function compareColumns(a: string, b: string): number;
|
@@ -4,6 +4,7 @@ export * from "./check-row.js";
|
|
4
4
|
export * from "./check-rows.js";
|
5
5
|
export * from "./check-start-row.js";
|
6
6
|
export * from "./column-index-to-letter.js";
|
7
|
+
export * from "./compare-columns.js";
|
7
8
|
export * from "./escape-xml.js";
|
8
9
|
export * from "./extract-xml-declaration.js";
|
9
10
|
export * from "./get-by-path.js";
|