@cj-tech-master/excelts 1.1.0 → 1.4.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 (41) hide show
  1. package/dist/browser/excelts.iife.js +1089 -568
  2. package/dist/browser/excelts.iife.js.map +1 -1
  3. package/dist/browser/excelts.iife.min.js +18 -18
  4. package/dist/cjs/doc/data-validations.js +29 -1
  5. package/dist/cjs/index.js +1 -1
  6. package/dist/cjs/utils/cell-format.js +815 -0
  7. package/dist/cjs/utils/parse-sax.js +2 -2
  8. package/dist/cjs/utils/{extra-utils.js → sheet-utils.js} +114 -89
  9. package/dist/cjs/utils/stream-buf.js +15 -4
  10. package/dist/cjs/utils/unzip/parse.js +82 -1
  11. package/dist/cjs/utils/utils.js +13 -17
  12. package/dist/cjs/utils/zip-stream.js +20 -32
  13. package/dist/cjs/xlsx/xform/sheet/data-validations-xform.js +46 -7
  14. package/dist/cjs/xlsx/xlsx.js +1 -2
  15. package/dist/esm/doc/data-validations.js +29 -1
  16. package/dist/esm/index.browser.js +1 -1
  17. package/dist/esm/index.js +1 -1
  18. package/dist/esm/utils/cell-format.js +810 -0
  19. package/dist/esm/utils/parse-sax.js +1 -1
  20. package/dist/esm/utils/{extra-utils.js → sheet-utils.js} +97 -72
  21. package/dist/esm/utils/stream-buf.js +15 -4
  22. package/dist/esm/utils/unzip/parse.js +83 -2
  23. package/dist/esm/utils/utils.js +12 -16
  24. package/dist/esm/utils/zip-stream.js +20 -32
  25. package/dist/esm/xlsx/xform/sheet/data-validations-xform.js +46 -7
  26. package/dist/esm/xlsx/xlsx.js +1 -2
  27. package/dist/types/index.browser.d.ts +1 -1
  28. package/dist/types/index.d.ts +1 -1
  29. package/dist/types/utils/cell-format.d.ts +32 -0
  30. package/dist/types/utils/{extra-utils.d.ts → sheet-utils.d.ts} +51 -52
  31. package/dist/types/utils/utils.d.ts +5 -2
  32. package/package.json +5 -5
  33. package/dist/cjs/utils/browser-buffer-decode.js +0 -13
  34. package/dist/cjs/utils/browser-buffer-encode.js +0 -13
  35. package/dist/cjs/utils/browser.js +0 -6
  36. package/dist/esm/utils/browser-buffer-decode.js +0 -11
  37. package/dist/esm/utils/browser-buffer-encode.js +0 -11
  38. package/dist/esm/utils/browser.js +0 -3
  39. package/dist/types/utils/browser-buffer-decode.d.ts +0 -2
  40. package/dist/types/utils/browser-buffer-encode.d.ts +0 -2
  41. package/dist/types/utils/browser.d.ts +0 -1
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseSax = parseSax;
4
4
  const saxes_1 = require("saxes");
