@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.
- package/build/cjs/lib/index.js +1 -0
- package/build/cjs/lib/template/index.js +17 -0
- package/build/cjs/lib/template/template-fs.js +465 -0
- package/build/cjs/lib/template/utils/check-row.js +23 -0
- package/build/cjs/lib/template/utils/check-rows.js +19 -0
- package/build/cjs/lib/template/utils/check-start-row.js +18 -0
- package/build/cjs/lib/template/utils/column-index-to-letter.js +17 -0
- package/build/cjs/lib/template/utils/escape-xml.js +24 -0
- package/build/cjs/lib/template/utils/get-max-row-number.js +20 -0
- package/build/cjs/lib/template/utils/get-rows-above.js +23 -0
- package/build/cjs/lib/template/utils/get-rows-below.js +23 -0
- package/build/cjs/lib/template/utils/index.js +27 -0
- package/build/cjs/lib/template/utils/parse-rows.js +30 -0
- package/build/cjs/lib/template/utils/to-excel-column-object.js +29 -0
- package/build/cjs/lib/template/utils/write-rows-to-stream.js +41 -0
- package/build/cjs/lib/xml/build-merged-sheet.js +1 -1
- package/build/cjs/lib/zip/constants.js +16 -1
- package/build/cjs/lib/zip/create-with-stream.js +214 -0
- package/build/cjs/lib/zip/index.js +1 -0
- package/build/cjs/lib/zip/utils/crc-32-stream.js +42 -0
- package/build/cjs/lib/zip/utils/crc-32.js +2 -35
- package/build/cjs/lib/zip/utils/index.js +1 -0
- package/build/esm/lib/index.js +1 -0
- package/build/esm/lib/template/index.js +1 -0
- package/build/esm/lib/template/template-fs.js +428 -0
- package/build/esm/lib/template/utils/check-row.js +20 -0
- package/build/esm/lib/template/utils/check-rows.js +16 -0
- package/build/esm/lib/template/utils/check-start-row.js +15 -0
- package/build/esm/lib/template/utils/column-index-to-letter.js +14 -0
- package/build/esm/lib/template/utils/escape-xml.js +21 -0
- package/build/esm/lib/template/utils/get-max-row-number.js +17 -0
- package/build/esm/lib/template/utils/get-rows-above.js +20 -0
- package/build/esm/lib/template/utils/get-rows-below.js +20 -0
- package/build/esm/lib/template/utils/index.js +11 -0
- package/build/esm/lib/template/utils/parse-rows.js +27 -0
- package/build/esm/lib/template/utils/to-excel-column-object.js +26 -0
- package/build/esm/lib/template/utils/write-rows-to-stream.js +38 -0
- package/build/esm/lib/xml/build-merged-sheet.js +1 -1
- package/build/esm/lib/zip/constants.js +15 -0
- package/build/esm/lib/zip/create-with-stream.js +175 -0
- package/build/esm/lib/zip/index.js +1 -0
- package/build/esm/lib/zip/utils/crc-32-stream.js +39 -0
- package/build/esm/lib/zip/utils/crc-32.js +2 -35
- package/build/esm/lib/zip/utils/index.js +1 -0
- package/build/types/lib/index.d.ts +1 -0
- package/build/types/lib/template/index.d.ts +1 -0
- package/build/types/lib/template/template-fs.d.ts +122 -0
- package/build/types/lib/template/utils/check-row.d.ts +14 -0
- package/build/types/lib/template/utils/check-rows.d.ts +11 -0
- package/build/types/lib/template/utils/check-start-row.d.ts +8 -0
- package/build/types/lib/template/utils/column-index-to-letter.d.ts +7 -0
- package/build/types/lib/template/utils/escape-xml.d.ts +14 -0
- package/build/types/lib/template/utils/get-max-row-number.d.ts +7 -0
- package/build/types/lib/template/utils/get-rows-above.d.ts +12 -0
- package/build/types/lib/template/utils/get-rows-below.d.ts +12 -0
- package/build/types/lib/template/utils/index.d.ts +11 -0
- package/build/types/lib/template/utils/parse-rows.d.ts +1 -0
- package/build/types/lib/template/utils/to-excel-column-object.d.ts +10 -0
- package/build/types/lib/template/utils/write-rows-to-stream.d.ts +25 -0
- package/build/types/lib/zip/constants.d.ts +9 -0
- package/build/types/lib/zip/create-with-stream.d.ts +13 -0
- package/build/types/lib/zip/index.d.ts +1 -0
- package/build/types/lib/zip/utils/crc-32-stream.d.ts +11 -0
- package/build/types/lib/zip/utils/index.d.ts +1 -0
- 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
|
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) ^
|
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);
|
package/build/esm/lib/index.js
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
export * from "./template-fs.js";
|