@js-ak/excel-toolbox 1.2.7 → 1.3.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 (65) hide show
  1. package/build/cjs/lib/index.js +1 -0
  2. package/build/cjs/lib/template/index.js +17 -0
  3. package/build/cjs/lib/template/template-fs.js +465 -0
  4. package/build/cjs/lib/template/utils/check-row.js +23 -0
  5. package/build/cjs/lib/template/utils/check-rows.js +19 -0
  6. package/build/cjs/lib/template/utils/check-start-row.js +18 -0
  7. package/build/cjs/lib/template/utils/column-index-to-letter.js +17 -0
  8. package/build/cjs/lib/template/utils/escape-xml.js +24 -0
  9. package/build/cjs/lib/template/utils/get-max-row-number.js +20 -0
  10. package/build/cjs/lib/template/utils/get-rows-above.js +23 -0
  11. package/build/cjs/lib/template/utils/get-rows-below.js +23 -0
  12. package/build/cjs/lib/template/utils/index.js +27 -0
  13. package/build/cjs/lib/template/utils/parse-rows.js +30 -0
  14. package/build/cjs/lib/template/utils/to-excel-column-object.js +29 -0
  15. package/build/cjs/lib/template/utils/write-rows-to-stream.js +41 -0
  16. package/build/cjs/lib/xml/build-merged-sheet.js +1 -1
  17. package/build/cjs/lib/zip/constants.js +16 -1
  18. package/build/cjs/lib/zip/create-with-stream.js +214 -0
  19. package/build/cjs/lib/zip/index.js +1 -0
  20. package/build/cjs/lib/zip/utils/crc-32-stream.js +42 -0
  21. package/build/cjs/lib/zip/utils/crc-32.js +2 -35
  22. package/build/cjs/lib/zip/utils/index.js +1 -0
  23. package/build/esm/lib/index.js +1 -0
  24. package/build/esm/lib/template/index.js +1 -0
  25. package/build/esm/lib/template/template-fs.js +428 -0
  26. package/build/esm/lib/template/utils/check-row.js +20 -0
  27. package/build/esm/lib/template/utils/check-rows.js +16 -0
  28. package/build/esm/lib/template/utils/check-start-row.js +15 -0
  29. package/build/esm/lib/template/utils/column-index-to-letter.js +14 -0
  30. package/build/esm/lib/template/utils/escape-xml.js +21 -0
  31. package/build/esm/lib/template/utils/get-max-row-number.js +17 -0
  32. package/build/esm/lib/template/utils/get-rows-above.js +20 -0
  33. package/build/esm/lib/template/utils/get-rows-below.js +20 -0
  34. package/build/esm/lib/template/utils/index.js +11 -0
  35. package/build/esm/lib/template/utils/parse-rows.js +27 -0
  36. package/build/esm/lib/template/utils/to-excel-column-object.js +26 -0
  37. package/build/esm/lib/template/utils/write-rows-to-stream.js +38 -0
  38. package/build/esm/lib/xml/build-merged-sheet.js +1 -1
  39. package/build/esm/lib/zip/constants.js +15 -0
  40. package/build/esm/lib/zip/create-with-stream.js +175 -0
  41. package/build/esm/lib/zip/index.js +1 -0
  42. package/build/esm/lib/zip/utils/crc-32-stream.js +39 -0
  43. package/build/esm/lib/zip/utils/crc-32.js +2 -35
  44. package/build/esm/lib/zip/utils/index.js +1 -0
  45. package/build/types/lib/index.d.ts +1 -0
  46. package/build/types/lib/template/index.d.ts +1 -0
  47. package/build/types/lib/template/template-fs.d.ts +122 -0
  48. package/build/types/lib/template/utils/check-row.d.ts +14 -0
  49. package/build/types/lib/template/utils/check-rows.d.ts +11 -0
  50. package/build/types/lib/template/utils/check-start-row.d.ts +8 -0
  51. package/build/types/lib/template/utils/column-index-to-letter.d.ts +7 -0
  52. package/build/types/lib/template/utils/escape-xml.d.ts +14 -0
  53. package/build/types/lib/template/utils/get-max-row-number.d.ts +7 -0
  54. package/build/types/lib/template/utils/get-rows-above.d.ts +12 -0
  55. package/build/types/lib/template/utils/get-rows-below.d.ts +12 -0
  56. package/build/types/lib/template/utils/index.d.ts +11 -0
  57. package/build/types/lib/template/utils/parse-rows.d.ts +1 -0
  58. package/build/types/lib/template/utils/to-excel-column-object.d.ts +10 -0
  59. package/build/types/lib/template/utils/write-rows-to-stream.d.ts +25 -0
  60. package/build/types/lib/zip/constants.d.ts +9 -0
  61. package/build/types/lib/zip/create-with-stream.d.ts +13 -0
  62. package/build/types/lib/zip/index.d.ts +1 -0
  63. package/build/types/lib/zip/utils/crc-32-stream.d.ts +11 -0
  64. package/build/types/lib/zip/utils/index.d.ts +1 -0
  65. package/package.json +1 -1
