@cj-tech-master/excelts 1.4.5 → 1.5.0

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 (49) hide show
  1. package/dist/browser/excelts.iife.js +454 -159
  2. package/dist/browser/excelts.iife.js.map +1 -1
  3. package/dist/browser/excelts.iife.min.js +28 -28
  4. package/dist/cjs/doc/anchor.js +25 -11
  5. package/dist/cjs/doc/cell.js +75 -43
  6. package/dist/cjs/doc/column.js +74 -22
  7. package/dist/cjs/doc/defined-names.js +53 -7
  8. package/dist/cjs/doc/image.js +11 -8
  9. package/dist/cjs/doc/range.js +64 -28
  10. package/dist/cjs/doc/row.js +72 -31
  11. package/dist/cjs/doc/table.js +3 -5
  12. package/dist/cjs/doc/workbook.js +30 -6
  13. package/dist/cjs/doc/worksheet.js +165 -41
  14. package/dist/cjs/utils/sheet-utils.js +3 -1
  15. package/dist/cjs/utils/unzip/extract.js +30 -82
  16. package/dist/cjs/utils/unzip/index.js +18 -2
  17. package/dist/cjs/utils/unzip/zip-parser.js +458 -0
  18. package/dist/esm/doc/anchor.js +25 -11
  19. package/dist/esm/doc/cell.js +75 -43
  20. package/dist/esm/doc/column.js +74 -22
  21. package/dist/esm/doc/defined-names.js +53 -7
  22. package/dist/esm/doc/image.js +11 -8
  23. package/dist/esm/doc/range.js +64 -28
  24. package/dist/esm/doc/row.js +72 -31
  25. package/dist/esm/doc/table.js +3 -5
  26. package/dist/esm/doc/workbook.js +30 -6
  27. package/dist/esm/doc/worksheet.js +165 -41
  28. package/dist/esm/utils/sheet-utils.js +3 -1
  29. package/dist/esm/utils/unzip/extract.js +28 -82
  30. package/dist/esm/utils/unzip/index.js +17 -2
  31. package/dist/esm/utils/unzip/zip-parser.js +451 -0
  32. package/dist/types/doc/anchor.d.ts +14 -7
  33. package/dist/types/doc/cell.d.ts +78 -37
  34. package/dist/types/doc/column.d.ts +72 -36
  35. package/dist/types/doc/defined-names.d.ts +11 -8
  36. package/dist/types/doc/image.d.ts +29 -12
  37. package/dist/types/doc/pivot-table.d.ts +1 -1
  38. package/dist/types/doc/range.d.ts +15 -4
  39. package/dist/types/doc/row.d.ts +78 -40
  40. package/dist/types/doc/table.d.ts +21 -36
  41. package/dist/types/doc/workbook.d.ts +54 -34
  42. package/dist/types/doc/worksheet.d.ts +255 -83
  43. package/dist/types/stream/xlsx/worksheet-reader.d.ts +3 -5
  44. package/dist/types/types.d.ts +86 -26
  45. package/dist/types/utils/col-cache.d.ts +11 -8
  46. package/dist/types/utils/unzip/extract.d.ts +16 -14
  47. package/dist/types/utils/unzip/index.d.ts +15 -1
  48. package/dist/types/utils/unzip/zip-parser.d.ts +92 -0
  49. package/package.json +1 -1
@@ -128,19 +128,26 @@ class Worksheet {
128
128
  }
129
129
  name = name.substring(0, 31);
130
130
  }
131
- if (this._workbook._worksheets.find((ws) => ws && ws.name.toLowerCase() === name.toLowerCase())) {
131
+ if (this._workbook.worksheets.find(ws => ws && ws.name.toLowerCase() === name.toLowerCase())) {
132
132
  throw new Error(`Worksheet name already exists: ${name}`);
133
133
  }
134
134
  this._name = name;
135
135
  }
136
+ /**
137
+ * The workbook that contains this worksheet
138
+ */
136
139
  get workbook() {
137
140
  return this._workbook;
138
141
  }
139
- // when you're done with this worksheet, call this to remove from workbook
142
+ /**
143
+ * When you're done with this worksheet, call this to remove from workbook
144
+ */
140
145
  destroy() {
141
146
  this._workbook.removeWorksheetEx(this);
142
147
  }
