@cj-tech-master/excelts 1.4.3 → 1.4.5-canary.20251212053535.13d32d8

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 (80) hide show
  1. package/README.md +3 -3
  2. package/README_zh.md +3 -3
  3. package/dist/browser/excelts.iife.js +13026 -7610
  4. package/dist/browser/excelts.iife.js.map +1 -1
  5. package/dist/browser/excelts.iife.min.js +87 -24
  6. package/dist/cjs/doc/anchor.js +25 -11
  7. package/dist/cjs/doc/cell.js +75 -43
  8. package/dist/cjs/doc/column.js +39 -16
  9. package/dist/cjs/doc/defined-names.js +53 -7
  10. package/dist/cjs/doc/image.js +11 -8
  11. package/dist/cjs/doc/range.js +64 -28
  12. package/dist/cjs/doc/row.js +33 -17
  13. package/dist/cjs/doc/table.js +3 -5
  14. package/dist/cjs/doc/workbook.js +5 -4
  15. package/dist/cjs/doc/worksheet.js +24 -20
  16. package/dist/cjs/stream/xlsx/workbook-writer.js +3 -2
  17. package/dist/cjs/utils/sheet-utils.js +3 -1
  18. package/dist/cjs/utils/unzip/extract.js +166 -0
  19. package/dist/cjs/utils/unzip/index.js +7 -1
  20. package/dist/cjs/utils/xml-stream.js +25 -3
  21. package/dist/cjs/utils/zip/compress.js +261 -0
  22. package/dist/cjs/utils/zip/crc32.js +154 -0
  23. package/dist/cjs/utils/zip/index.js +70 -0
  24. package/dist/cjs/utils/zip/zip-builder.js +378 -0
  25. package/dist/cjs/utils/zip-stream.js +30 -34
  26. package/dist/cjs/xlsx/xform/book/defined-name-xform.js +36 -2
  27. package/dist/cjs/xlsx/xform/list-xform.js +6 -0
  28. package/dist/cjs/xlsx/xform/sheet/cell-xform.js +6 -1
  29. package/dist/cjs/xlsx/xform/sheet/row-xform.js +24 -2
  30. package/dist/cjs/xlsx/xform/table/filter-column-xform.js +4 -0
  31. package/dist/esm/doc/anchor.js +25 -11
  32. package/dist/esm/doc/cell.js +75 -43
  33. package/dist/esm/doc/column.js +39 -16
  34. package/dist/esm/doc/defined-names.js +53 -7
  35. package/dist/esm/doc/image.js +11 -8
  36. package/dist/esm/doc/range.js +64 -28
  37. package/dist/esm/doc/row.js +33 -17
  38. package/dist/esm/doc/table.js +3 -5
  39. package/dist/esm/doc/workbook.js +5 -4
  40. package/dist/esm/doc/worksheet.js +24 -20
  41. package/dist/esm/stream/xlsx/workbook-writer.js +3 -2
  42. package/dist/esm/utils/sheet-utils.js +3 -1
  43. package/dist/esm/utils/unzip/extract.js +160 -0
  44. package/dist/esm/utils/unzip/index.js +2 -0
  45. package/dist/esm/utils/xml-stream.js +25 -3
  46. package/dist/esm/utils/zip/compress.js +220 -0
  47. package/dist/esm/utils/zip/crc32.js +116 -0
  48. package/dist/esm/utils/zip/index.js +55 -0
  49. package/dist/esm/utils/zip/zip-builder.js +372 -0
  50. package/dist/esm/utils/zip-stream.js +30 -34
  51. package/dist/esm/xlsx/xform/book/defined-name-xform.js +36 -2
  52. package/dist/esm/xlsx/xform/list-xform.js +6 -0
  53. package/dist/esm/xlsx/xform/sheet/cell-xform.js +6 -1
  54. package/dist/esm/xlsx/xform/sheet/row-xform.js +24 -2
  55. package/dist/esm/xlsx/xform/table/filter-column-xform.js +4 -0
  56. package/dist/types/doc/anchor.d.ts +14 -7
  57. package/dist/types/doc/cell.d.ts +85 -40
  58. package/dist/types/doc/column.d.ts +39 -34
  59. package/dist/types/doc/defined-names.d.ts +11 -8
  60. package/dist/types/doc/image.d.ts +29 -12
  61. package/dist/types/doc/pivot-table.d.ts +1 -1
  62. package/dist/types/doc/range.d.ts +15 -4
  63. package/dist/types/doc/row.d.ts +34 -40
  64. package/dist/types/doc/table.d.ts +21 -36
  65. package/dist/types/doc/workbook.d.ts +30 -33
  66. package/dist/types/doc/worksheet.d.ts +105 -80
  67. package/dist/types/stream/xlsx/worksheet-reader.d.ts +3 -5
  68. package/dist/types/types.d.ts +86 -26
  69. package/dist/types/utils/col-cache.d.ts +11 -8
  70. package/dist/types/utils/unzip/extract.d.ts +92 -0
  71. package/dist/types/utils/unzip/index.d.ts +1 -0
  72. package/dist/types/utils/xml-stream.d.ts +2 -0
  73. package/dist/types/utils/zip/compress.d.ts +83 -0
  74. package/dist/types/utils/zip/crc32.d.ts +55 -0
  75. package/dist/types/utils/zip/index.d.ts +52 -0
  76. package/dist/types/utils/zip/zip-builder.d.ts +110 -0
  77. package/dist/types/utils/zip-stream.d.ts +6 -12
  78. package/dist/types/xlsx/xform/list-xform.d.ts +1 -0
  79. package/dist/types/xlsx/xform/sheet/row-xform.d.ts +2 -0
  80. package/package.json +8 -8
