@cj-tech-master/excelts 5.1.17 → 5.1.18

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 (64) hide show
  1. package/dist/browser/modules/archive/unzip/stream.base.js +11 -4
  2. package/dist/browser/modules/archive/unzip/stream.browser.js +3 -3
  3. package/dist/browser/modules/excel/anchor.js +2 -5
  4. package/dist/browser/modules/excel/cell.js +11 -9
  5. package/dist/browser/modules/excel/column.js +2 -2
  6. package/dist/browser/modules/excel/defined-names.js +2 -2
  7. package/dist/browser/modules/excel/note.js +1 -1
  8. package/dist/browser/modules/excel/row.js +7 -4
  9. package/dist/browser/modules/excel/stream/worksheet-reader.js +4 -1
  10. package/dist/browser/modules/excel/table.d.ts +20 -1
  11. package/dist/browser/modules/excel/table.js +118 -15
  12. package/dist/browser/modules/excel/utils/sheet-utils.js +1 -1
  13. package/dist/browser/modules/excel/worksheet.d.ts +1 -1
  14. package/dist/browser/modules/excel/worksheet.js +5 -4
  15. package/dist/browser/modules/excel/xlsx/xform/book/workbook-xform.d.ts +3 -0
  16. package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +1 -1
  17. package/dist/browser/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +6 -5
  18. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.d.ts +3 -0
  19. package/dist/browser/modules/excel/xlsx/xform/style/styles-xform.d.ts +4 -0
  20. package/dist/browser/modules/stream/streams.browser.d.ts +5 -5
  21. package/dist/browser/modules/stream/streams.browser.js +12 -4
  22. package/dist/browser/utils/utils.base.js +1 -1
  23. package/dist/cjs/modules/archive/unzip/stream.base.js +11 -4
  24. package/dist/cjs/modules/archive/unzip/stream.browser.js +3 -3
  25. package/dist/cjs/modules/excel/anchor.js +2 -5
  26. package/dist/cjs/modules/excel/cell.js +11 -9
  27. package/dist/cjs/modules/excel/column.js +2 -2
  28. package/dist/cjs/modules/excel/defined-names.js +2 -2
  29. package/dist/cjs/modules/excel/note.js +1 -1
  30. package/dist/cjs/modules/excel/row.js +7 -4
  31. package/dist/cjs/modules/excel/stream/worksheet-reader.js +4 -1
  32. package/dist/cjs/modules/excel/table.js +118 -14
  33. package/dist/cjs/modules/excel/utils/sheet-utils.js +1 -1
  34. package/dist/cjs/modules/excel/worksheet.js +5 -4
  35. package/dist/cjs/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +1 -1
  36. package/dist/cjs/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +6 -5
  37. package/dist/cjs/modules/stream/streams.browser.js +12 -4
  38. package/dist/cjs/utils/utils.base.js +1 -1
  39. package/dist/esm/modules/archive/unzip/stream.base.js +11 -4
  40. package/dist/esm/modules/archive/unzip/stream.browser.js +3 -3
  41. package/dist/esm/modules/excel/anchor.js +2 -5
  42. package/dist/esm/modules/excel/cell.js +11 -9
  43. package/dist/esm/modules/excel/column.js +2 -2
  44. package/dist/esm/modules/excel/defined-names.js +2 -2
  45. package/dist/esm/modules/excel/note.js +1 -1
  46. package/dist/esm/modules/excel/row.js +7 -4
  47. package/dist/esm/modules/excel/stream/worksheet-reader.js +4 -1
  48. package/dist/esm/modules/excel/table.js +118 -15
  49. package/dist/esm/modules/excel/utils/sheet-utils.js +1 -1
  50. package/dist/esm/modules/excel/worksheet.js +5 -4
  51. package/dist/esm/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +1 -1
  52. package/dist/esm/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +6 -5
  53. package/dist/esm/modules/stream/streams.browser.js +12 -4
  54. package/dist/esm/utils/utils.base.js +1 -1
  55. package/dist/iife/excelts.iife.js +724 -888
  56. package/dist/iife/excelts.iife.js.map +1 -1
  57. package/dist/iife/excelts.iife.min.js +24 -23
  58. package/dist/types/modules/excel/table.d.ts +20 -1
  59. package/dist/types/modules/excel/worksheet.d.ts +1 -1
  60. package/dist/types/modules/excel/xlsx/xform/book/workbook-xform.d.ts +3 -0
  61. package/dist/types/modules/excel/xlsx/xform/sheet/worksheet-xform.d.ts +3 -0
  62. package/dist/types/modules/excel/xlsx/xform/style/styles-xform.d.ts +4 -0
  63. package/dist/types/modules/stream/streams.browser.d.ts +5 -5
  64. package/package.json +16 -16
