@js-ak/excel-toolbox 1.1.0 → 1.2.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.
- package/README.md +100 -0
- package/build/cjs/index.js +17 -0
- package/build/cjs/lib/index.js +18 -0
- package/build/cjs/lib/merge-sheets-to-base-file-process.js +96 -0
- package/build/cjs/lib/merge-sheets-to-base-file-sync.js +68 -0
- package/build/cjs/lib/merge-sheets-to-base-file.js +68 -0
- package/build/cjs/lib/utils/get-max-row-number.js +23 -0
- package/build/cjs/lib/utils/index.js +23 -0
- package/build/cjs/lib/utils/is-same-buffer.js +13 -0
- package/build/cjs/lib/utils/remove-sheet-by-name.js +45 -0
- package/build/cjs/lib/utils/remove-sheet-from-content-types.js +13 -0
- package/build/cjs/lib/utils/remove-sheet-from-rels.js +13 -0
- package/build/cjs/lib/utils/remove-sheet-from-workbook.js +13 -0
- package/build/cjs/lib/utils/shift-cell-ref.js +26 -0
- package/build/cjs/lib/xml/build-merged-sheet.js +32 -0
- package/build/cjs/lib/xml/extract-rows-from-sheet.js +65 -0
- package/build/cjs/lib/xml/extract-xml-from-sheet.js +49 -0
- package/build/cjs/lib/xml/extract-xml-from-system-content.js +53 -0
- package/build/cjs/lib/xml/index.js +21 -0
- package/build/cjs/lib/xml/shift-row-indices.js +36 -0
- package/build/cjs/lib/zip/constants.js +32 -0
- package/build/cjs/lib/zip/create-sync.js +84 -0
- package/build/cjs/lib/zip/create.js +89 -0
- package/build/cjs/lib/zip/index.js +20 -0
- package/build/cjs/lib/zip/read-sync.js +57 -0
- package/build/cjs/lib/zip/read.js +62 -0
- package/build/cjs/lib/zip/utils.js +158 -0
- package/build/esm/lib/index.js +2 -0
- package/build/esm/lib/merge-sheets-to-base-file-process.js +69 -0
- package/build/esm/lib/merge-sheets-to-base-file-sync.js +41 -0
- package/build/esm/lib/merge-sheets-to-base-file.js +41 -0
- package/build/esm/lib/utils/get-max-row-number.js +19 -0
- package/build/esm/lib/utils/index.js +7 -0
- package/build/esm/lib/utils/is-same-buffer.js +9 -0
- package/build/esm/lib/utils/remove-sheet-by-name.js +41 -0
- package/build/esm/lib/utils/remove-sheet-from-content-types.js +9 -0
- package/build/esm/lib/utils/remove-sheet-from-rels.js +9 -0
- package/build/esm/lib/utils/remove-sheet-from-workbook.js +9 -0
- package/build/esm/lib/utils/shift-cell-ref.js +22 -0
- package/build/esm/lib/xml/build-merged-sheet.js +28 -0
- package/build/{lib → esm/lib}/xml/extract-rows-from-sheet.js +1 -1
- package/build/esm/lib/xml/index.js +5 -0
- package/build/{lib/zip/create.js → esm/lib/zip/create-sync.js} +1 -1
- package/build/esm/lib/zip/create.js +82 -0
- package/build/esm/lib/zip/index.js +4 -0
- package/build/{lib/zip/read.js → esm/lib/zip/read-sync.js} +1 -1
- package/build/esm/lib/zip/read.js +55 -0
- package/build/{lib → esm/lib}/zip/utils.js +1 -1
- package/build/types/index.d.ts +1 -0
- package/build/types/lib/index.d.ts +2 -0
- package/build/types/lib/merge-sheets-to-base-file-process.d.ts +27 -0
- package/build/{lib/merge-sheets-to-base-file.d.ts → types/lib/merge-sheets-to-base-file-sync.d.ts} +5 -5
- package/build/types/lib/merge-sheets-to-base-file.d.ts +29 -0
- package/build/types/lib/utils/get-max-row-number.d.ts +6 -0
- package/build/types/lib/utils/index.d.ts +7 -0
- package/build/types/lib/utils/is-same-buffer.d.ts +9 -0
- package/build/types/lib/utils/remove-sheet-by-name.d.ts +7 -0
- package/build/types/lib/utils/remove-sheet-from-content-types.d.ts +7 -0
- package/build/types/lib/utils/remove-sheet-from-rels.d.ts +7 -0
- package/build/types/lib/utils/remove-sheet-from-workbook.d.ts +7 -0
- package/build/types/lib/utils/shift-cell-ref.d.ts +13 -0
- package/build/{lib → types/lib}/xml/build-merged-sheet.d.ts +7 -8
- package/build/{lib → types/lib}/xml/extract-rows-from-sheet.d.ts +0 -1
- package/build/{lib → types/lib}/xml/extract-xml-from-sheet.d.ts +0 -1
- package/build/{lib → types/lib}/xml/extract-xml-from-system-content.d.ts +0 -1
- package/build/types/lib/xml/index.d.ts +5 -0
- package/build/{lib → types/lib}/xml/shift-row-indices.d.ts +0 -1
- package/build/{lib → types/lib}/zip/constants.d.ts +0 -1
- package/build/types/lib/zip/create-sync.d.ts +12 -0
- package/build/{lib → types/lib}/zip/create.d.ts +1 -2
- package/build/types/lib/zip/index.d.ts +4 -0
- package/build/types/lib/zip/read-sync.d.ts +10 -0
- package/build/{lib → types/lib}/zip/read.d.ts +1 -4
- package/build/{lib → types/lib}/zip/utils.d.ts +1 -2
- package/package.json +22 -8
- package/build/index.d.ts +0 -2
- package/build/lib/index.d.ts +0 -2
- package/build/lib/index.d.ts.map +0 -1
- package/build/lib/index.js +0 -1
- package/build/lib/merge-sheets-to-base-file.d.ts.map +0 -1
- package/build/lib/merge-sheets-to-base-file.js +0 -190
- package/build/lib/xml/build-merged-sheet.d.ts.map +0 -1
- package/build/lib/xml/build-merged-sheet.js +0 -32
- package/build/lib/xml/extract-rows-from-sheet.d.ts.map +0 -1
- package/build/lib/xml/extract-xml-from-sheet.d.ts.map +0 -1
- package/build/lib/xml/extract-xml-from-system-content.d.ts.map +0 -1
- package/build/lib/xml/shift-row-indices.d.ts.map +0 -1
- package/build/lib/zip/constants.d.ts.map +0 -1
- package/build/lib/zip/create.d.ts.map +0 -1
- package/build/lib/zip/index.d.ts +0 -3
- package/build/lib/zip/index.d.ts.map +0 -1
- package/build/lib/zip/index.js +0 -2
- package/build/lib/zip/read.d.ts.map +0 -1
- package/build/lib/zip/utils.d.ts.map +0 -1
- /package/build/{index.js → esm/index.js} +0 -0
- /package/build/{lib → esm/lib}/xml/extract-xml-from-sheet.js +0 -0
- /package/build/{lib → esm/lib}/xml/extract-xml-from-system-content.js +0 -0
- /package/build/{lib → esm/lib}/xml/shift-row-indices.js +0 -0
- /package/build/{lib → esm/lib}/zip/constants.js +0 -0
package/README.md
CHANGED
@@ -1 +1,101 @@
|
|
1
1
|
# excel-toolbox
|
2
|
+
|
3
|
+