143
- // Get the bounding range of the cells in this worksheet
148
+ /**
149
+ * Get the bounding range of the cells in this worksheet
150
+ */
144
151
  get dimensions() {
145
152
  const dimensions = new range_js_1.Range();
146
153
  this._rows.forEach(row => {
@@ -155,16 +162,22 @@ class Worksheet {
155
162
  }
156
163
  // =========================================================================
157
164
  // Columns
158
- // get the current columns array.
165
+ /**
166
+ * Get the current columns array
167
+ */
159
168
  get columns() {
160
169
  return this._columns;
161
170
  }
162
- // set the columns from an array of column definitions.
163
- // Note: any headers defined will overwrite existing values.
171
+ /**
172
+ * Add column headers and define column keys and widths.
173
+ *
174
+ * Note: these column structures are a workbook-building convenience only,
175
+ * apart from the column width, they will not be fully persisted.
176
+ */
164
177
  set columns(value) {
165
178
  // calculate max header row count
166
179
  this._headerRowCount = value.reduce((pv, cv) => {
167
- const headerCount = (cv.header && 1) || (cv.headers && cv.headers.length) || 0;
180
+ const headerCount = Array.isArray(cv.header) ? cv.header.length : cv.header ? 1 : 0;
168
181
  return Math.max(pv, headerCount);
169
182
  }, 0);
170
183
  // construct Column objects
@@ -188,7 +201,9 @@ class Worksheet {
188
201
  eachColumnKey(f) {
189
202
  Object.keys(this._keys).forEach(key => f(this._keys[key], key));
190
203
  }
191
- // get a single column by col number. If it doesn't exist, create it and any gaps before it
204
+ /**
205
+ * Access an individual column by key, letter and 1-based column number
206
+ */
192
207
  getColumn(c) {
193
208
  let colNum;
194
209
  if (typeof c === "string") {
@@ -214,18 +229,26 @@ class Worksheet {
214
229
  }
215
230
  return this._columns[colNum - 1];
216
231
  }
232
+ /**
233
+ * Cut one or more columns (columns to the right are shifted left)
234
+ * and optionally insert more
235
+ *
236
+ * If column properties have been defined, they will be cut or moved accordingly
237
+ *
238
+ * Known Issue: If a splice causes any merged cells to move, the results may be unpredictable
239
+ *
240
+ * Also: If the worksheet has more rows than values in the column inserts,
241
+ * the rows will still be shifted as if the values existed
242
+ */
217
243
  spliceColumns(start, count, ...inserts) {
218
244
  const rows = this._rows;
219
245
  const nRows = rows.length;
220
246
  if (inserts.length > 0) {
221
247
  // must iterate over all rows whether they exist yet or not
222
248
  for (let i = 0; i < nRows; i++) {
223
- const rowArguments = [start, count];
224
- inserts.forEach(insert => {
225
- rowArguments.push(insert[i] || null);
226
- });
249
+ const insertValues = inserts.map(insert => insert[i] || null);
227
250
  const row = this.getRow(i + 1);
228
- row.splice(...rowArguments);
251
+ row.splice(start, count, ...insertValues);
229
252
  }
230
253
  }
231
254
  else {
@@ -251,26 +274,35 @@ class Worksheet {
251
274
  }
252
275
  }
253
276
  for (let i = start; i < start + inserts.length; i++) {
254
- this.getColumn(i).defn = null;
277
+ this.getColumn(i).defn = undefined;
255
278
  }
256
279
  // account for defined names
257
280
  this.workbook.definedNames.spliceColumns(this.name, start, count, inserts.length);
258
281
  }
282
+ /**
283
+ * Get the last column in a worksheet
284
+ */
259
285
  get lastColumn() {
260
286
  return this.getColumn(this.columnCount);
261
287
  }
288
+ /**
289
+ * The total column size of the document. Equal to the maximum cell count from all of the rows
290
+ */
262
291
  get columnCount() {
263
292
  let maxCount = 0;
264
- this.eachRow((row) => {
293
+ this.eachRow(row => {
265
294
  maxCount = Math.max(maxCount, row.cellCount);
266
295
  });
267
296
  return maxCount;
268
297
  }
298
+ /**
299
+ * A count of the number of columns that have values
300
+ */
269
301
  get actualColumnCount() {
270
302
  // performance nightmare - for each row, counts all the columns used
271
303
  const counts = [];
272
304
  let count = 0;
273
- this.eachRow((row) => {
305
+ this.eachRow(row => {
274
306
  row.eachCell(({ col }) => {
275
307
  if (!counts[col]) {
276
308
  counts[col] = true;
@@ -297,23 +329,41 @@ class Worksheet {
297
329
  get _nextRow() {
298
330
  return this._lastRowNumber + 1;
299
331
  }
332
+ /**
333
+ * Get the last editable row in a worksheet (or undefined if there are none)
334
+ */
300
335
  get lastRow() {
301
336
  if (this._rows.length) {
302
337
  return this._rows[this._rows.length - 1];
303
338
  }
304
339
  return undefined;
305
340
  }
306
- // find a row (if exists) by row number
341
+ /**
342
+ * Tries to find and return row for row number, else undefined
343
+ *
344
+ * @param r - The 1-indexed row number
345
+ */
307
346
  findRow(r) {
308
347
  return this._rows[r - 1];
309
348
  }
310
- // find multiple rows (if exists) by row number
349
+ /**
350
+ * Tries to find and return rows for row number start and length, else undefined
351
+ *
352
+ * @param start - The 1-indexed starting row number
353
+ * @param length - The length of the expected array
354
+ */
311
355
  findRows(start, length) {
312
356
  return this._rows.slice(start - 1, start - 1 + length);
313
357
  }
358
+ /**
359
+ * The total row size of the document. Equal to the row number of the last row that has values.
360
+ */
314
361
  get rowCount() {
315
362
  return this._lastRowNumber;
316
363
  }
364
+ /**
365
+ * A count of the number of rows that have values. If a mid-document row is empty, it will not be included in the count.
366
+ */
317
367
  get actualRowCount() {
318
368
  // counts actual rows that have actual data
319
369
  let count = 0;
@@ -322,7 +372,9 @@ class Worksheet {
322
372
  });
323
373
  return count;
324
374
  }
325
- // get a row by row number.
375
+ /**
376
+ * Get or create row by 1-based index
377
+ */
326
378
  getRow(r) {
327
379
  let row = this._rows[r - 1];
328
380
  if (!row) {
@@ -330,7 +382,9 @@ class Worksheet {
330
382
  }
331
383
  return row;
332
384
  }
333
- // get multiple rows by row number.
385
+ /**
386
+ * Get or create rows by 1-based index
387
+ */
334
388
  getRows(start, length) {
335
389
  if (length < 1) {
336
390
  return undefined;
@@ -341,6 +395,10 @@ class Worksheet {
341
395
  }
342
396
  return rows;
343
397
  }
398
+ /**
399
+ * Add a couple of Rows by key-value, after the last current row, using the column keys,
400
+ * or add a row by contiguous Array (assign to columns A, B & C)
401
+ */
344
402
  addRow(value, style = "n") {
345
403
  const rowNo = this._nextRow;
346
404
  const row = this.getRow(rowNo);
@@ -348,6 +406,9 @@ class Worksheet {
348
406
  this._setStyleOption(rowNo, style[0] === "i" ? style : "n");
349
407
  return row;
350
408
  }
409
+ /**
410
+ * Add multiple rows by providing an array of arrays or key-value pairs
411
+ */
351
412
  addRows(value, style = "n") {
352
413
  const rows = [];
353
414
  value.forEach(row => {
@@ -355,11 +416,19 @@ class Worksheet {
355
416
  });
356
417
  return rows;
357
418
  }
419
+ /**
420
+ * Insert a Row by key-value, at the position (shifting down all rows from position),
421
+ * using the column keys, or add a row by contiguous Array (assign to columns A, B & C)
422
+ */
358
423
  insertRow(pos, value, style = "n") {
359
424
  this.spliceRows(pos, 0, value);
360
425
  this._setStyleOption(pos, style);
361
426
  return this.getRow(pos);
362
427
  }
428
+ /**
429
+ * Insert multiple rows at position (shifting down all rows from position)
430
+ * by providing an array of arrays or key-value pairs
431
+ */
363
432
  insertRows(pos, values, style = "n") {
364
433
  this.spliceRows(pos, 0, ...values);
365
434
  if (style !== "n") {
@@ -393,6 +462,9 @@ class Worksheet {
393
462
  });
394
463
  rDst.height = rSrc.height;
395
464
  }
465
+ /**
466
+ * Duplicate rows and insert new rows
467
+ */
396
468
  duplicateRow(rowNum, count, insert = false) {
397
469
  // create count duplicates of rowNum
398
470
  // either inserting new or overwriting existing rows
@@ -409,6 +481,12 @@ class Worksheet {
409
481
  });
410
482
  }
411
483
  }
484
+ /**
485
+ * Cut one or more rows (rows below are shifted up)
486
+ * and optionally insert more
487
+ *
488
+ * Known Issue: If a splice causes any merged cells to move, the results may be unpredictable
489
+ */
412
490
  spliceRows(start, count, ...inserts) {
413
491
  // same problem as row.splice, except worse.
414
492
  const nKeep = start + count;
@@ -451,10 +529,10 @@ class Worksheet {
451
529
  rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
452
530
  rDst.getCell(colNumber).style = cell.style;
453
531
  // remerge cells accounting for insert offset
454
- if (cell._value.constructor.name === "MergeValue") {
455
- const cellToBeMerged = this.getRow(cell._row._number + nInserts).getCell(colNumber);
456
- const prevMaster = cell._value._master;
457
- const newMaster = this.getRow(prevMaster._row._number + nInserts).getCell(prevMaster._column._number);
532
+ if (cell.type === enums_js_1.Enums.ValueType.Merge) {
533
+ const cellToBeMerged = this.getRow(cell.row + nInserts).getCell(colNumber);
534
+ const prevMaster = cell.master;
535
+ const newMaster = this.getRow(prevMaster.row + nInserts).getCell(prevMaster.col);
458
536
  cellToBeMerged.merge(newMaster);
459
537
  }
460
538
  });
@@ -473,31 +551,33 @@ class Worksheet {
473
551
  // account for defined names
474
552
  this.workbook.definedNames.spliceRows(this.name, start, count, nInserts);
475
553
  }
476
- eachRow(optionsOrIteratee, maybeIteratee) {
554
+ eachRow(optOrCallback, maybeCallback) {
477
555
  let options;
478
- let iteratee;
479
- if (typeof optionsOrIteratee === "function") {
480
- iteratee = optionsOrIteratee;
556
+ let callback;
557
+ if (typeof optOrCallback === "function") {
558
+ callback = optOrCallback;
481
559
  }
482
560
  else {
483
- options = optionsOrIteratee;
484
- iteratee = maybeIteratee;
561
+ options = optOrCallback;
562
+ callback = maybeCallback;
485
563
  }
486
564
  if (options && options.includeEmpty) {
487
565
  const n = this._rows.length;
488
566
  for (let i = 1; i <= n; i++) {
489
- iteratee(this.getRow(i), i);
567
+ callback(this.getRow(i), i);
490
568
  }
491
569
  }
492
570
  else {
493
571
  this._rows.forEach(row => {
494
572
  if (row && row.hasValues) {
495
- iteratee(row, row.number);
573
+ callback(row, row.number);
496
574
  }
497
575
  });
498
576
  }
499
577
  }
500
- // return all rows as sparse array
578
+ /**
579
+ * Return all rows as sparse array
580
+ */
501
581
  getSheetValues() {
502
582
  const rows = [];
503
583
  this._rows.forEach(row => {
@@ -509,13 +589,17 @@ class Worksheet {
509
589
  }
510
590
  // =========================================================================
511
591
  // Cells
512
- // returns the cell at [r,c] or address given by r. If not found, return undefined
592
+ /**
593
+ * Returns the cell at [r,c] or address given by r. If not found, return undefined
594
+ */
513
595
  findCell(r, c) {
514
596
  const address = col_cache_js_1.colCache.getAddress(r, c);
515
597
  const row = this._rows[address.row - 1];
516
598
  return row ? row.findCell(address.col) : undefined;
517
599
  }
518
- // return the cell at [r,c] or address given by r. If not found, create a new one.
600
+ /**
601
+ * Get or create cell at [r,c] or address given by r
602
+ */
519
603
  getCell(r, c) {
520
604
  const address = col_cache_js_1.colCache.getAddress(r, c);
521
605
  const row = this.getRow(address.row);
@@ -523,7 +607,15 @@ class Worksheet {
523
607
  }
524
608
  // =========================================================================
525
609
  // Merge
526
- // convert the range defined by ['tl:br'], [tl,br] or [t,l,b,r] into a single 'merged' cell
610
+ /**
611
+ * Merge cells, either:
612
+ *
613
+ * tlbr string, e.g. `'A4:B5'`
614
+ *
615
+ * tl string, br string, e.g. `'G10', 'H11'`
616
+ *
617
+ * t, l, b, r numbers, e.g. `10,11,12,13`
618
+ */
527
619
  mergeCells(...cells) {
528
620
  const dimensions = new range_js_1.Range(cells);
529
621
  this._mergeCellsInternal(dimensions);
@@ -568,9 +660,11 @@ class Worksheet {
568
660
  // return true if this._merges has a merge object
569
661
  return Object.values(this._merges).some(Boolean);
570
662
  }
571
- // scan the range defined by ['tl:br'], [tl,br] or [t,l,b,r] and if any cell is part of a merge,
572
- // un-merge the group. Note this function can affect multiple merges and merge-blocks are
573
- // atomic - either they're all merged or all un-merged.
663
+ /**
664
+ * Scan the range and if any cell is part of a merge, un-merge the group.
665
+ * Note this function can affect multiple merges and merge-blocks are
666
+ * atomic - either they're all merged or all un-merged.
667
+ */
574
668
  unMergeCells(...cells) {
575
669
  const dimensions = new range_js_1.Range(cells);
576
670
  // find any cells in that range and unmerge them
@@ -619,12 +713,14 @@ class Worksheet {
619
713
  for (let r = top; r <= bottom; r++) {
620
714
  for (let c = left; c <= right; c++) {
621
715
  if (first) {
622
- this.getCell(r, c).value = {
716
+ const cell = this.getCell(r, c);
717
+ const formulaValue = {
623
718
  shareType,
624
719
  formula,
625
720
  ref: range,
626
721
  result: getResult(r, c)
627
722
  };
723
+ cell.value = formulaValue;
628
724
  first = false;
629
725
  }
630
726
  else {
@@ -640,6 +736,10 @@ class Worksheet {
640
736
  }
641
737
  // =========================================================================
642
738
  // Images
739
+ /**
740
+ * Using the image id from `Workbook.addImage`,
741
+ * embed an image within the worksheet to cover a range
742
+ */
643
743
  addImage(imageId, range) {
644
744
  const model = {
645
745
  type: "image",
@@ -651,6 +751,9 @@ class Worksheet {
651
751
  getImages() {
652
752
  return this._media.filter(m => m.type === "image");
653
753
  }
754
+ /**
755
+ * Using the image id from `Workbook.addImage`, set the background to the worksheet
756
+ */
654
757
  addBackgroundImage(imageId) {
655
758
  const model = {
656
759
  type: "background",
@@ -664,6 +767,9 @@ class Worksheet {
664
767
  }
665
768
  // =========================================================================
666
769
  // Worksheet Protection
770
+ /**
771
+ * Protect the worksheet with optional password and options
772
+ */
667
773
  protect(password, options) {
668
774
  // TODO: make this function truly async
669
775
  // perhaps marshal to worker thread or something
@@ -698,17 +804,29 @@ class Worksheet {
698
804
  }
699
805
  // =========================================================================
700
806
  // Tables
807
+ /**
808
+ * Add a new table and return a reference to it
809
+ */
701
810
  addTable(model) {
702
811
  const table = new table_js_1.Table(this, model);
703
812
  this.tables[model.name] = table;
704
813
  return table;
705
814
  }
815
+ /**
816
+ * Fetch table by name
817
+ */
706
818
  getTable(name) {
707
819
  return this.tables[name];
708
820
  }
821
+ /**
822
+ * Delete table by name
823
+ */
709
824
  removeTable(name) {
710
825
  delete this.tables[name];
711
826
  }
827
+ /**
828
+ * Fetch all tables in the worksheet
829
+ */
712
830
  getTables() {
713
831
  return Object.values(this.tables);
714
832
  }
@@ -724,9 +842,15 @@ Please leave feedback at https://github.com/excelts/excelts/discussions/2575`);
724
842
  }
725
843
  // ===========================================================================
726
844
  // Conditional Formatting
845
+ /**
846
+ * Add conditional formatting rules
847
+ */
727
848
  addConditionalFormatting(cf) {
728
849
  this.conditionalFormattings.push(cf);
729
850
  }
851
+ /**
852
+ * Delete conditional formatting rules
853
+ */
730
854
  removeConditionalFormatting(filter) {
731
855
  if (typeof filter === "number") {
732
856
  this.conditionalFormattings.splice(filter, 1);
@@ -760,7 +884,7 @@ Please leave feedback at https://github.com/excelts/excelts/discussions/2575`);
760
884
  };
761
885
  // =================================================
762
886
  // columns
763
- model.cols = column_js_1.Column.toModel(this.columns);
887
+ model.cols = column_js_1.Column.toModel(this.columns || []);
764
888
  // ==========================================================
765
889
  // Rows
766
890
  const rows = (model.rows = []);
@@ -132,7 +132,9 @@ function formatValue(value, fmt, dateFormat) {
132
132
  */
133
133
  function getCellDisplayText(cell, dateFormat) {
134
134
  const value = cell.value;
135
- const fmt = cell.numFmt || "General";
135
+ const numFmt = cell.numFmt;
136
+ // Extract format code string from numFmt (which can be string or NumFmt object)
137
+ const fmt = typeof numFmt === "string" ? numFmt : (numFmt?.formatCode ?? "General");
136
138
  // Null/undefined
137
139
  if (value == null) {
138
140
  return "";
@@ -2,18 +2,19 @@
2
2
  /**
3
3
  * Simple ZIP extraction utilities
4
4
  * Provides easy-to-use Promise-based API for extracting ZIP files
5
+ * Works in both Node.js and browser environments
5
6
  */
6
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.ZipParser = void 0;
7
9
  exports.extractAll = extractAll;
8
10
  exports.extractFile = extractFile;
9
11
  exports.listFiles = listFiles;
10
12
  exports.forEachEntry = forEachEntry;
11
- const stream_1 = require("stream");
12
- const parse_js_1 = require("./parse");
13
+ const zip_parser_js_1 = require("./zip-parser");
13
14
  /**
14
15
  * Extract all files from a ZIP buffer
15
16
  *
16
- * @param zipData - ZIP file data as Buffer or Uint8Array
17
+ * @param zipData - ZIP file data as Buffer, Uint8Array, or ArrayBuffer
17
18
  * @returns Map of file paths to their content
18
19
  *
19
20
  * @example
@@ -30,40 +31,24 @@ const parse_js_1 = require("./parse");
30
31
  */
31
32
  async function extractAll(zipData) {
32
33
  const files = new Map();
33
- const buffer = Buffer.isBuffer(zipData) ? zipData : Buffer.from(zipData);
34
- const parse = (0, parse_js_1.createParse)({ forceStream: true });
35
- const stream = stream_1.Readable.from([buffer]);
36
- stream.pipe(parse);
37
- for await (const entry of parse) {
38
- const zipEntry = entry;
39
- const isDirectory = zipEntry.type === "Directory";
40
- if (isDirectory) {
41
- files.set(zipEntry.path, {
42
- path: zipEntry.path,
43
- data: Buffer.alloc(0),
44
- isDirectory: true,
45
- size: 0
46
- });
47
- zipEntry.autodrain();
48
- }
49
- else {
50
- const data = await zipEntry.buffer();
51
- files.set(zipEntry.path, {
52
- path: zipEntry.path,
53
- data,
54
- isDirectory: false,
55
- size: data.length
56
- });
57
- }
34
+ const parser = new zip_parser_js_1.ZipParser(zipData);
35
+ for (const entry of parser.getEntries()) {
36
+ const data = await parser.extract(entry.path);
37
+ files.set(entry.path, {
38
+ path: entry.path,
39
+ data: data || new Uint8Array(0),
40
+ isDirectory: entry.isDirectory,
41
+ size: entry.uncompressedSize
42
+ });
58
43
  }
59
44
  return files;
60
45
  }
61
46
  /**
62
47
  * Extract a single file from a ZIP buffer
63
48
  *
64
- * @param zipData - ZIP file data as Buffer or Uint8Array
49
+ * @param zipData - ZIP file data as Buffer, Uint8Array, or ArrayBuffer
65
50
  * @param filePath - Path of the file to extract
66
- * @returns File content as Buffer, or null if not found
51
+ * @returns File content as Uint8Array, or null if not found
67
52
  *
68
53
  * @example
69
54
  * ```ts
@@ -72,31 +57,18 @@ async function extractAll(zipData) {
72
57
  * const zipData = fs.readFileSync("archive.zip");
73
58
  * const content = await extractFile(zipData, "readme.txt");
74
59
  * if (content) {
75
- * console.log(content.toString("utf-8"));
60
+ * console.log(new TextDecoder().decode(content));
76
61
  * }
77
62
  * ```
78
63
  */
79
64
  async function extractFile(zipData, filePath) {
80
- const buffer = Buffer.isBuffer(zipData) ? zipData : Buffer.from(zipData);
81
- const parse = (0, parse_js_1.createParse)({ forceStream: true });
82
- const stream = stream_1.Readable.from([buffer]);
83
- stream.pipe(parse);
84
- for await (const entry of parse) {
85
- const zipEntry = entry;
86
- if (zipEntry.path === filePath) {
87
- if (zipEntry.type === "Directory") {
88
- return Buffer.alloc(0);
89
- }
90
- return zipEntry.buffer();
91
- }
92
- zipEntry.autodrain();
93
- }
94
- return null;
65
+ const parser = new zip_parser_js_1.ZipParser(zipData);
66
+ return parser.extract(filePath);
95
67
  }
96
68
  /**
97
69
  * List all file paths in a ZIP buffer (without extracting content)
98
70
  *
99
- * @param zipData - ZIP file data as Buffer or Uint8Array
71
+ * @param zipData - ZIP file data as Buffer, Uint8Array, or ArrayBuffer
100
72
  * @returns Array of file paths
101
73
  *
102
74
  * @example
@@ -109,22 +81,13 @@ async function extractFile(zipData, filePath) {
109
81
  * ```
110
82
  */
111
83
  async function listFiles(zipData) {
112
- const paths = [];
113
- const buffer = Buffer.isBuffer(zipData) ? zipData : Buffer.from(zipData);
114
- const parse = (0, parse_js_1.createParse)({ forceStream: true });
115
- const stream = stream_1.Readable.from([buffer]);
116
- stream.pipe(parse);
117
- for await (const entry of parse) {
118
- const zipEntry = entry;
119
- paths.push(zipEntry.path);
120
- zipEntry.autodrain();
121
- }
122
- return paths;
84
+ const parser = new zip_parser_js_1.ZipParser(zipData);
85
+ return parser.listFiles();
123
86
  }
124
87
  /**
125
88
  * Iterate over ZIP entries with a callback (memory efficient for large ZIPs)
126
89
  *
127
- * @param zipData - ZIP file data as Buffer or Uint8Array
90
+ * @param zipData - ZIP file data as Buffer, Uint8Array, or ArrayBuffer
128
91
  * @param callback - Async callback for each entry, return false to stop iteration
129
92
  *
130
93
  * @example
@@ -134,33 +97,18 @@ async function listFiles(zipData) {
134
97
  * await forEachEntry(zipData, async (path, getData) => {
135
98
  * if (path.endsWith(".xml")) {
136
99
  * const content = await getData();
137
- * console.log(content.toString("utf-8"));
100
+ * console.log(new TextDecoder().decode(content));
138
101
  * }
139
102
  * return true; // continue iteration
140
103
  * });
141
104
  * ```
142
105
  */
143
106
  async function forEachEntry(zipData, callback) {
144
- const buffer = Buffer.isBuffer(zipData) ? zipData : Buffer.from(zipData);
145
- const parse = (0, parse_js_1.createParse)({ forceStream: true });
146
- const stream = stream_1.Readable.from([buffer]);
147
- stream.pipe(parse);
148
- for await (const entry of parse) {
149
- const zipEntry = entry;
150
- let dataPromise = null;
151
- const getData = () => {
152
- if (!dataPromise) {
153
- dataPromise = zipEntry.buffer();
154
- }
155
- return dataPromise;
156
- };
157
- const shouldContinue = await callback(zipEntry.path, getData, zipEntry);
158
- // If callback didn't read data, drain it
159
- if (!dataPromise) {
160
- zipEntry.autodrain();
161
- }
162
- if (shouldContinue === false) {
163
- break;
164
- }
165
- }
107
+ const parser = new zip_parser_js_1.ZipParser(zipData);
108
+ await parser.forEach(async (entry, getData) => {
109
+ return callback(entry.path, getData, entry);
110
+ });
166
111
  }
112
+ // Re-export ZipParser for advanced usage
113
+ var zip_parser_js_2 = require("./zip-parser");
114
+ Object.defineProperty(exports, "ZipParser", { enumerable: true, get: function () { return zip_parser_js_2.ZipParser; } });