@xlsxflow/core 1.1.4 → 1.1.6
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/CHANGELOG.md +24 -0
- package/README.md +33 -12
- package/dist/index.cjs +52 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +52 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -2
package/dist/index.mjs
CHANGED
|
@@ -56,21 +56,41 @@ class ZipStreamWriter {
|
|
|
56
56
|
// Stream data, tracking sizes and CRC32
|
|
57
57
|
let uncompressedSize = 0;
|
|
58
58
|
let crc = 0xffffffff;
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
const compressor = new CompressionStream('deflate-raw');
|
|
60
|
+
const writer = compressor.writable.getWriter();
|
|
61
|
+
const reader = compressor.readable.getReader();
|
|
62
|
+
const input = inputStream.getReader();
|
|
63
|
+
// Node's and Bun's CompressionStream accept thousands of writes without backpressure, so only a few
|
|
64
|
+
// chunks are fed ahead: a write resolves once the chunk is compressed, which waits while nobody reads
|
|
65
|
+
// the output. Rows are then only pulled as fast as the ZIP is consumed.
|
|
66
|
+
// A few writes in flight keep the compressor busy while the next chunk is built
|
|
67
|
+
const inFlight = [];
|
|
68
|
+
const feed = (async () => {
|
|
69
|
+
try {
|
|
70
|
+
while (true) {
|
|
71
|
+
const { done, value } = await input.read();
|
|
72
|
+
if (done)
|
|
73
|
+
break;
|
|
74
|
+
await this.roomInQueue();
|
|
75
|
+
uncompressedSize += value.length;
|
|
76
|
+
crc = crc32Update(crc, value);
|
|
77
|
+
const written = writer.write(value);
|
|
78
|
+
written.catch(() => { }); // after a failure, writes nobody awaits any more must not go unhandled
|
|
79
|
+
inFlight.push(written);
|
|
80
|
+
if (inFlight.length >= 4)
|
|
81
|
+
await inFlight.shift();
|
|
82
|
+
}
|
|
83
|
+
await Promise.all(inFlight);
|
|
84
|
+
await writer.close();
|
|
67
85
|
}
|
|
68
|
-
|
|
86
|
+
catch (err) {
|
|
87
|
+
// Stop the source too (a row generator's finally runs, a database cursor closes)
|
|
88
|
+
await input.cancel(err).catch(() => { });
|
|
89
|
+
await writer.abort(err).catch(() => { });
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
})();
|
|
69
93
|
let compressedSize = 0;
|
|
70
|
-
const reader = inputStream
|
|
71
|
-
.pipeThrough(crcStream)
|
|
72
|
-
.pipeThrough(new CompressionStream('deflate-raw'))
|
|
73
|
-
.getReader();
|
|
74
94
|
try {
|
|
75
95
|
while (true) {
|
|
76
96
|
const { done, value } = await reader.read();
|
|
@@ -79,10 +99,12 @@ class ZipStreamWriter {
|
|
|
79
99
|
compressedSize += value.length;
|
|
80
100
|
await this.pushChunk(value);
|
|
81
101
|
}
|
|
102
|
+
await feed;
|
|
82
103
|
}
|
|
83
104
|
catch (err) {
|
|
84
|
-
// Stop the source too (a row generator's finally runs, a database cursor closes)
|
|
85
105
|
await reader.cancel(err).catch(() => { });
|
|
106
|
+
await input.cancel(err).catch(() => { });
|
|
107
|
+
await feed.catch(() => { });
|
|
86
108
|
throw err;
|
|
87
109
|
}
|
|
88
110
|
crc = (crc ^ 0xffffffff) >>> 0;
|
|
@@ -3856,6 +3878,10 @@ class SheetWriter {
|
|
|
3856
3878
|
const box = parseRange$1(table.ref, 'table range');
|
|
3857
3879
|
if (boxes.some(b => overlaps(b, box)))
|
|
3858
3880
|
throw new Error(`Table "${table.name}" overlaps another table on sheet "${sheet.name}".`);
|
|
3881
|
+
// Excel tables cannot hold merged cells: it repairs the file by removing the table
|
|
3882
|
+
const merge = sheet.options.mergeCells?.find(ref => overlaps(parseRange$1(ref, 'merge range'), box));
|
|
3883
|
+
if (merge)
|
|
3884
|
+
throw new Error(`Merge "${merge}" overlaps table "${table.name}" on sheet "${sheet.name}"; Excel tables cannot contain merged cells.`);
|
|
3859
3885
|
boxes.push(box);
|
|
3860
3886
|
const first = colIndex(m[1]);
|
|
3861
3887
|
const width = colIndex(m[3]) - first + 1;
|
|
@@ -4357,8 +4383,18 @@ function createBlobReader(blob) {
|
|
|
4357
4383
|
return new Uint8Array(await slice.arrayBuffer());
|
|
4358
4384
|
},
|
|
4359
4385
|
stream(offset, length) {
|
|
4360
|
-
|
|
4361
|
-
|
|
4386
|
+
// Bun's Blob.slice(start, end).stream() runs on to the end of the original blob, so stop at length
|
|
4387
|
+
let left = length;
|
|
4388
|
+
return blob.slice(offset, offset + length).stream().pipeThrough(new TransformStream({
|
|
4389
|
+
start(controller) { if (left <= 0)
|
|
4390
|
+
controller.terminate(); },
|
|
4391
|
+
transform(chunk, controller) {
|
|
4392
|
+
controller.enqueue(chunk.length > left ? chunk.subarray(0, left) : chunk);
|
|
4393
|
+
left -= chunk.length;
|
|
4394
|
+
if (left <= 0)
|
|
4395
|
+
controller.terminate();
|
|
4396
|
+
}
|
|
4397
|
+
}));
|
|
4362
4398
|
},
|
|
4363
4399
|
async close() { }
|
|
4364
4400
|
};
|