|
4
|
+
|
5
|
+
A lightweight toolkit for merging sheets from multiple `.xlsx` Excel files without dependencies.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
You can install the package via npm:
|
10
|
+
|
11
|
+
```bash
|
12
|
+
npm install @js-ak/excel-toolbox
|
13
|
+
```
|
14
|
+
|
15
|
+
## Getting Started
|
16
|
+
|
17
|
+
To merge rows from multiple Excel files into one:
|
18
|
+
|
19
|
+
```ts
|
20
|
+
import fs from "node:fs";
|
21
|
+
import { mergeSheetsToBaseFileSync } from "@js-ak/excel-toolbox";
|
22
|
+
|
23
|
+
const baseFile = fs.readFileSync("base.xlsx");
|
24
|
+
const otherFile = fs.readFileSync("data.xlsx");
|
25
|
+
|
26
|
+
const resultBuffer = mergeSheetsToBaseFileSync({
|
27
|
+
baseFile,
|
28
|
+
additions: [
|
29
|
+
{ file: otherFile, sheetIndexes: [1] }
|
30
|
+
],
|
31
|
+
gap: 2,
|
32
|
+
});
|
33
|
+
|
34
|
+
fs.writeFileSync("output.xlsx", resultBuffer);
|
35
|
+
```
|
36
|
+
|
37
|
+
## Features
|
38
|
+
|
39
|
+
- 🧩 **Merge sheets** from multiple Excel files
|
40
|
+
- 🧼 **Clean sheet removal** — by name or index
|
41
|
+
- 📎 **Keeps styles and merged cells**
|
42
|
+
- 🪶 **Lightweight ZIP and XML handling**
|
43
|
+
|
44
|
+
## API
|
45
|
+
|
46
|
+
### `mergeSheetsToBaseFileSync(options)`
|
47
|
+
|
48
|
+
#### Parameters
|
49
|
+
|
50
|
+
| Name | Type | Description |
|
51
|
+
|-----------------------|--------------------------------------------------------------------|------------------------------------------------|
|
52
|
+
| `baseFile` | `Buffer` | The base Excel file. |
|
53
|
+
| `additions` | `{ file: Buffer; sheetIndexes: number[]; isBaseFile?: boolean }[]` | Files and sheet indices to merge. |
|
54
|
+
| `baseSheetIndex` | `number` (default: `1`) | The sheet index in the base file to append to. |
|
55
|
+
| `gap` | `number` (default: `0`) | Empty rows inserted between merged blocks. |
|
56
|
+
| `sheetNamesToRemove` | `string[]` (default: `[]`) | Sheets to remove by name. |
|
57
|
+
| `sheetsToRemove` | `number[]` (default: `[]`) | Sheets to remove by index (1-based). |
|
58
|
+
|
59
|
+
#### Returns
|
60
|
+
|
61
|
+
`Buffer` — the merged Excel file.
|
62
|
+
|
63
|
+
### `mergeSheetsToBaseFile(options): Promise<Buffer>`
|
64
|
+
|
65
|
+
Asynchronous version of `mergeSheetsToBaseFileSync`.
|
66
|
+
|
67
|
+
#### Parameters
|
68
|
+
|
69
|
+
Same as [`mergeSheetsToBaseFileSync`](#mergesheetstobasefilesyncoptions).
|
70
|
+
|
71
|
+
#### Returns
|
72
|
+
|
73
|
+
`Promise<Buffer>` — resolves with the merged Excel file.
|
74
|
+
|
75
|
+
#### Example
|
76
|
+
|
77
|
+
```ts
|
78
|
+
import fs from "node:fs/promises";
|
79
|
+
import { mergeSheetsToBaseFile } from "@js-ak/excel-toolbox";
|
80
|
+
|
81
|
+
const baseFile = await fs.readFile("base.xlsx");
|
82
|
+
const otherFile = await fs.readFile("data.xlsx");
|
83
|
+
|
84
|
+
const output = await mergeSheetsToBaseFile({
|
85
|
+
baseFile,
|
86
|
+
additions: [
|
87
|
+
{ file: otherFile, sheetIndexes: [1] }
|
88
|
+
],
|
89
|
+
gap: 1,
|
90
|
+
});
|
91
|
+
|
92
|
+
await fs.writeFile("output.xlsx", output);
|
93
|
+
```
|
94
|
+
|
95
|
+
## Contributing
|
96
|
+
|
97
|
+
Contributions are welcome! Feel free to open an issue or submit a pull request if you have ideas or encounter bugs.
|
98
|
+
|
99
|
+
## License
|
100
|
+
|
101
|
+
MIT — see [LICENSE](./LICENSE) for details.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
|
+
};
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
17
|
+
__exportStar(require("./lib/index.js"), exports);
|
@@ -0,0 +1,18 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
|
+
};
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
17
|
+
__exportStar(require("./merge-sheets-to-base-file-sync.js"), exports);
|
18
|
+
__exportStar(require("./merge-sheets-to-base-file.js"), exports);
|
@@ -0,0 +1,96 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
26
|
+
exports.mergeSheetsToBaseFileProcess = void 0;
|
27
|
+
const Utils = __importStar(require("./utils/index.js"));
|
28
|
+
const Xml = __importStar(require("./xml/index.js"));
|
29
|
+
/**
|
30
|
+
* Merges rows from other Excel files into a base Excel file.
|
31
|
+
*
|
32
|
+
* This function is a process-friendly version of mergeSheetsToBaseFile.
|
33
|
+
* It takes a single object with the following properties:
|
34
|
+
* - additions: An array of objects with two properties:
|
35
|
+
* - files: A dictionary of file paths to their corresponding XML content
|
36
|
+
* - sheetIndexes: The 1-based indexes of the sheet to extract rows from
|
37
|
+
* - baseFiles: A dictionary of file paths to their corresponding XML content
|
38
|
+
* - baseSheetIndex: The 1-based index of the sheet in the base file to add rows to
|
39
|
+
* - gap: The number of empty rows to insert between each added section
|
40
|
+
* - sheetNamesToRemove: The names of sheets to remove from the output file
|
41
|
+
* - sheetsToRemove: The 1-based indices of sheets to remove from the output file
|
42
|
+
*
|
43
|
+
* The function returns a dictionary of file paths to their corresponding XML content.
|
44
|
+
*/
|
45
|
+
function mergeSheetsToBaseFileProcess(data) {
|
46
|
+
const { additions, baseFiles, baseSheetIndex, gap, sheetNamesToRemove, sheetsToRemove, } = data;
|
47
|
+
const basePath = `xl/worksheets/sheet${baseSheetIndex}.xml`;
|
48
|
+
if (!baseFiles[basePath]) {
|
49
|
+
throw new Error(`Base file does not contain ${basePath}`);
|
50
|
+
}
|
51
|
+
const { lastRowNumber, mergeCells: baseMergeCells, rows: baseRows, } = Xml.extractRowsFromSheet(baseFiles[basePath]);
|
52
|
+
const allRows = [...baseRows];
|
53
|
+
const allMergeCells = [...baseMergeCells];
|
54
|
+
let currentRowOffset = lastRowNumber + gap;
|
55
|
+
for (const { files, sheetIndexes } of additions) {
|
56
|
+
for (const sheetIndex of sheetIndexes) {
|
57
|
+
const sheetPath = `xl/worksheets/sheet${sheetIndex}.xml`;
|
58
|
+
if (!files[sheetPath]) {
|
59
|
+
throw new Error(`File does not contain ${sheetPath}`);
|
60
|
+
}
|
61
|
+
const { mergeCells, rows } = Xml.extractRowsFromSheet(files[sheetPath]);
|
62
|
+
const shiftedRows = Xml.shiftRowIndices(rows, currentRowOffset);
|
63
|
+
const shiftedMergeCells = mergeCells.map(cell => {
|
64
|
+
const [start, end] = cell.ref.split(":");
|
65
|
+
if (!start || !end) {
|
66
|
+
return cell;
|
67
|
+
}
|
68
|
+
const shiftedStart = Utils.shiftCellRef(start, currentRowOffset);
|
69
|
+
const shiftedEnd = Utils.shiftCellRef(end, currentRowOffset);
|
70
|
+
return { ...cell, ref: `${shiftedStart}:${shiftedEnd}` };
|
71
|
+
});
|
72
|
+
allRows.push(...shiftedRows);
|
73
|
+
allMergeCells.push(...shiftedMergeCells);
|
74
|
+
currentRowOffset += Utils.getMaxRowNumber(rows) + gap;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
const mergedXml = Xml.buildMergedSheet(baseFiles[basePath], allRows, allMergeCells);
|
78
|
+
baseFiles[basePath] = mergedXml;
|
79
|
+
for (const sheetIndex of sheetsToRemove) {
|
80
|
+
const sheetPath = `xl/worksheets/sheet${sheetIndex}.xml`;
|
81
|
+
delete baseFiles[sheetPath];
|
82
|
+
if (baseFiles["xl/workbook.xml"]) {
|
83
|
+
baseFiles["xl/workbook.xml"] = Utils.removeSheetFromWorkbook(baseFiles["xl/workbook.xml"], sheetIndex);
|
84
|
+
}
|
85
|
+
if (baseFiles["xl/_rels/workbook.xml.rels"]) {
|
86
|
+
baseFiles["xl/_rels/workbook.xml.rels"] = Utils.removeSheetFromRels(baseFiles["xl/_rels/workbook.xml.rels"], sheetIndex);
|
87
|
+
}
|
88
|
+
if (baseFiles["[Content_Types].xml"]) {
|
89
|
+
baseFiles["[Content_Types].xml"] = Utils.removeSheetFromContentTypes(baseFiles["[Content_Types].xml"], sheetIndex);
|
90
|
+
}
|
91
|
+
}
|
92
|
+
for (const sheetName of sheetNamesToRemove) {
|
93
|
+
Utils.removeSheetByName(baseFiles, sheetName);
|
94
|
+
}
|
95
|
+
}
|
96
|
+
exports.mergeSheetsToBaseFileProcess = mergeSheetsToBaseFileProcess;
|
@@ -0,0 +1,68 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
26
|
+
exports.mergeSheetsToBaseFileSync = void 0;
|
27
|
+
const Utils = __importStar(require("./utils/index.js"));
|
28
|
+
const Zip = __importStar(require("./zip/index.js"));
|
29
|
+
const merge_sheets_to_base_file_process_js_1 = require("./merge-sheets-to-base-file-process.js");
|
30
|
+
/**
|
31
|
+
* Merge rows from other Excel files into a base Excel file.
|
32
|
+
* The output is a new Excel file with the merged content.
|
33
|
+
*
|
34
|
+
* @param {Object} data
|
35
|
+
* @param {Object[]} data.additions
|
36
|
+
* @param {Buffer} data.additions.file - The file to extract rows from
|
37
|
+
* @param {number[]} data.additions.sheetIndexes - The 1-based indexes of the sheet to extract rows from
|
38
|
+
* @param {Buffer} data.baseFile - The base file to add rows to
|
39
|
+
* @param {number} [data.baseSheetIndex=1] - The 1-based index of the sheet in the base file to add rows to
|
40
|
+
* @param {number} [data.gap=0] - The number of empty rows to insert between each added section
|
41
|
+
* @param {string[]} [data.sheetNamesToRemove=[]] - The names of sheets to remove from the output file
|
42
|
+
* @param {number[]} [data.sheetsToRemove=[]] - The 1-based indices of sheets to remove from the output file
|
43
|
+
* @returns {Buffer} - The merged Excel file
|
44
|
+
*/
|
45
|
+
function mergeSheetsToBaseFileSync(data) {
|
46
|
+
const { additions = [], baseFile, baseSheetIndex = 1, gap = 0, sheetNamesToRemove = [], sheetsToRemove = [], } = data;
|
47
|
+
const baseFiles = Zip.readSync(baseFile);
|
48
|
+
const additionsUpdated = [];
|
49
|
+
for (const { file, isBaseFile, sheetIndexes } of additions) {
|
50
|
+
const files = (isBaseFile || Utils.isSameBuffer(file, baseFile))
|
51
|
+
? baseFiles
|
52
|
+
: Zip.readSync(file);
|
53
|
+
additionsUpdated.push({
|
54
|
+
files,
|
55
|
+
sheetIndexes,
|
56
|
+
});
|
57
|
+
}
|
58
|
+
(0, merge_sheets_to_base_file_process_js_1.mergeSheetsToBaseFileProcess)({
|
59
|
+
additions: additionsUpdated,
|
60
|
+
baseFiles,
|
61
|
+
baseSheetIndex,
|
62
|
+
gap,
|
63
|
+
sheetNamesToRemove,
|
64
|
+
sheetsToRemove,
|
65
|
+
});
|
66
|
+
return Zip.createSync(baseFiles);
|
67
|
+
}
|
68
|
+
exports.mergeSheetsToBaseFileSync = mergeSheetsToBaseFileSync;
|
@@ -0,0 +1,68 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
26
|
+
exports.mergeSheetsToBaseFile = void 0;
|
27
|
+
const Utils = __importStar(require("./utils/index.js"));
|
28
|
+
const Zip = __importStar(require("./zip/index.js"));
|
29
|
+
const merge_sheets_to_base_file_process_js_1 = require("./merge-sheets-to-base-file-process.js");
|
30
|
+
/**
|
31
|
+
* Merge rows from other Excel files into a base Excel file.
|
32
|
+
* The output is a new Excel file with the merged content.
|
33
|
+
*
|
34
|
+
* @param {Object} data
|
35
|
+
* @param {Object[]} data.additions
|
36
|
+
* @param {Buffer} data.additions.file - The file to extract rows from
|
37
|
+
* @param {number[]} data.additions.sheetIndexes - The 1-based indexes of the sheet to extract rows from
|
38
|
+
* @param {Buffer} data.baseFile - The base file to add rows to
|
39
|
+
* @param {number} [data.baseSheetIndex=1] - The 1-based index of the sheet in the base file to add rows to
|
40
|
+
* @param {number} [data.gap=0] - The number of empty rows to insert between each added section
|
41
|
+
* @param {string[]} [data.sheetNamesToRemove=[]] - The names of sheets to remove from the output file
|
42
|
+
* @param {number[]} [data.sheetsToRemove=[]] - The 1-based indices of sheets to remove from the output file
|
43
|
+
* @returns {Promise<Buffer>} - The merged Excel file
|
44
|
+
*/
|
45
|
+
async function mergeSheetsToBaseFile(data) {
|
46
|
+
const { additions = [], baseFile, baseSheetIndex = 1, gap = 0, sheetNamesToRemove = [], sheetsToRemove = [], } = data;
|
47
|
+
const baseFiles = await Zip.read(baseFile);
|
48
|
+
const additionsUpdated = [];
|
49
|
+
for (const { file, isBaseFile, sheetIndexes } of additions) {
|
50
|
+
const files = (isBaseFile || Utils.isSameBuffer(file, baseFile))
|
51
|
+
? baseFiles
|
52
|
+
: await Zip.read(file);
|
53
|
+
additionsUpdated.push({
|
54
|
+
files,
|
55
|
+
sheetIndexes,
|
56
|
+
});
|
57
|
+
}
|
58
|
+
(0, merge_sheets_to_base_file_process_js_1.mergeSheetsToBaseFileProcess)({
|
59
|
+
additions: additionsUpdated,
|
60
|
+
baseFiles,
|
61
|
+
baseSheetIndex,
|
62
|
+
gap,
|
63
|
+
sheetNamesToRemove,
|
64
|
+
sheetsToRemove,
|
65
|
+
});
|
66
|
+
return Zip.create(baseFiles);
|
67
|
+
}
|
68
|
+
exports.mergeSheetsToBaseFile = mergeSheetsToBaseFile;
|
@@ -0,0 +1,23 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.getMaxRowNumber = void 0;
|
4
|
+
/**
|
5
|
+
* Finds the maximum row number in a list of <row> elements.
|
6
|
+
* @param {string[]} rows - An array of strings, each representing a <row> element.
|
7
|
+
* @returns {number} - The maximum row number.
|
8
|
+
*/
|
9
|
+
function getMaxRowNumber(rows) {
|
10
|
+
let max = 0;
|
11
|
+
for (const row of rows) {
|
12
|
+
const match = row.match(/<row[^>]* r="(\d+)"/);
|
13
|
+
if (match) {
|
14
|
+
if (!match[1])
|
15
|
+
continue;
|
16
|
+
const num = parseInt(match[1], 10);
|
17
|
+
if (num > max)
|
18
|
+
max = num;
|
19
|
+
}
|
20
|
+
}
|
21
|
+
return max;
|
22
|
+
}
|
23
|
+
exports.getMaxRowNumber = getMaxRowNumber;
|
@@ -0,0 +1,23 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
|
+
};
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
17
|
+
__exportStar(require("./get-max-row-number.js"), exports);
|
18
|
+
__exportStar(require("./is-same-buffer.js"), exports);
|
19
|
+
__exportStar(require("./remove-sheet-by-name.js"), exports);
|
20
|
+
__exportStar(require("./remove-sheet-from-content-types.js"), exports);
|
21
|
+
__exportStar(require("./remove-sheet-from-rels.js"), exports);
|
22
|
+
__exportStar(require("./remove-sheet-from-workbook.js"), exports);
|
23
|
+
__exportStar(require("./shift-cell-ref.js"), exports);
|
@@ -0,0 +1,13 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.isSameBuffer = void 0;
|
4
|
+
/**
|
5
|
+
* Checks if two Buffers are the same
|
6
|
+
* @param {Buffer} buf1 - the first Buffer
|
7
|
+
* @param {Buffer} buf2 - the second Buffer
|
8
|
+
* @returns {boolean} - true if the Buffers are the same, false otherwise
|
9
|
+
*/
|
10
|
+
function isSameBuffer(buf1, buf2) {
|
11
|
+
return buf1.equals(buf2);
|
12
|
+
}
|
13
|
+
exports.isSameBuffer = isSameBuffer;
|
@@ -0,0 +1,45 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.removeSheetByName = void 0;
|
4
|
+
/**
|
5
|
+
* Removes a sheet from the Excel workbook by name.
|
6
|
+
* @param {Object.<string, string | Buffer>} files - The dictionary of files in the workbook.
|
7
|
+
* @param {string} sheetName - The name of the sheet to remove.
|
8
|
+
* @returns {void}
|
9
|
+
*/
|
10
|
+
function removeSheetByName(files, sheetName) {
|
11
|
+
const workbookXml = files["xl/workbook.xml"];
|
12
|
+
const relsXml = files["xl/_rels/workbook.xml.rels"];
|
13
|
+
if (!workbookXml || !relsXml) {
|
14
|
+
return;
|
15
|
+
}
|
16
|
+
const sheetMatch = workbookXml.match(new RegExp(`<sheet[^>]+name=["']${sheetName}["'][^>]*/>`));
|
17
|
+
if (!sheetMatch) {
|
18
|
+
return;
|
19
|
+
}
|
20
|
+
const sheetTag = sheetMatch[0];
|
21
|
+
const sheetIdMatch = sheetTag.match(/sheetId=["'](\d+)["']/);
|
22
|
+
const ridMatch = sheetTag.match(/r:id=["'](rId\d+)["']/);
|
23
|
+
if (!sheetIdMatch || !ridMatch) {
|
24
|
+
return;
|
25
|
+
}
|
26
|
+
const relId = ridMatch[1];
|
27
|
+
const relMatch = relsXml.match(new RegExp(`<Relationship[^>]+Id=["']${relId}["'][^>]+Target=["']([^"']+)["'][^>]*/>`));
|
28
|
+
if (!relMatch) {
|
29
|
+
return;
|
30
|
+
}
|
31
|
+
const relTag = relMatch[0];
|
32
|
+
const targetMatch = relTag.match(/Target=["']([^"']+)["']/);
|
33
|
+
if (!targetMatch) {
|
34
|
+
return;
|
35
|
+
}
|
36
|
+
const targetPath = `xl/${targetMatch[1]}`.replace(/\\/g, "/");
|
37
|
+
delete files[targetPath];
|
38
|
+
files["xl/workbook.xml"] = workbookXml.replace(sheetTag, "");
|
39
|
+
files["xl/_rels/workbook.xml.rels"] = relsXml.replace(relTag, "");
|
40
|
+
const contentTypes = files["[Content_Types].xml"];
|
41
|
+
if (contentTypes) {
|
42
|
+
files["[Content_Types].xml"] = contentTypes.replace(new RegExp(`<Override[^>]+PartName=["']/${targetPath}["'][^>]*/>`, "g"), "");
|
43
|
+
}
|
44
|
+
}
|
45
|
+
exports.removeSheetByName = removeSheetByName;
|
@@ -0,0 +1,13 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.removeSheetFromContentTypes = void 0;
|
4
|
+
/**
|
5
|
+
* Removes the specified sheet from the Content_Types.xml file.
|
6
|
+
* @param {string} xml - The Content_Types.xml file contents as a string
|
7
|
+
* @param {number} sheetIndex - The 1-based index of the sheet to remove
|
8
|
+
* @returns {string} - The modified Content_Types.xml file contents
|
9
|
+
*/
|
10
|
+
function removeSheetFromContentTypes(xml, sheetIndex) {
|
11
|
+
return xml.replace(new RegExp(`<Override[^>]+PartName=["']/xl/worksheets/sheet${sheetIndex}\\.xml["'][^>]*/>`, "g"), "");
|
12
|
+
}
|
13
|
+
exports.removeSheetFromContentTypes = removeSheetFromContentTypes;
|
@@ -0,0 +1,13 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.removeSheetFromRels = void 0;
|
4
|
+
/**
|
5
|
+
* Removes the specified sheet from the workbook relationships file (xl/_rels/workbook.xml.rels).
|
6
|
+
* @param {string} xml - The workbook relationships file contents as a string
|
7
|
+
* @param {number} sheetIndex - The 1-based index of the sheet to remove
|
8
|
+
* @returns {string} - The modified workbook relationships file contents
|
9
|
+
*/
|
10
|
+
function removeSheetFromRels(xml, sheetIndex) {
|
11
|
+
return xml.replace(new RegExp(`<Relationship[^>]+Target=["']worksheets/sheet${sheetIndex}\\.xml["'][^>]*/>`, "g"), "");
|
12
|
+
}
|
13
|
+
exports.removeSheetFromRels = removeSheetFromRels;
|
@@ -0,0 +1,13 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.removeSheetFromWorkbook = void 0;
|
4
|
+
/**
|
5
|
+
* Removes the specified sheet from the workbook (xl/workbook.xml).
|
6
|
+
* @param {string} xml - The workbook file contents as a string
|
7
|
+
* @param {number} sheetIndex - The 1-based index of the sheet to remove
|
8
|
+
* @returns {string} - The modified workbook file contents
|
9
|
+
*/
|
10
|
+
function removeSheetFromWorkbook(xml, sheetIndex) {
|
11
|
+
return xml.replace(new RegExp(`<sheet[^>]+sheetId=["']${sheetIndex}["'][^>]*/>`, "g"), "");
|
12
|
+
}
|
13
|
+
exports.removeSheetFromWorkbook = removeSheetFromWorkbook;
|
@@ -0,0 +1,26 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.shiftCellRef = void 0;
|
4
|
+
/**
|
5
|
+
* Shifts the row number in a cell reference by the specified number of rows.
|
6
|
+
* The function takes a cell reference string in the format "A1" and a row shift value.
|
7
|
+
* It returns the shifted cell reference string.
|
8
|
+
*
|
9
|
+
* @example
|
10
|
+
* // Shifts the cell reference "A1" down by 2 rows, resulting in "A3"
|
11
|
+
* shiftCellRef('A1', 2);
|
12
|
+
* @param {string} cellRef - The cell reference string to be shifted
|
13
|
+
* @param {number} rowShift - The number of rows to shift the reference by
|
14
|
+
* @returns {string} - The shifted cell reference string
|
15
|
+
*/
|
16
|
+
function shiftCellRef(cellRef, rowShift) {
|
17
|
+
const match = cellRef.match(/^([A-Z]+)(\d+)$/);
|
18
|
+
if (!match)
|
19
|
+
return cellRef;
|
20
|
+
const col = match[1];
|
21
|
+
if (!match[2])
|
22
|
+
return cellRef;
|
23
|
+
const row = parseInt(match[2], 10);
|
24
|
+
return `${col}${row + rowShift}`;
|
25
|
+
}
|
26
|
+
exports.shiftCellRef = shiftCellRef;
|
@@ -0,0 +1,32 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.buildMergedSheet = void 0;
|
4
|
+
/**
|
5
|
+
* Builds a new XML string for a merged Excel sheet by combining the original XML
|
6
|
+
* with merged rows and optional cell merge information.
|
7
|
+
*
|
8
|
+
* This function replaces the <sheetData> section in the original XML with the provided merged rows,
|
9
|
+
* and optionally adds <mergeCells> definitions after the </sheetData> tag.
|
10
|
+
*
|
11
|
+
* @param {string} originalXml - The original XML string of the Excel worksheet.
|
12
|
+
* @param {string[]} mergedRows - Array of XML strings representing each row in the merged sheet.
|
13
|
+
* @param {Object[]} [mergeCells] - Optional array of merge cell definitions.
|
14
|
+
* Each object should have a 'ref' property specifying the merge range (e.g., "A1:B2").
|
15
|
+
* @returns {string} - The reconstructed XML string with merged content.
|
16
|
+
*/
|
17
|
+
function buildMergedSheet(originalXml, mergedRows, mergeCells = []) {
|
18
|
+
// Remove any existing <mergeCells> section from the XML
|
19
|
+
let xmlData = originalXml.replace(/<mergeCells[^>]*>[\s\S]*?<\/mergeCells>/g, "");
|
20
|
+
// Construct a new <sheetData> section with the provided rows
|
21
|
+
const sheetDataXml = `<sheetData>${mergedRows.join("")}</sheetData>`;
|
22
|
+
// Replace the existing <sheetData> section with the new one
|
23
|
+
xmlData = xmlData.replace(/<sheetData[^>]*>[\s\S]*?<\/sheetData>/, sheetDataXml);
|
24
|
+
if (mergeCells.length > 0) {
|
25
|
+
// Construct a new <mergeCells> section with the provided merge references
|
26
|
+
const mergeCellsXml = `<mergeCells count="${mergeCells.length}">${mergeCells.map(mc => `<mergeCell ref="${mc.ref}"/>`).join("")}</mergeCells>`;
|
27
|
+
// Insert <mergeCells> after </sheetData> and before the next XML tag
|
28
|
+
xmlData = xmlData.replace(/(<\/sheetData>)(\s*<)/, `$1\n${mergeCellsXml}\n$2`);
|
29
|
+
}
|
30
|
+
return xmlData;
|
31
|
+
}
|
32
|
+
exports.buildMergedSheet = buildMergedSheet;
|
@@ -0,0 +1,65 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.extractRowsFromSheet = void 0;
|
4
|
+
const extract_xml_from_sheet_js_1 = require("./extract-xml-from-sheet.js");
|
5
|
+
/**
|
6
|
+
* Parses a worksheet (either as Buffer or string) to extract row data,
|
7
|
+
* last row number, and merge cell information from Excel XML format.
|
8
|
+
*
|
9
|
+
* This function is particularly useful for processing Excel files in
|
10
|
+
* Open XML Spreadsheet format (.xlsx).
|
11
|
+
*
|
12
|
+
* @param {Buffer|string} sheet - The worksheet content to parse, either as:
|
13
|
+
* - Buffer (binary Excel sheet)
|
14
|
+
* - string (raw XML content)
|
15
|
+
* @returns {{
|
16
|
+
* rows: string[],
|
17
|
+
* lastRowNumber: number,
|
18
|
+
* mergeCells: {ref: string}[]
|
19
|
+
* }} An object containing:
|
20
|
+
* - rows: Array of raw XML strings for each <row> element
|
21
|
+
* - lastRowNumber: Highest row number found in the sheet (1-based)
|
22
|
+
* - mergeCells: Array of merged cell ranges (e.g., [{ref: "A1:B2"}])
|
23
|
+
* @throws {Error} If the sheetData section is not found in the XML
|
24
|
+
*/
|
25
|
+
function extractRowsFromSheet(sheet) {
|
26
|
+
// Convert Buffer input to XML string if needed
|
27
|
+
const xml = typeof sheet === "string" ? sheet : (0, extract_xml_from_sheet_js_1.extractXmlFromSheet)(sheet);
|
28
|
+
// Extract the sheetData section containing all rows
|
29
|
+
const sheetDataMatch = xml.match(/<sheetData[^>]*>([\s\S]*?)<\/sheetData>/);
|
30
|
+
if (!sheetDataMatch) {
|
31
|
+
throw new Error("sheetData not found in worksheet XML");
|
32
|
+
}
|
33
|
+
const sheetDataContent = sheetDataMatch[1] || "";
|
34
|
+
// Extract all <row> elements using regex
|
35
|
+
const rowMatches = [...sheetDataContent.matchAll(/<row\b[^>]*\/>|<row\b[^>]*>[\s\S]*?<\/row>/g)];
|
36
|
+
const rows = rowMatches.map(match => match[0]);
|
37
|
+
// Calculate the highest row number present in the sheet
|
38
|
+
const lastRowNumber = rowMatches
|
39
|
+
.map(match => {
|
40
|
+
// Extract row number from r="..." attribute (1-based)
|
41
|
+
const rowNumMatch = match[0].match(/r="(\d+)"/);
|
42
|
+
return rowNumMatch?.[1] ? parseInt(rowNumMatch[1], 10) : null;
|
43
|
+
})
|
44
|
+
.filter((row) => row !== null) // Type guard to filter out nulls
|
45
|
+
.reduce((max, current) => Math.max(max, current), 0); // Find maximum row number
|
46
|
+
// Extract all merged cell ranges from the worksheet
|
47
|
+
const mergeCells = [];
|
48
|
+
const mergeCellsMatch = xml.match(/<mergeCells[^>]*>([\s\S]*?)<\/mergeCells>/);
|
49
|
+
if (mergeCellsMatch) {
|
50
|
+
// Find all mergeCell entries with ref attributes
|
51
|
+
const mergeCellMatches = mergeCellsMatch[1]?.match(/<mergeCell[^>]+ref="([^"]+)"[^>]*>/g) || [];
|
52
|
+
mergeCellMatches.forEach(match => {
|
53
|
+
const refMatch = match.match(/ref="([^"]+)"/);
|
54
|
+
if (refMatch?.[1]) {
|
55
|
+
mergeCells.push({ ref: refMatch[1] }); // Store the cell range (e.g., "A1:B2")
|
56
|
+
}
|
57
|
+
});
|
58
|
+
}
|
59
|
+
return {
|
60
|
+
lastRowNumber,
|
61
|
+
mergeCells,
|
62
|
+
rows,
|
63
|
+
};
|
64
|
+
}
|
65
|
+
exports.extractRowsFromSheet = extractRowsFromSheet;
|