@shbernal/ts-xlsx 1.3.1 → 2.1.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/README.md +20 -10
- package/dist/bytes.d.ts +24 -0
- package/dist/bytes.js +34 -0
- package/dist/core/address.d.ts +72 -3
- package/dist/core/address.js +50 -10
- package/dist/core/autofilter.d.ts +13 -2
- package/dist/core/autofilter.js +35 -10
- package/dist/core/cell.d.ts +17 -16
- package/dist/core/cell.js +3 -7
- package/dist/core/color-resolution.d.ts +8 -8
- package/dist/core/color-resolution.js +7 -8
- package/dist/core/column.d.ts +8 -9
- package/dist/core/column.js +2 -4
- package/dist/core/comment-thread.d.ts +32 -23
- package/dist/core/comment-thread.js +4 -4
- package/dist/core/conditional-formatting-overlay.d.ts +6 -1
- package/dist/core/conditional-formatting-overlay.js +11 -0
- package/dist/core/conditional-formatting.d.ts +48 -8
- package/dist/core/conditional-formatting.js +88 -0
- package/dist/core/data-validation-overlay.d.ts +12 -1
- package/dist/core/data-validation-overlay.js +21 -2
- package/dist/core/data-validation.d.ts +12 -5
- package/dist/core/data-validation.js +34 -0
- package/dist/core/date.d.ts +3 -3
- package/dist/core/formula.d.ts +6 -6
- package/dist/core/grid-edits.d.ts +16 -0
- package/dist/core/grid-edits.js +29 -11
- package/dist/core/grid-shift.d.ts +19 -0
- package/dist/core/grid-shift.js +8 -0
- package/dist/core/image.d.ts +39 -2
- package/dist/core/image.js +10 -0
- package/dist/core/internal.d.ts +9 -1
- package/dist/core/limits.d.ts +4 -4
- package/dist/core/merge.d.ts +17 -12
- package/dist/core/merge.js +36 -5
- package/dist/core/page-setup.d.ts +20 -6
- package/dist/core/page-setup.js +8 -1
- package/dist/core/pivot-table.d.ts +4 -4
- package/dist/core/pivot-table.js +29 -20
- package/dist/core/preserved.d.ts +3 -3
- package/dist/core/protection.d.ts +7 -4
- package/dist/core/protection.js +20 -14
- package/dist/core/range.d.ts +16 -14
- package/dist/core/range.js +5 -5
- package/dist/core/row-input.d.ts +9 -8
- package/dist/core/row-input.js +12 -10
- package/dist/core/row.d.ts +7 -8
- package/dist/core/row.js +2 -4
- package/dist/core/style.d.ts +41 -14
- package/dist/core/style.js +82 -67
- package/dist/core/table-style.d.ts +9 -9
- package/dist/core/table-style.js +1 -1
- package/dist/core/table.d.ts +53 -51
- package/dist/core/table.js +83 -41
- package/dist/core/theme.d.ts +16 -44
- package/dist/core/theme.js +6 -148
- package/dist/core/value.d.ts +7 -7
- package/dist/core/workbook-protection.d.ts +2 -2
- package/dist/core/workbook-styles.d.ts +26 -0
- package/dist/core/workbook-styles.js +48 -0
- package/dist/core/workbook-theme.d.ts +25 -0
- package/dist/core/workbook-theme.js +49 -0
- package/dist/core/workbook-vba.d.ts +17 -0
- package/dist/core/workbook-vba.js +79 -0
- package/dist/core/workbook.d.ts +133 -87
- package/dist/core/workbook.js +74 -133
- package/dist/core/worksheet-comments.d.ts +17 -0
- package/dist/core/worksheet-comments.js +70 -0
- package/dist/core/worksheet-model.d.ts +4 -4
- package/dist/core/worksheet-model.js +1 -0
- package/dist/core/worksheet-pictures.d.ts +29 -0
- package/dist/core/worksheet-pictures.js +42 -0
- package/dist/core/worksheet.d.ts +100 -79
- package/dist/core/worksheet.js +63 -142
- package/dist/customui/errors.d.ts +1 -1
- package/dist/customui/ribbon.d.ts +3 -3
- package/dist/customui/ribbon.js +24 -23
- package/dist/entries/core.d.ts +7 -7
- package/dist/entries/core.js +1 -1
- package/dist/entries/csv.d.ts +1 -1
- package/dist/entries/node-unavailable.d.ts +15 -0
- package/dist/entries/node-unavailable.js +20 -0
- package/dist/entries/node.d.ts +1 -0
- package/dist/entries/node.js +1 -0
- package/dist/entries/vba.d.ts +1 -1
- package/dist/entries/vba.js +1 -1
- package/dist/entries/xlsx.d.ts +1 -1
- package/dist/entries/xlsx.js +1 -1
- package/dist/errors.d.ts +12 -12
- package/dist/io/csv/read.js +2 -3
- package/dist/io/csv/write.d.ts +19 -4
- package/dist/io/csv/write.js +34 -4
- package/dist/io/opc/errors.d.ts +6 -6
- package/dist/io/opc/inflate.d.ts +1 -1
- package/dist/io/opc/inflate.js +2 -12
- package/dist/io/opc/namespaces.d.ts +1 -1
- package/dist/io/opc/read-opc.d.ts +19 -3
- package/dist/io/opc/read-opc.js +14 -8
- package/dist/io/opc/read-options.d.ts +2 -2
- package/dist/io/opc/rels.d.ts +11 -0
- package/dist/io/opc/rels.js +3 -2
- package/dist/io/opc/sniff-format.d.ts +2 -2
- package/dist/io/style/xf-style.d.ts +44 -7
- package/dist/io/style/xf-style.js +27 -0
- package/dist/io/xlsb/errors.d.ts +1 -1
- package/dist/io/xlsb/formula.d.ts +4 -4
- package/dist/io/xlsb/primitives.d.ts +8 -8
- package/dist/io/xlsb/ptg-functions.d.ts +1 -1
- package/dist/io/xlsb/read-styles.js +2 -20
- package/dist/io/xlsb/read.d.ts +2 -2
- package/dist/io/xlsx/cell-accumulator.d.ts +26 -9
- package/dist/io/xlsx/cell-accumulator.js +89 -46
- package/dist/io/xlsx/cell-value.d.ts +3 -3
- package/dist/io/xlsx/cell-value.js +9 -6
- package/dist/io/xlsx/color-xml.d.ts +1 -1
- package/dist/io/xlsx/color-xml.js +18 -23
- package/dist/io/xlsx/comments.d.ts +5 -5
- package/dist/io/xlsx/comments.js +17 -8
- package/dist/io/xlsx/conditional-formatting.d.ts +4 -4
- package/dist/io/xlsx/conditional-formatting.js +64 -58
- package/dist/io/xlsx/data-validation.d.ts +3 -3
- package/dist/io/xlsx/data-validation.js +35 -33
- package/dist/io/xlsx/errors.d.ts +3 -3
- package/dist/io/xlsx/hyperlinks.d.ts +4 -2
- package/dist/io/xlsx/hyperlinks.js +10 -18
- package/dist/io/xlsx/images.d.ts +1 -1
- package/dist/io/xlsx/images.js +25 -28
- package/dist/io/xlsx/namespaces.d.ts +2 -2
- package/dist/io/xlsx/package-plan.js +5 -2
- package/dist/io/xlsx/read-pivot.js +4 -13
- package/dist/io/xlsx/read-rows.d.ts +13 -13
- package/dist/io/xlsx/read-rows.js +19 -55
- package/dist/io/xlsx/read-shared-strings.js +7 -44
- package/dist/io/xlsx/read-styles.d.ts +3 -3
- package/dist/io/xlsx/read-styles.js +42 -66
- package/dist/io/xlsx/read-worksheet.js +73 -129
- package/dist/io/xlsx/read.d.ts +4 -6
- package/dist/io/xlsx/read.js +104 -142
- package/dist/io/xlsx/rich-runs.d.ts +41 -7
- package/dist/io/xlsx/rich-runs.js +94 -30
- package/dist/io/xlsx/rich-text.d.ts +1 -1
- package/dist/io/xlsx/shared-strings.d.ts +2 -2
- package/dist/io/xlsx/sheet-properties.d.ts +1 -1
- package/dist/io/xlsx/sheet-properties.js +14 -10
- package/dist/io/xlsx/styles.d.ts +9 -22
- package/dist/io/xlsx/styles.js +65 -89
- package/dist/io/xlsx/tables.d.ts +2 -2
- package/dist/io/xlsx/tables.js +20 -25
- package/dist/io/xlsx/theme-xml.d.ts +37 -0
- package/dist/io/xlsx/theme-xml.js +145 -0
- package/dist/io/xlsx/threaded-comments.d.ts +18 -27
- package/dist/io/xlsx/threaded-comments.js +26 -38
- package/dist/io/xlsx/workbook-xml.js +14 -8
- package/dist/io/xlsx/worksheet-xml.d.ts +2 -2
- package/dist/io/xlsx/worksheet-xml.js +40 -48
- package/dist/io/xlsx/write-stream.d.ts +23 -16
- package/dist/io/xlsx/write-stream.js +13 -14
- package/dist/io/xlsx/write.d.ts +8 -7
- package/dist/io/xlsx/write.js +6 -3
- package/dist/io/xlsx/x14-ext.d.ts +1 -1
- package/dist/sha512.d.ts +2 -0
- package/dist/sha512.js +146 -0
- package/dist/vba/bytes.d.ts +11 -0
- package/dist/vba/bytes.js +29 -0
- package/dist/vba/cfb-writer.d.ts +1 -1
- package/dist/vba/cfb.d.ts +1 -1
- package/dist/vba/cfb.js +15 -51
- package/dist/vba/codepage.d.ts +2 -2
- package/dist/vba/dir-records.d.ts +53 -0
- package/dist/vba/dir-records.js +28 -0
- package/dist/vba/errors.d.ts +2 -2
- package/dist/vba/index.d.ts +2 -2
- package/dist/vba/index.js +2 -2
- package/dist/vba/ms-ovba.d.ts +1 -1
- package/dist/vba/ms-ovba.js +1 -3
- package/dist/vba/project-editor.d.ts +9 -9
- package/dist/vba/project-editor.js +6 -44
- package/dist/vba/project.d.ts +5 -5
- package/dist/vba/project.js +3 -28
- package/dist/vba/vba-encoding.d.ts +1 -1
- package/dist/xml/errors.d.ts +1 -1
- package/dist/xml/xml-read.d.ts +98 -9
- package/dist/xml/xml-read.js +70 -0
- package/dist/xml/xml.d.ts +74 -10
- package/dist/xml/xml.js +39 -7
- package/package.json +59 -36
|
@@ -3,23 +3,40 @@ import type { Worksheet } from '../../core/worksheet.ts';
|
|
|
3
3
|
import { type XmlAttributes } from '../../xml/xml-read.ts';
|
|
4
4
|
import { type XfStyle } from '../style/xf-style.ts';
|
|
5
5
|
import { type SharedString } from './cell-value.ts';
|
|
6
|
-
import { RunAccumulator } from './rich-runs.ts';
|
|
7
6
|
export declare class CellAccumulator {
|
|
8
7
|
#private;
|
|
8
|
+
constructor(options: {
|
|
9
|
+
readonly richRuns: boolean;
|
|
10
|
+
});
|
|
9
11
|
/** This cell's `<c r>` address (`"B3"`), or '' when it carried none. */
|
|
10
12
|
get ref(): string;
|
|
11
13
|
/** This cell's own `<c s>` style index, or -1 when it carries none. */
|
|
12
14
|
get styleIndex(): number;
|
|
13
15
|
/** This cell's 1-based column, or -1 when its address was absent or unparseable. */
|
|
14
16
|
get col(): number;
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
/**
|
|
18
|
+
* The text gathered since the current element opened. A caller reads it for the elements it
|
|
19
|
+
* captures itself (see {@link capture}); the machine reads it for its own.
|
|
20
|
+
*/
|
|
21
|
+
get capturedText(): string;
|
|
22
|
+
/** Gather the current element's text for the caller's own use, the way `<v>` and `<t>` do. */
|
|
23
|
+
capture(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Drive one element open, and return whether it was one of the cell machine's own. Every open
|
|
26
|
+
* resets the capture state first, which is true of both readers and of every element, not just
|
|
27
|
+
* these; a caller that captures its own text calls {@link capture} after this returns.
|
|
28
|
+
*/
|
|
29
|
+
openElement(local: string, attrs: XmlAttributes, selfClosing: boolean): boolean;
|
|
30
|
+
/** Feed one run of character data. Ignored unless something is capturing. */
|
|
31
|
+
appendChunk(chunk: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* Drive one element close. `'cell'` means a `</c>` closed and the caller should commit the
|
|
34
|
+
* gathered cell, which is the one step the two readers do differently; `'claimed'` means the
|
|
35
|
+
* machine handled it; `'other'` leaves it to the caller. Capture always ends here, as it does on
|
|
36
|
+
* every close in both readers.
|
|
37
|
+
*/
|
|
38
|
+
closeElement(local: string): 'cell' | 'claimed' | 'other';
|
|
23
39
|
finalize(sheet: Worksheet, sharedStrings: readonly SharedString[], style: XfStyle | undefined): void;
|
|
40
|
+
private cachedResult;
|
|
24
41
|
decode(sharedStrings: readonly SharedString[], style: XfStyle | undefined): CellValue;
|
|
25
42
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { encodeAddress, tryDecodeCellRef } from '../../core/address.js';
|
|
2
2
|
import { translateFormula, unmangleFunctions } from '../../core/formula.js';
|
|
3
|
-
import {
|
|
3
|
+
import { boolStrict, numInteger } from '../../xml/xml-read.js';
|
|
4
4
|
import { applyXfToCell } from '../style/xf-style.js';
|
|
5
5
|
import { decodeCellContent, decodeFormulaResult, } from './cell-value.js';
|
|
6
6
|
import { RunAccumulator } from './rich-runs.js';
|
|
@@ -16,11 +16,15 @@ export class CellAccumulator {
|
|
|
16
16
|
#sharedClone = false;
|
|
17
17
|
#dataTable = null;
|
|
18
18
|
#valueText = '';
|
|
19
|
-
#inlineText = '';
|
|
20
19
|
#hasFormula = false;
|
|
21
20
|
#hasValue = false;
|
|
22
|
-
#runs
|
|
21
|
+
#runs;
|
|
23
22
|
#masters = new Map();
|
|
23
|
+
#capture = false;
|
|
24
|
+
#text = '';
|
|
25
|
+
constructor(options) {
|
|
26
|
+
this.#runs = new RunAccumulator({ container: 'is', readRuns: options.richRuns });
|
|
27
|
+
}
|
|
24
28
|
get ref() {
|
|
25
29
|
return this.#ref;
|
|
26
30
|
}
|
|
@@ -30,19 +34,16 @@ export class CellAccumulator {
|
|
|
30
34
|
get col() {
|
|
31
35
|
return this.#col;
|
|
32
36
|
}
|
|
33
|
-
|
|
34
|
-
return this.#runs;
|
|
35
|
-
}
|
|
36
|
-
beginCell(attrs) {
|
|
37
|
-
this.#ref = attrs.r ?? '';
|
|
37
|
+
#beginCell(attrs) {
|
|
38
38
|
this.#type = attrs.t ?? '';
|
|
39
|
-
this.#style = attrs.s
|
|
40
|
-
|
|
41
|
-
this.#
|
|
39
|
+
this.#style = numInteger(attrs.s, 0) ?? -1;
|
|
40
|
+
const decoded = tryDecodeCellRef(attrs.r ?? '');
|
|
41
|
+
this.#ref = decoded === undefined ? '' : (attrs.r ?? '');
|
|
42
|
+
this.#col = decoded?.col ?? -1;
|
|
43
|
+
this.#row = decoded?.row ?? -1;
|
|
42
44
|
this.#formula = '';
|
|
43
45
|
this.#valueText = '';
|
|
44
|
-
this.#
|
|
45
|
-
this.#runs.reset();
|
|
46
|
+
this.#runs.beginContainer();
|
|
46
47
|
this.#hasFormula = false;
|
|
47
48
|
this.#hasValue = false;
|
|
48
49
|
this.#formulaShared = false;
|
|
@@ -50,9 +51,9 @@ export class CellAccumulator {
|
|
|
50
51
|
this.#sharedClone = false;
|
|
51
52
|
this.#dataTable = null;
|
|
52
53
|
}
|
|
53
|
-
beginFormula(attrs, selfClosing) {
|
|
54
|
+
#beginFormula(attrs, selfClosing) {
|
|
54
55
|
this.#formulaShared = attrs.t === 'shared';
|
|
55
|
-
this.#formulaSi = attrs.si
|
|
56
|
+
this.#formulaSi = numInteger(attrs.si, 0) ?? -1;
|
|
56
57
|
if (selfClosing && this.#formulaShared)
|
|
57
58
|
this.#sharedClone = true;
|
|
58
59
|
if (attrs.t === 'dataTable' && attrs.ref !== undefined) {
|
|
@@ -65,41 +66,85 @@ export class CellAccumulator {
|
|
|
65
66
|
};
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
|
-
setFormula(text) {
|
|
69
|
+
#setFormula(text) {
|
|
69
70
|
this.#formula = text;
|
|
70
71
|
this.#hasFormula = true;
|
|
71
72
|
}
|
|
72
|
-
setValue(text) {
|
|
73
|
+
#setValue(text) {
|
|
73
74
|
this.#valueText = text;
|
|
74
75
|
this.#hasValue = true;
|
|
75
76
|
}
|
|
76
|
-
|
|
77
|
-
this.#
|
|
78
|
-
|
|
77
|
+
get capturedText() {
|
|
78
|
+
return this.#text;
|
|
79
|
+
}
|
|
80
|
+
capture() {
|
|
81
|
+
this.#capture = true;
|
|
82
|
+
}
|
|
83
|
+
openElement(local, attrs, selfClosing) {
|
|
84
|
+
this.#text = '';
|
|
85
|
+
this.#capture = false;
|
|
86
|
+
if (this.#runs.open(local, attrs, selfClosing))
|
|
87
|
+
return true;
|
|
88
|
+
switch (local) {
|
|
89
|
+
case 'c':
|
|
90
|
+
this.#beginCell(attrs);
|
|
91
|
+
return true;
|
|
92
|
+
case 'f':
|
|
93
|
+
this.#capture = !selfClosing;
|
|
94
|
+
this.#beginFormula(attrs, selfClosing);
|
|
95
|
+
return true;
|
|
96
|
+
case 'v':
|
|
97
|
+
this.#capture = !selfClosing;
|
|
98
|
+
return true;
|
|
99
|
+
default:
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
appendChunk(chunk) {
|
|
104
|
+
this.#runs.text(chunk);
|
|
105
|
+
if (this.#capture)
|
|
106
|
+
this.#text += chunk;
|
|
79
107
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
108
|
+
closeElement(local) {
|
|
109
|
+
const verdict = this.#closeElement(local);
|
|
110
|
+
this.#capture = false;
|
|
111
|
+
return verdict;
|
|
112
|
+
}
|
|
113
|
+
#closeElement(local) {
|
|
114
|
+
if (this.#runs.close(local) !== 'other')
|
|
115
|
+
return 'claimed';
|
|
116
|
+
switch (local) {
|
|
117
|
+
case 'f':
|
|
118
|
+
this.#setFormula(this.#text);
|
|
119
|
+
return 'claimed';
|
|
120
|
+
case 'v':
|
|
121
|
+
this.#setValue(this.#text);
|
|
122
|
+
return 'claimed';
|
|
123
|
+
case 'c':
|
|
124
|
+
return 'cell';
|
|
125
|
+
default:
|
|
126
|
+
return 'other';
|
|
127
|
+
}
|
|
83
128
|
}
|
|
84
129
|
finalize(sheet, sharedStrings, style) {
|
|
85
130
|
if (this.#ref === '')
|
|
86
131
|
return;
|
|
132
|
+
const value = this.#resolveValue(sharedStrings, style);
|
|
133
|
+
const cell = sheet.getCell(this.#ref);
|
|
134
|
+
applyXfToCell(cell, style);
|
|
135
|
+
cell.value = value;
|
|
136
|
+
}
|
|
137
|
+
#resolveValue(sharedStrings, style) {
|
|
87
138
|
if (this.#dataTable !== null) {
|
|
88
|
-
|
|
139
|
+
return {
|
|
89
140
|
shareType: 'dataTable',
|
|
90
141
|
ref: this.#dataTable.ref,
|
|
91
|
-
...(
|
|
92
|
-
...(
|
|
142
|
+
...(boolStrict(this.#dataTable.dt2D) ? { dataTable2D: true } : {}),
|
|
143
|
+
...(boolStrict(this.#dataTable.dtr) ? { dataTableRow: true } : {}),
|
|
93
144
|
...(this.#dataTable.r1 !== undefined ? { r1: this.#dataTable.r1 } : {}),
|
|
94
145
|
...(this.#dataTable.r2 !== undefined ? { r2: this.#dataTable.r2 } : {}),
|
|
95
|
-
...(
|
|
96
|
-
? { result: decodeFormulaResult(this.#type, this.#valueText, style?.numFmt) }
|
|
97
|
-
: {}),
|
|
146
|
+
...this.cachedResult(style),
|
|
98
147
|
};
|
|
99
|
-
const cell = sheet.getCell(this.#ref);
|
|
100
|
-
applyXfToCell(cell, style);
|
|
101
|
-
cell.value = value;
|
|
102
|
-
return;
|
|
103
148
|
}
|
|
104
149
|
if (this.#hasFormula && this.#formulaShared && this.#formulaSi >= 0) {
|
|
105
150
|
this.#masters.set(this.#formulaSi, { formula: this.#formula, col: this.#col, row: this.#row });
|
|
@@ -108,22 +153,20 @@ export class CellAccumulator {
|
|
|
108
153
|
const master = this.#masters.get(this.#formulaSi);
|
|
109
154
|
if (master !== undefined) {
|
|
110
155
|
const translated = translateFormula(master.formula, this.#col - master.col, this.#row - master.row);
|
|
111
|
-
|
|
156
|
+
return {
|
|
112
157
|
sharedFormula: encodeAddress(master.col, master.row),
|
|
113
158
|
formula: unmangleFunctions(translated),
|
|
114
|
-
...(
|
|
115
|
-
? { result: decodeFormulaResult(this.#type, this.#valueText, style?.numFmt) }
|
|
116
|
-
: {}),
|
|
159
|
+
...this.cachedResult(style),
|
|
117
160
|
};
|
|
118
|
-
const cell = sheet.getCell(this.#ref);
|
|
119
|
-
applyXfToCell(cell, style);
|
|
120
|
-
cell.value = value;
|
|
121
|
-
return;
|
|
122
161
|
}
|
|
123
162
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
163
|
+
return this.decode(sharedStrings, style);
|
|
164
|
+
}
|
|
165
|
+
cachedResult(style) {
|
|
166
|
+
if (!this.#hasValue)
|
|
167
|
+
return {};
|
|
168
|
+
const result = decodeFormulaResult(this.#type, this.#valueText, style?.numFmt);
|
|
169
|
+
return result === undefined ? {} : { result };
|
|
127
170
|
}
|
|
128
171
|
decode(sharedStrings, style) {
|
|
129
172
|
const raw = {
|
|
@@ -132,7 +175,7 @@ export class CellAccumulator {
|
|
|
132
175
|
formula: this.#formula,
|
|
133
176
|
hasValue: this.#hasValue,
|
|
134
177
|
valueText: this.#valueText,
|
|
135
|
-
inlineText: this.#
|
|
178
|
+
inlineText: this.#runs.plainText,
|
|
136
179
|
richTextRuns: this.#runs.runs,
|
|
137
180
|
};
|
|
138
181
|
return decodeCellContent(raw, sharedStrings, style?.numFmt);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type CellValue, type FormulaResult, type RichTextRun, type RichTextValue } from '../../core/value.ts';
|
|
2
2
|
/**
|
|
3
3
|
* One entry of the shared-strings pool. A `<si>` built from a bare `<t>` is a plain string; a `<si>`
|
|
4
|
-
* built from `<r>` runs is rich text
|
|
4
|
+
* built from `<r>` runs is rich text, so a `t="s"` cell can resolve to either kind, and rich text
|
|
5
5
|
* that Excel pooled reads back with its per-run formatting intact rather than flattened to text.
|
|
6
6
|
*/
|
|
7
7
|
export type SharedString = string | RichTextValue;
|
|
@@ -26,7 +26,7 @@ export interface RawCell {
|
|
|
26
26
|
*/
|
|
27
27
|
export declare function decodeCellContent(raw: RawCell, sharedStrings: readonly SharedString[], numFmt: string | undefined): CellValue;
|
|
28
28
|
/** Decode a formula's cached `<v>` result by its `t` type, coercing a numeric result under a date
|
|
29
|
-
* `numFmt` to a {@link Date} exactly as a bare numeric cell is
|
|
29
|
+
* `numFmt` to a {@link Date} exactly as a bare numeric cell is, so a date-valued formula result
|
|
30
30
|
* (e.g. `TODAY()`) reads back as a Date, not a serial. Shared by the buffered reader's shared-formula
|
|
31
31
|
* clone resolution, which caches a result the same way a plain formula cell does. */
|
|
32
|
-
export declare function decodeFormulaResult(type: string, valueText: string, numFmt?: string): FormulaResult;
|
|
32
|
+
export declare function decodeFormulaResult(type: string, valueText: string, numFmt?: string): FormulaResult | undefined;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isDateFormat, serialToDate } from '../../core/date.js';
|
|
2
2
|
import { unmangleFunctions } from '../../core/formula.js';
|
|
3
3
|
import { isErrorCode, } from '../../core/value.js';
|
|
4
|
-
import { boolStrict } from '../../xml/xml-read.js';
|
|
4
|
+
import { boolStrict, decodeSpreadsheetText, numFinite } from '../../xml/xml-read.js';
|
|
5
5
|
export function decodeCellContent(raw, sharedStrings, numFmt) {
|
|
6
6
|
if (raw.hasFormula) {
|
|
7
7
|
const stored = unmangleFunctions(raw.formula);
|
|
@@ -21,7 +21,7 @@ function decodeValue(type, valueText, inlineText, hasValue, sharedStrings) {
|
|
|
21
21
|
case 'inlineStr':
|
|
22
22
|
return inlineText;
|
|
23
23
|
case 'str':
|
|
24
|
-
return valueText;
|
|
24
|
+
return decodeSpreadsheetText(valueText);
|
|
25
25
|
case 'd':
|
|
26
26
|
return valueText === '' ? null : new Date(valueText);
|
|
27
27
|
case 's': {
|
|
@@ -32,8 +32,11 @@ function decodeValue(type, valueText, inlineText, hasValue, sharedStrings) {
|
|
|
32
32
|
return boolStrict(valueText);
|
|
33
33
|
case 'e':
|
|
34
34
|
return isErrorCode(valueText) ? { error: valueText } : valueText;
|
|
35
|
-
default:
|
|
36
|
-
|
|
35
|
+
default: {
|
|
36
|
+
if (!hasValue)
|
|
37
|
+
return null;
|
|
38
|
+
return numFinite(valueText) ?? null;
|
|
39
|
+
}
|
|
37
40
|
}
|
|
38
41
|
}
|
|
39
42
|
export function decodeFormulaResult(type, valueText, numFmt) {
|
|
@@ -45,12 +48,12 @@ export function decodeFormulaResult(type, valueText, numFmt) {
|
|
|
45
48
|
function decodeResult(type, valueText) {
|
|
46
49
|
switch (type) {
|
|
47
50
|
case 'str':
|
|
48
|
-
return valueText;
|
|
51
|
+
return decodeSpreadsheetText(valueText);
|
|
49
52
|
case 'b':
|
|
50
53
|
return boolStrict(valueText);
|
|
51
54
|
case 'e':
|
|
52
55
|
return isErrorCode(valueText) ? { error: valueText } : valueText;
|
|
53
56
|
default:
|
|
54
|
-
return
|
|
57
|
+
return numFinite(valueText);
|
|
55
58
|
}
|
|
56
59
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Color } from '../../core/style.ts';
|
|
2
2
|
/** Serialise a {@link Color} as the attribute list a `<color>`-shaped element carries. */
|
|
3
3
|
export declare function colorAttrs(color: Color): string;
|
|
4
4
|
export declare function parseColor(attrs: {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parseArgb } from '../../core/style.js';
|
|
2
|
+
import { numFinite, numInteger } from '../../xml/xml-read.js';
|
|
3
|
+
import { numberText } from '../../xml/xml.js';
|
|
2
4
|
function normalizeArgb(argb) {
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
throw new AuthoringError(`Invalid ARGB colour ${JSON.stringify(argb)}: expected 6 or 8 hexadecimal digits`);
|
|
5
|
+
const rgb = parseArgb(argb);
|
|
6
|
+
if (rgb === undefined) {
|
|
7
|
+
throw new SyntaxError(`Invalid ARGB colour ${JSON.stringify(argb)}: expected 6 or 8 hexadecimal digits`);
|
|
7
8
|
}
|
|
8
9
|
return rgb;
|
|
9
10
|
}
|
|
@@ -12,31 +13,25 @@ export function colorAttrs(color) {
|
|
|
12
13
|
if (color.argb !== undefined)
|
|
13
14
|
parts.push(`rgb="${normalizeArgb(color.argb)}"`);
|
|
14
15
|
if (color.theme !== undefined)
|
|
15
|
-
parts.push(`theme="${color.theme}"`);
|
|
16
|
+
parts.push(`theme="${numberText(color.theme)}"`);
|
|
16
17
|
if (color.tint !== undefined)
|
|
17
|
-
parts.push(`tint="${color.tint}"`);
|
|
18
|
+
parts.push(`tint="${numberText(color.tint)}"`);
|
|
18
19
|
if (color.indexed !== undefined)
|
|
19
|
-
parts.push(`indexed="${color.indexed}"`);
|
|
20
|
+
parts.push(`indexed="${numberText(color.indexed)}"`);
|
|
20
21
|
return parts.join(' ');
|
|
21
22
|
}
|
|
22
23
|
export function parseColor(attrs) {
|
|
23
24
|
const color = {};
|
|
24
25
|
if (attrs.rgb !== undefined)
|
|
25
26
|
color.argb = attrs.rgb;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
if (attrs.indexed !== undefined) {
|
|
37
|
-
const indexed = Number(attrs.indexed);
|
|
38
|
-
if (Number.isInteger(indexed))
|
|
39
|
-
color.indexed = indexed;
|
|
40
|
-
}
|
|
27
|
+
const theme = numInteger(attrs.theme, 0);
|
|
28
|
+
if (theme !== undefined)
|
|
29
|
+
color.theme = theme;
|
|
30
|
+
const tint = numFinite(attrs.tint);
|
|
31
|
+
if (tint !== undefined)
|
|
32
|
+
color.tint = tint;
|
|
33
|
+
const indexed = numInteger(attrs.indexed, 0);
|
|
34
|
+
if (indexed !== undefined)
|
|
35
|
+
color.indexed = indexed;
|
|
41
36
|
return color;
|
|
42
37
|
}
|
|
@@ -20,12 +20,12 @@ export interface CommentCell {
|
|
|
20
20
|
* in `threads`. A comment anchors to its cell regardless of the cell's value, so a note (or a thread) on
|
|
21
21
|
* an otherwise-empty cell is collected too.
|
|
22
22
|
*
|
|
23
|
-
* `threads` is the conversations the *package* will carry, not simply the ones the sheet holds
|
|
23
|
+
* `threads` is the conversations the *package* will carry, not simply the ones the sheet holds. The
|
|
24
24
|
* caller decides, because a fallback beside a thread whose `threadedComment` part is missing is worse
|
|
25
25
|
* than no fallback at all: verified against desktop Excel, such a comment shows as neither a thread nor
|
|
26
26
|
* a note, so the text disappears entirely.
|
|
27
27
|
*
|
|
28
|
-
* Ordered by cell, row-major, the way Excel writes the list
|
|
28
|
+
* Ordered by cell, row-major, the way Excel writes the list, so a fallback lands interleaved among the
|
|
29
29
|
* notes rather than appended after them, and the VML shapes follow the same order.
|
|
30
30
|
*/
|
|
31
31
|
export declare function collectComments(sheet: Worksheet, threads: readonly CommentThread[]): CommentCell[];
|
|
@@ -35,13 +35,13 @@ export declare function collectComments(sheet: Worksheet, threads: readonly Comm
|
|
|
35
35
|
* Authors are laid out the way Excel lays them out: one synthetic `tc={headId}` entry per threaded
|
|
36
36
|
* conversation first, then a single anonymous author shared by every note (the model carries no note
|
|
37
37
|
* author). Each comment points at its own author by index, and a fallback additionally carries the
|
|
38
|
-
* `xr:uid` naming its thread
|
|
38
|
+
* `xr:uid` naming its thread: the pair that keeps Excel treating the cell as threaded.
|
|
39
39
|
*/
|
|
40
40
|
export declare function commentsXml(comments: readonly CommentCell[]): string;
|
|
41
41
|
/** The `xl/drawings/vmlDrawing{n}.vml` companion: one hidden text-box shape per comment, in the same
|
|
42
42
|
* order as the comments part. Anchor coordinates place the box a couple of cells down-and-right of its
|
|
43
43
|
* owner; Excel refines them on open, so the values are a sensible starting geometry rather than a
|
|
44
|
-
* pixel-exact layout. A thread's fallback shape is `ObjectType="Note"` like any other
|
|
44
|
+
* pixel-exact layout. A thread's fallback shape is `ObjectType="Note"` like any other: Excel draws the
|
|
45
45
|
* threaded-comment card itself and only needs the shape to exist. */
|
|
46
46
|
export declare function vmlDrawingXml(comments: readonly CommentCell[]): string;
|
|
47
47
|
/** One `<comment>` read back from a comments part. */
|
|
@@ -63,7 +63,7 @@ export declare function parseComments(xml: string): Map<string, ParsedComment>;
|
|
|
63
63
|
* Apply a parsed comments part onto a sheet's cells as notes, addressing each by its A1 reference.
|
|
64
64
|
*
|
|
65
65
|
* A thread's legacy fallback is not a note and does not become one: its text is boilerplate wrapping a
|
|
66
|
-
* copy of the conversation, so surfacing it as `cell.note` hands the caller garbage
|
|
66
|
+
* copy of the conversation, so surfacing it as `cell.note` hands the caller garbage, and on write it
|
|
67
67
|
* would be re-emitted as a plain note, destroying the `tc=`/`xr:uid` binding and leaving Excel unable to
|
|
68
68
|
* see the thread at all.
|
|
69
69
|
*
|
package/dist/io/xlsx/comments.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { tryDecodeCellRef } from '../../core/address.js';
|
|
2
|
+
import { decodeSpreadsheetText, localName, numInteger, parseXml } from '../../xml/xml-read.js';
|
|
3
|
+
import { escapeText, textAttr, textElement, XML_DECLARATION } from '../../xml/xml.js';
|
|
4
4
|
import { MARKUP_COMPATIBILITY_NS, REVISION_NS, SPREADSHEETML_NS } from './namespaces.js';
|
|
5
5
|
export function collectComments(sheet, threads) {
|
|
6
6
|
const fallbacks = threadFallbacks(threads);
|
|
@@ -19,10 +19,16 @@ function threadFallbacks(threads) {
|
|
|
19
19
|
const fallbacks = [];
|
|
20
20
|
for (const thread of threads) {
|
|
21
21
|
const head = thread.comments[0];
|
|
22
|
-
const
|
|
23
|
-
if (head === undefined ||
|
|
22
|
+
const cell = tryDecodeCellRef(thread.ref);
|
|
23
|
+
if (head === undefined || cell === undefined)
|
|
24
24
|
continue;
|
|
25
|
-
fallbacks.push({
|
|
25
|
+
fallbacks.push({
|
|
26
|
+
ref: thread.ref,
|
|
27
|
+
row: cell.row,
|
|
28
|
+
col: cell.col,
|
|
29
|
+
text: fallbackText(thread),
|
|
30
|
+
threadId: head.id,
|
|
31
|
+
});
|
|
26
32
|
}
|
|
27
33
|
return fallbacks;
|
|
28
34
|
}
|
|
@@ -50,7 +56,7 @@ export function commentsXml(comments) {
|
|
|
50
56
|
.map((comment) => {
|
|
51
57
|
const { threadId } = comment;
|
|
52
58
|
const authorId = threadId === undefined ? noteAuthorId : authorIdByThreadId.get(threadId);
|
|
53
|
-
const uid =
|
|
59
|
+
const uid = textAttr('xr:uid', threadId);
|
|
54
60
|
return (`<comment ref="${comment.ref}" authorId="${authorId}"${uid}>` +
|
|
55
61
|
`<text><r>${textElement(comment.text)}</r></text>` +
|
|
56
62
|
'</comment>');
|
|
@@ -125,10 +131,11 @@ export function parseComments(xml) {
|
|
|
125
131
|
buffer = '';
|
|
126
132
|
}
|
|
127
133
|
else if (local === 'text') {
|
|
134
|
+
buffer = decodeSpreadsheetText(buffer);
|
|
128
135
|
capture = undefined;
|
|
129
136
|
}
|
|
130
137
|
else if (local === 'comment' && currentRef !== undefined) {
|
|
131
|
-
const threadId = threadIdOf(authors[
|
|
138
|
+
const threadId = threadIdOf(authors[numInteger(currentAuthorId, 0) ?? -1]);
|
|
132
139
|
comments.set(currentRef, {
|
|
133
140
|
text: buffer,
|
|
134
141
|
...(threadId !== undefined ? { threadId } : {}),
|
|
@@ -154,6 +161,8 @@ export function applyNotes(sheet, comments) {
|
|
|
154
161
|
for (const [ref, comment] of comments) {
|
|
155
162
|
if (comment.threadId !== undefined && headIds.has(comment.threadId))
|
|
156
163
|
continue;
|
|
164
|
+
if (tryDecodeCellRef(ref) === undefined)
|
|
165
|
+
continue;
|
|
157
166
|
sheet.getCell(ref).note = comment.text;
|
|
158
167
|
}
|
|
159
168
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ConditionalFormatting } from '../../core/conditional-formatting.ts';
|
|
2
2
|
import type { StyleRegistry } from './styles.ts';
|
|
3
3
|
/**
|
|
4
4
|
* Serialise every conditional formatting on a sheet into its `<conditionalFormatting>` blocks, in
|
|
@@ -17,15 +17,15 @@ export declare function conditionalFormattingsExtXml(formattings: readonly Condi
|
|
|
17
17
|
/**
|
|
18
18
|
* Parse a worksheet's conditional formatting into the model. The classic `<conditionalFormatting>`
|
|
19
19
|
* blocks supply every rule; the x14 extension (`<x14:conditionalFormatting>` inside `<extLst>`) is
|
|
20
|
-
* read only to enrich a classic data bar with the facets the classic element cannot carry
|
|
21
|
-
* gradient flag and the negative-fill and axis colours
|
|
20
|
+
* read only to enrich a classic data bar with the facets the classic element cannot carry (the
|
|
21
|
+
* gradient flag and the negative-fill and axis colours) matched by the shared id the two ends link
|
|
22
22
|
* on. An extension rule with no classic counterpart (a rule that lives only in x14) is ignored, so it
|
|
23
23
|
* is never half-read into a broken classic rule.
|
|
24
24
|
*/
|
|
25
25
|
export declare function parseConditionalFormattings(xml: string): ConditionalFormatting[];
|
|
26
26
|
/**
|
|
27
27
|
* Extract the differential-style (`<dxf>`) fragments from styles.xml, each verbatim. Preserving the
|
|
28
|
-
* raw XML
|
|
28
|
+
* raw XML, rather than reparsing and re-serialising, is what keeps a foreign dxf's number format a
|
|
29
29
|
* real format code on re-write instead of a coerced `"[object Object]"`, and keeps every conditional
|
|
30
30
|
* formatting's `dxfId` index pointing at the same style it did in the source file.
|
|
31
31
|
*/
|