@@ -83,12 +83,12 @@ class Row {
83
83
  cDst = this.getCell(i);
84
84
  cDst.value = cSrc.value;
85
85
  cDst.style = cSrc.style;
86
- cDst._comment = cSrc._comment;
86
+ cDst.comment = cSrc.comment;
87
87
  }
88
88
  else if (cDst) {
89
89
  cDst.value = null;
90
90
  cDst.style = {};
91
- cDst._comment = undefined;
91
+ cDst.comment = undefined;
92
92
  }
93
93
  }
94
94
  }
@@ -100,7 +100,7 @@ class Row {
100
100
  cDst = this.getCell(i + nExpand);
101
101
  cDst.value = cSrc.value;
102
102
  cDst.style = cSrc.style;
103
- cDst._comment = cSrc._comment;
103
+ cDst.comment = cSrc.comment;
104
104
  }
105
105
  else {
106
106
  this._cells[i + nExpand - 1] = undefined;
@@ -112,13 +112,18 @@ class Row {
112
112
  cDst = this.getCell(start + i);
113
113
  cDst.value = inserts[i];
114
114
  cDst.style = {};
115
- cDst._comment = undefined;
115
+ cDst.comment = undefined;
116
116
  }
117
117
  }
118
- eachCell(options, iteratee) {
119
- if (!iteratee) {
120
- iteratee = options;
121
- options = null;
118
+ eachCell(optionsOrIteratee, maybeIteratee) {
119
+ let options = null;
120
+ let iteratee;
121
+ if (typeof optionsOrIteratee === "function") {
122
+ iteratee = optionsOrIteratee;
123
+ }
124
+ else {
125
+ options = optionsOrIteratee;
126
+ iteratee = maybeIteratee;
122
127
  }
123
128
  if (options && options.includeEmpty) {
124
129
  const n = this._cells.length;
@@ -198,7 +203,7 @@ class Row {
198
203
  }
199
204
  // returns true if the row includes at least one cell with a value
200
205
  get hasValues() {
201
- return this._cells.some((cell) => cell && cell.type !== enums_js_1.Enums.ValueType.Null);
206
+ return this._cells.some(cell => cell && cell.type !== enums_js_1.Enums.ValueType.Null);
202
207
  }
203
208
  get cellCount() {
204
209
  return this._cells.length;
@@ -237,46 +242,57 @@ class Row {
237
242
  this.style[name] = value;
238
243
  this._cells.forEach(cell => {
239
244
  if (cell) {
240
- cell[name] = value;
245
+ cell.style[name] = value;
241
246
  }
242
247
  });
243
- return value;
244
248
  }
245
249
  get numFmt() {
246
250
  return this.style.numFmt;
247
251
  }
248
252
  set numFmt(value) {
249
- this._applyStyle("numFmt", value);
253
+ if (value !== undefined) {
254
+ this._applyStyle("numFmt", value);
255
+ }
250
256
  }
251
257
  get font() {
252
258
  return this.style.font;
253
259
  }
254
260
  set font(value) {
255
- this._applyStyle("font", value);
261
+ if (value !== undefined) {
262
+ this._applyStyle("font", value);
263
+ }
256
264
  }
257
265
  get alignment() {
258
266
  return this.style.alignment;
259
267
  }
260
268
  set alignment(value) {
261
- this._applyStyle("alignment", value);
269
+ if (value !== undefined) {
270
+ this._applyStyle("alignment", value);
271
+ }
262
272
  }
263
273
  get protection() {
264
274
  return this.style.protection;
265
275
  }
266
276
  set protection(value) {
267
- this._applyStyle("protection", value);
277
+ if (value !== undefined) {
278
+ this._applyStyle("protection", value);
279
+ }
268
280
  }
269
281
  get border() {
270
282
  return this.style.border;
271
283
  }
272
284
  set border(value) {
273
- this._applyStyle("border", value);
285
+ if (value !== undefined) {
286
+ this._applyStyle("border", value);
287
+ }
274
288
  }
275
289
  get fill() {
276
290
  return this.style.fill;
277
291
  }
278
292
  set fill(value) {
279
- this._applyStyle("fill", value);
293
+ if (value !== undefined) {
294
+ this._applyStyle("fill", value);
295
+ }
280
296
  }
281
297
  get hidden() {
282
298
  return !!this._hidden;
@@ -157,9 +157,7 @@ class Table {
157
157
  // the sheet...
158
158
  const assignStyle = (cell, style) => {
159
159
  if (style) {
160
- Object.keys(style).forEach(key => {
161
- cell.style[key] = style[key];
162
- });
160
+ Object.assign(cell.style, style);
163
161
  }
164
162
  };
165
163
  const { worksheet, table } = this;
@@ -377,10 +375,10 @@ class Table {
377
375
  this._assign(this.table, "totalsRow", value);
378
376
  }
379
377
  get theme() {
380
- return this.table.style.name;
378
+ return this.table.style.theme;
381
379
  }
382
380
  set theme(value) {
383
- this.table.style.name = value;
381
+ this.table.style.theme = value;
384
382
  }
385
383
  get showFirstColumn() {
386
384
  return this.table.style.showFirstColumn;
@@ -53,12 +53,13 @@ class Workbook {
53
53
  addWorksheet(name, options) {
54
54
  const id = this.nextId;
55
55
  const lastOrderNo = this._worksheets.reduce((acc, ws) => ((ws && ws.orderNo) > acc ? ws.orderNo : acc), 0);
56
- const worksheetOptions = Object.assign({}, options, {
56
+ const worksheetOptions = {
57
+ ...options,
57
58
  id,
58
59
  name,
59
60
  orderNo: lastOrderNo + 1,
60
61
  workbook: this
61
- });
62
+ };
62
63
  const worksheet = new worksheet_js_1.Worksheet(worksheetOptions);
63
64
  this._worksheets[id] = worksheet;
64
65
  return worksheet;
@@ -106,11 +107,11 @@ class Workbook {
106
107
  addImage(image) {
107
108
  // TODO: validation?
108
109
  const id = this.media.length;
109
- this.media.push(Object.assign({}, image, { type: "image" }));
110
+ this.media.push({ ...image, type: "image" });
110
111
  return id;
111
112
  }
112
113
  getImage(id) {
113
- return this.media[id];
114
+ return this.media[Number(id)];
114
115
  }
115
116
  get model() {
116
117
  return {
@@ -128,7 +128,7 @@ 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;
@@ -164,7 +164,7 @@ class Worksheet {
164
164
  set columns(value) {
165
165
  // calculate max header row count
166
166
  this._headerRowCount = value.reduce((pv, cv) => {
167
- const headerCount = (cv.header && 1) || (cv.headers && cv.headers.length) || 0;
167
+ const headerCount = Array.isArray(cv.header) ? cv.header.length : cv.header ? 1 : 0;
168
168
  return Math.max(pv, headerCount);
169
169
  }, 0);
170
170
  // construct Column objects
@@ -220,12 +220,9 @@ class Worksheet {
220
220
  if (inserts.length > 0) {
221
221
  // must iterate over all rows whether they exist yet or not
222
222
  for (let i = 0; i < nRows; i++) {
223
- const rowArguments = [start, count];
224
- inserts.forEach(insert => {
225
- rowArguments.push(insert[i] || null);
226
- });
223
+ const insertValues = inserts.map(insert => insert[i] || null);
227
224
  const row = this.getRow(i + 1);
228
- row.splice(...rowArguments);
225
+ row.splice(start, count, ...insertValues);
229
226
  }
230
227
  }
231
228
  else {
@@ -251,7 +248,7 @@ class Worksheet {
251
248
  }
252
249
  }
253
250
  for (let i = start; i < start + inserts.length; i++) {
254
- this.getColumn(i).defn = null;
251
+ this.getColumn(i).defn = undefined;
255
252
  }
256
253
  // account for defined names
257
254
  this.workbook.definedNames.spliceColumns(this.name, start, count, inserts.length);
@@ -261,7 +258,7 @@ class Worksheet {
261
258
  }
262
259
  get columnCount() {
263
260
  let maxCount = 0;
264
- this.eachRow((row) => {
261
+ this.eachRow(row => {
265
262
  maxCount = Math.max(maxCount, row.cellCount);
266
263
  });
267
264
  return maxCount;
@@ -270,7 +267,7 @@ class Worksheet {
270
267
  // performance nightmare - for each row, counts all the columns used
271
268
  const counts = [];
272
269
  let count = 0;
273
- this.eachRow((row) => {
270
+ this.eachRow(row => {
274
271
  row.eachCell(({ col }) => {
275
272
  if (!counts[col]) {
276
273
  counts[col] = true;
@@ -451,10 +448,10 @@ class Worksheet {
451
448
  rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
452
449
  rDst.getCell(colNumber).style = cell.style;
453
450
  // 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);
451
+ if (cell.type === enums_js_1.Enums.ValueType.Merge) {
452
+ const cellToBeMerged = this.getRow(cell.row + nInserts).getCell(colNumber);
453
+ const prevMaster = cell.master;
454
+ const newMaster = this.getRow(prevMaster.row + nInserts).getCell(prevMaster.col);
458
455
  cellToBeMerged.merge(newMaster);
459
456
  }
460
457
  });
@@ -473,10 +470,15 @@ class Worksheet {
473
470
  // account for defined names
474
471
  this.workbook.definedNames.spliceRows(this.name, start, count, nInserts);
475
472
  }
476
- eachRow(options, iteratee) {
477
- if (!iteratee) {
478
- iteratee = options;
479
- options = undefined;
473
+ eachRow(optionsOrIteratee, maybeIteratee) {
474
+ let options;
475
+ let iteratee;
476
+ if (typeof optionsOrIteratee === "function") {
477
+ iteratee = optionsOrIteratee;
478
+ }
479
+ else {
480
+ options = optionsOrIteratee;
481
+ iteratee = maybeIteratee;
480
482
  }
481
483
  if (options && options.includeEmpty) {
482
484
  const n = this._rows.length;
@@ -614,12 +616,14 @@ class Worksheet {
614
616
  for (let r = top; r <= bottom; r++) {
615
617
  for (let c = left; c <= right; c++) {
616
618
  if (first) {
617
- this.getCell(r, c).value = {
619
+ const cell = this.getCell(r, c);
620
+ const formulaValue = {
618
621
  shareType,
619
622
  formula,
620
623
  ref: range,
621
624
  result: getResult(r, c)
622
625
  };
626
+ cell.value = formulaValue;
623
627
  first = false;
624
628
  }
625
629
  else {
@@ -755,7 +759,7 @@ Please leave feedback at https://github.com/excelts/excelts/discussions/2575`);
755
759
  };
756
760
  // =================================================
757
761
  // columns
758
- model.cols = column_js_1.Column.toModel(this.columns);
762
+ model.cols = column_js_1.Column.toModel(this.columns || []);
759
763
  // ==========================================================
760
764
  // Rows
761
765
  const rows = (model.rows = []);
@@ -37,8 +37,9 @@ class WorkbookWriter {
37
37
  this.views = [];
38
38
  this.zipOptions = options.zip;
39
39
  // Extract compression level from zip options (supports both zlib.level and compressionOptions.level)
40
- // Default compression level is 6 (good balance of speed and size)
41
- const level = options.zip?.zlib?.level ?? options.zip?.compressionOptions?.level ?? 6;
40
+ // Default compression level is 1 (fast compression with good ratio)
41
+ // Level 1 is ~2x faster than level 6 with only ~7% larger files
42
+ const level = options.zip?.zlib?.level ?? options.zip?.compressionOptions?.level ?? 1;
42
43
  this.compressionLevel = Math.max(0, Math.min(9, level));
43
44
  this.media = [];
44
45
  this.commentRefs = [];
@@ -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 "";
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ /**
3
+ * Simple ZIP extraction utilities
4
+ * Provides easy-to-use Promise-based API for extracting ZIP files
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.extractAll = extractAll;
8
+ exports.extractFile = extractFile;
9
+ exports.listFiles = listFiles;
10
+ exports.forEachEntry = forEachEntry;
11
+ const stream_1 = require("stream");
12
+ const parse_js_1 = require("./parse");
13
+ /**
14
+ * Extract all files from a ZIP buffer
15
+ *
16
+ * @param zipData - ZIP file data as Buffer or Uint8Array
17
+ * @returns Map of file paths to their content
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { extractAll } from "./utils/unzip/extract.js";
22
+ *
23
+ * const zipData = fs.readFileSync("archive.zip");
24
+ * const files = await extractAll(zipData);
25
+ *
26
+ * for (const [path, file] of files) {
27
+ * console.log(`${path}: ${file.data.length} bytes`);
28
+ * }
29
+ * ```
30
+ */
31
+ async function extractAll(zipData) {
32
+ 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
+ }
58
+ }
59
+ return files;
60
+ }
61
+ /**
62
+ * Extract a single file from a ZIP buffer
63
+ *
64
+ * @param zipData - ZIP file data as Buffer or Uint8Array
65
+ * @param filePath - Path of the file to extract
66
+ * @returns File content as Buffer, or null if not found
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * import { extractFile } from "./utils/unzip/extract.js";
71
+ *
72
+ * const zipData = fs.readFileSync("archive.zip");
73
+ * const content = await extractFile(zipData, "readme.txt");
74
+ * if (content) {
75
+ * console.log(content.toString("utf-8"));
76
+ * }
77
+ * ```
78
+ */
79
+ 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;
95
+ }
96
+ /**
97
+ * List all file paths in a ZIP buffer (without extracting content)
98
+ *
99
+ * @param zipData - ZIP file data as Buffer or Uint8Array
100
+ * @returns Array of file paths
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * import { listFiles } from "./utils/unzip/extract.js";
105
+ *
106
+ * const zipData = fs.readFileSync("archive.zip");
107
+ * const paths = await listFiles(zipData);
108
+ * console.log(paths); // ["file1.txt", "folder/file2.txt", ...]
109
+ * ```
110
+ */
111
+ 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;
123
+ }
124
+ /**
125
+ * Iterate over ZIP entries with a callback (memory efficient for large ZIPs)
126
+ *
127
+ * @param zipData - ZIP file data as Buffer or Uint8Array
128
+ * @param callback - Async callback for each entry, return false to stop iteration
129
+ *
130
+ * @example
131
+ * ```ts
132
+ * import { forEachEntry } from "./utils/unzip/extract.js";
133
+ *
134
+ * await forEachEntry(zipData, async (path, getData) => {
135
+ * if (path.endsWith(".xml")) {
136
+ * const content = await getData();
137
+ * console.log(content.toString("utf-8"));
138
+ * }
139
+ * return true; // continue iteration
140
+ * });
141
+ * ```
142
+ */
143
+ 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
+ }
166
+ }
@@ -5,7 +5,7 @@
5
5
  * License: MIT
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.parseExtraField = exports.parseDateTime = exports.parseBuffer = exports.bufferStream = exports.NoopStream = exports.PullStream = exports.createParse = exports.Parse = void 0;
8
+ exports.forEachEntry = exports.listFiles = exports.extractFile = exports.extractAll = exports.parseExtraField = exports.parseDateTime = exports.parseBuffer = exports.bufferStream = exports.NoopStream = exports.PullStream = exports.createParse = exports.Parse = void 0;
9
9
  var parse_js_1 = require("./parse");
10
10
  Object.defineProperty(exports, "Parse", { enumerable: true, get: function () { return parse_js_1.Parse; } });
11
11
  Object.defineProperty(exports, "createParse", { enumerable: true, get: function () { return parse_js_1.createParse; } });
@@ -21,3 +21,9 @@ var parse_datetime_js_1 = require("./parse-datetime");
21
21
  Object.defineProperty(exports, "parseDateTime", { enumerable: true, get: function () { return parse_datetime_js_1.parseDateTime; } });
22
22
  var parse_extra_field_js_1 = require("./parse-extra-field");
23
23
  Object.defineProperty(exports, "parseExtraField", { enumerable: true, get: function () { return parse_extra_field_js_1.parseExtraField; } });
24
+ // Simple extraction API
25
+ var extract_js_1 = require("./extract");
26
+ Object.defineProperty(exports, "extractAll", { enumerable: true, get: function () { return extract_js_1.extractAll; } });
27
+ Object.defineProperty(exports, "extractFile", { enumerable: true, get: function () { return extract_js_1.extractFile; } });
28
+ Object.defineProperty(exports, "listFiles", { enumerable: true, get: function () { return extract_js_1.listFiles; } });
29
+ Object.defineProperty(exports, "forEachEntry", { enumerable: true, get: function () { return extract_js_1.forEachEntry; } });
@@ -7,6 +7,8 @@ const OPEN_ANGLE = "<";
7
7
  const CLOSE_ANGLE = ">";
8
8
  const OPEN_ANGLE_SLASH = "</";
9
9
  const CLOSE_SLASH_ANGLE = "/>";
10
+ // Chunk size for periodic consolidation (reduces final join overhead)
11
+ const CHUNK_SIZE = 10000;
10
12
  function pushAttribute(xml, name, value) {
11
13
  xml.push(` ${name}="${(0, utils_js_1.xmlEncode)(value.toString())}"`);
12
14
  }
@@ -24,15 +26,23 @@ function pushAttributes(xml, attributes) {
24
26
  class XmlStream {
25
27
  constructor() {
26
28
  this._xml = [];
29
+ this._chunks = [];
27
30
  this._stack = [];
28
31
  this._rollbacks = [];
29
32
  }
33
+ _consolidate() {
34
+ // Periodically join small strings into larger chunks to reduce final join overhead
35
+ if (this._xml.length >= CHUNK_SIZE) {
36
+ this._chunks.push(this._xml.join(""));
37
+ this._xml = [];
38
+ }
39
+ }
30
40
  get tos() {
31
41
  return this._stack.length ? this._stack[this._stack.length - 1] : undefined;
32
42
  }
33
43
  get cursor() {
34
44
  // handy way to track whether anything has been added
35
- return this._xml.length;
45
+ return this._chunks.length * CHUNK_SIZE + this._xml.length;
36
46
  }
37
47
  openXml(docAttributes) {
38
48
  const xml = this._xml;
@@ -99,6 +109,7 @@ class XmlStream {
99
109
  }
100
110
  this.open = false;
101
111
  this.leaf = false;
112
+ this._consolidate();
102
113
  }
103
114
  leafNode(name, attributes, text) {
104
115
  this.openNode(name, attributes);
@@ -118,7 +129,8 @@ class XmlStream {
118
129
  xml: this._xml.length,
119
130
  stack: this._stack.length,
120
131
  leaf: this.leaf,
121
- open: this.open
132
+ open: this.open,
133
+ chunksLength: this._chunks.length
122
134
  });
123
135
  return this.cursor;
124
136
  }
@@ -133,12 +145,22 @@ class XmlStream {
133
145
  if (this._stack.length > r.stack) {
134
146
  this._stack.splice(r.stack, this._stack.length - r.stack);
135
147
  }
148
+ if (this._chunks.length > r.chunksLength) {
149
+ this._chunks.splice(r.chunksLength, this._chunks.length - r.chunksLength);
150
+ }
136
151
  this.leaf = r.leaf;
137
152
  this.open = r.open;
138
153
  }
139
154
  get xml() {
140
155
  this.closeAll();
141
- return this._xml.join("");
156
+ // Join chunks first, then remaining xml array
157
+ if (this._chunks.length === 0) {
158
+ return this._xml.join("");
159
+ }
160
+ if (this._xml.length > 0) {
161
+ this._chunks.push(this._xml.join(""));
162
+ }
163
+ return this._chunks.join("");
142
164
  }
143
165
  }
144
166
  exports.XmlStream = XmlStream;