@@ -0,0 +1,27 @@
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("./check-row.js"), exports);
18
+ __exportStar(require("./check-rows.js"), exports);
19
+ __exportStar(require("./check-start-row.js"), exports);
20
+ __exportStar(require("./column-index-to-letter.js"), exports);
21
+ __exportStar(require("./escape-xml.js"), exports);
22
+ __exportStar(require("./get-max-row-number.js"), exports);
23
+ __exportStar(require("./get-rows-above.js"), exports);
24
+ __exportStar(require("./get-rows-below.js"), exports);
25
+ __exportStar(require("./parse-rows.js"), exports);
26
+ __exportStar(require("./to-excel-column-object.js"), exports);
27
+ __exportStar(require("./write-rows-to-stream.js"), exports);
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseRows = parseRows;
4
+ function parseRows(innerRows) {
5
+ const rowsMap = new Map();
6
+ // Regex to match all <row> elements
7
+ // 1. `(<row[^>]+r="(\d+)"[^>]*\/>)` - for self-closing tags (<row ... />)
8
+ // 2. `|(<row[^>]+r="(\d+)"[^>]*>[\s\S]*?<\/row>)` — for self-closing tags (<row ... />)
9
+ const rowRegex = /(<row[^>]+r="(\d+)"[^>]*\/>)|(<row[^>]+r="(\d+)"[^>]*>[\s\S]*?<\/row>)/g;
10
+ let match;
11
+ while ((match = rowRegex.exec(innerRows)) !== null) {
12
+ // if this is a self-closing tag (<row ... />)
13
+ if (match[1]) {
14
+ const fullRow = match[1];
15
+ const rowNumber = match[2];
16
+ if (!rowNumber)
17
+ throw new Error("Row number not found");
18
+ rowsMap.set(Number(rowNumber), fullRow);
19
+ }
20
+ // if this is a regular tag (<row>...</row>)
21
+ else if (match[3]) {
22
+ const fullRow = match[3];
23
+ const rowNumber = match[4];
24
+ if (!rowNumber)
25
+ throw new Error("Row number not found");
26
+ rowsMap.set(Number(rowNumber), fullRow);
27
+ }
28
+ }
29
+ return rowsMap;
30
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toExcelColumnObject = toExcelColumnObject;
4
+ /**
5
+ * Converts an array of values into a Record<string, string> with Excel column names as keys.
6
+ *
7
+ * The column names are generated in the standard Excel column naming convention (A, B, ..., Z, AA, AB, ...).
8
+ * The corresponding values are converted to strings using the String() function.
9
+ *
10
+ * @param values - The array of values to convert
11
+ * @returns The resulting Record<string, string>
12
+ */
13
+ function toExcelColumnObject(values) {
14
+ const toExcelColumn = (index) => {
15
+ let column = "";
16
+ let i = index;
17
+ while (i >= 0) {
18
+ column = String.fromCharCode((i % 26) + 65) + column;
19
+ i = Math.floor(i / 26) - 1;
20
+ }
21
+ return column;
22
+ };
23
+ const result = {};
24
+ for (let i = 0; i < values.length; i++) {
25
+ const key = toExcelColumn(i);
26
+ result[key] = String(values[i]);
27
+ }
28
+ return result;
29
+ }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.writeRowsToStream = writeRowsToStream;
4
+ const column_index_to_letter_js_1 = require("./column-index-to-letter.js");
5
+ /**
6
+ * Writes an async iterable of rows to an Excel XML file.
7
+ *
8
+ * Each row is expected to be an array of values, where each value is
9
+ * converted to a string using the `String()` function. Empty values are
10
+ * replaced with an empty string.
11
+ *
12
+ * The `startRowNumber` parameter is used as the starting row number
13
+ * for the first row written to the file. Subsequent rows are written
14
+ * with incrementing row numbers.
15
+ *
16
+ * @param output - A file write stream to write the Excel XML to.
17
+ * @param rows - An async iterable of rows, where each row is an array
18
+ * of values.
19
+ * @param startRowNumber - The starting row number to use for the first
20
+ * row written to the file.
21
+ *
22
+ * @returns An object with a single property `rowNumber`, which is the
23
+ * last row number written to the file (i.e., the `startRowNumber`
24
+ * plus the number of rows written).
25
+ */
26
+ async function writeRowsToStream(output, rows, startRowNumber) {
27
+ let rowNumber = startRowNumber;
28
+ for await (const row of rows) {
29
+ // Transform the row into XML
30
+ const cells = row.map((value, colIndex) => {
31
+ const colLetter = (0, column_index_to_letter_js_1.columnIndexToLetter)(colIndex);
32
+ const cellRef = `${colLetter}${rowNumber}`;
33
+ const cellValue = String(value ?? "");
34
+ return `<c r="${cellRef}" t="inlineStr"><is><t>${cellValue}</t></is></c>`;
35
+ });
36
+ // Write the row to the file
37
+ output.write(`<row r="${rowNumber}">${cells.join("")}</row>`);
38
+ rowNumber++;
39
+ }
40
+ return { rowNumber };
41
+ }
@@ -25,7 +25,7 @@ function buildMergedSheet(originalXml, mergedRows, mergeCells = []) {
25
25
  // Construct a new <mergeCells> section with the provided merge references
26
26
  const mergeCellsXml = `<mergeCells count="${mergeCells.length}">${mergeCells.map(mc => `<mergeCell ref="${mc.ref}"/>`).join("")}</mergeCells>`;
27
27
  // Insert <mergeCells> after </sheetData> and before the next XML tag
28
- xmlData = xmlData.replace(/(<\/sheetData>)(\s*<)/, `$1\n${mergeCellsXml}\n$2`);
28
+ xmlData = xmlData.replace(/(<\/sheetData>)(\s*<)/, `$1${mergeCellsXml}$2`);
29
29
  }
30
30
  return Buffer.from(xmlData);
31
31
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LOCAL_FILE_HEADER_SIG = exports.END_OF_CENTRAL_DIR_SIG = exports.CENTRAL_DIR_HEADER_SIG = void 0;
3
+ exports.LOCAL_FILE_HEADER_SIG = exports.END_OF_CENTRAL_DIR_SIG = exports.CRC32_TABLE = exports.CENTRAL_DIR_HEADER_SIG = void 0;
4
4
  const node_buffer_1 = require("node:buffer");
5
5
  /**
6
6
  * ZIP file signature constants in Buffer format.
@@ -15,6 +15,21 @@ const node_buffer_1 = require("node:buffer");
15
15
  * Found in the central directory that appears at the end of the ZIP file.
16
16
  */
17
17
  exports.CENTRAL_DIR_HEADER_SIG = node_buffer_1.Buffer.from("504b0102", "hex");
18
+ /**
19
+ * Precomputed CRC-32 lookup table for optimized checksum calculation.
20
+ * The table is generated using the standard IEEE 802.3 (Ethernet) polynomial:
21
+ * 0xEDB88320 (reversed representation of 0x04C11DB7).
22
+ *
23
+ * The table is immediately invoked and cached as a constant for performance,
24
+ * following the common implementation pattern for CRC algorithms.
25
+ */
26
+ exports.CRC32_TABLE = new Uint32Array(256).map((_, n) => {
27
+ let c = n;
28
+ for (let k = 0; k < 8; k++) {
29
+ c = c & 1 ? 0xEDB88320 ^ (c >>> 1) : c >>> 1;
30
+ }
31
+ return c >>> 0;
32
+ });
18
33
  /**
19
34
  * End of Central Directory Record signature (0x504b0506).
20
35
  * Marks the end of the central directory and contains global information
@@ -0,0 +1,214 @@
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 () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.createWithStream = createWithStream;
40
+ const path = __importStar(require("node:path"));
41
+ const node_stream_1 = require("node:stream");
42
+ const node_fs_1 = require("node:fs");
43
+ const promises_1 = require("node:stream/promises");
44
+ const node_zlib_1 = __importDefault(require("node:zlib"));
45
+ const index_js_1 = require("./utils/index.js");
46
+ const constants_js_1 = require("./constants.js");
47
+ /**
48
+ * Creates a ZIP archive from a collection of files, streaming the output to a provided writable stream.
49
+ *
50
+ * @param fileKeys - An array of file paths (relative to the destination) that will be used to create a new workbook.
51
+ * @param destination - The path where the template files are located.
52
+ * @param output - A Writable stream that the ZIP archive will be written to.
53
+ *
54
+ * @throws {Error} - If a file does not exist in the destination.
55
+ * @throws {Error} - If a file is not readable.
56
+ * @throws {Error} - If the writable stream emits an error.
57
+ */
58
+ async function createWithStream(fileKeys, destination, output) {
59
+ const centralDirectory = [];
60
+ let offset = 0;
61
+ for (const filename of fileKeys.sort((a, b) => a.localeCompare(b))) {
62
+ if (filename.includes("..")) {
63
+ throw new Error(`Invalid filename: ${filename}`);
64
+ }
65
+ const fullPath = path.join(destination, ...filename.split("/"));
66
+ const fileNameBuf = Buffer.from(filename, "utf8");
67
+ const modTime = (0, index_js_1.dosTime)(new Date());
68
+ const source = (0, node_fs_1.createReadStream)(fullPath);
69
+ const crc32 = (0, index_js_1.crc32Stream)();
70
+ const deflater = node_zlib_1.default.createDeflateRaw();
71
+ let uncompSize = 0;
72
+ let compSize = 0;
73
+ const compressedChunks = [];
74
+ const sizeCounter = new node_stream_1.Transform({
75
+ transform(chunk, _enc, cb) {
76
+ uncompSize += chunk.length;
77
+ cb(null, chunk);
78
+ },
79
+ });
80
+ const collectCompressed = new node_stream_1.Transform({
81
+ transform(chunk, _enc, cb) {
82
+ compressedChunks.push(chunk);
83
+ compSize += chunk.length;
84
+ cb(null, chunk);
85
+ },
86
+ });
87
+ // deflater.on("data", (chunk) => { console.log("deflater data path:", fullPath, "length:", chunk.length); });
88
+ // deflater.on("finish", () => { console.log("deflater finished path:", fullPath, "uncompSize:", uncompSize, "compSize:", compSize); });
89
+ // deflater.on("error", (err) => { console.log("deflater error path:", fullPath, "error:", err); });
90
+ // deflater.on("close", () => { console.log("deflater closed path:", fullPath); });
91
+ // deflater.on("pipe", (src) => { console.log("deflater pipe path:", fullPath); });
92
+ // deflater.on("unpipe", (src) => { console.log("deflater unpipe path:", fullPath); });
93
+ // deflater.on("drain", () => { console.log("deflater drain path:", fullPath); });
94
+ // deflater.on("pause", () => { console.log("deflater pause path:", fullPath); });
95
+ // deflater.on("resume", () => { console.log("deflater resume path:", fullPath); });
96
+ // deflater.on("end", () => console.log("deflater ended, path:", fullPath));
97
+ // source.on("data", (chunk) => { console.log("source data path:", fullPath, "length:", chunk.length); });
98
+ // source.on("finish", () => { console.log("source finished path:", fullPath, "uncompSize:", uncompSize, "compSize:", compSize); });
99
+ // source.on("error", (err) => { console.log("source error path:", fullPath, "error:", err); });
100
+ // source.on("close", () => { console.log("source closed path:", fullPath); });
101
+ // source.on("pipe", (src) => { console.log("source pipe path:", fullPath); });
102
+ // source.on("unpipe", (src) => { console.log("source unpipe path:", fullPath); });
103
+ // source.on("drain", () => { console.log("source drain path:", fullPath); });
104
+ // source.on("pause", () => { console.log("source pause path:", fullPath); });
105
+ // source.on("resume", () => { console.log("source resume path:", fullPath); });
106
+ // source.on("end", () => console.log("source ended, path:", fullPath));
107
+ // sizeCounter.on("data", (chunk) => { console.log("sizeCounter data path:", fullPath, "length:", chunk.length); });
108
+ // sizeCounter.on("finish", () => { console.log("sizeCounter finished path:", fullPath, "uncompSize:", uncompSize, "compSize:", compSize); });
109
+ // sizeCounter.on("error", (err) => { console.log("sizeCounter error path:", fullPath, "error:", err); });
110
+ // sizeCounter.on("close", () => { console.log("sizeCounter closed path:", fullPath); });
111
+ // sizeCounter.on("pipe", (src) => { console.log("sizeCounter pipe path:", fullPath); });
112
+ // sizeCounter.on("unpipe", (src) => { console.log("sizeCounter unpipe path:", fullPath); });
113
+ // sizeCounter.on("drain", () => { console.log("sizeCounter drain path:", fullPath); });
114
+ // sizeCounter.on("pause", () => { console.log("sizeCounter pause path:", fullPath); });
115
+ // sizeCounter.on("resume", () => { console.log("sizeCounter resume path:", fullPath); });
116
+ // sizeCounter.on("end", () => console.log("sizeCounter ended, path:", fullPath));
117
+ // crc32.on("data", (chunk) => { console.log("crc32 data path:", fullPath, "length:", chunk.length); });
118
+ // crc32.on("finish", () => { console.log("crc32 finished path:", fullPath, "uncompSize:", uncompSize, "compSize:", compSize); });
119
+ // crc32.on("error", (err) => { console.log("crc32 error path:", fullPath, "error:", err); });
120
+ // crc32.on("close", () => { console.log("crc32 closed path:", fullPath); });
121
+ // crc32.on("pipe", (src) => { console.log("crc32 pipe path:", fullPath); });
122
+ // crc32.on("unpipe", (src) => { console.log("crc32 unpipe path:", fullPath); });
123
+ // crc32.on("drain", () => { console.log("crc32 drain path:", fullPath); });
124
+ // crc32.on("pause", () => { console.log("crc32 pause path:", fullPath); });
125
+ // crc32.on("resume", () => { console.log("crc32 resume path:", fullPath); });
126
+ // crc32.on("end", () => console.log("crc32 ended, path:", fullPath));
127
+ collectCompressed.on("data", ( /* chunk */) => { });
128
+ // collectCompressed.on("finish", () => { console.log("collectCompressed finished path:", fullPath, "uncompSize:", uncompSize, "compSize:", compSize); });
129
+ // collectCompressed.on("error", (err) => { console.log("collectCompressed error path:", fullPath, "error:", err); });
130
+ // collectCompressed.on("close", () => { console.log("collectCompressed closed path:", fullPath); });
131
+ // collectCompressed.on("pipe", (src) => { console.log("collectCompressed pipe path:", fullPath); });
132
+ // collectCompressed.on("unpipe", (src) => { console.log("collectCompressed unpipe path:", fullPath); });
133
+ // collectCompressed.on("drain", () => { console.log("collectCompressed drain path:", fullPath); });
134
+ // collectCompressed.on("pause", () => { console.log("collectCompressed pause path:", fullPath); });
135
+ // collectCompressed.on("resume", () => { console.log("collectCompressed resume path:", fullPath); });
136
+ // collectCompressed.on("end", () => console.log("collectCompressed ended, path:", fullPath));
137
+ // deflater.on("readable", () => {
138
+ // console.log("deflater readable path:", fullPath);
139
+ // });
140
+ await (0, promises_1.pipeline)(source, sizeCounter, crc32, deflater, collectCompressed);
141
+ // await new Promise<void>((resolve, reject) => {
142
+ // source
143
+ // .pipe(sizeCounter)
144
+ // .pipe(crc32)
145
+ // .pipe(deflater)
146
+ // .pipe(collectCompressed)
147
+ // .on("finish", resolve)
148
+ // .on("error", reject);
149
+ // source.on("error", reject);
150
+ // deflater.on("error", reject);
151
+ // });
152
+ const crc = crc32.digest();
153
+ const compressed = Buffer.concat(compressedChunks);
154
+ const localHeader = Buffer.concat([
155
+ constants_js_1.LOCAL_FILE_HEADER_SIG,
156
+ (0, index_js_1.toBytes)(20, 2),
157
+ (0, index_js_1.toBytes)(0, 2),
158
+ (0, index_js_1.toBytes)(8, 2),
159
+ modTime,
160
+ (0, index_js_1.toBytes)(crc, 4),
161
+ (0, index_js_1.toBytes)(compSize, 4),
162
+ (0, index_js_1.toBytes)(uncompSize, 4),
163
+ (0, index_js_1.toBytes)(fileNameBuf.length, 2),
164
+ (0, index_js_1.toBytes)(0, 2),
165
+ fileNameBuf,
166
+ compressed,
167
+ ]);
168
+ await new Promise((resolve, reject) => {
169
+ output.write(localHeader, err => err ? reject(err) : resolve());
170
+ });
171
+ const centralEntry = Buffer.concat([
172
+ constants_js_1.CENTRAL_DIR_HEADER_SIG,
173
+ (0, index_js_1.toBytes)(20, 2),
174
+ (0, index_js_1.toBytes)(20, 2),
175
+ (0, index_js_1.toBytes)(0, 2),
176
+ (0, index_js_1.toBytes)(8, 2),
177
+ modTime,
178
+ (0, index_js_1.toBytes)(crc, 4),
179
+ (0, index_js_1.toBytes)(compSize, 4),
180
+ (0, index_js_1.toBytes)(uncompSize, 4),
181
+ (0, index_js_1.toBytes)(fileNameBuf.length, 2),
182
+ (0, index_js_1.toBytes)(0, 2),
183
+ (0, index_js_1.toBytes)(0, 2),
184
+ (0, index_js_1.toBytes)(0, 2),
185
+ (0, index_js_1.toBytes)(0, 2),
186
+ (0, index_js_1.toBytes)(0, 4),
187
+ (0, index_js_1.toBytes)(offset, 4),
188
+ fileNameBuf,
189
+ ]);
190
+ centralDirectory.push(centralEntry);
191
+ offset += localHeader.length;
192
+ }
193
+ const centralDirSize = centralDirectory.reduce((sum, entry) => sum + entry.length, 0);
194
+ const centralDirOffset = offset;
195
+ for (const entry of centralDirectory) {
196
+ await new Promise((resolve, reject) => {
197
+ output.write(entry, err => err ? reject(err) : resolve());
198
+ });
199
+ }
200
+ const endRecord = Buffer.concat([
201
+ constants_js_1.END_OF_CENTRAL_DIR_SIG,
202
+ (0, index_js_1.toBytes)(0, 2),
203
+ (0, index_js_1.toBytes)(0, 2),
204
+ (0, index_js_1.toBytes)(centralDirectory.length, 2),
205
+ (0, index_js_1.toBytes)(centralDirectory.length, 2),
206
+ (0, index_js_1.toBytes)(centralDirSize, 4),
207
+ (0, index_js_1.toBytes)(centralDirOffset, 4),
208
+ (0, index_js_1.toBytes)(0, 2),
209
+ ]);
210
+ await new Promise((resolve, reject) => {
211
+ output.write(endRecord, err => err ? reject(err) : resolve());
212
+ });
213
+ output.end();
214
+ }
@@ -15,6 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./create-sync.js"), exports);
18
+ __exportStar(require("./create-with-stream.js"), exports);
18
19
  __exportStar(require("./create.js"), exports);
19
20
  __exportStar(require("./read-sync.js"), exports);
20
21
  __exportStar(require("./read.js"), exports);
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.crc32Stream = crc32Stream;
4
+ const node_stream_1 = require("node:stream");
5
+ const constants_js_1 = require("../constants.js");
6
+ /**
7
+ * Computes the CRC-32 checksum for the given byte, using the standard IEEE 802.3 polynomial.
8
+ * This is a low-level function that is used by the crc32Stream() function.
9
+ *
10
+ * @param {number} byte - The byte (0-255) to add to the checksum.
11
+ * @param {number} crc - The current checksum value to update.
12
+ * @returns {number} - The new checksum value.
13
+ */
14
+ function crc32(byte, crc = 0xffffffff) {
15
+ return constants_js_1.CRC32_TABLE[(crc ^ byte) & 0xff] ^ (crc >>> 8);
16
+ }
17
+ /**
18
+ * Creates a Transform stream that computes the CRC-32 checksum of the input data.
19
+ *
20
+ * The `digest()` method can be called on the returned stream to get the final checksum value.
21
+ *
22
+ * @returns {Transform & { digest: () => number }} - The Transform stream.
23
+ */
24
+ function crc32Stream() {
25
+ let crc = 0xffffffff;
26
+ const transform = new node_stream_1.Transform({
27
+ final(callback) {
28
+ callback();
29
+ },
30
+ flush(callback) {
31
+ callback();
32
+ },
33
+ transform(chunk, _encoding, callback) {
34
+ for (let i = 0; i < chunk.length; i++) {
35
+ crc = crc32(chunk[i], crc);
36
+ }
37
+ callback(null, chunk);
38
+ },
39
+ });
40
+ transform.digest = () => (crc ^ 0xffffffff) >>> 0;
41
+ return transform;
42
+ }
@@ -1,40 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.crc32 = crc32;
4
- /**
5
- * Precomputed CRC-32 lookup table for optimized checksum calculation.
6
- * The table is generated using the standard IEEE 802.3 (Ethernet) polynomial:
7
- * 0xEDB88320 (reversed representation of 0x04C11DB7).
8
- *
9
- * The table is immediately invoked and cached as a constant for performance,
10
- * following the common implementation pattern for CRC algorithms.
11
- */
12
- const crcTable = (() => {
13
- // Create a typed array for better performance with 256 32-bit unsigned integers
14
- const table = new Uint32Array(256);
15
- // Generate table entries for all possible byte values (0-255)
16
- for (let i = 0; i < 256; i++) {
17
- let crc = i; // Initialize with current byte value
18
- // Process each bit (8 times)
19
- for (let j = 0; j < 8; j++) {
20
- /*
21
- * CRC division algorithm:
22
- * 1. If LSB is set (crc & 1), XOR with polynomial
23
- * 2. Right-shift by 1 (unsigned)
24
- *
25
- * The polynomial 0xEDB88320 is:
26
- * - Bit-reversed version of 0x04C11DB7
27
- * - Uses reflected input/output algorithm
28
- */
29
- crc = crc & 1
30
- ? 0xedb88320 ^ (crc >>> 1) // XOR with polynomial if LSB is set
31
- : crc >>> 1; // Just shift right if LSB is not set
32
- }
33
- // Store final 32-bit value (>>> 0 ensures unsigned 32-bit representation)
34
- table[i] = crc >>> 0;
35
- }
36
- return table;
37
- })();
4
+ const constants_js_1 = require("../constants.js");
38
5
  /**
39
6
  * Computes a CRC-32 checksum for the given Buffer using the standard IEEE 802.3 polynomial.
40
7
  * This implementation uses a precomputed lookup table for optimal performance.
@@ -65,7 +32,7 @@ function crc32(buf) {
65
32
  * - crc >>> 8 - Shift CRC right by 8 bits (unsigned)
66
33
  * - ^ crcTable[...] - XOR with precomputed table value
67
34
  */
68
- crc = (crc >>> 8) ^ crcTable[(crc ^ buf[i]) & 0xff];
35
+ crc = (crc >>> 8) ^ constants_js_1.CRC32_TABLE[(crc ^ buf[i]) & 0xff];
69
36
  }
70
37
  /*
71
38
  * Final processing:
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./crc-32-stream.js"), exports);
17
18
  __exportStar(require("./crc-32.js"), exports);
18
19
  __exportStar(require("./dos-time.js"), exports);
19
20
  __exportStar(require("./find-data-descriptor.js"), exports);
@@ -1,2 +1,3 @@
1
1
  export * from "./merge-sheets-to-base-file-sync.js";
2
2
  export * from "./merge-sheets-to-base-file.js";
3
+ export * from "./template/index.js";
@@ -0,0 +1 @@
1
+ export * from "./template-fs.js";