@@ -646,7 +646,6 @@ export function streamUntilValidatedDataDescriptor(options) {
646
646
  if (written > 0) {
647
647
  source.discard(written);
648
648
  bytesEmitted += written;
649
- available -= written;
650
649
  scanner.onConsume(written);
651
650
  }
652
651
  if (waitingDrain) {
@@ -656,7 +655,6 @@ export function streamUntilValidatedDataDescriptor(options) {
656
655
  else {
657
656
  const ok = output.write(source.read(idx));
658
657
  bytesEmitted += idx;
659
- available -= idx;
660
658
  scanner.onConsume(idx);
661
659
  if (!ok) {
662
660
  waitingDrain = true;
@@ -957,8 +955,17 @@ async function readFileRecord(opts, io, emitter, inflateFactory, state, threshol
957
955
  }
958
956
  }
959
957
  }
960
- const extra = parseExtraField(extraFieldData, vars);
961
- vars.lastModifiedDateTime = resolveZipEntryLastModifiedDateTime(vars, extra);
958
+ const zipVars = {
959
+ uncompressedSize: vars.uncompressedSize ?? 0,
960
+ compressedSize: vars.compressedSize ?? 0
961
+ };
962
+ const extra = parseExtraField(extraFieldData, zipVars);
963
+ vars.lastModifiedDateTime = resolveZipEntryLastModifiedDateTime({
964
+ flags: vars.flags,
965
+ uncompressedSize: zipVars.uncompressedSize,
966
+ lastModifiedDate: vars.lastModifiedDate,
967
+ lastModifiedTime: vars.lastModifiedTime
968
+ }, extra);
962
969
  entry.vars = vars;
963
970
  entry.extraFields = extra;
964
971
  entry.__autodraining = autodraining;
@@ -174,7 +174,7 @@ class BrowserInflateRaw extends Duplex {
174
174
  this.writer.abort(error ?? undefined).catch(() => { });
175
175
  }
176
176
  this.reader.cancel(error ?? undefined).catch(() => { });
177
- return super.destroy(error);
177
+ return super.destroy(error ?? undefined);
178
178
  }
179
179
  }
180
180
  // =============================================================================
@@ -393,7 +393,7 @@ class WorkerInflateRaw extends Duplex {
393
393
  }
394
394
  }
395
395
  this._terminateWorker();
396
- return super.destroy(error);
396
+ return super.destroy(error ?? undefined);
397
397
  }
398
398
  }
399
399
  // =============================================================================
@@ -439,7 +439,7 @@ class FallbackInflateRaw extends Duplex {
439
439
  destroy(error) {
440
440
  this._finished = true;
441
441
  this.chunks = [];
442
- return super.destroy(error);
442
+ return super.destroy(error ?? undefined);
443
443
  }
444
444
  }
445
445
  // =============================================================================
@@ -73,11 +73,8 @@ class Anchor {
73
73
  : 640000;
74
74
  }
75
75
  get rowHeight() {
76
- return this.worksheet &&
77
- this.worksheet.getRow(this.nativeRow + 1) &&
78
- this.worksheet.getRow(this.nativeRow + 1).height
79
- ? Math.floor(this.worksheet.getRow(this.nativeRow + 1).height * 10000)
80
- : 180000;
76
+ const height = this.worksheet?.getRow(this.nativeRow + 1)?.height;
77
+ return height ? Math.floor(height * 10000) : 180000;
81
78
  }
