@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.
- package/dist/browser/modules/archive/unzip/stream.base.js +11 -4
- package/dist/browser/modules/archive/unzip/stream.browser.js +3 -3
- package/dist/browser/modules/excel/anchor.js +2 -5
- package/dist/browser/modules/excel/cell.js +11 -9
- package/dist/browser/modules/excel/column.js +2 -2
- package/dist/browser/modules/excel/defined-names.js +2 -2
- package/dist/browser/modules/excel/note.js +1 -1
- package/dist/browser/modules/excel/row.js +7 -4
- package/dist/browser/modules/excel/stream/worksheet-reader.js +4 -1
- package/dist/browser/modules/excel/table.d.ts +20 -1
- package/dist/browser/modules/excel/table.js +118 -15
- package/dist/browser/modules/excel/utils/sheet-utils.js +1 -1
- package/dist/browser/modules/excel/worksheet.d.ts +1 -1
- package/dist/browser/modules/excel/worksheet.js +5 -4
- package/dist/browser/modules/excel/xlsx/xform/book/workbook-xform.d.ts +3 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +1 -1
- package/dist/browser/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +6 -5
- package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.d.ts +3 -0
- package/dist/browser/modules/excel/xlsx/xform/style/styles-xform.d.ts +4 -0
- package/dist/browser/modules/stream/streams.browser.d.ts +5 -5
- package/dist/browser/modules/stream/streams.browser.js +12 -4
- package/dist/browser/utils/utils.base.js +1 -1
- package/dist/cjs/modules/archive/unzip/stream.base.js +11 -4
- package/dist/cjs/modules/archive/unzip/stream.browser.js +3 -3
- package/dist/cjs/modules/excel/anchor.js +2 -5
- package/dist/cjs/modules/excel/cell.js +11 -9
- package/dist/cjs/modules/excel/column.js +2 -2
- package/dist/cjs/modules/excel/defined-names.js +2 -2
- package/dist/cjs/modules/excel/note.js +1 -1
- package/dist/cjs/modules/excel/row.js +7 -4
- package/dist/cjs/modules/excel/stream/worksheet-reader.js +4 -1
- package/dist/cjs/modules/excel/table.js +118 -14
- package/dist/cjs/modules/excel/utils/sheet-utils.js +1 -1
- package/dist/cjs/modules/excel/worksheet.js +5 -4
- package/dist/cjs/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +1 -1
- package/dist/cjs/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +6 -5
- package/dist/cjs/modules/stream/streams.browser.js +12 -4
- package/dist/cjs/utils/utils.base.js +1 -1
- package/dist/esm/modules/archive/unzip/stream.base.js +11 -4
- package/dist/esm/modules/archive/unzip/stream.browser.js +3 -3
- package/dist/esm/modules/excel/anchor.js +2 -5
- package/dist/esm/modules/excel/cell.js +11 -9
- package/dist/esm/modules/excel/column.js +2 -2
- package/dist/esm/modules/excel/defined-names.js +2 -2
- package/dist/esm/modules/excel/note.js +1 -1
- package/dist/esm/modules/excel/row.js +7 -4
- package/dist/esm/modules/excel/stream/worksheet-reader.js +4 -1
- package/dist/esm/modules/excel/table.js +118 -15
- package/dist/esm/modules/excel/utils/sheet-utils.js +1 -1
- package/dist/esm/modules/excel/worksheet.js +5 -4
- package/dist/esm/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +1 -1
- package/dist/esm/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +6 -5
- package/dist/esm/modules/stream/streams.browser.js +12 -4
- package/dist/esm/utils/utils.base.js +1 -1
- package/dist/iife/excelts.iife.js +724 -888
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +24 -23
- package/dist/types/modules/excel/table.d.ts +20 -1
- package/dist/types/modules/excel/worksheet.d.ts +1 -1
- package/dist/types/modules/excel/xlsx/xform/book/workbook-xform.d.ts +3 -0
- package/dist/types/modules/excel/xlsx/xform/sheet/worksheet-xform.d.ts +3 -0
- package/dist/types/modules/excel/xlsx/xform/style/styles-xform.d.ts +4 -0
- package/dist/types/modules/stream/streams.browser.d.ts +5 -5
- 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
|
|
961
|
-
|
|
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
|
-
|
|
77
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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 &&
|
|
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(
|
|
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
|
|
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,
|
|
@@ -34,9 +34,9 @@ class Row {
|
|
|
34
34
|
* Helps GC by breaking cyclic references
|
|
35
35
|
*/
|
|
36
36
|
destroy() {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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(
|
|
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
|
-
|
|
140
|
-
assign(
|
|
141
|
-
assign(
|
|
142
|
-
assign(
|
|
143
|
-
assign(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
}
|
|
@@ -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
|
-
|
|
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
|
|
22
|
-
const
|
|
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
|
|
70
|
+
for (const control of formControls) {
|
|
70
71
|
this._renderCheckboxShape(xmlStream, control);
|
|
71
72
|
}
|
|
72
73
|
}
|
|
@@ -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?: (
|
|
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:
|
|
817
|
-
write?: (this:
|
|
818
|
-
final?: (this:
|
|
819
|
-
destroy?: (this:
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|