@shbernal/ts-xlsx 2.1.0 → 3.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 +4 -1
- package/dist/bytes.d.ts +7 -0
- package/dist/bytes.js +22 -0
- package/dist/core/address.d.ts +60 -2
- package/dist/core/address.js +40 -24
- package/dist/core/autofilter.d.ts +5 -4
- package/dist/core/autofilter.js +34 -35
- package/dist/core/axis-handle.d.ts +10 -0
- package/dist/core/axis-handle.js +17 -0
- package/dist/core/cell.d.ts +25 -0
- package/dist/core/cell.js +9 -3
- package/dist/core/clone.d.ts +29 -0
- package/dist/core/clone.js +24 -0
- package/dist/core/color-resolution.js +2 -4
- package/dist/core/column.d.ts +5 -1
- package/dist/core/column.js +34 -35
- package/dist/core/comment-thread.js +2 -1
- package/dist/core/conditional-formatting-overlay.d.ts +2 -1
- package/dist/core/conditional-formatting-overlay.js +2 -2
- package/dist/core/conditional-formatting.d.ts +14 -6
- package/dist/core/conditional-formatting.js +45 -43
- package/dist/core/containers.d.ts +12 -0
- package/dist/core/containers.js +5 -0
- package/dist/core/data-validation-overlay.d.ts +2 -1
- package/dist/core/data-validation-overlay.js +4 -4
- package/dist/core/data-validation.d.ts +9 -3
- package/dist/core/data-validation.js +21 -18
- package/dist/core/date-format.d.ts +20 -0
- package/dist/core/date-format.js +160 -0
- package/dist/core/date.d.ts +43 -8
- package/dist/core/date.js +18 -2
- package/dist/core/formula.d.ts +26 -0
- package/dist/core/formula.js +20 -4
- package/dist/core/grid-edits.d.ts +2 -3
- package/dist/core/grid-edits.js +69 -70
- package/dist/core/grid-shift.d.ts +58 -9
- package/dist/core/grid-shift.js +26 -4
- package/dist/core/image.d.ts +14 -10
- package/dist/core/image.js +9 -9
- package/dist/core/internal.d.ts +8 -2
- package/dist/core/limits.d.ts +23 -0
- package/dist/core/limits.js +4 -0
- package/dist/core/merge-index.d.ts +31 -0
- package/dist/core/merge-index.js +60 -0
- package/dist/core/merge.d.ts +5 -14
- package/dist/core/merge.js +18 -27
- package/dist/core/page-setup.d.ts +72 -2
- package/dist/core/page-setup.js +34 -8
- package/dist/core/pivot-table.d.ts +1 -1
- package/dist/core/pivot-table.js +67 -53
- package/dist/core/protection.js +2 -11
- package/dist/core/range.js +34 -30
- package/dist/core/row-input.js +2 -2
- package/dist/core/row.d.ts +5 -1
- package/dist/core/row.js +22 -23
- package/dist/core/style.d.ts +134 -75
- package/dist/core/style.js +112 -53
- package/dist/core/table-style.d.ts +1 -1
- package/dist/core/table-style.js +4 -4
- package/dist/core/table.d.ts +28 -10
- package/dist/core/table.js +54 -39
- package/dist/core/theme.js +6 -5
- package/dist/core/used-extent.d.ts +44 -0
- package/dist/core/used-extent.js +102 -0
- package/dist/core/value.d.ts +9 -0
- package/dist/core/value.js +36 -34
- package/dist/core/workbook-media.d.ts +34 -0
- package/dist/core/workbook-media.js +44 -0
- package/dist/core/workbook-styles.d.ts +67 -1
- package/dist/core/workbook-vba.js +3 -2
- package/dist/core/workbook.d.ts +23 -2
- package/dist/core/workbook.js +24 -40
- package/dist/core/worksheet-comments.d.ts +2 -1
- package/dist/core/worksheet-comments.js +20 -13
- package/dist/core/worksheet-merges.d.ts +44 -0
- package/dist/core/worksheet-merges.js +59 -0
- package/dist/core/worksheet-model.d.ts +9 -1
- package/dist/core/worksheet-model.js +24 -9
- package/dist/core/worksheet.d.ts +72 -12
- package/dist/core/worksheet.js +68 -70
- package/dist/customui/ribbon.js +6 -7
- package/dist/entries/core.d.ts +18 -13
- package/dist/entries/core.js +12 -6
- package/dist/entries/xlsx.d.ts +1 -1
- package/dist/errors.d.ts +64 -0
- package/dist/errors.js +22 -0
- package/dist/hex.d.ts +8 -0
- package/dist/hex.js +3 -0
- package/dist/io/csv/delimiter.d.ts +9 -0
- package/dist/io/csv/delimiter.js +6 -0
- package/dist/io/csv/read.js +11 -4
- package/dist/io/csv/write.d.ts +9 -2
- package/dist/io/csv/write.js +9 -38
- package/dist/io/opc/inflate.js +15 -1
- package/dist/io/opc/namespaces.d.ts +16 -0
- package/dist/io/opc/namespaces.js +4 -0
- package/dist/io/opc/part-paths.d.ts +10 -0
- package/dist/io/opc/part-paths.js +16 -1
- package/dist/io/opc/read-opc.d.ts +69 -10
- package/dist/io/opc/read-opc.js +49 -55
- package/dist/io/opc/read-options.d.ts +5 -1
- package/dist/io/opc/rels.d.ts +1 -6
- package/dist/io/opc/rels.js +1 -4
- package/dist/io/opc/sniff-format.d.ts +3 -3
- package/dist/io/opc/sniff-format.js +2 -2
- package/dist/io/style/xf-style.d.ts +48 -2
- package/dist/io/style/xf-style.js +14 -0
- package/dist/io/xlsb/formula.d.ts +2 -2
- package/dist/io/xlsb/formula.js +49 -34
- package/dist/io/xlsb/primitives.js +8 -14
- package/dist/io/xlsb/ptg-functions.d.ts +19 -10
- package/dist/io/xlsb/ptg-functions.js +385 -596
- package/dist/io/xlsb/read-styles.js +50 -83
- package/dist/io/xlsb/read-worksheet.d.ts +20 -1
- package/dist/io/xlsb/read-worksheet.js +73 -89
- package/dist/io/xlsb/read.d.ts +6 -3
- package/dist/io/xlsb/read.js +47 -29
- package/dist/io/xlsb/record-stream.d.ts +30 -0
- package/dist/io/xlsb/record-stream.js +20 -0
- package/dist/io/xlsb/record-types.d.ts +1 -5
- package/dist/io/xlsb/record-types.js +1 -5
- package/dist/io/xlsx/cell-accumulator.d.ts +9 -2
- package/dist/io/xlsx/cell-accumulator.js +32 -9
- package/dist/io/xlsx/cell-style-resolution.d.ts +25 -0
- package/dist/io/xlsx/cell-style-resolution.js +29 -0
- package/dist/io/xlsx/cell-value.d.ts +5 -3
- package/dist/io/xlsx/cell-value.js +13 -15
- package/dist/io/xlsx/color-xml.js +3 -2
- package/dist/io/xlsx/column-budget.d.ts +26 -0
- package/dist/io/xlsx/column-budget.js +22 -0
- package/dist/io/xlsx/comments.d.ts +6 -2
- package/dist/io/xlsx/comments.js +36 -31
- package/dist/io/xlsx/conditional-formatting.d.ts +9 -5
- package/dist/io/xlsx/conditional-formatting.js +51 -46
- package/dist/io/xlsx/data-validation.d.ts +9 -7
- package/dist/io/xlsx/data-validation.js +38 -35
- package/dist/io/xlsx/edit-vba.d.ts +7 -2
- package/dist/io/xlsx/edit-vba.js +15 -29
- package/dist/io/xlsx/font-xml.d.ts +7 -0
- package/dist/io/xlsx/font-xml.js +104 -0
- package/dist/io/xlsx/hyperlinks.d.ts +41 -7
- package/dist/io/xlsx/hyperlinks.js +40 -28
- package/dist/io/xlsx/images.js +24 -25
- package/dist/io/xlsx/namespaces.d.ts +16 -0
- package/dist/io/xlsx/namespaces.js +7 -0
- package/dist/io/xlsx/package-plan.d.ts +23 -3
- package/dist/io/xlsx/package-plan.js +66 -25
- package/dist/io/xlsx/part-names.d.ts +41 -0
- package/dist/io/xlsx/part-names.js +46 -0
- package/dist/io/xlsx/pivot.js +8 -7
- package/dist/io/xlsx/read-parts.d.ts +59 -0
- package/dist/io/xlsx/read-parts.js +252 -0
- package/dist/io/xlsx/read-pivot.js +3 -1
- package/dist/io/xlsx/read-repair.d.ts +26 -0
- package/dist/io/xlsx/read-repair.js +39 -0
- package/dist/io/xlsx/{rich-runs.d.ts → read-rich-runs.d.ts} +1 -1
- package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +7 -3
- package/dist/io/xlsx/read-rows.d.ts +18 -5
- package/dist/io/xlsx/read-rows.js +50 -37
- package/dist/io/xlsx/read-shared-strings.js +5 -3
- package/dist/io/xlsx/read-styles.d.ts +1 -6
- package/dist/io/xlsx/read-styles.js +65 -109
- package/dist/io/xlsx/read-workbook-xml.d.ts +36 -0
- package/dist/io/xlsx/read-workbook-xml.js +170 -0
- package/dist/io/xlsx/read-worksheet.d.ts +11 -1
- package/dist/io/xlsx/read-worksheet.js +51 -193
- package/dist/io/xlsx/read.d.ts +5 -13
- package/dist/io/xlsx/read.js +111 -436
- package/dist/io/xlsx/rich-text.js +1 -1
- package/dist/io/xlsx/row-position.d.ts +18 -0
- package/dist/io/xlsx/row-position.js +11 -0
- package/dist/io/xlsx/row-xml.d.ts +128 -0
- package/dist/io/xlsx/row-xml.js +203 -0
- package/dist/io/xlsx/shared-formulas.js +2 -2
- package/dist/io/xlsx/sheet-properties.d.ts +10 -1
- package/dist/io/xlsx/sheet-properties.js +166 -37
- package/dist/io/xlsx/style-elements.d.ts +43 -0
- package/dist/io/xlsx/style-elements.js +156 -0
- package/dist/io/xlsx/styles.d.ts +12 -3
- package/dist/io/xlsx/styles.js +5 -204
- package/dist/io/xlsx/tables.js +11 -14
- package/dist/io/xlsx/theme-xml.d.ts +26 -4
- package/dist/io/xlsx/theme-xml.js +107 -69
- package/dist/io/xlsx/threaded-comments.d.ts +8 -10
- package/dist/io/xlsx/threaded-comments.js +3 -1
- package/dist/io/xlsx/workbook-xml.d.ts +54 -4
- package/dist/io/xlsx/workbook-xml.js +84 -57
- package/dist/io/xlsx/worksheet-xml.d.ts +23 -70
- package/dist/io/xlsx/worksheet-xml.js +59 -242
- package/dist/io/xlsx/write-stream.d.ts +71 -16
- package/dist/io/xlsx/write-stream.js +79 -41
- package/dist/io/xlsx/write.d.ts +6 -2
- package/dist/io/xlsx/write.js +217 -153
- package/dist/rel-type.d.ts +16 -0
- package/dist/rel-type.js +6 -0
- package/dist/token-set.d.ts +28 -0
- package/dist/token-set.js +7 -0
- package/dist/vba/bytes.d.ts +14 -5
- package/dist/vba/bytes.js +16 -6
- package/dist/vba/cfb-format.d.ts +32 -0
- package/dist/vba/cfb-format.js +13 -0
- package/dist/vba/cfb-writer.d.ts +9 -0
- package/dist/vba/cfb-writer.js +28 -25
- package/dist/vba/cfb.d.ts +13 -1
- package/dist/vba/cfb.js +73 -57
- package/dist/vba/codepage.js +2 -1
- package/dist/vba/errors.d.ts +7 -0
- package/dist/vba/ms-ovba.js +79 -23
- package/dist/vba/project-editor.js +35 -40
- package/dist/vba/project.d.ts +11 -1
- package/dist/vba/project.js +40 -21
- package/dist/vba/vba-encoding.js +5 -6
- package/dist/xml/xml-attrs.d.ts +37 -0
- package/dist/xml/xml-attrs.js +30 -0
- package/dist/xml/xml-chars.d.ts +40 -0
- package/dist/xml/xml-chars.js +12 -0
- package/dist/xml/xml-namespaces.d.ts +31 -0
- package/dist/xml/xml-namespaces.js +50 -0
- package/dist/xml/xml-read.d.ts +128 -81
- package/dist/xml/xml-read.js +161 -178
- package/dist/xml/xml-scan.d.ts +78 -0
- package/dist/xml/xml-scan.js +180 -0
- package/dist/xml/xml.d.ts +29 -28
- package/dist/xml/xml.js +24 -24
- package/package.json +13 -9
|
@@ -16,7 +16,6 @@ export declare const BRT: {
|
|
|
16
16
|
readonly ColInfo: 60;
|
|
17
17
|
readonly MergeCell: 176;
|
|
18
18
|
readonly SSTItem: 19;
|
|
19
|
-
readonly BeginSst: 159;
|
|
20
19
|
readonly EndSst: 160;
|
|
21
20
|
readonly Fmt: 44;
|
|
22
21
|
readonly Font: 43;
|
|
@@ -38,6 +37,7 @@ export declare const BRT: {
|
|
|
38
37
|
readonly EndCellXFs: 618;
|
|
39
38
|
readonly BeginStyles: 619;
|
|
40
39
|
readonly EndStyles: 620;
|
|
40
|
+
readonly WbProp: 153;
|
|
41
41
|
readonly BundleSh: 156;
|
|
42
42
|
readonly BeginBundleShs: 143;
|
|
43
43
|
readonly EndBundleShs: 144;
|
|
@@ -46,10 +46,6 @@ export declare const BRT: {
|
|
|
46
46
|
readonly EndExternals: 354;
|
|
47
47
|
readonly SupSelf: 357;
|
|
48
48
|
readonly ExternSheet: 362;
|
|
49
|
-
readonly WsProp: 147;
|
|
50
|
-
readonly WsDim: 148;
|
|
51
49
|
readonly WsFmtInfo: 485;
|
|
52
|
-
readonly BeginSheetData: 145;
|
|
53
|
-
readonly EndSheetData: 146;
|
|
54
50
|
readonly ArrFmla: 426;
|
|
55
51
|
};
|
|
@@ -15,7 +15,6 @@ export const BRT = {
|
|
|
15
15
|
ColInfo: 60,
|
|
16
16
|
MergeCell: 176,
|
|
17
17
|
SSTItem: 19,
|
|
18
|
-
BeginSst: 159,
|
|
19
18
|
EndSst: 160,
|
|
20
19
|
Fmt: 44,
|
|
21
20
|
Font: 43,
|
|
@@ -37,6 +36,7 @@ export const BRT = {
|
|
|
37
36
|
EndCellXFs: 618,
|
|
38
37
|
BeginStyles: 619,
|
|
39
38
|
EndStyles: 620,
|
|
39
|
+
WbProp: 153,
|
|
40
40
|
BundleSh: 156,
|
|
41
41
|
BeginBundleShs: 143,
|
|
42
42
|
EndBundleShs: 144,
|
|
@@ -45,10 +45,6 @@ export const BRT = {
|
|
|
45
45
|
EndExternals: 354,
|
|
46
46
|
SupSelf: 357,
|
|
47
47
|
ExternSheet: 362,
|
|
48
|
-
WsProp: 147,
|
|
49
|
-
WsDim: 148,
|
|
50
48
|
WsFmtInfo: 485,
|
|
51
|
-
BeginSheetData: 145,
|
|
52
|
-
EndSheetData: 146,
|
|
53
49
|
ArrFmla: 426,
|
|
54
50
|
};
|
|
@@ -1,19 +1,26 @@
|
|
|
1
|
+
import type { DateEpoch } from '../../core/date.ts';
|
|
1
2
|
import type { CellValue } from '../../core/value.ts';
|
|
2
3
|
import type { Worksheet } from '../../core/worksheet.ts';
|
|
3
|
-
import { type XmlAttributes } from '../../xml/xml-
|
|
4
|
+
import { type XmlAttributes } from '../../xml/xml-scan.ts';
|
|
4
5
|
import { type XfStyle } from '../style/xf-style.ts';
|
|
5
6
|
import { type SharedString } from './cell-value.ts';
|
|
6
7
|
export declare class CellAccumulator {
|
|
7
8
|
#private;
|
|
8
9
|
constructor(options: {
|
|
9
10
|
readonly richRuns: boolean;
|
|
11
|
+
readonly dateEpoch: DateEpoch;
|
|
10
12
|
});
|
|
11
13
|
/** This cell's `<c r>` address (`"B3"`), or '' when it carried none. */
|
|
12
14
|
get ref(): string;
|
|
13
15
|
/** This cell's own `<c s>` style index, or -1 when it carries none. */
|
|
14
16
|
get styleIndex(): number;
|
|
15
|
-
/** This cell's 1-based column, or -1 when its address was
|
|
17
|
+
/** This cell's 1-based column, or -1 when its address was unparseable. */
|
|
16
18
|
get col(): number;
|
|
19
|
+
/**
|
|
20
|
+
* Open a `<row>`: the cells that follow belong to it, and the next one with no `r` of its own is
|
|
21
|
+
* its first column. Both readers call this where they already tell the style resolver a row opened.
|
|
22
|
+
*/
|
|
23
|
+
openRow(number: number): void;
|
|
17
24
|
/**
|
|
18
25
|
* The text gathered since the current element opened. A caller reads it for the elements it
|
|
19
26
|
* captures itself (see {@link capture}); the machine reads it for its own.
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { encodeAddress, tryDecodeCellRef } from '../../core/address.js';
|
|
1
|
+
import { encodeAddress, MAX_COLUMN, tryDecodeCellRef } from '../../core/address.js';
|
|
2
2
|
import { translateFormula, unmangleFunctions } from '../../core/formula.js';
|
|
3
|
-
import {
|
|
3
|
+
import { numInteger } from '../../xml/xml-attrs.js';
|
|
4
|
+
import { boolStrict } from '../../xml/xml-scan.js';
|
|
4
5
|
import { applyXfToCell } from '../style/xf-style.js';
|
|
5
6
|
import { decodeCellContent, decodeFormulaResult, } from './cell-value.js';
|
|
6
|
-
import { RunAccumulator } from './rich-runs.js';
|
|
7
|
+
import { RunAccumulator } from './read-rich-runs.js';
|
|
7
8
|
export class CellAccumulator {
|
|
8
9
|
#ref = '';
|
|
9
10
|
#type = '';
|
|
10
11
|
#style = -1;
|
|
11
12
|
#col = -1;
|
|
12
13
|
#row = -1;
|
|
14
|
+
#nextCol = 1;
|
|
13
15
|
#formula = '';
|
|
14
16
|
#formulaShared = false;
|
|
15
17
|
#formulaSi = -1;
|
|
@@ -22,8 +24,10 @@ export class CellAccumulator {
|
|
|
22
24
|
#masters = new Map();
|
|
23
25
|
#capture = false;
|
|
24
26
|
#text = '';
|
|
27
|
+
#dateEpoch;
|
|
25
28
|
constructor(options) {
|
|
26
29
|
this.#runs = new RunAccumulator({ container: 'is', readRuns: options.richRuns });
|
|
30
|
+
this.#dateEpoch = options.dateEpoch;
|
|
27
31
|
}
|
|
28
32
|
get ref() {
|
|
29
33
|
return this.#ref;
|
|
@@ -34,13 +38,14 @@ export class CellAccumulator {
|
|
|
34
38
|
get col() {
|
|
35
39
|
return this.#col;
|
|
36
40
|
}
|
|
41
|
+
openRow(number) {
|
|
42
|
+
this.#row = number;
|
|
43
|
+
this.#nextCol = 1;
|
|
44
|
+
}
|
|
37
45
|
#beginCell(attrs) {
|
|
38
46
|
this.#type = attrs.t ?? '';
|
|
39
47
|
this.#style = numInteger(attrs.s, 0) ?? -1;
|
|
40
|
-
|
|
41
|
-
this.#ref = decoded === undefined ? '' : (attrs.r ?? '');
|
|
42
|
-
this.#col = decoded?.col ?? -1;
|
|
43
|
-
this.#row = decoded?.row ?? -1;
|
|
48
|
+
this.#placeCell(attrs.r);
|
|
44
49
|
this.#formula = '';
|
|
45
50
|
this.#valueText = '';
|
|
46
51
|
this.#runs.beginContainer();
|
|
@@ -51,6 +56,24 @@ export class CellAccumulator {
|
|
|
51
56
|
this.#sharedClone = false;
|
|
52
57
|
this.#dataTable = null;
|
|
53
58
|
}
|
|
59
|
+
#placeCell(ref) {
|
|
60
|
+
const decoded = ref === undefined ? undefined : tryDecodeCellRef(ref);
|
|
61
|
+
if (decoded !== undefined) {
|
|
62
|
+
this.#ref = ref ?? '';
|
|
63
|
+
this.#col = decoded.col;
|
|
64
|
+
this.#row = decoded.row;
|
|
65
|
+
}
|
|
66
|
+
else if (ref === undefined && this.#row > 0 && this.#nextCol <= MAX_COLUMN) {
|
|
67
|
+
this.#col = this.#nextCol;
|
|
68
|
+
this.#ref = encodeAddress(this.#col, this.#row);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
this.#ref = '';
|
|
72
|
+
this.#col = -1;
|
|
73
|
+
}
|
|
74
|
+
if (this.#col > 0)
|
|
75
|
+
this.#nextCol = this.#col + 1;
|
|
76
|
+
}
|
|
54
77
|
#beginFormula(attrs, selfClosing) {
|
|
55
78
|
this.#formulaShared = attrs.t === 'shared';
|
|
56
79
|
this.#formulaSi = numInteger(attrs.si, 0) ?? -1;
|
|
@@ -165,7 +188,7 @@ export class CellAccumulator {
|
|
|
165
188
|
cachedResult(style) {
|
|
166
189
|
if (!this.#hasValue)
|
|
167
190
|
return {};
|
|
168
|
-
const result = decodeFormulaResult(this.#type, this.#valueText, style?.numFmt);
|
|
191
|
+
const result = decodeFormulaResult(this.#type, this.#valueText, style?.numFmt, this.#dateEpoch);
|
|
169
192
|
return result === undefined ? {} : { result };
|
|
170
193
|
}
|
|
171
194
|
decode(sharedStrings, style) {
|
|
@@ -178,6 +201,6 @@ export class CellAccumulator {
|
|
|
178
201
|
inlineText: this.#runs.plainText,
|
|
179
202
|
richTextRuns: this.#runs.runs,
|
|
180
203
|
};
|
|
181
|
-
return decodeCellContent(raw, sharedStrings, style?.numFmt);
|
|
204
|
+
return decodeCellContent(raw, sharedStrings, style?.numFmt, this.#dateEpoch);
|
|
182
205
|
}
|
|
183
206
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** The attributes this resolver reads, the subset both readers' scanners already hand it. */
|
|
2
|
+
interface StyleAttributes {
|
|
3
|
+
readonly [key: string]: string | undefined;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* The cell → row → column style resolution for one worksheet, fed by the same elements in the same
|
|
7
|
+
* order both readers already visit them: `<col>` before any cell references it, `<row>` before its
|
|
8
|
+
* own cells.
|
|
9
|
+
*/
|
|
10
|
+
export declare class CellStyleResolver {
|
|
11
|
+
#private;
|
|
12
|
+
/** Record a `<col min max style>` span's default for the columns it covers. */
|
|
13
|
+
noteColumnSpan(first: number, last: number, attrs: StyleAttributes): void;
|
|
14
|
+
/** Open a `<row>`, taking the format it declares for its own bare cells. */
|
|
15
|
+
openRow(attrs: StyleAttributes): void;
|
|
16
|
+
/** Close the row, so a cell outside one never inherits the last row's format. */
|
|
17
|
+
closeRow(): void;
|
|
18
|
+
/**
|
|
19
|
+
* The `xfStyles` index a cell's format resolves to, or `-1` when nothing declares one. A row's
|
|
20
|
+
* format applies only when the row is marked `customFormat`; without that flag the `s` on a `<row>`
|
|
21
|
+
* describes the row itself and is not inherited by its cells.
|
|
22
|
+
*/
|
|
23
|
+
indexFor(col: number, cellStyleIndex: number): number;
|
|
24
|
+
}
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { numInteger } from '../../xml/xml-attrs.js';
|
|
2
|
+
import { boolStrict } from '../../xml/xml-scan.js';
|
|
3
|
+
export class CellStyleResolver {
|
|
4
|
+
#columnStyle = new Map();
|
|
5
|
+
#rowStyle = -1;
|
|
6
|
+
#rowCustomFormat = false;
|
|
7
|
+
noteColumnSpan(first, last, attrs) {
|
|
8
|
+
const styleIndex = numInteger(attrs.style, 0) ?? -1;
|
|
9
|
+
if (styleIndex < 0)
|
|
10
|
+
return;
|
|
11
|
+
for (let index = first; index <= last; index++)
|
|
12
|
+
this.#columnStyle.set(index, styleIndex);
|
|
13
|
+
}
|
|
14
|
+
openRow(attrs) {
|
|
15
|
+
this.#rowStyle = numInteger(attrs.s, 0) ?? -1;
|
|
16
|
+
this.#rowCustomFormat = boolStrict(attrs.customFormat);
|
|
17
|
+
}
|
|
18
|
+
closeRow() {
|
|
19
|
+
this.#rowStyle = -1;
|
|
20
|
+
this.#rowCustomFormat = false;
|
|
21
|
+
}
|
|
22
|
+
indexFor(col, cellStyleIndex) {
|
|
23
|
+
if (cellStyleIndex >= 0)
|
|
24
|
+
return cellStyleIndex;
|
|
25
|
+
if (this.#rowCustomFormat && this.#rowStyle >= 0)
|
|
26
|
+
return this.#rowStyle;
|
|
27
|
+
return this.#columnStyle.get(col) ?? -1;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type DateEpoch } from '../../core/date.ts';
|
|
1
2
|
import { type CellValue, type FormulaResult, type RichTextRun, type RichTextValue } from '../../core/value.ts';
|
|
2
3
|
/**
|
|
3
4
|
* One entry of the shared-strings pool. A `<si>` built from a bare `<t>` is a plain string; a `<si>`
|
|
@@ -22,11 +23,12 @@ export interface RawCell {
|
|
|
22
23
|
* Decode a gathered cell into its model value. A formula cell becomes a `{formula, result?}`
|
|
23
24
|
* object (the on-disk `_xlfn.`/`_xlpm.` mangling stripped back to the readable name); a plain
|
|
24
25
|
* numeric cell under a date number format becomes a {@link Date}; everything else decodes by its
|
|
25
|
-
* `t` type. `numFmt` is the cell's resolved number-format code, used only for date detection
|
|
26
|
+
* `t` type. `numFmt` is the cell's resolved number-format code, used only for date detection, and
|
|
27
|
+
* `epoch` the workbook's date system, which is what a serial under such a format counts from.
|
|
26
28
|
*/
|
|
27
|
-
export declare function decodeCellContent(raw: RawCell, sharedStrings: readonly SharedString[], numFmt: string | undefined): CellValue;
|
|
29
|
+
export declare function decodeCellContent(raw: RawCell, sharedStrings: readonly SharedString[], numFmt: string | undefined, epoch: DateEpoch): CellValue;
|
|
28
30
|
/** Decode a formula's cached `<v>` result by its `t` type, coercing a numeric result under a date
|
|
29
31
|
* `numFmt` to a {@link Date} exactly as a bare numeric cell is, so a date-valued formula result
|
|
30
32
|
* (e.g. `TODAY()`) reads back as a Date, not a serial. Shared by the buffered reader's shared-formula
|
|
31
33
|
* clone resolution, which caches a result the same way a plain formula cell does. */
|
|
32
|
-
export declare function decodeFormulaResult(type: string, valueText: string, numFmt
|
|
34
|
+
export declare function decodeFormulaResult(type: string, valueText: string, numFmt: string | undefined, epoch: DateEpoch): FormulaResult | undefined;
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { coerceDateSerial, parseDateText } from '../../core/date.js';
|
|
2
2
|
import { unmangleFunctions } from '../../core/formula.js';
|
|
3
3
|
import { isErrorCode, } from '../../core/value.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import { decodeSpreadsheetText, numFinite, numInteger } from '../../xml/xml-attrs.js';
|
|
5
|
+
import { boolStrict } from '../../xml/xml-scan.js';
|
|
6
|
+
export function decodeCellContent(raw, sharedStrings, numFmt, epoch) {
|
|
6
7
|
if (raw.hasFormula) {
|
|
7
8
|
const stored = unmangleFunctions(raw.formula);
|
|
8
|
-
const result = raw.hasValue
|
|
9
|
+
const result = raw.hasValue
|
|
10
|
+
? decodeFormulaResult(raw.type, raw.valueText, numFmt, epoch)
|
|
11
|
+
: undefined;
|
|
9
12
|
return result === undefined ? { formula: stored } : { formula: stored, result };
|
|
10
13
|
}
|
|
11
14
|
if (raw.type === 'inlineStr' && raw.richTextRuns !== undefined && raw.richTextRuns.length > 0) {
|
|
12
15
|
return { richText: raw.richTextRuns };
|
|
13
16
|
}
|
|
14
17
|
const value = decodeValue(raw.type, raw.valueText, raw.inlineText, raw.hasValue, sharedStrings);
|
|
15
|
-
return
|
|
16
|
-
? serialToDate(value)
|
|
17
|
-
: value;
|
|
18
|
+
return coerceDateSerial(value, numFmt, epoch);
|
|
18
19
|
}
|
|
19
20
|
function decodeValue(type, valueText, inlineText, hasValue, sharedStrings) {
|
|
20
21
|
switch (type) {
|
|
@@ -23,10 +24,10 @@ function decodeValue(type, valueText, inlineText, hasValue, sharedStrings) {
|
|
|
23
24
|
case 'str':
|
|
24
25
|
return decodeSpreadsheetText(valueText);
|
|
25
26
|
case 'd':
|
|
26
|
-
return
|
|
27
|
+
return parseDateText(valueText);
|
|
27
28
|
case 's': {
|
|
28
|
-
const index =
|
|
29
|
-
return
|
|
29
|
+
const index = numInteger(valueText, 0);
|
|
30
|
+
return index === undefined ? '' : (sharedStrings[index] ?? '');
|
|
30
31
|
}
|
|
31
32
|
case 'b':
|
|
32
33
|
return boolStrict(valueText);
|
|
@@ -39,11 +40,8 @@ function decodeValue(type, valueText, inlineText, hasValue, sharedStrings) {
|
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
|
-
export function decodeFormulaResult(type, valueText, numFmt) {
|
|
43
|
-
|
|
44
|
-
return typeof result === 'number' && numFmt !== undefined && isDateFormat(numFmt)
|
|
45
|
-
? serialToDate(result)
|
|
46
|
-
: result;
|
|
43
|
+
export function decodeFormulaResult(type, valueText, numFmt, epoch) {
|
|
44
|
+
return coerceDateSerial(decodeResult(type, valueText), numFmt, epoch);
|
|
47
45
|
}
|
|
48
46
|
function decodeResult(type, valueText) {
|
|
49
47
|
switch (type) {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { parseArgb } from '../../core/style.js';
|
|
2
|
-
import {
|
|
2
|
+
import { quoted } from '../../errors.js';
|
|
3
|
+
import { numFinite, numInteger } from '../../xml/xml-attrs.js';
|
|
3
4
|
import { numberText } from '../../xml/xml.js';
|
|
4
5
|
function normalizeArgb(argb) {
|
|
5
6
|
const rgb = parseArgb(argb);
|
|
6
7
|
if (rgb === undefined) {
|
|
7
|
-
throw new SyntaxError(`Invalid ARGB colour ${
|
|
8
|
+
throw new SyntaxError(`Invalid ARGB colour ${quoted(argb)}: expected 6 or 8 hexadecimal digits`);
|
|
8
9
|
}
|
|
9
10
|
return rgb;
|
|
10
11
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type XmlAttributes } from '../../xml/xml-scan.ts';
|
|
2
|
+
/**
|
|
3
|
+
* A per-sheet allowance of column touches, spent by each `<col>` span the reader applies.
|
|
4
|
+
*
|
|
5
|
+
* A span past the allowance is truncated, and one starting past it is dropped, rather than the read
|
|
6
|
+
* being refused: that is the stance both readers already take on an out-of-grid span, and it means a
|
|
7
|
+
* hostile file loses formatting it could not have meant while a real one is untouched.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ColumnRecordBudget {
|
|
10
|
+
#private;
|
|
11
|
+
/** The last column of `[first, last]` this sheet can still afford, or `undefined` when none is. */
|
|
12
|
+
take(first: number, last: number): number | undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The columns a `<col min max>` element actually applies to, or `undefined` for one that applies to
|
|
16
|
+
* none: unreadable bounds, a span starting past the grid, or a budget already spent.
|
|
17
|
+
*
|
|
18
|
+
* Beside the budget because the two decisions are one decision. Both readers had their own copy, and
|
|
19
|
+
* the copies had already drifted: one tested `min > MAX_COLUMN` and the other did not, which happened
|
|
20
|
+
* not to matter only because `budget.take` returns `undefined` when `first > last` - an accident of
|
|
21
|
+
* this class's contract rather than an agreement between the readers.
|
|
22
|
+
*/
|
|
23
|
+
export declare function takeColumnSpan(attrs: XmlAttributes, budget: ColumnRecordBudget): {
|
|
24
|
+
first: number;
|
|
25
|
+
last: number;
|
|
26
|
+
} | undefined;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { MAX_COLUMN } from '../../core/address.js';
|
|
2
|
+
import { numInteger } from '../../xml/xml-attrs.js';
|
|
3
|
+
import {} from '../../xml/xml-scan.js';
|
|
4
|
+
const MAX_COLUMN_RECORD_TOUCHES = MAX_COLUMN * 4;
|
|
5
|
+
export class ColumnRecordBudget {
|
|
6
|
+
#remaining = MAX_COLUMN_RECORD_TOUCHES;
|
|
7
|
+
take(first, last) {
|
|
8
|
+
if (this.#remaining <= 0 || first > last)
|
|
9
|
+
return undefined;
|
|
10
|
+
const affordable = Math.min(last, first + this.#remaining - 1);
|
|
11
|
+
this.#remaining -= affordable - first + 1;
|
|
12
|
+
return affordable;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function takeColumnSpan(attrs, budget) {
|
|
16
|
+
const first = numInteger(attrs.min, 1);
|
|
17
|
+
const declared = numInteger(attrs.max, 1);
|
|
18
|
+
if (first === undefined || declared === undefined || first > MAX_COLUMN)
|
|
19
|
+
return undefined;
|
|
20
|
+
const last = budget.take(first, Math.min(declared, MAX_COLUMN));
|
|
21
|
+
return last === undefined ? undefined : { first, last };
|
|
22
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { Cell } from '../../core/cell.ts';
|
|
1
2
|
import type { CommentThread } from '../../core/comment-thread.ts';
|
|
2
3
|
import type { Worksheet } from '../../core/worksheet.ts';
|
|
3
|
-
/** A comment bound for `comments{n}.xml`, paired with the coordinates the VML anchor needs.
|
|
4
|
+
/** A comment bound for `comments{n}.xml`, paired with the coordinates the VML anchor needs.
|
|
5
|
+
*/
|
|
4
6
|
export interface CommentCell {
|
|
5
7
|
readonly ref: string;
|
|
6
8
|
/** 1-based row of the commented cell. */
|
|
@@ -28,7 +30,9 @@ export interface CommentCell {
|
|
|
28
30
|
* Ordered by cell, row-major, the way Excel writes the list, so a fallback lands interleaved among the
|
|
29
31
|
* notes rather than appended after them, and the VML shapes follow the same order.
|
|
30
32
|
*/
|
|
31
|
-
export declare function collectComments(
|
|
33
|
+
export declare function collectComments(cells: Iterable<Cell>, threads: readonly CommentThread[], alreadyCollected?: readonly CommentCell[]): CommentCell[];
|
|
34
|
+
/** The notes among a run of cells, for a writer that must ask before the cells are evicted. */
|
|
35
|
+
export declare function collectNotes(cells: Iterable<Cell>): CommentCell[];
|
|
32
36
|
/**
|
|
33
37
|
* The `xl/comments{n}.xml` part.
|
|
34
38
|
*
|
package/dist/io/xlsx/comments.js
CHANGED
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
import { tryDecodeCellRef } from '../../core/address.js';
|
|
2
|
-
import { decodeSpreadsheetText,
|
|
2
|
+
import { decodeSpreadsheetText, numInteger } from '../../xml/xml-attrs.js';
|
|
3
|
+
import { parseXml, TextCapture } from '../../xml/xml-read.js';
|
|
4
|
+
import { localName } from '../../xml/xml-scan.js';
|
|
3
5
|
import { escapeText, textAttr, textElement, XML_DECLARATION } from '../../xml/xml.js';
|
|
4
6
|
import { MARKUP_COMPATIBILITY_NS, REVISION_NS, SPREADSHEETML_NS } from './namespaces.js';
|
|
5
|
-
export function collectComments(
|
|
7
|
+
export function collectComments(cells, threads, alreadyCollected = []) {
|
|
6
8
|
const fallbacks = threadFallbacks(threads);
|
|
7
9
|
const anchored = new Set(fallbacks.map((fallback) => fallback.ref));
|
|
8
|
-
const comments = [...fallbacks];
|
|
9
|
-
for (const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
const comments = [...fallbacks, ...alreadyCollected];
|
|
11
|
+
for (const cell of cells) {
|
|
12
|
+
if (cell.note === undefined || anchored.has(cell.address))
|
|
13
|
+
continue;
|
|
14
|
+
comments.push(noteOn(cell, cell.note));
|
|
15
|
+
}
|
|
16
|
+
return comments
|
|
17
|
+
.filter((comment) => comment.threadId !== undefined || !anchored.has(comment.ref))
|
|
18
|
+
.sort((a, b) => a.row - b.row || a.col - b.col);
|
|
19
|
+
}
|
|
20
|
+
export function collectNotes(cells) {
|
|
21
|
+
const notes = [];
|
|
22
|
+
for (const cell of cells) {
|
|
23
|
+
if (cell.note !== undefined)
|
|
24
|
+
notes.push(noteOn(cell, cell.note));
|
|
15
25
|
}
|
|
16
|
-
return
|
|
26
|
+
return notes;
|
|
27
|
+
}
|
|
28
|
+
function noteOn(cell, text) {
|
|
29
|
+
return { ref: cell.address, row: cell.row, col: cell.col, text };
|
|
17
30
|
}
|
|
18
31
|
function threadFallbacks(threads) {
|
|
19
32
|
const fallbacks = [];
|
|
@@ -75,13 +88,14 @@ const VML_HEADER = '<xml xmlns:v="urn:schemas-microsoft-com:vml" ' +
|
|
|
75
88
|
'<v:shapetype id="_x0000_t202" coordsize="21600,21600" o:spt="202" ' +
|
|
76
89
|
'path="m,l,21600r21600,l21600,xe"><v:stroke joinstyle="miter"/>' +
|
|
77
90
|
'<v:path gradientshapeok="t" o:connecttype="rect"/></v:shapetype>';
|
|
91
|
+
const FIRST_SHAPE_ID = 1025;
|
|
78
92
|
export function vmlDrawingXml(comments) {
|
|
79
93
|
const shapes = comments
|
|
80
94
|
.map((comment, i) => {
|
|
81
95
|
const row0 = comment.row - 1;
|
|
82
96
|
const col0 = comment.col - 1;
|
|
83
97
|
const anchor = `${col0 + 1}, 15, ${row0}, 2, ${col0 + 3}, 15, ${row0 + 4}, 4`;
|
|
84
|
-
return (`<v:shape id="_x0000_s${
|
|
98
|
+
return (`<v:shape id="_x0000_s${FIRST_SHAPE_ID + i}" type="#_x0000_t202" ` +
|
|
85
99
|
'style="position:absolute;margin-left:59.25pt;margin-top:1.5pt;width:108pt;height:59.25pt;' +
|
|
86
100
|
`z-index:${i + 1};visibility:hidden" fillcolor="#ffffe1" o:insetmode="auto">` +
|
|
87
101
|
'<v:fill color2="#ffffe1"/><v:shadow on="t" color="black" obscured="t"/>' +
|
|
@@ -94,50 +108,41 @@ export function vmlDrawingXml(comments) {
|
|
|
94
108
|
.join('');
|
|
95
109
|
return `${VML_HEADER}${shapes}</xml>`;
|
|
96
110
|
}
|
|
97
|
-
const COMMENT_EMPTY_CLOSES = new Set(['author']);
|
|
111
|
+
const COMMENT_EMPTY_CLOSES = new Set(['author', 'text']);
|
|
98
112
|
const THREAD_AUTHOR_PREFIX = 'tc=';
|
|
99
113
|
export function parseComments(xml) {
|
|
100
114
|
const comments = new Map();
|
|
101
115
|
const authors = [];
|
|
102
116
|
let currentRef;
|
|
103
117
|
let currentAuthorId;
|
|
104
|
-
|
|
105
|
-
let
|
|
118
|
+
const capture = new TextCapture(['author', 'text']);
|
|
119
|
+
let body = '';
|
|
106
120
|
parseXml(xml, {
|
|
107
|
-
onOpen(name, attrs) {
|
|
121
|
+
onOpen(name, attrs, selfClosing) {
|
|
108
122
|
const local = localName(name);
|
|
109
123
|
if (local === 'comment') {
|
|
110
124
|
currentRef = attrs.ref;
|
|
111
125
|
currentAuthorId = attrs.authorId;
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
else if (local === 'author') {
|
|
115
|
-
capture = 'author';
|
|
116
|
-
buffer = '';
|
|
117
|
-
}
|
|
118
|
-
else if (local === 'text') {
|
|
119
|
-
capture = 'text';
|
|
126
|
+
body = '';
|
|
120
127
|
}
|
|
128
|
+
capture.open(local, selfClosing);
|
|
121
129
|
},
|
|
122
130
|
onText(text) {
|
|
123
|
-
|
|
124
|
-
buffer += text;
|
|
131
|
+
capture.text(text);
|
|
125
132
|
},
|
|
126
133
|
onClose(name) {
|
|
127
134
|
const local = localName(name);
|
|
135
|
+
const text = capture.close(local);
|
|
128
136
|
if (local === 'author') {
|
|
129
|
-
authors.push(
|
|
130
|
-
capture = undefined;
|
|
131
|
-
buffer = '';
|
|
137
|
+
authors.push(text ?? '');
|
|
132
138
|
}
|
|
133
139
|
else if (local === 'text') {
|
|
134
|
-
|
|
135
|
-
capture = undefined;
|
|
140
|
+
body = decodeSpreadsheetText(text ?? '');
|
|
136
141
|
}
|
|
137
142
|
else if (local === 'comment' && currentRef !== undefined) {
|
|
138
143
|
const threadId = threadIdOf(authors[numInteger(currentAuthorId, 0) ?? -1]);
|
|
139
144
|
comments.set(currentRef, {
|
|
140
|
-
text:
|
|
145
|
+
text: body,
|
|
141
146
|
...(threadId !== undefined ? { threadId } : {}),
|
|
142
147
|
});
|
|
143
148
|
currentRef = undefined;
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import { type ConditionalFormatting } from '../../core/conditional-formatting.ts';
|
|
1
|
+
import { type ConditionalFormatting, type ConditionalFormattingRule } from '../../core/conditional-formatting.ts';
|
|
2
|
+
import { type CollectingPass } from '../../xml/xml-read.ts';
|
|
2
3
|
import type { StyleRegistry } from './styles.ts';
|
|
4
|
+
/** Each extended data bar's link id, keyed by rule identity: the one map both passes are handed. */
|
|
5
|
+
export type DataBarExtLinks = ReadonlyMap<ConditionalFormattingRule, string>;
|
|
6
|
+
export declare function dataBarExtLinks(formattings: readonly ConditionalFormatting[]): DataBarExtLinks;
|
|
3
7
|
/**
|
|
4
8
|
* Serialise every conditional formatting on a sheet into its `<conditionalFormatting>` blocks, in
|
|
5
9
|
* insertion order. Returns '' when the sheet has none. A rule missing a `priority` is assigned the
|
|
6
10
|
* next free one, so the output always satisfies Excel's requirement that every cfRule carry one.
|
|
7
11
|
*/
|
|
8
|
-
export declare function conditionalFormattingsXml(formattings: readonly ConditionalFormatting[], styles: StyleRegistry): string;
|
|
12
|
+
export declare function conditionalFormattingsXml(formattings: readonly ConditionalFormatting[], styles: StyleRegistry, extLinks: DataBarExtLinks): string;
|
|
9
13
|
/**
|
|
10
14
|
* The worksheet `<extLst>` `<ext>` carrying the x14 data-bar extensions, or '' when no data bar needs
|
|
11
15
|
* one. Each extension's `<x14:cfRule id>` is read from the same {@link dataBarExtLinks} map the classic
|
|
@@ -13,16 +17,16 @@ export declare function conditionalFormattingsXml(formattings: readonly Conditio
|
|
|
13
17
|
* (no `<extLst>` wrapper) so the worksheet serialiser can gather it into a single `<extLst>` beside the
|
|
14
18
|
* data-validation extension.
|
|
15
19
|
*/
|
|
16
|
-
export declare function conditionalFormattingsExtXml(formattings: readonly ConditionalFormatting[]): string;
|
|
20
|
+
export declare function conditionalFormattingsExtXml(formattings: readonly ConditionalFormatting[], extLinks: DataBarExtLinks): string;
|
|
17
21
|
/**
|
|
18
|
-
*
|
|
22
|
+
* A pass reading a worksheet's conditional formatting into the model. The classic `<conditionalFormatting>`
|
|
19
23
|
* blocks supply every rule; the x14 extension (`<x14:conditionalFormatting>` inside `<extLst>`) is
|
|
20
24
|
* read only to enrich a classic data bar with the facets the classic element cannot carry (the
|
|
21
25
|
* gradient flag and the negative-fill and axis colours) matched by the shared id the two ends link
|
|
22
26
|
* on. An extension rule with no classic counterpart (a rule that lives only in x14) is ignored, so it
|
|
23
27
|
* is never half-read into a broken classic rule.
|
|
24
28
|
*/
|
|
25
|
-
export declare function
|
|
29
|
+
export declare function conditionalFormattingPass(): CollectingPass<ConditionalFormatting[]>;
|
|
26
30
|
/**
|
|
27
31
|
* Extract the differential-style (`<dxf>`) fragments from styles.xml, each verbatim. Preserving the
|
|
28
32
|
* raw XML, rather than reparsing and re-serialising, is what keeps a foreign dxf's number format a
|