82
79
  get model() {
83
80
  return {
@@ -34,11 +34,11 @@ class Cell {
34
34
  }
35
35
  // help GC by removing cyclic (and other) references
36
36
  destroy() {
37
- delete this.style;
38
- delete this._value;
39
- delete this._row;
40
- delete this._column;
41
- delete this._address;
37
+ this.style = undefined;
38
+ this._value = undefined;
39
+ this._row = undefined;
40
+ this._column = undefined;
41
+ this._address = undefined;
42
42
  }
43
43
  // =========================================================================
44
44
  // Styles stuff
@@ -164,7 +164,7 @@ class Cell {
164
164
  if (this._value.type !== Cell.Types.Merge) {
165
165
  return false;
166
166
  }
167
- return this._value.isMergedTo(master);
167
+ return this._value.isMergedTo ? this._value.isMergedTo(master) : false;
168
168
  }
169
169
  get master() {
170
170
  if (this.type === Cell.Types.Merge) {
@@ -246,7 +246,7 @@ class Cell {
246
246
  return this._value.result;
247
247
  }
248
248
  get formulaType() {
249
- return this._value.formulaType;
249
+ return this._value.formulaType ?? Enums.FormulaType.None;
250
250
  }
251
251
  // =========================================================================
252
252
  // Name stuff
@@ -607,7 +607,7 @@ class MergeValue {
607
607
  this._master.releaseMergeRef();
608
608
  }
609
609
  toString() {
610
- return this.value.toString();
610
+ return this.value != null ? this.value.toString() : "";
611
611
  }
612
612
  }
613
613
  class FormulaValue {
@@ -740,7 +740,9 @@ class FormulaValue {
740
740
  const { worksheet } = this.cell;
741
741
  const master = worksheet.findCell(this.model.sharedFormula);
742
742
  this._translatedFormula =
743
- master && slideFormula(master.formula, master.address, this.model.address);
743
+ master && master.formula
744
+ ? slideFormula(master.formula, master.address, this.model.address)
745
+ : undefined;
744
746
  }
745
747
  return this._translatedFormula;
746
748
  }
@@ -110,7 +110,7 @@ class Column {
110
110
  }
111
111
  this._key = value;
112
112
  if (value) {
113
- this._worksheet.setColumnKey(this._key, this);
113
+ this._worksheet.setColumnKey(value, this);
114
114
  }
115
115
  }
116
116
  /**
@@ -135,7 +135,7 @@ class Column {
135
135
  * Indicate the collapsed state based on outlineLevel
136
136
  */
137
137
  get collapsed() {
138
- return !!(this._outlineLevel && this._outlineLevel >= this._worksheet.properties.outlineLevelCol);
138
+ return !!(this._outlineLevel && this._outlineLevel >= (this._worksheet.properties.outlineLevelCol ?? 0));
139
139
  }
140
140
  toString() {
141
141
  return JSON.stringify({
@@ -107,7 +107,7 @@ class DefinedNames {
107
107
  }
108
108
  _explore(matrix, cell) {
109
109
  cell.mark = false;
110
- const { sheetName } = cell;
110
+ const sheetName = cell.sheetName; // Always set for cells in defined names
111
111
  const range = new Range(cell.row, cell.col, cell.row, cell.col, sheetName);
112
112
  let x;
113
113
  let y;
@@ -160,7 +160,7 @@ class DefinedNames {
160
160
  });
161
161
  const ranges = matrix
162
162
  .map((cell) => cell.mark && this._explore(matrix, cell))
163
- .filter(Boolean)
163
+ .filter((range) => Boolean(range))
164
164
  .map((range) => range.$shortRange);
165
165
  return {
166
166
  name,
@@ -4,7 +4,7 @@ class Note {
4
4
  this.note = note;
5
5
  }
6
6
  get model() {
7
- let value = null;
7
+ let value;
8
8
  switch (typeof this.note) {
9
9
  case "string":
10
10
  value = {
@@ -34,9 +34,9 @@ class Row {
34
34
  * Helps GC by breaking cyclic references
35
35
  */
36
36
  destroy() {
37
- delete this._worksheet;
38
- delete this._cells;
39
- delete this.style;
37
+ this._worksheet = undefined;
38
+ this._cells = undefined;
39
+ this.style = undefined;
40
40
  }
41
41
  findCell(colNumber) {
42
42
  return this._cells[colNumber - 1];
@@ -358,7 +358,7 @@ class Row {
358
358
  this._outlineLevel = value;
359
359
  }
360
360
  get collapsed() {
361
- return !!(this._outlineLevel && this._outlineLevel >= this._worksheet.properties.outlineLevelRow);
361
+ return !!(this._outlineLevel && this._outlineLevel >= (this._worksheet.properties.outlineLevelRow ?? 0));
362
362
  }
363
363
  // =========================================================================
364
364
  get model() {
@@ -424,6 +424,9 @@ class Row {
424
424
  };
425
425
  }
426
426
  previousAddress = address;
427
+ if (!address) {
428
+ break;
429
+ }
427
430
  const cell = this.getCellEx(address);
428
431
  cell.model = cellModel;
429
432
  break;
@@ -267,7 +267,10 @@ class WorksheetReader extends EventEmitter {
267
267
  break;
268
268
  case "row":
269
269
  if (row) {
270
- this._dimensions.expandRow(row);
270
+ this._dimensions.expandRow({
271
+ number: row.number,
272
+ dimensions: row.dimensions ?? undefined
273
+ });
271
274
  (worksheetEvents || (worksheetEvents = [])).push({ eventType: "row", value: row });
272
275
  }
273
276
  row = null;
@@ -14,6 +14,25 @@ interface TableModel {
14
14
  autoFilterRef?: string;
15
15
  tableRef?: string;
16
16
  }
17
+ /**
18
+ * Sanitize a table name to comply with OOXML defined name rules
19
+ * (ECMA-376, 4th edition, Part 1, §18.5.1.2).
20
+ *
21
+ * Rules enforced (per Microsoft documentation):
22
+ * - First character must be a letter (any script), underscore (_), or backslash (\)
23
+ * - Subsequent characters may be letters, digits, underscores, or periods (.)
24
+ * - Backslash is only valid as the first character
25
+ * - Spaces are replaced with underscores
26
+ * - Other invalid characters are stripped
27
+ * - Single-character names "C", "c", "R", "r" are prefixed with _
28
+ * - Names that look like cell references (e.g. A1, R1C1) are prefixed with _
29
+ * - Maximum 255 characters
30
+ * - Empty result falls back to "_Table"
31
+ *
32
+ * This library applies these rules automatically so that generated files
33
+ * always comply with the OOXML schema, avoiding Excel "repair" dialogs.
34
+ */
35
+ declare function sanitizeTableName(name: string): string;
17
36
  declare class Column {
18
37
  table: Table;
19
38
  column: TableColumnProperties;
@@ -83,4 +102,4 @@ declare class Table {
83
102
  get showColumnStripes(): boolean | undefined;
84
103
  set showColumnStripes(value: boolean | undefined);
85
104
  }
86
- export { Table, type TableModel };
105
+ export { Table, sanitizeTableName, type TableModel };
@@ -1,4 +1,82 @@
1
1
  import { colCache } from "./utils/col-cache.js";
2
+ /**
3
+ * Maximum length for an Excel defined name (and therefore table name).
4
+ */
5
+ const MAX_TABLE_NAME_LENGTH = 255;
6
+ /**
7
+ * Matches an A1-style cell reference pattern like A1, Z99, XFD1048576.
8
+ * Excel rejects table names that match this pattern.
9
+ */
10
+ const CELL_REF_PATTERN = /^[A-Za-z]{1,3}\d+$/;
11
+ /**
12
+ * Matches an R1C1-style cell reference, e.g. R1C1, R100C200.
13
+ * Must have at least one digit after R and at least one digit after C
14
+ * to be considered a cell reference. Bare "RC" is NOT a cell reference.
15
+ */
16
+ const R1C1_PATTERN = /^[Rr]\d+[Cc]\d+$/;
17
+ /**
18
+ * Single-character names that Excel reserves for row/column navigation.
19
+ * Per Microsoft docs: "You cannot use the uppercase and lowercase characters
20
+ * 'C', 'c', 'R', or 'r' as a defined name."
21
+ */
22
+ const RESERVED_SINGLE_CHARS = new Set(["C", "c", "R", "r"]);
23
+ /**
24
+ * Sanitize a table name to comply with OOXML defined name rules
25
+ * (ECMA-376, 4th edition, Part 1, §18.5.1.2).
26
+ *
27
+ * Rules enforced (per Microsoft documentation):
28
+ * - First character must be a letter (any script), underscore (_), or backslash (\)
29
+ * - Subsequent characters may be letters, digits, underscores, or periods (.)
30
+ * - Backslash is only valid as the first character
31
+ * - Spaces are replaced with underscores
32
+ * - Other invalid characters are stripped
33
+ * - Single-character names "C", "c", "R", "r" are prefixed with _
34
+ * - Names that look like cell references (e.g. A1, R1C1) are prefixed with _
35
+ * - Maximum 255 characters
36
+ * - Empty result falls back to "_Table"
37
+ *
38
+ * This library applies these rules automatically so that generated files
39
+ * always comply with the OOXML schema, avoiding Excel "repair" dialogs.
40
+ */
41
+ function sanitizeTableName(name) {
42
+ // Replace all whitespace characters (space, tab, newline, etc.) with underscores
43
+ let sanitized = name.replace(/\s/g, "_");
44
+ // Preserve a leading backslash (valid only as first character per spec)
45
+ let leadingBackslash = false;
46
+ if (sanitized.startsWith("\\")) {
47
+ leadingBackslash = true;
48
+ sanitized = sanitized.slice(1);
49
+ }
50
+ // Strip characters not valid in defined names.
51
+ // Subsequent characters: Unicode letters, digits, underscore, period.
52
+ // Backslash is NOT valid in subsequent positions.
53
+ sanitized = sanitized.replace(/[^\p{L}\p{N}_.]/gu, "");
54
+ // Re-attach leading backslash
55
+ if (leadingBackslash) {
56
+ sanitized = `\\${sanitized}`;
57
+ }
58
+ // Ensure the first character is valid (letter, underscore, or backslash)
59
+ if (sanitized.length > 0 && !/^[\p{L}_\\]/u.test(sanitized[0])) {
60
+ sanitized = `_${sanitized}`;
61
+ }
62
+ // Truncate to max length
63
+ if (sanitized.length > MAX_TABLE_NAME_LENGTH) {
64
+ sanitized = sanitized.slice(0, MAX_TABLE_NAME_LENGTH);
65
+ }
66
+ // Fallback if empty after sanitization
67
+ if (sanitized.length === 0) {
68
+ return "_Table";
69
+ }
70
+ // Avoid reserved single-character names (C, c, R, r)
71
+ if (sanitized.length === 1 && RESERVED_SINGLE_CHARS.has(sanitized)) {
72
+ sanitized = `_${sanitized}`;
73
+ }
74
+ // Avoid names that look like cell references
75
+ if (CELL_REF_PATTERN.test(sanitized) || R1C1_PATTERN.test(sanitized)) {
76
+ sanitized = `_${sanitized}`;
77
+ }
78
+ return sanitized;
79
+ }
2
80
  class Column {
3
81
  constructor(table, column, index) {
4
82
  this.table = table;
@@ -136,16 +214,26 @@ class Table {
136
214
  assign(table, "headerRow", true);
137
215
  assign(table, "totalsRow", false);
138
216
  assign(table, "style", {});
139
- assign(table.style, "theme", "TableStyleMedium2");
140
- assign(table.style, "showFirstColumn", false);
141
- assign(table.style, "showLastColumn", false);
142
- assign(table.style, "showRowStripes", false);
143
- assign(table.style, "showColumnStripes", false);
217
+ const style = table.style;
218
+ assign(style, "theme", "TableStyleMedium2");
219
+ assign(style, "showFirstColumn", false);
220
+ assign(style, "showLastColumn", false);
221
+ assign(style, "showRowStripes", false);
222
+ assign(style, "showColumnStripes", false);
223
+ // Sanitize table name and displayName to comply with OOXML defined name rules.
224
+ // Excel UI rejects invalid names; here we auto-correct to avoid "repair" dialogs.
225
+ if (table.name) {
226
+ table.name = sanitizeTableName(table.name);
227
+ }
228
+ if (table.displayName) {
229
+ table.displayName = sanitizeTableName(table.displayName);
230
+ }
144
231
  const assert = (test, message) => {
145
232
  if (!test) {
146
233
  throw new Error(message);
147
234
  }
148
235
  };
236
+ assert(!!table.name, "Table must have a name");
149
237
  assert(!!table.ref, "Table must have ref");
150
238
  assert(!!table.columns, "Table must have column definitions");
151
239
  assert(!!table.rows, "Table must have row definitions");
@@ -221,7 +309,7 @@ class Table {
221
309
  const formula = this.getFormula(column);
222
310
  if (formula) {
223
311
  cell.value = {
224
- formula: column.totalsRowFormula,
312
+ formula,
225
313
  result: column.totalsRowResult
226
314
  };
227
315
  }
@@ -263,7 +351,7 @@ class Table {
263
351
  const formula = this.getFormula(column);
264
352
  if (formula) {
265
353
  cell.value = {
266
- formula: column.totalsRowFormula,
354
+ formula,
267
355
  result: column.totalsRowResult
268
356
  };
269
357
  }
@@ -391,13 +479,13 @@ class Table {
391
479
  return this.table.name;
392
480
  }
393
481
  set name(value) {
394
- this.table.name = value;
482
+ this.table.name = sanitizeTableName(value);
395
483
  }
396
484
  get displayName() {
397
485
  return this.table.displayName || this.table.name;
398
486
  }
399
487
  set displayName(value) {
400
- this.table.displayName = value;
488
+ this.table.displayName = sanitizeTableName(value);
401
489
  }
402
490
  get headerRow() {
403
491
  return this.table.headerRow;
@@ -412,34 +500,49 @@ class Table {
412
500
  this._assign(this.table, "totalsRow", value);
413
501
  }
414
502
  get theme() {
415
- return this.table.style.theme;
503
+ return this.table.style?.theme;
416
504
  }
417
505
  set theme(value) {
506
+ if (!this.table.style) {
507
+ this.table.style = {};
508
+ }
418
509
  this.table.style.theme = value;
419
510
  }
420
511
  get showFirstColumn() {
421
- return this.table.style.showFirstColumn;
512
+ return this.table.style?.showFirstColumn;
422
513
  }
423
514
  set showFirstColumn(value) {
515
+ if (!this.table.style) {
516
+ this.table.style = {};
517
+ }
424
518
  this.table.style.showFirstColumn = value;
425
519
  }
426
520
  get showLastColumn() {
427
- return this.table.style.showLastColumn;
521
+ return this.table.style?.showLastColumn;
428
522
  }
429
523
  set showLastColumn(value) {
524
+ if (!this.table.style) {
525
+ this.table.style = {};
526
+ }
430
527
  this.table.style.showLastColumn = value;
431
528
  }
432
529
  get showRowStripes() {
433
- return this.table.style.showRowStripes;
530
+ return this.table.style?.showRowStripes;
434
531
  }
435
532
  set showRowStripes(value) {
533
+ if (!this.table.style) {
534
+ this.table.style = {};
535
+ }
436
536
  this.table.style.showRowStripes = value;
437
537
  }
438
538
  get showColumnStripes() {
439
- return this.table.style.showColumnStripes;
539
+ return this.table.style?.showColumnStripes;
440
540
  }
441
541
  set showColumnStripes(value) {
542
+ if (!this.table.style) {
543
+ this.table.style = {};
544
+ }
442
545
  this.table.style.showColumnStripes = value;
443
546
  }
444
547
  }
445
- export { Table };
548
+ export { Table, sanitizeTableName };
@@ -569,7 +569,7 @@ export function bookAppendSheet(workbook, worksheet, name) {
569
569
  });
570
570
  // Copy column properties
571
571
  worksheet.columns?.forEach((col, idx) => {
572
- if (col && newWs.columns[idx]) {
572
+ if (col && newWs.columns?.[idx]) {
573
573
  if (col.width) {
574
574
  newWs.getColumn(idx + 1).width = col.width;
575
575
  }
@@ -162,7 +162,7 @@ declare class Worksheet {
162
162
  /**
163
163
  * Get the current columns array
164
164
  */
165
- get columns(): Column[];
165
+ get columns(): Column[] | null;
166
166
  /**
167
167
  * Add column headers and define column keys and widths.
168
168
  *
@@ -472,9 +472,9 @@ class Worksheet {
472
472
  _copyStyle(src, dest, styleEmpty = false) {
473
473
  const rSrc = this.getRow(src);
474
474
  const rDst = this.getRow(dest);
475
- rDst.style = copyStyle(rSrc.style);
475
+ rDst.style = copyStyle(rSrc.style) ?? {};
476
476
  rSrc.eachCell({ includeEmpty: styleEmpty }, (cell, colNumber) => {
477
- rDst.getCell(colNumber).style = copyStyle(cell.style);
477
+ rDst.getCell(colNumber).style = copyStyle(cell.style) ?? {};
478
478
  });
479
479
  rDst.height = rSrc.height;
480
480
  }
@@ -1050,7 +1050,8 @@ class Worksheet {
1050
1050
  */
1051
1051
  addTable(model) {
1052
1052
  const table = new Table(this, model);
1053
- this.tables[model.name] = table;
1053
+ // Use table.name (sanitized by Table.validate()) as the key
1054
+ this.tables[table.name] = table;
1054
1055
  return table;
1055
1056
  }
1056
1057
  /**
@@ -1167,7 +1168,7 @@ class Worksheet {
1167
1168
  }
1168
1169
  set model(value) {
1169
1170
  this.name = value.name;
1170
- this._columns = Column.fromModel(this, value.cols);
1171
+ this._columns = Column.fromModel(this, value.cols ?? []);
1171
1172
  this._parseRows(value);
1172
1173
  this._parseMergeCells(value);
1173
1174
  this.dataValidations = new DataValidations(value.dataValidations);
@@ -2,6 +2,9 @@ import { BaseXform } from "@excel/xlsx/xform/base-xform";
2
2
  import { StaticXform } from "@excel/xlsx/xform/static-xform";
3
3
  declare class WorkbookXform extends BaseXform {
4
4
  parser: any;
5
+ map: {
6
+ [key: string]: any;
7
+ };
5
8
  constructor();
6
9
  prepare(model: any): void;
7
10
  render(xmlStream: any, model: any): void;
@@ -22,7 +22,7 @@ class CtrlPropXform extends BaseXform {
22
22
  return "formControlPr";
23
23
  }
24
24
  render(xmlStream, model) {
25
- const renderModel = model || this.model;
25
+ const renderModel = (model || this.model);
26
26
  const attrs = {
27
27
  xmlns: "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main",
28
28
  objectType: "CheckBox",
@@ -17,9 +17,11 @@ class VmlDrawingXform extends BaseXform {
17
17
  * Render VML drawing containing both notes and form controls
18
18
  */
19
19
  render(xmlStream, model) {
20
- const renderModel = model || this.model;
21
- const hasComments = renderModel.comments && renderModel.comments.length > 0;
22
- const hasFormControls = renderModel.formControls && renderModel.formControls.length > 0;
20
+ const renderModel = (model || this.model);
21
+ const comments = renderModel.comments;
22
+ const formControls = renderModel.formControls;
23
+ const hasComments = comments && comments.length > 0;
24
+ const hasFormControls = formControls && formControls.length > 0;
23
25
  xmlStream.openXml(XmlStream.StdDocAttributes);
24
26
  xmlStream.openNode(this.tag, VmlDrawingXform.DRAWING_ATTRIBUTES);
25
27
  // Shape layout - shared by both notes and form controls
@@ -59,14 +61,13 @@ class VmlDrawingXform extends BaseXform {
59
61
  }
60
62
  // Render comment shapes
61
63
  if (hasComments) {
62
- const comments = renderModel.comments;
63
64
  for (let i = 0; i < comments.length; i++) {
64
65
  this.map["v:shape"].render(xmlStream, comments[i], i);
65
66
  }
66
67
  }
67
68
  // Render form control shapes
68
69
  if (hasFormControls) {
69
- for (const control of renderModel.formControls) {
70
+ for (const control of formControls) {
70
71
  this._renderCheckboxShape(xmlStream, control);
71
72
  }
72
73
  }
@@ -1,5 +1,8 @@
1
1
  import { BaseXform } from "@excel/xlsx/xform/base-xform";
2
2
  declare class WorkSheetXform extends BaseXform {
3
+ map: {
4
+ [key: string]: any;
5
+ };
3
6
  private ignoreNodes;
4
7
  parser: any;
5
8
  private preImageId;
@@ -9,6 +9,10 @@ interface StylesModel {
9
9
  dxfs?: any[];
10
10
  }
11
11
  declare class StylesXform extends BaseXform {
12
+ map: {
13
+ [key: string]: any;
14
+ };
15
+ model: any;
12
16
  private index?;
13
17
  private weakMap?;
14
18
  private _hasCheckboxes?;
@@ -664,7 +664,7 @@ export { PullStream, BufferedStream, StringChunk, BufferChunk };
664
664
  * Create a readable stream with custom read implementation
665
665
  */
666
666
  export declare function createReadable<T = Uint8Array>(options?: ReadableStreamOptions & {
667
- read?: (size: number) => void;
667
+ read?: (this: Readable<T>, size?: number) => void;
668
668
  destroy?: (error: Error | null, callback: (error: Error | null) => void) => void;
669
669
  }): IReadable<T>;
670
670
  /**
@@ -813,10 +813,10 @@ export declare function createDuplex<TRead = Uint8Array, TWrite = Uint8Array>(op
813
813
  writable?: unknown;
814
814
  allowHalfOpen?: boolean;
815
815
  objectMode?: boolean;
816
- read?: (this: any, size: number) => void;
817
- write?: (this: any, chunk: TWrite, encoding: string, callback: (error?: Error | null) => void) => void;
818
- final?: (this: any, callback: (error?: Error | null) => void) => void;
819
- destroy?: (this: any, error: Error | null, callback: (error: Error | null) => void) => void;
816
+ read?: (this: Duplex<TRead, TWrite>, size?: number) => void;
817
+ write?: (this: Duplex<TRead, TWrite>, chunk: TWrite, encoding: string, callback: (error?: Error | null) => void) => void;
818
+ final?: (this: Duplex<TRead, TWrite>, callback: (error?: Error | null) => void) => void;
819
+ destroy?: (this: Duplex<TRead, TWrite>, error: Error | null, callback: (error: Error | null) => void) => void;
820
820
  }): IDuplex<TRead, TWrite>;
821
821
  /**
822
822
  * Create a readable stream from a generator function
@@ -1671,7 +1671,7 @@ export class Transform extends EventEmitter {
1671
1671
  return;
1672
1672
  }
1673
1673
  const result = userTransform.call(this, chunk);
1674
- if (result && typeof result.then === "function") {
1674
+ if (result instanceof Promise) {
1675
1675
  const awaited = await result;
1676
1676
  if (awaited !== undefined) {
1677
1677
  this.push(awaited);
@@ -1728,7 +1728,7 @@ export class Transform extends EventEmitter {
1728
1728
  return;
1729
1729
  }
1730
1730
  const result = userFlush.call(this);
1731
- if (result && typeof result.then === "function") {
1731
+ if (result instanceof Promise) {
1732
1732
  const awaited = await result;
1733
1733
  if (awaited !== undefined && awaited !== null) {
1734
1734
  this.push(awaited);
@@ -3335,14 +3335,22 @@ export function duplexPair(options) {
3335
3335
  stream2.push(chunk);
3336
3336
  }
3337
3337
  stream2.push(null);
3338
- return originalEnd1(typeof chunk === "function" ? chunk : undefined);
3338
+ if (typeof chunk === "function") {
3339
+ const cb = chunk;
3340
+ return originalEnd1(cb);
3341
+ }
3342
+ return originalEnd1();
3339
3343
  };
3340
3344
  stream2.end = function (chunk) {
3341
3345
  if (chunk !== undefined && typeof chunk !== "function") {
3342
3346
  stream1.push(chunk);
3343
3347
  }
3344
3348
  stream1.push(null);
3345
- return originalEnd2(typeof chunk === "function" ? chunk : undefined);
3349
+ if (typeof chunk === "function") {
3350
+ const cb = chunk;
3351
+ return originalEnd2(cb);
3352
+ }
3353
+ return originalEnd2();
3346
3354
  };
3347
3355
  return [stream1, stream2];
3348
3356
  }
@@ -89,7 +89,7 @@ export function xmlEncode(text) {
89
89
  let lastIndex = 0;
90
90
  for (let i = regexResult.index; i < text.length; i++) {
91
91
  const charCode = text.charCodeAt(i);
92
- let escape = null;
92
+ let escape;
93
93
  switch (charCode) {
94
94
  case 34: // "
95
95
  escape = "&quot;";