5
- const browser_buffer_decode_js_1 = require("./browser-buffer-decode");
5
+ const utils_js_1 = require("./utils");
6
6
  async function* parseSax(iterable) {
7
7
  const saxesParser = new saxes_1.SaxesParser({
8
8
  xmlns: false,
@@ -17,7 +17,7 @@ async function* parseSax(iterable) {
17
17
  saxesParser.on("text", (value) => events.push({ eventType: "text", value }));
18
18
  saxesParser.on("closetag", (value) => events.push({ eventType: "closetag", value }));
19
19
  for await (const chunk of iterable) {
20
- saxesParser.write((0, browser_buffer_decode_js_1.bufferToString)(chunk));
20
+ saxesParser.write((0, utils_js_1.bufferToString)(chunk));
21
21
  // saxesParser.write and saxesParser.on() are synchronous,
22
22
  // so we can only reach the below line once all events have been emitted
23
23
  if (error) {
@@ -2,106 +2,131 @@
2
2
  /**
3
3
  * Utility functions for ExcelTS
4
4
  * Provides convenient helper functions for common spreadsheet operations
5
- * compatible with xlsx library's utils API but built on excelts native types
6
5
  */
7
6
  Object.defineProperty(exports, "__esModule", { value: true });
8
7
  exports.utils = void 0;
9
- exports.decode_col = decode_col;
10
- exports.encode_col = encode_col;
11
- exports.decode_row = decode_row;
12
- exports.encode_row = encode_row;
13
- exports.decode_cell = decode_cell;
14
- exports.encode_cell = encode_cell;
15
- exports.decode_range = decode_range;
16
- exports.encode_range = encode_range;
17
- exports.json_to_sheet = json_to_sheet;
18
- exports.sheet_add_json = sheet_add_json;
19
- exports.sheet_to_json = sheet_to_json;
20
- exports.sheet_to_csv = sheet_to_csv;
21
- exports.book_new = book_new;
22
- exports.book_append_sheet = book_append_sheet;
23
- exports.aoa_to_sheet = aoa_to_sheet;
24
- exports.sheet_add_aoa = sheet_add_aoa;
25
- exports.sheet_to_aoa = sheet_to_aoa;
8
+ exports.decodeCol = decodeCol;
9
+ exports.encodeCol = encodeCol;
10
+ exports.decodeRow = decodeRow;
11
+ exports.encodeRow = encodeRow;
12
+ exports.decodeCell = decodeCell;
13
+ exports.encodeCell = encodeCell;
14
+ exports.decodeRange = decodeRange;
15
+ exports.encodeRange = encodeRange;
16
+ exports.jsonToSheet = jsonToSheet;
17
+ exports.sheetAddJson = sheetAddJson;
18
+ exports.sheetToJson = sheetToJson;
19
+ exports.sheetToCsv = sheetToCsv;
20
+ exports.bookNew = bookNew;
21
+ exports.bookAppendSheet = bookAppendSheet;
22
+ exports.aoaToSheet = aoaToSheet;
23
+ exports.sheetAddAoa = sheetAddAoa;
24
+ exports.sheetToAoa = sheetToAoa;
26
25
  const workbook_js_1 = require("../doc/workbook");
27
26
  const col_cache_js_1 = require("./col-cache");
27
+ const utils_js_1 = require("./utils");
28
+ const cell_format_js_1 = require("./cell-format");
29
+ /**
30
+ * Get formatted display text for a cell value
31
+ * Returns the value formatted according to the cell's numFmt
32
+ * This matches Excel's display exactly
33
+ */
34
+ function getCellDisplayText(cell) {
35
+ const value = cell.value;
36
+ const fmt = cell.numFmt || "General";
37
+ // Null/undefined
38
+ if (value == null) {
39
+ return "";
40
+ }
41
+ // Date object - convert to Excel serial number
42
+ if (value instanceof Date) {
43
+ const serial = (0, utils_js_1.dateToExcel)(value, false);
44
+ return (0, cell_format_js_1.format)(fmt, serial);
45
+ }
46
+ // Number/Boolean/String - let cellFormat handle it
47
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "string") {
48
+ return (0, cell_format_js_1.format)(fmt, value);
49
+ }
50
+ // Fallback to cell.text for other types (rich text, hyperlink, error, formula, etc.)
51
+ return cell.text;
52
+ }
28
53
  // =============================================================================
29
54
  // Cell Address Encoding/Decoding
30
55
  // =============================================================================
31
56
  /**
32
57
  * Decode column string to 0-indexed number
33
- * @example decode_col("A") => 0, decode_col("Z") => 25, decode_col("AA") => 26
58
+ * @example decodeCol("A") => 0, decodeCol("Z") => 25, decodeCol("AA") => 26
34
59
  */
35
- function decode_col(colstr) {
60
+ function decodeCol(colstr) {
36
61
  return col_cache_js_1.colCache.l2n(colstr.toUpperCase()) - 1;
37
62
  }
38
63
  /**
39
64
  * Encode 0-indexed column number to string
40
- * @example encode_col(0) => "A", encode_col(25) => "Z", encode_col(26) => "AA"
65
+ * @example encodeCol(0) => "A", encodeCol(25) => "Z", encodeCol(26) => "AA"
41
66
  */
42
- function encode_col(col) {
67
+ function encodeCol(col) {
43
68
  return col_cache_js_1.colCache.n2l(col + 1);
44
69
  }
45
70
  /**
46
71
  * Decode row string to 0-indexed number
47
- * @example decode_row("1") => 0, decode_row("10") => 9
72
+ * @example decodeRow("1") => 0, decodeRow("10") => 9
48
73
  */
49
- function decode_row(rowstr) {
74
+ function decodeRow(rowstr) {
50
75
  return parseInt(rowstr, 10) - 1;
51
76
  }
52
77
  /**
53
78
  * Encode 0-indexed row number to string
54
- * @example encode_row(0) => "1", encode_row(9) => "10"
79
+ * @example encodeRow(0) => "1", encodeRow(9) => "10"
55
80
  */
56
- function encode_row(row) {
81
+ function encodeRow(row) {
57
82
  return String(row + 1);
58
83
  }
59
84
  /**
60
85
  * Decode cell address string to CellAddress object
61
- * @example decode_cell("A1") => {c: 0, r: 0}, decode_cell("B2") => {c: 1, r: 1}
86
+ * @example decodeCell("A1") => {c: 0, r: 0}, decodeCell("B2") => {c: 1, r: 1}
62
87
  */
63
- function decode_cell(cstr) {
88
+ function decodeCell(cstr) {
64
89
  const addr = col_cache_js_1.colCache.decodeAddress(cstr.toUpperCase());
65
90
  return { c: addr.col - 1, r: addr.row - 1 };
66
91
  }
67
92
  /**
68
93
  * Encode CellAddress object to cell address string
69
- * @example encode_cell({c: 0, r: 0}) => "A1", encode_cell({c: 1, r: 1}) => "B2"
94
+ * @example encodeCell({c: 0, r: 0}) => "A1", encodeCell({c: 1, r: 1}) => "B2"
70
95
  */
71
- function encode_cell(cell) {
96
+ function encodeCell(cell) {
72
97
  return col_cache_js_1.colCache.encodeAddress(cell.r + 1, cell.c + 1);
73
98
  }
74
99
  /**
75
100
  * Decode range string to Range object
76
- * @example decode_range("A1:B2") => {s: {c: 0, r: 0}, e: {c: 1, r: 1}}
101
+ * @example decodeRange("A1:B2") => {s: {c: 0, r: 0}, e: {c: 1, r: 1}}
77
102
  */
78
- function decode_range(range) {
103
+ function decodeRange(range) {
79
104
  const idx = range.indexOf(":");
80
105
  if (idx === -1) {
81
- const cell = decode_cell(range);
106
+ const cell = decodeCell(range);
82
107
  return { s: cell, e: { ...cell } };
83
108
  }
84
109
  return {
85
- s: decode_cell(range.slice(0, idx)),
86
- e: decode_cell(range.slice(idx + 1))
110
+ s: decodeCell(range.slice(0, idx)),
111
+ e: decodeCell(range.slice(idx + 1))
87
112
  };
88
113
  }
89
- function encode_range(startOrRange, end) {
114
+ function encodeRange(startOrRange, end) {
90
115
  if (end === undefined) {
91
116
  const range = startOrRange;
92
- return encode_range(range.s, range.e);
117
+ return encodeRange(range.s, range.e);
93
118
  }
94
119
  const start = startOrRange;
95
- const startStr = encode_cell(start);
96
- const endStr = encode_cell(end);
120
+ const startStr = encodeCell(start);
121
+ const endStr = encodeCell(end);
97
122
  return startStr === endStr ? startStr : `${startStr}:${endStr}`;
98
123
  }
99
124
  /**
100
125
  * Create a worksheet from an array of objects (xlsx compatible)
101
126
  * @example
102
- * const ws = json_to_sheet([{name: "Alice", age: 30}, {name: "Bob", age: 25}])
127
+ * const ws = jsonToSheet([{name: "Alice", age: 30}, {name: "Bob", age: 25}])
103
128
  */
104
- function json_to_sheet(data, opts) {
129
+ function jsonToSheet(data, opts) {
105
130
  const o = opts || {};
106
131
  // Create a temporary workbook to get a worksheet
107
132
  const tempWb = new workbook_js_1.Workbook();
@@ -147,7 +172,7 @@ function json_to_sheet(data, opts) {
147
172
  /**
148
173
  * Add data from an array of objects to an existing worksheet (xlsx compatible)
149
174
  */
150
- function sheet_add_json(worksheet, data, opts) {
175
+ function sheetAddJson(worksheet, data, opts) {
151
176
  const o = opts || {};
152
177
  if (data.length === 0) {
153
178
  return worksheet;
@@ -157,7 +182,7 @@ function sheet_add_json(worksheet, data, opts) {
157
182
  let startCol = 1;
158
183
  if (o.origin !== undefined) {
159
184
  if (typeof o.origin === "string") {
160
- const addr = decode_cell(o.origin);
185
+ const addr = decodeCell(o.origin);
161
186
  startRow = addr.r + 1;
162
187
  startCol = addr.c + 1;
163
188
  }
@@ -213,18 +238,18 @@ function sheet_add_json(worksheet, data, opts) {
213
238
  * Convert worksheet to JSON array (xlsx compatible)
214
239
  * @example
215
240
  * // Default: array of objects with first row as headers
216
- * const data = sheet_to_json(worksheet)
241
+ * const data = sheetToJson(worksheet)
217
242
  * // => [{name: "Alice", age: 30}, {name: "Bob", age: 25}]
218
243
  *
219
244
  * // Array of arrays
220
- * const aoa = sheet_to_json(worksheet, { header: 1 })
245
+ * const aoa = sheetToJson(worksheet, { header: 1 })
221
246
  * // => [["name", "age"], ["Alice", 30], ["Bob", 25]]
222
247
  *
223
248
  * // Column letters as keys
224
- * const cols = sheet_to_json(worksheet, { header: "A" })
249
+ * const cols = sheetToJson(worksheet, { header: "A" })
225
250
  * // => [{A: "name", B: "age"}, {A: "Alice", B: 30}]
226
251
  */
227
- function sheet_to_json(worksheet, opts) {
252
+ function sheetToJson(worksheet, opts) {
228
253
  const o = opts || {};
229
254
  // Determine range
230
255
  let startRow = 1;
@@ -236,7 +261,7 @@ function sheet_to_json(worksheet, opts) {
236
261
  startRow = o.range + 1; // 0-indexed to 1-indexed
237
262
  }
238
263
  else if (typeof o.range === "string") {
239
- const r = decode_range(o.range);
264
+ const r = decodeRange(o.range);
240
265
  startRow = r.s.r + 1;
241
266
  endRow = r.e.r + 1;
242
267
  startCol = r.s.c + 1;
@@ -258,8 +283,8 @@ function sheet_to_json(worksheet, opts) {
258
283
  let isEmpty = true;
259
284
  for (let col = startCol; col <= endCol; col++) {
260
285
  const cell = worksheet.getCell(row, col);
261
- const val = cell.value;
262
- if (val != null) {
286
+ const val = o.raw === false ? getCellDisplayText(cell).trim() : cell.value;
287
+ if (val != null && val !== "") {
263
288
  rowData[col - startCol] = val;
264
289
  isEmpty = false;
265
290
  }
@@ -286,9 +311,9 @@ function sheet_to_json(worksheet, opts) {
286
311
  let isEmpty = true;
287
312
  for (let col = startCol; col <= endCol; col++) {
288
313
  const cell = worksheet.getCell(row, col);
289
- const val = cell.value;
290
- const key = encode_col(col - 1); // 0-indexed for encode_col
291
- if (val != null) {
314
+ const val = o.raw === false ? getCellDisplayText(cell).trim() : cell.value;
315
+ const key = encodeCol(col - 1); // 0-indexed for encodeCol
316
+ if (val != null && val !== "") {
292
317
  rowData[key] = val;
293
318
  isEmpty = false;
294
319
  }
@@ -313,8 +338,8 @@ function sheet_to_json(worksheet, opts) {
313
338
  const colIdx = col - startCol;
314
339
  const key = headerOpt[colIdx] ?? `__EMPTY_${colIdx}`;
315
340
  const cell = worksheet.getCell(row, col);
316
- const val = cell.value;
317
- if (val != null) {
341
+ const val = o.raw === false ? getCellDisplayText(cell).trim() : cell.value;
342
+ if (val != null && val !== "") {
318
343
  rowData[key] = val;
319
344
  isEmpty = false;
320
345
  }
@@ -355,9 +380,9 @@ function sheet_to_json(worksheet, opts) {
355
380
  let isEmpty = true;
356
381
  for (let col = startCol; col <= endCol; col++) {
357
382
  const cell = worksheet.getCell(row, col);
358
- const val = cell.value;
383
+ const val = o.raw === false ? getCellDisplayText(cell).trim() : cell.value;
359
384
  const key = headers[col - startCol];
360
- if (val != null) {
385
+ if (val != null && val !== "") {
361
386
  rowData[key] = val;
362
387
  isEmpty = false;
363
388
  }
@@ -374,7 +399,7 @@ function sheet_to_json(worksheet, opts) {
374
399
  /**
375
400
  * Convert worksheet to CSV string
376
401
  */
377
- function sheet_to_csv(worksheet, opts) {
402
+ function sheetToCsv(worksheet, opts) {
378
403
  const o = opts || {};
379
404
  const FS = o.FS ?? ",";
380
405
  const RS = o.RS ?? "\n";
@@ -435,17 +460,17 @@ function sheet_to_csv(worksheet, opts) {
435
460
  /**
436
461
  * Create a new workbook
437
462
  */
438
- function book_new() {
463
+ function bookNew() {
439
464
  return new workbook_js_1.Workbook();
440
465
  }
441
466
  /**
442
467
  * Append worksheet to workbook (xlsx compatible)
443
468
  * @example
444
- * const wb = book_new();
445
- * const ws = json_to_sheet([{a: 1, b: 2}]);
446
- * book_append_sheet(wb, ws, "Sheet1");
469
+ * const wb = bookNew();
470
+ * const ws = jsonToSheet([{a: 1, b: 2}]);
471
+ * bookAppendSheet(wb, ws, "Sheet1");
447
472
  */
448
- function book_append_sheet(workbook, worksheet, name) {
473
+ function bookAppendSheet(workbook, worksheet, name) {
449
474
  // Copy the worksheet data to a new sheet in the workbook
450
475
  const newWs = workbook.addWorksheet(name);
451
476
  // Copy all cells from source worksheet
@@ -470,9 +495,9 @@ function book_append_sheet(workbook, worksheet, name) {
470
495
  /**
471
496
  * Create a worksheet from an array of arrays (xlsx compatible)
472
497
  * @example
473
- * const ws = aoa_to_sheet([["Name", "Age"], ["Alice", 30], ["Bob", 25]])
498
+ * const ws = aoaToSheet([["Name", "Age"], ["Alice", 30], ["Bob", 25]])
474
499
  */
475
- function aoa_to_sheet(data, opts) {
500
+ function aoaToSheet(data, opts) {
476
501
  const tempWb = new workbook_js_1.Workbook();
477
502
  const worksheet = tempWb.addWorksheet("Sheet1");
478
503
  if (data.length === 0) {
@@ -483,7 +508,7 @@ function aoa_to_sheet(data, opts) {
483
508
  let startCol = 1;
484
509
  if (opts?.origin !== undefined) {
485
510
  if (typeof opts.origin === "string") {
486
- const addr = decode_cell(opts.origin);
511
+ const addr = decodeCell(opts.origin);
487
512
  startRow = addr.r + 1;
488
513
  startCol = addr.c + 1;
489
514
  }
@@ -510,7 +535,7 @@ function aoa_to_sheet(data, opts) {
510
535
  /**
511
536
  * Add data from an array of arrays to an existing worksheet (xlsx compatible)
512
537
  */
513
- function sheet_add_aoa(worksheet, data, opts) {
538
+ function sheetAddAoa(worksheet, data, opts) {
514
539
  if (data.length === 0) {
515
540
  return worksheet;
516
541
  }
@@ -519,7 +544,7 @@ function sheet_add_aoa(worksheet, data, opts) {
519
544
  let startCol = 1;
520
545
  if (opts?.origin !== undefined) {
521
546
  if (typeof opts.origin === "string") {
522
- const addr = decode_cell(opts.origin);
547
+ const addr = decodeCell(opts.origin);
523
548
  startRow = addr.r + 1;
524
549
  startCol = addr.c + 1;
525
550
  }
@@ -552,7 +577,7 @@ function sheet_add_aoa(worksheet, data, opts) {
552
577
  /**
553
578
  * Convert worksheet to array of arrays
554
579
  */
555
- function sheet_to_aoa(worksheet) {
580
+ function sheetToAoa(worksheet) {
556
581
  const result = [];
557
582
  worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => {
558
583
  const rowData = [];
@@ -567,24 +592,24 @@ function sheet_to_aoa(worksheet) {
567
592
  // Export utils object
568
593
  // =============================================================================
569
594
  exports.utils = {
570
- // Cell encoding/decoding
571
- decode_col,
572
- encode_col,
573
- decode_row,
574
- encode_row,
575
- decode_cell,
576
- encode_cell,
577
- decode_range,
578
- encode_range,
579
- // Sheet/JSON conversion
580
- json_to_sheet,
581
- sheet_add_json,
582
- sheet_to_json,
583
- sheet_to_csv,
584
- aoa_to_sheet,
585
- sheet_add_aoa,
586
- sheet_to_aoa,
587
- // Workbook functions
588
- book_new,
589
- book_append_sheet
595
+ // Cell encoding/decoding (camelCase)
596
+ decodeCol,
597
+ encodeCol,
598
+ decodeRow,
599
+ encodeRow,
600
+ decodeCell,
601
+ encodeCell,
602
+ decodeRange,
603
+ encodeRange,
604
+ // Sheet/JSON conversion (camelCase)
605
+ jsonToSheet,
606
+ sheetAddJson,
607
+ sheetToJson,
608
+ sheetToCsv,
609
+ aoaToSheet,
610
+ sheetAddAoa,
611
+ sheetToAoa,
612
+ // Workbook functions (camelCase)
613
+ bookNew,
614
+ bookAppendSheet
590
615
  };
@@ -202,14 +202,24 @@ exports.StreamBuf = StreamBuf;
202
202
  if (data instanceof string_buf_js_1.StringBuf || (data && data.constructor?.name === "StringBuf")) {
203
203
  chunk = new StringBufChunk(data);
204
204
  }
205
- else if (data instanceof Buffer) {
205
+ else if (Buffer.isBuffer(data)) {
206
+ // Use Buffer.isBuffer() instead of instanceof for cross-realm compatibility
207
+ // (e.g., Web Workers where Buffer polyfill instances may differ)
206
208
  chunk = new BufferChunk(data);
207
209
  }
208
- else if (typeof data === "string" || data instanceof String || data instanceof ArrayBuffer) {
210
+ else if (ArrayBuffer.isView(data)) {
211
+ // Handle typed arrays (Uint8Array, Int8Array, etc.) - cross-realm safe
212
+ chunk = new BufferChunk(Buffer.from(data.buffer, data.byteOffset, data.byteLength));
213
+ }
214
+ else if (data instanceof ArrayBuffer) {
215
+ // Handle ArrayBuffer - convert to Buffer
216
+ chunk = new BufferChunk(Buffer.from(data));
217
+ }
218
+ else if (typeof data === "string" || data instanceof String) {
209
219
  chunk = new StringChunk(String(data), encoding);
210
220
  }
211
221
  else {
212
- throw new Error("Chunk must be one of type String, Buffer or StringBuf.");
222
+ throw new Error("Chunk must be one of type String, Buffer, Uint8Array, ArrayBuffer or StringBuf.");
213
223
  }
214
224
  // now, do something with the chunk
215
225
  if (this.pipes.length) {
@@ -225,7 +235,8 @@ exports.StreamBuf = StreamBuf;
225
235
  }
226
236
  else {
227
237
  this._writeToBuffers(chunk);
228
- process.nextTick(callback);
238
+ // Use queueMicrotask for cross-platform compatibility (ES2020+)
239
+ queueMicrotask(() => callback());
229
240
  }
230
241
  }
231
242
  else {
@@ -20,6 +20,87 @@ const buffer_stream_js_1 = require("./buffer-stream");
20
20
  const parse_extra_field_js_1 = require("./parse-extra-field");
21
21
  const parse_datetime_js_1 = require("./parse-datetime");
22
22
  const parse_buffer_js_1 = require("./parse-buffer");
23
+ // Check if native zlib is available (Node.js environment)
24
+ // In browser with polyfill, createInflateRaw may not exist or may not work properly
25
+ const hasNativeZlib = typeof zlib_1.default?.createInflateRaw === "function" &&
26
+ typeof process !== "undefined" &&
27
+ process.versions?.node;
28
+ /**
29
+ * A Transform stream that wraps browser's native DecompressionStream.
30
+ * Used when native zlib is not available (browser environment).
31
+ */
32
+ class BrowserInflateRawStream extends stream_1.Transform {
33
+ constructor() {
34
+ super();
35
+ this.chunks = [];
36
+ this.totalLength = 0;
37
+ }
38
+ _transform(chunk, _encoding, callback) {
39
+ // Avoid unnecessary copy - Buffer extends Uint8Array
40
+ this.chunks.push(chunk);
41
+ this.totalLength += chunk.length;
42
+ callback();
43
+ }
44
+ _flush(callback) {
45
+ try {
46
+ // Use pre-calculated totalLength for better performance
47
+ const combined = new Uint8Array(this.totalLength);
48
+ let offset = 0;
49
+ for (const chunk of this.chunks) {
50
+ combined.set(chunk, offset);
51
+ offset += chunk.length;
52
+ }
53
+ // Clear chunks to free memory
54
+ this.chunks = [];
55
+ // Use native DecompressionStream
56
+ const ds = new DecompressionStream("deflate-raw");
57
+ const writer = ds.writable.getWriter();
58
+ const reader = ds.readable.getReader();
59
+ // Optimized read loop - collect chunks and concatenate at the end
60
+ const readAll = async () => {
61
+ const results = [];
62
+ let total = 0;
63
+ while (true) {
64
+ const { done, value } = await reader.read();
65
+ if (done) {
66
+ break;
67
+ }
68
+ results.push(value);
69
+ total += value.length;
70
+ }
71
+ // Single allocation for final result
72
+ const result = Buffer.allocUnsafe(total);
73
+ let off = 0;
74
+ for (const r of results) {
75
+ result.set(r, off);
76
+ off += r.length;
77
+ }
78
+ return result;
79
+ };
80
+ writer.write(combined);
81
+ writer.close();
82
+ readAll()
83
+ .then(decompressed => {
84
+ this.push(decompressed);
85
+ callback();
86
+ })
87
+ .catch(callback);
88
+ }
89
+ catch (err) {
90
+ callback(err);
91
+ }
92
+ }
93
+ }
94
+ /**
95
+ * Creates an InflateRaw stream.
96
+ * Uses native zlib in Node.js for best performance, falls back to DecompressionStream in browser.
97
+ */
98
+ function createInflateRaw() {
99
+ if (hasNativeZlib) {
100
+ return zlib_1.default.createInflateRaw();
101
+ }
102
+ return new BrowserInflateRawStream();
103
+ }
23
104
  const endDirectorySignature = Buffer.alloc(4);
24
105
  endDirectorySignature.writeUInt32LE(0x06054b50, 0);
25
106
  class Parse extends pull_stream_js_1.PullStream {
@@ -175,7 +256,7 @@ class Parse extends pull_stream_js_1.PullStream {
175
256
  const fileSizeKnown = !((vars.flags || 0) & 0x08) || vars.compressedSize > 0;
176
257
  let eof;
177
258
  entry.__autodraining = __autodraining; // expose __autodraining for test purposes
178
- const inflater = vars.compressionMethod && !__autodraining ? zlib_1.default.createInflateRaw() : new stream_1.PassThrough();
259
+ const inflater = vars.compressionMethod && !__autodraining ? createInflateRaw() : new stream_1.PassThrough();
179
260
  if (fileSizeKnown) {
180
261
  entry.size = vars.uncompressedSize;
181
262
  eof = vars.compressedSize;
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.utils = exports.inherits = void 0;
7
7
  exports.delay = delay;
8
8
  exports.nop = nop;
9
- exports.promiseImmediate = promiseImmediate;
10
9
  exports.dateToExcel = dateToExcel;
11
10
  exports.excelToDate = excelToDate;
12
11
  exports.parsePath = parsePath;
@@ -21,26 +20,12 @@ exports.parseBoolean = parseBoolean;
21
20
  exports.range = range;
22
21
  exports.toSortedArray = toSortedArray;
23
22
  exports.objectFromProps = objectFromProps;
23
+ exports.bufferToString = bufferToString;
24
24
  const fs_1 = __importDefault(require("fs"));
25
25
  function delay(ms) {
26
26
  return new Promise(resolve => setTimeout(resolve, ms));
27
27
  }
28
28
  function nop() { }
29
- function promiseImmediate(value) {
30
- return new Promise(resolve => {
31
- if (global.setImmediate) {
32
- setImmediate(() => {
33
- resolve(value);
34
- });
35
- }
36
- else {
37
- // poorman's setImmediate - must wait at least 1ms
38
- setTimeout(() => {
39
- resolve(value);
40
- }, 1);
41
- }
42
- });
43
- }
44
29
  // useful stuff
45
30
  const inherits = function (cls, superCtor, statics, prototype) {
46
31
  cls.super_ = superCtor;
@@ -213,7 +198,6 @@ function objectFromProps(props, value = null) {
213
198
  /** @deprecated Import functions directly instead of using the utils object */
214
199
  exports.utils = {
215
200
  nop,
216
- promiseImmediate,
217
201
  inherits: exports.inherits,
218
202
  dateToExcel,
219
203
  excelToDate,
@@ -232,3 +216,15 @@ exports.utils = {
232
216
  toSortedArray,
233
217
  objectFromProps
234
218
  };
219
+ // TextDecoder is available in ES2020+ and all modern browsers/Node.js
220
+ const textDecoder = new TextDecoder("utf-8");
221
+ /**
222
+ * Convert a Buffer or ArrayBuffer to a UTF-8 string
223
+ * Works in both Node.js and browser environments
224
+ */
225
+ function bufferToString(chunk) {
226
+ if (typeof chunk === "string") {
227
+ return chunk;
228
+ }
229
+ return textDecoder.decode(chunk);
230
+ }
@@ -7,8 +7,6 @@ exports.ZipWriter = void 0;
7
7
  const events_1 = __importDefault(require("events"));
8
8
  const fflate_1 = require("fflate");
9
9
  const stream_buf_js_1 = require("./stream-buf");
10
- const browser_buffer_encode_js_1 = require("./browser-buffer-encode");
11
- const browser_js_1 = require("./browser");
12
10
  // =============================================================================
13
11
  // The ZipWriter class
14
12
  // Packs streamed data into an output zip stream
@@ -42,39 +40,29 @@ class ZipWriter extends events_1.default.EventEmitter {
42
40
  append(data, options) {
43
41
  let buffer;
44
42
  if (Object.prototype.hasOwnProperty.call(options, "base64") && options.base64) {
45
- // Use Buffer.from for efficient base64 decoding
43
+ // Decode base64 data - Buffer.from works in both Node.js and browser (via polyfill)
46
44
  const base64Data = typeof data === "string" ? data : data.toString();
47
- if (browser_js_1.isBrowser) {
48
- // Browser: use atob with optimized Uint8Array conversion
49
- const binaryString = atob(base64Data);
50
- const len = binaryString.length;
51
- buffer = new Uint8Array(len);
52
- // Use a single loop with cached length for better performance
53
- for (let i = 0; i < len; i++) {
54
- buffer[i] = binaryString.charCodeAt(i);
55
- }
56
- }
57
- else {
58
- // Node.js: use efficient Buffer.from
59
- buffer = Buffer.from(base64Data, "base64");
60
- }
45
+ buffer = Buffer.from(base64Data, "base64");
46
+ }
47
+ else if (typeof data === "string") {
48
+ // Convert string to Buffer - works in both environments
49
+ buffer = Buffer.from(data, "utf8");
50
+ }
51
+ else if (Buffer.isBuffer(data)) {
52
+ // Buffer extends Uint8Array, fflate can use it directly - no copy needed
53
+ buffer = data;
54
+ }
55
+ else if (ArrayBuffer.isView(data)) {
56
+ // Handle typed arrays - create view without copy
57
+ buffer = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
58
+ }
59
+ else if (data instanceof ArrayBuffer) {
60
+ // Handle ArrayBuffer directly
61
+ buffer = new Uint8Array(data);
61
62
  }
62
63
  else {
63
- if (typeof data === "string") {
64
- // Convert string to Uint8Array
65
- if (browser_js_1.isBrowser) {
66
- buffer = (0, browser_buffer_encode_js_1.stringToBuffer)(data);
67
- }
68
- else {
69
- buffer = Buffer.from(data, "utf8");
70
- }
71
- }
72
- else if (Buffer.isBuffer(data)) {
73
- buffer = new Uint8Array(data);
74
- }
75
- else {
76
- buffer = data;
77
- }
64
+ // Assume it's already a Uint8Array or compatible type
65
+ buffer = data;
78
66
  }
79
67
  // Add file to zip using streaming API
80
68
  // Use ZipDeflate for compression or ZipPassThrough for no compression