@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.
- package/dist/browser/excelts.iife.js +454 -159
- package/dist/browser/excelts.iife.js.map +1 -1
- package/dist/browser/excelts.iife.min.js +28 -28
- package/dist/cjs/doc/anchor.js +25 -11
- package/dist/cjs/doc/cell.js +75 -43
- package/dist/cjs/doc/column.js +74 -22
- package/dist/cjs/doc/defined-names.js +53 -7
- package/dist/cjs/doc/image.js +11 -8
- package/dist/cjs/doc/range.js +64 -28
- package/dist/cjs/doc/row.js +72 -31
- package/dist/cjs/doc/table.js +3 -5
- package/dist/cjs/doc/workbook.js +30 -6
- package/dist/cjs/doc/worksheet.js +165 -41
- package/dist/cjs/utils/sheet-utils.js +3 -1
- package/dist/cjs/utils/unzip/extract.js +30 -82
- package/dist/cjs/utils/unzip/index.js +18 -2
- package/dist/cjs/utils/unzip/zip-parser.js +458 -0
- package/dist/esm/doc/anchor.js +25 -11
- package/dist/esm/doc/cell.js +75 -43
- package/dist/esm/doc/column.js +74 -22
- package/dist/esm/doc/defined-names.js +53 -7
- package/dist/esm/doc/image.js +11 -8
- package/dist/esm/doc/range.js +64 -28
- package/dist/esm/doc/row.js +72 -31
- package/dist/esm/doc/table.js +3 -5
- package/dist/esm/doc/workbook.js +30 -6
- package/dist/esm/doc/worksheet.js +165 -41
- package/dist/esm/utils/sheet-utils.js +3 -1
- package/dist/esm/utils/unzip/extract.js +28 -82
- package/dist/esm/utils/unzip/index.js +17 -2
- package/dist/esm/utils/unzip/zip-parser.js +451 -0
- package/dist/types/doc/anchor.d.ts +14 -7
- package/dist/types/doc/cell.d.ts +78 -37
- package/dist/types/doc/column.d.ts +72 -36
- package/dist/types/doc/defined-names.d.ts +11 -8
- package/dist/types/doc/image.d.ts +29 -12
- package/dist/types/doc/pivot-table.d.ts +1 -1
- package/dist/types/doc/range.d.ts +15 -4
- package/dist/types/doc/row.d.ts +78 -40
- package/dist/types/doc/table.d.ts +21 -36
- package/dist/types/doc/workbook.d.ts +54 -34
- package/dist/types/doc/worksheet.d.ts +255 -83
- package/dist/types/stream/xlsx/worksheet-reader.d.ts +3 -5
- package/dist/types/types.d.ts +86 -26
- package/dist/types/utils/col-cache.d.ts +11 -8
- package/dist/types/utils/unzip/extract.d.ts +16 -14
- package/dist/types/utils/unzip/index.d.ts +15 -1
- package/dist/types/utils/unzip/zip-parser.d.ts +92 -0
- 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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Get the current columns array
|
|
167
|
+
*/
|
|
159
168
|
get columns() {
|
|
160
169
|
return this._columns;
|
|
161
170
|
}
|
|
162
|
-
|
|
163
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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(...
|
|
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 =
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
455
|
-
const cellToBeMerged = this.getRow(cell.
|
|
456
|
-
const prevMaster = cell.
|
|
457
|
-
const newMaster = this.getRow(prevMaster.
|
|
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(
|
|
554
|
+
eachRow(optOrCallback, maybeCallback) {
|
|
477
555
|
let options;
|
|
478
|
-
let
|
|
479
|
-
if (typeof
|
|
480
|
-
|
|
556
|
+
let callback;
|
|
557
|
+
if (typeof optOrCallback === "function") {
|
|
558
|
+
callback = optOrCallback;
|
|
481
559
|
}
|
|
482
560
|
else {
|
|
483
|
-
options =
|
|
484
|
-
|
|
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
|
-
|
|
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
|
-
|
|
573
|
+
callback(row, row.number);
|
|
496
574
|
}
|
|
497
575
|
});
|
|
498
576
|
}
|
|
499
577
|
}
|
|
500
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
572
|
-
|
|
573
|
-
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
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
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
|
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
|
|
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(
|
|
60
|
+
* console.log(new TextDecoder().decode(content));
|
|
76
61
|
* }
|
|
77
62
|
* ```
|
|
78
63
|
*/
|
|
79
64
|
async function extractFile(zipData, filePath) {
|
|
80
|
-
const
|
|
81
|
-
|
|
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
|
|
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
|
|
113
|
-
|
|
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
|
|
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(
|
|
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
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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; } });
|