@shbernal/ts-xlsx 3.0.0 → 3.2.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 +34 -24
- package/dist/bytes.d.ts +10 -2
- package/dist/bytes.js +22 -0
- package/dist/core/address.d.ts +96 -2
- package/dist/core/address.js +87 -33
- package/dist/core/array-formula-ranges.d.ts +33 -0
- package/dist/core/array-formula-ranges.js +62 -0
- package/dist/core/autofilter.d.ts +4 -3
- package/dist/core/autofilter.js +31 -30
- package/dist/core/axis-handle.d.ts +2 -0
- package/dist/core/axis-handle.js +5 -2
- package/dist/core/cell.d.ts +4 -3
- package/dist/core/cell.js +4 -6
- package/dist/core/clone.d.ts +29 -0
- package/dist/core/clone.js +24 -0
- package/dist/core/color-resolution.js +4 -6
- package/dist/core/column.d.ts +1 -0
- package/dist/core/column.js +6 -2
- package/dist/core/comment-thread.d.ts +7 -3
- package/dist/core/comment-thread.js +2 -1
- package/dist/core/conditional-formatting-overlay.d.ts +11 -1
- package/dist/core/conditional-formatting-overlay.js +30 -3
- package/dist/core/conditional-formatting.d.ts +107 -11
- package/dist/core/conditional-formatting.js +76 -19
- package/dist/core/containers.d.ts +12 -0
- package/dist/core/containers.js +5 -0
- package/dist/core/data-validation-overlay.d.ts +7 -1
- package/dist/core/data-validation-overlay.js +19 -4
- package/dist/core/data-validation.d.ts +22 -0
- package/dist/core/data-validation.js +30 -4
- package/dist/core/date-format.d.ts +20 -0
- package/dist/core/date-format.js +170 -0
- package/dist/core/date.d.ts +43 -8
- package/dist/core/date.js +19 -3
- package/dist/core/formula-references.d.ts +26 -0
- package/dist/core/formula-references.js +173 -0
- package/dist/core/formula-scan.d.ts +2 -0
- package/dist/core/formula-scan.js +58 -0
- package/dist/core/formula.d.ts +76 -17
- package/dist/core/formula.js +87 -80
- package/dist/core/function-values.d.ts +4 -0
- package/dist/core/function-values.js +58 -0
- package/dist/core/future-functions.d.ts +3 -0
- package/dist/core/{modern-functions.js → future-functions.js} +119 -88
- package/dist/core/grid-edits.d.ts +30 -3
- package/dist/core/grid-edits.js +248 -81
- package/dist/core/grid-shift.d.ts +58 -9
- package/dist/core/grid-shift.js +26 -4
- package/dist/core/hyperlink.d.ts +39 -0
- package/dist/core/hyperlink.js +88 -0
- package/dist/core/image.d.ts +49 -14
- package/dist/core/image.js +16 -5
- package/dist/core/internal.d.ts +10 -2
- package/dist/core/limits.d.ts +25 -0
- package/dist/core/limits.js +4 -0
- package/dist/core/merge.d.ts +18 -4
- package/dist/core/merge.js +33 -20
- package/dist/core/page-setup.d.ts +26 -11
- package/dist/core/pivot-table.d.ts +49 -10
- package/dist/core/pivot-table.js +112 -60
- package/dist/core/protection.d.ts +66 -4
- package/dist/core/protection.js +6 -11
- package/dist/core/range.js +34 -30
- package/dist/core/row-input.js +2 -2
- package/dist/core/row.d.ts +1 -0
- package/dist/core/row.js +6 -2
- package/dist/core/structured-reference.d.ts +7 -0
- package/dist/core/structured-reference.js +7 -0
- package/dist/core/style.d.ts +85 -70
- package/dist/core/style.js +92 -28
- package/dist/core/table-style.d.ts +1 -1
- package/dist/core/table-style.js +4 -4
- package/dist/core/table.d.ts +64 -16
- package/dist/core/table.js +87 -40
- package/dist/core/theme.d.ts +2 -0
- package/dist/core/theme.js +9 -5
- package/dist/core/value.d.ts +60 -28
- package/dist/core/value.js +48 -43
- package/dist/core/workbook-media.d.ts +34 -0
- package/dist/core/workbook-media.js +44 -0
- package/dist/core/workbook-styles.d.ts +83 -1
- package/dist/core/workbook-styles.js +4 -0
- package/dist/core/workbook-theme.js +5 -3
- package/dist/core/workbook-vba.js +3 -2
- package/dist/core/workbook.d.ts +41 -3
- package/dist/core/workbook.js +46 -41
- package/dist/core/worksheet-comments.d.ts +2 -1
- package/dist/core/worksheet-comments.js +20 -13
- package/dist/core/worksheet-merges.d.ts +49 -0
- package/dist/core/worksheet-merges.js +65 -0
- package/dist/core/worksheet-model.d.ts +10 -2
- package/dist/core/worksheet-model.js +28 -9
- package/dist/core/worksheet-pictures.d.ts +3 -3
- package/dist/core/worksheet-pictures.js +7 -6
- package/dist/core/worksheet.d.ts +165 -27
- package/dist/core/worksheet.js +206 -89
- package/dist/customui/ribbon.js +2 -1
- package/dist/entries/core.d.ts +21 -14
- package/dist/entries/core.js +14 -7
- package/dist/entries/errors.d.ts +1 -0
- package/dist/entries/errors.js +1 -0
- 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/cell-metadata/metadata.d.ts +42 -0
- package/dist/io/cell-metadata/metadata.js +35 -0
- package/dist/io/cell-metadata/rich-values.d.ts +11 -0
- package/dist/io/cell-metadata/rich-values.js +80 -0
- package/dist/io/csv/delimiter.d.ts +21 -0
- package/dist/io/csv/delimiter.js +18 -0
- package/dist/io/csv/errors.d.ts +14 -0
- package/dist/io/csv/errors.js +5 -0
- package/dist/io/csv/read.d.ts +6 -1
- package/dist/io/csv/read.js +51 -22
- package/dist/io/csv/write.d.ts +19 -5
- package/dist/io/csv/write.js +24 -44
- package/dist/io/opc/inflate.js +14 -0
- 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 +9 -0
- package/dist/io/opc/part-paths.js +5 -5
- package/dist/io/opc/read-opc.d.ts +58 -14
- package/dist/io/opc/read-opc.js +49 -21
- package/dist/io/opc/read-options.d.ts +5 -1
- package/dist/io/opc/sniff-format.d.ts +3 -3
- package/dist/io/opc/sniff-format.js +2 -2
- package/dist/io/opc/strict-relationships.d.ts +2 -0
- package/dist/io/opc/strict-relationships.js +12 -0
- package/dist/io/read-policy/column-budget.d.ts +26 -0
- package/dist/io/read-policy/column-budget.js +18 -0
- package/dist/io/read-policy/read-repair.d.ts +74 -0
- package/dist/io/read-policy/read-repair.js +119 -0
- package/dist/io/style/cell-style-resolution.d.ts +25 -0
- package/dist/io/style/cell-style-resolution.js +30 -0
- package/dist/io/style/xf-style.d.ts +23 -1
- package/dist/io/style/xf-style.js +8 -0
- package/dist/io/xlsb/formula.d.ts +2 -2
- package/dist/io/xlsb/formula.js +52 -35
- 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 +495 -596
- package/dist/io/xlsb/read-metadata.d.ts +7 -0
- package/dist/io/xlsb/read-metadata.js +69 -0
- package/dist/io/xlsb/read-styles.js +45 -81
- package/dist/io/xlsb/read-worksheet.d.ts +26 -1
- package/dist/io/xlsb/read-worksheet.js +148 -106
- package/dist/io/xlsb/read.d.ts +6 -3
- package/dist/io/xlsb/read.js +70 -31
- 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 +14 -5
- package/dist/io/xlsb/record-types.js +14 -5
- package/dist/io/xlsb/sheet-protection.d.ts +20 -0
- package/dist/io/xlsb/sheet-protection.js +60 -0
- package/dist/io/xlsx/cell-accumulator.d.ts +24 -9
- package/dist/io/xlsx/cell-accumulator.js +74 -21
- package/dist/io/xlsx/cell-metadata.d.ts +39 -0
- package/dist/io/xlsx/cell-metadata.js +162 -0
- package/dist/io/xlsx/cell-value.d.ts +19 -5
- package/dist/io/xlsx/cell-value.js +45 -30
- package/dist/io/xlsx/color-xml.js +3 -2
- package/dist/io/xlsx/column-span.d.ts +11 -0
- package/dist/io/xlsx/column-span.js +9 -0
- package/dist/io/xlsx/comments.d.ts +9 -30
- package/dist/io/xlsx/comments.js +25 -83
- package/dist/io/xlsx/conditional-formatting.d.ts +43 -23
- package/dist/io/xlsx/conditional-formatting.js +437 -138
- package/dist/io/xlsx/data-validation.d.ts +12 -7
- package/dist/io/xlsx/data-validation.js +67 -53
- package/dist/io/xlsx/edit-vba.d.ts +7 -2
- package/dist/io/xlsx/edit-vba.js +52 -52
- 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 +19 -21
- package/dist/io/xlsx/hyperlinks.js +12 -32
- package/dist/io/xlsx/images.d.ts +49 -16
- package/dist/io/xlsx/images.js +149 -50
- package/dist/io/xlsx/namespaces.d.ts +24 -0
- package/dist/io/xlsx/namespaces.js +11 -0
- package/dist/io/xlsx/package-plan.d.ts +60 -15
- package/dist/io/xlsx/package-plan.js +83 -18
- package/dist/io/xlsx/part-names.d.ts +6 -8
- package/dist/io/xlsx/part-names.js +3 -7
- package/dist/io/xlsx/pivot.d.ts +5 -5
- package/dist/io/xlsx/pivot.js +26 -24
- package/dist/io/xlsx/preserved-splices.d.ts +6 -0
- package/dist/io/xlsx/preserved-splices.js +74 -0
- package/dist/io/xlsx/read-comments.d.ts +29 -0
- package/dist/io/xlsx/read-comments.js +75 -0
- package/dist/io/xlsx/read-parts.d.ts +59 -0
- package/dist/io/xlsx/read-parts.js +259 -0
- package/dist/io/xlsx/read-pivot.js +11 -4
- package/dist/io/xlsx/{rich-runs.d.ts → read-rich-runs.d.ts} +8 -5
- package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +24 -4
- package/dist/io/xlsx/read-rows.d.ts +35 -11
- package/dist/io/xlsx/read-rows.js +73 -49
- package/dist/io/xlsx/read-shared-strings.js +3 -2
- package/dist/io/xlsx/read-styles.d.ts +0 -30
- package/dist/io/xlsx/read-styles.js +45 -105
- package/dist/io/xlsx/read-workbook-xml.d.ts +42 -0
- package/dist/io/xlsx/read-workbook-xml.js +175 -0
- package/dist/io/xlsx/read-worksheet.d.ts +9 -3
- package/dist/io/xlsx/read-worksheet.js +70 -177
- package/dist/io/xlsx/read.d.ts +3 -14
- package/dist/io/xlsx/read.js +74 -411
- package/dist/io/xlsx/relationships.d.ts +3 -0
- package/dist/io/xlsx/relationships.js +4 -0
- package/dist/io/xlsx/rich-text.js +1 -1
- package/dist/io/xlsx/row-position.d.ts +20 -0
- package/dist/io/xlsx/row-position.js +11 -0
- package/dist/io/xlsx/row-xml.d.ts +139 -0
- package/dist/io/xlsx/row-xml.js +222 -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 +182 -20
- package/dist/io/xlsx/strict-parts.d.ts +7 -0
- package/dist/io/xlsx/strict-parts.js +171 -0
- package/dist/io/xlsx/style-elements.d.ts +41 -0
- package/dist/io/xlsx/style-elements.js +136 -0
- package/dist/io/xlsx/styles.d.ts +17 -3
- package/dist/io/xlsx/styles.js +13 -209
- package/dist/io/xlsx/tables.d.ts +10 -2
- package/dist/io/xlsx/tables.js +55 -52
- package/dist/io/xlsx/theme-xml.d.ts +32 -4
- package/dist/io/xlsx/theme-xml.js +106 -71
- package/dist/io/xlsx/threaded-comments.d.ts +14 -11
- package/dist/io/xlsx/threaded-comments.js +16 -8
- package/dist/io/xlsx/workbook-xml.d.ts +45 -6
- package/dist/io/xlsx/workbook-xml.js +62 -54
- package/dist/io/xlsx/worksheet-xml.d.ts +26 -70
- package/dist/io/xlsx/worksheet-xml.js +69 -282
- package/dist/io/xlsx/write-stream.d.ts +90 -19
- package/dist/io/xlsx/write-stream.js +80 -25
- package/dist/io/xlsx/write.d.ts +12 -6
- package/dist/io/xlsx/write.js +226 -123
- package/dist/rel-type.d.ts +25 -0
- package/dist/rel-type.js +9 -0
- package/dist/token-set.d.ts +13 -0
- package/dist/token-set.js +4 -1
- package/dist/vba/bytes.d.ts +16 -5
- package/dist/vba/bytes.js +27 -6
- package/dist/vba/cfb-format.d.ts +55 -0
- package/dist/vba/cfb-format.js +35 -0
- package/dist/vba/cfb-writer.d.ts +8 -0
- package/dist/vba/cfb-writer.js +40 -40
- package/dist/vba/cfb.d.ts +21 -4
- package/dist/vba/cfb.js +124 -90
- package/dist/vba/codepage.js +2 -1
- package/dist/vba/dir-records.d.ts +6 -0
- package/dist/vba/dir-records.js +10 -2
- package/dist/vba/errors.d.ts +11 -4
- package/dist/vba/index.d.ts +0 -2
- package/dist/vba/index.js +0 -2
- package/dist/vba/ms-ovba.d.ts +6 -2
- package/dist/vba/ms-ovba.js +66 -22
- package/dist/vba/project-editor.js +129 -119
- package/dist/vba/project.d.ts +15 -1
- package/dist/vba/project.js +38 -13
- package/dist/vba/vba-encoding.d.ts +4 -10
- package/dist/vba/vba-encoding.js +3 -17
- 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 +101 -11
- package/dist/xml/xml-read.js +150 -18
- package/dist/xml/xml-scan.d.ts +25 -34
- package/dist/xml/xml-scan.js +69 -46
- package/dist/xml/xml.d.ts +59 -26
- package/dist/xml/xml.js +45 -23
- package/package.json +15 -9
- package/skills/ts-xlsx-upstream/SKILL.md +21 -13
- package/dist/core/modern-functions.d.ts +0 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { XfStyle } from './xf-style.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The cell → row → column → xf 0 style resolution for one worksheet, fed in the order every reader
|
|
4
|
+
* already visits a sheet: column formats before any cell refers to them, a row before its own cells.
|
|
5
|
+
* Columns are 1-based, and a negative style index means "declares no format".
|
|
6
|
+
*/
|
|
7
|
+
export declare class CellStyleResolver {
|
|
8
|
+
#private;
|
|
9
|
+
/** Record the format a span of columns gives its cells. */
|
|
10
|
+
noteColumnSpan(first: number, last: number, styleIndex: number): void;
|
|
11
|
+
/**
|
|
12
|
+
* Open a row. Its format reaches its cells only when the row is marked `customFormat`; without that
|
|
13
|
+
* flag the format describes the row itself and is not inherited.
|
|
14
|
+
*/
|
|
15
|
+
openRow(styleIndex: number, customFormat: boolean): void;
|
|
16
|
+
/** Close the row, so a cell outside one never inherits the last row's format. */
|
|
17
|
+
closeRow(): void;
|
|
18
|
+
/**
|
|
19
|
+
* The style a cell resolves to: its own, else its row's, else its column's, else xf 0. `undefined`
|
|
20
|
+
* only when the index it resolves to names no record in `xfStyles`, a damaged or truncated table.
|
|
21
|
+
*/
|
|
22
|
+
styleFor(col: number, cellStyleIndex: number, xfStyles: ReadonlyArray<XfStyle>): XfStyle | undefined;
|
|
23
|
+
/** Whether the cell, its row or its column declares a format, rather than the cell falling to xf 0. */
|
|
24
|
+
declaresFormat(col: number, cellStyleIndex: number): boolean;
|
|
25
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class CellStyleResolver {
|
|
2
|
+
#columnStyle = new Map();
|
|
3
|
+
#rowStyle = -1;
|
|
4
|
+
noteColumnSpan(first, last, styleIndex) {
|
|
5
|
+
if (styleIndex < 0)
|
|
6
|
+
return;
|
|
7
|
+
for (let index = first; index <= last; index++)
|
|
8
|
+
this.#columnStyle.set(index, styleIndex);
|
|
9
|
+
}
|
|
10
|
+
openRow(styleIndex, customFormat) {
|
|
11
|
+
this.#rowStyle = customFormat ? styleIndex : -1;
|
|
12
|
+
}
|
|
13
|
+
closeRow() {
|
|
14
|
+
this.#rowStyle = -1;
|
|
15
|
+
}
|
|
16
|
+
styleFor(col, cellStyleIndex, xfStyles) {
|
|
17
|
+
const index = this.#indexFor(col, cellStyleIndex);
|
|
18
|
+
return xfStyles[index < 0 ? 0 : index];
|
|
19
|
+
}
|
|
20
|
+
declaresFormat(col, cellStyleIndex) {
|
|
21
|
+
return this.#indexFor(col, cellStyleIndex) >= 0;
|
|
22
|
+
}
|
|
23
|
+
#indexFor(col, cellStyleIndex) {
|
|
24
|
+
if (cellStyleIndex >= 0)
|
|
25
|
+
return cellStyleIndex;
|
|
26
|
+
if (this.#rowStyle >= 0)
|
|
27
|
+
return this.#rowStyle;
|
|
28
|
+
return this.#columnStyle.get(col) ?? -1;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Cell } from '../../core/cell.ts';
|
|
2
|
-
import { type Border, type CellStyle, type Fill, type Font, type
|
|
2
|
+
import { type Border, type CellStyle, type Fill, type Font, type Protection } from '../../core/style.ts';
|
|
3
|
+
import type { NamedCellStyle, TableStyleTable } from '../../core/workbook-styles.ts';
|
|
3
4
|
/**
|
|
4
5
|
* What an xf resolves to: the {@link CellStyle} facet tuple, plus the two flags an xf carries that
|
|
5
6
|
* are not facets. Absent facets stay undefined, matching the contract that an unset facet is simply
|
|
@@ -74,6 +75,27 @@ export declare function numFmtCodeFor(id: number, custom: ReadonlyMap<number, st
|
|
|
74
75
|
* from, and the two cannot drift on what "applying a style" means.
|
|
75
76
|
*/
|
|
76
77
|
export declare function applyXfToCell(cell: Cell, style: XfStyle | undefined): void;
|
|
78
|
+
/**
|
|
79
|
+
* A cell's protection facets from the two flags either serialisation states, keeping only what
|
|
80
|
+
* carries information.
|
|
81
|
+
*
|
|
82
|
+
* `locked` defaults to TRUE in OOXML, so an explicitly *unlocked* cell is the state worth recording
|
|
83
|
+
* and a locked one merely restates the default; `hidden` defaults to false, so only a set flag does.
|
|
84
|
+
* An xf that states neither yields no protection at all rather than an empty object, which is what
|
|
85
|
+
* keeps the two readings of one workbook identical.
|
|
86
|
+
*
|
|
87
|
+
* Here rather than once per codec because that is exactly what it was: `parseProtection` in the XML
|
|
88
|
+
* reader and `readProtection` in the binary one, two spellings of two default rules, agreeing by
|
|
89
|
+
* review. The inputs differ (an attribute is tri-state, a bit is not) and the rule does not, so the
|
|
90
|
+
* codecs keep the parsing and share the rule.
|
|
91
|
+
*
|
|
92
|
+
* @param locked the `locked` attribute's tri-state reading, or the bit's boolean; `undefined` where
|
|
93
|
+
* the file states nothing.
|
|
94
|
+
*/
|
|
95
|
+
export declare function protectionFrom(flags: {
|
|
96
|
+
readonly locked?: boolean | undefined;
|
|
97
|
+
readonly hidden?: boolean | undefined;
|
|
98
|
+
}): Protection | undefined;
|
|
77
99
|
/**
|
|
78
100
|
* A `<cellStyle>` / `BrtStyle` label: the name and builtinId that title one `cellStyleXfs` entry,
|
|
79
101
|
* keyed to that entry's index.
|
|
@@ -69,6 +69,14 @@ export function applyXfToCell(cell, style) {
|
|
|
69
69
|
if (style.xfId !== undefined)
|
|
70
70
|
cell[NAMED_STYLE_ID] = style.xfId;
|
|
71
71
|
}
|
|
72
|
+
export function protectionFrom(flags) {
|
|
73
|
+
const out = {};
|
|
74
|
+
if (flags.locked === false)
|
|
75
|
+
out.locked = false;
|
|
76
|
+
if (flags.hidden === true)
|
|
77
|
+
out.hidden = true;
|
|
78
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
79
|
+
}
|
|
72
80
|
export function resolveStyleTable(tables) {
|
|
73
81
|
const { directXfs, namedXfs, labels, fonts } = tables;
|
|
74
82
|
const cellXfs = directXfs.map((xf) => {
|
|
@@ -34,8 +34,8 @@ export interface FormulaAnchor {
|
|
|
34
34
|
* @param rgce the token stream.
|
|
35
35
|
* @param rgcb the trailing extra-data block: the array constants, and the cell ranges a precomputed
|
|
36
36
|
* range token refers to. Its entries are consumed in token order.
|
|
37
|
-
* @returns the formula text, or `undefined` if the stream uses a token this reader does not decode
|
|
38
|
-
*
|
|
37
|
+
* @returns the formula text, or `undefined` if the stream uses a token this reader does not decode,
|
|
38
|
+
* or runs off the end of its own record.
|
|
39
39
|
*/
|
|
40
40
|
export declare function decodeFormula(rgce: Uint8Array, rgcb: Uint8Array, scope: FormulaScope): string | undefined;
|
|
41
41
|
/**
|
package/dist/io/xlsb/formula.js
CHANGED
|
@@ -1,19 +1,35 @@
|
|
|
1
|
-
import { MAX_COLUMN, numberToColumn } from '../../core/address.js';
|
|
2
|
-
import { quoteSheetName } from '../../core/formula.js';
|
|
1
|
+
import { MAX_COLUMN, MAX_COLUMN_INDEX, MAX_ROW_INDEX, numberToColumn } from '../../core/address.js';
|
|
2
|
+
import { formulaNumberLiteral, quoteSheetName } from '../../core/formula.js';
|
|
3
|
+
import { REF_ERROR } from '../../core/value.js';
|
|
4
|
+
import { XlsbParseError } from './errors.js';
|
|
3
5
|
import { errorCodeFor, RecordReader } from './primitives.js';
|
|
4
|
-
import {
|
|
6
|
+
import { builtinFunctionAt, FTAB_USER_DEFINED, functionNameFor } from './ptg-functions.js';
|
|
5
7
|
export function decodeFormula(rgce, rgcb, scope) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
try {
|
|
9
|
+
return decodeTokens(rgce, rgcb, scope);
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
if (error instanceof XlsbParseError)
|
|
13
|
+
return undefined;
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function decodeTokens(rgce, rgcb, scope) {
|
|
8
18
|
const stack = [];
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
stack
|
|
13
|
-
|
|
19
|
+
const decode = {
|
|
20
|
+
tokens: new RecordReader(rgce),
|
|
21
|
+
extra: new RecordReader(rgcb),
|
|
22
|
+
stack,
|
|
23
|
+
scope,
|
|
24
|
+
push: (text) => {
|
|
25
|
+
if (text === undefined || text.length > MAX_DECODED_FORMULA_LENGTH)
|
|
26
|
+
return false;
|
|
27
|
+
stack.push(text);
|
|
28
|
+
return true;
|
|
29
|
+
},
|
|
14
30
|
};
|
|
15
|
-
while (!tokens.done) {
|
|
16
|
-
if (!step(tokens.u8(),
|
|
31
|
+
while (!decode.tokens.done) {
|
|
32
|
+
if (!step(decode.tokens.u8(), decode))
|
|
17
33
|
return undefined;
|
|
18
34
|
}
|
|
19
35
|
return stack.length === 1 ? stack[0] : undefined;
|
|
@@ -29,7 +45,8 @@ export function formulaAnchor(rgce, rgcb) {
|
|
|
29
45
|
return undefined;
|
|
30
46
|
return { row, column: extra.u32() };
|
|
31
47
|
}
|
|
32
|
-
function step(ptg,
|
|
48
|
+
function step(ptg, decode) {
|
|
49
|
+
const { tokens, stack, push } = decode;
|
|
33
50
|
const binary = BINARY_OPERATORS.get(ptg);
|
|
34
51
|
if (binary !== undefined) {
|
|
35
52
|
const right = stack.pop();
|
|
@@ -54,33 +71,33 @@ function step(ptg, tokens, extra, stack, scope, push) {
|
|
|
54
71
|
case PTG.Str:
|
|
55
72
|
return push(quoteString(tokens.shortString()));
|
|
56
73
|
case PTG.Attr:
|
|
57
|
-
return attribute(
|
|
74
|
+
return attribute(decode);
|
|
58
75
|
case PTG.Err:
|
|
59
76
|
return push(errorCodeFor(tokens.u8()));
|
|
60
77
|
case PTG.Bool:
|
|
61
78
|
return push(tokens.u8() !== 0 ? 'TRUE' : 'FALSE');
|
|
62
79
|
case PTG.Int:
|
|
63
|
-
return push(
|
|
80
|
+
return push(numberLiteral(tokens.u16()));
|
|
64
81
|
case PTG.Num:
|
|
65
|
-
return push(
|
|
82
|
+
return push(numberLiteral(tokens.f64()));
|
|
66
83
|
default:
|
|
67
|
-
return ptg >= CLASSED_TOKEN_FLOOR
|
|
68
|
-
? operand((ptg & CLASSED_TOKEN_MASK) | CLASSED_TOKEN_FLOOR,
|
|
84
|
+
return ptg >= CLASSED_TOKEN_FLOOR && ptg <= CLASSED_TOKEN_CEILING
|
|
85
|
+
? operand((ptg & CLASSED_TOKEN_MASK) | CLASSED_TOKEN_FLOOR, decode)
|
|
69
86
|
: false;
|
|
70
87
|
}
|
|
71
88
|
}
|
|
72
|
-
function operand(base,
|
|
89
|
+
function operand(base, decode) {
|
|
90
|
+
const { tokens, extra, stack, scope, push } = decode;
|
|
73
91
|
switch (base) {
|
|
74
92
|
case PTG.Array:
|
|
75
93
|
tokens.skip(14);
|
|
76
94
|
return push(arrayConstant(extra));
|
|
77
95
|
case PTG.Func: {
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
return name !== undefined && arity !== undefined && push(call(name, arity, stack));
|
|
96
|
+
const fn = builtinFunctionAt(tokens.u16());
|
|
97
|
+
return fn !== undefined && fn[1] !== 'variadic' && push(call(fn[0], fn[1], stack));
|
|
81
98
|
}
|
|
82
99
|
case PTG.FuncVar:
|
|
83
|
-
return variadicCall(
|
|
100
|
+
return variadicCall(decode);
|
|
84
101
|
case PTG.Name: {
|
|
85
102
|
return push(scope.names[tokens.u32() - 1]);
|
|
86
103
|
}
|
|
@@ -100,16 +117,16 @@ function operand(base, tokens, extra, stack, scope, push) {
|
|
|
100
117
|
}
|
|
101
118
|
case PTG.RefErr:
|
|
102
119
|
tokens.skip(6);
|
|
103
|
-
return push(
|
|
120
|
+
return push(REF_ERROR);
|
|
104
121
|
case PTG.AreaErr:
|
|
105
122
|
tokens.skip(12);
|
|
106
|
-
return push(
|
|
123
|
+
return push(REF_ERROR);
|
|
107
124
|
case PTG.RefErr3d:
|
|
108
125
|
tokens.skip(8);
|
|
109
|
-
return push(
|
|
126
|
+
return push(REF_ERROR);
|
|
110
127
|
case PTG.AreaErr3d:
|
|
111
128
|
tokens.skip(14);
|
|
112
|
-
return push(
|
|
129
|
+
return push(REF_ERROR);
|
|
113
130
|
case PTG.MemArea:
|
|
114
131
|
tokens.skip(6);
|
|
115
132
|
return skipExtraRanges(extra);
|
|
@@ -117,7 +134,7 @@ function operand(base, tokens, extra, stack, scope, push) {
|
|
|
117
134
|
return false;
|
|
118
135
|
}
|
|
119
136
|
}
|
|
120
|
-
function attribute(tokens, stack, push) {
|
|
137
|
+
function attribute({ tokens, stack, push }) {
|
|
121
138
|
const flags = tokens.u8();
|
|
122
139
|
const data = tokens.u16();
|
|
123
140
|
if ((flags & ATTR_CHOOSE) !== 0) {
|
|
@@ -128,7 +145,7 @@ function attribute(tokens, stack, push) {
|
|
|
128
145
|
return push(call('SUM', 1, stack));
|
|
129
146
|
return true;
|
|
130
147
|
}
|
|
131
|
-
function variadicCall(tokens, stack, push) {
|
|
148
|
+
function variadicCall({ tokens, stack, push }) {
|
|
132
149
|
const count = tokens.u8() & FUNCVAR_PARAM_MASK;
|
|
133
150
|
const index = tokens.u16() & FUNCVAR_INDEX_MASK;
|
|
134
151
|
if (index !== FTAB_USER_DEFINED) {
|
|
@@ -167,7 +184,7 @@ function arrayConstant(extra) {
|
|
|
167
184
|
function arrayElement(extra) {
|
|
168
185
|
switch (extra.u8()) {
|
|
169
186
|
case SER_NUM:
|
|
170
|
-
return
|
|
187
|
+
return numberLiteral(extra.f64());
|
|
171
188
|
case SER_STR:
|
|
172
189
|
return quoteString(extra.shortString());
|
|
173
190
|
case SER_BOOL:
|
|
@@ -212,7 +229,7 @@ function rangeText(rowFirst, rowLast, packedFirst, packedLast) {
|
|
|
212
229
|
const last = columnOnly(packedLast);
|
|
213
230
|
return first === undefined || last === undefined ? undefined : `${first}:${last}`;
|
|
214
231
|
}
|
|
215
|
-
if ((packedFirst & COLUMN_MASK) === 0 && (packedLast & COLUMN_MASK) ===
|
|
232
|
+
if ((packedFirst & COLUMN_MASK) === 0 && (packedLast & COLUMN_MASK) === MAX_COLUMN_INDEX) {
|
|
216
233
|
return rowFirst > MAX_ROW_INDEX || rowLast > MAX_ROW_INDEX
|
|
217
234
|
? undefined
|
|
218
235
|
: `${rowOnly(rowFirst, packedFirst)}:${rowOnly(rowLast, packedLast)}`;
|
|
@@ -233,10 +250,9 @@ function rowOnly(row, packedColumn) {
|
|
|
233
250
|
function quoteString(text) {
|
|
234
251
|
return `"${text.replace(/"/g, '""')}"`;
|
|
235
252
|
}
|
|
236
|
-
function
|
|
237
|
-
return
|
|
253
|
+
function numberLiteral(value) {
|
|
254
|
+
return Number.isFinite(value) ? formulaNumberLiteral(value) : undefined;
|
|
238
255
|
}
|
|
239
|
-
const REFERENCE_ERROR = '#REF!';
|
|
240
256
|
const BINARY_OPERATORS = new Map([
|
|
241
257
|
[0x03, '+'],
|
|
242
258
|
[0x04, '-'],
|
|
@@ -283,7 +299,9 @@ const PTG = {
|
|
|
283
299
|
AreaErr3d: 0x3d,
|
|
284
300
|
};
|
|
285
301
|
const CLASSED_TOKEN_FLOOR = 0x20;
|
|
302
|
+
const CLASSED_TOKEN_CEILING = 0x7f;
|
|
286
303
|
const CLASSED_TOKEN_MASK = 0x1f;
|
|
304
|
+
const MAX_DECODED_FORMULA_LENGTH = 4 * 8_192;
|
|
287
305
|
const ATTR_CHOOSE = 0x04;
|
|
288
306
|
const ATTR_SUM = 0x10;
|
|
289
307
|
const FUNCVAR_PARAM_MASK = 0x7f;
|
|
@@ -291,7 +309,6 @@ const FUNCVAR_INDEX_MASK = 0x7fff;
|
|
|
291
309
|
const COLUMN_MASK = 0x3fff;
|
|
292
310
|
const COLUMN_RELATIVE = 0x4000;
|
|
293
311
|
const ROW_RELATIVE = 0x8000;
|
|
294
|
-
const MAX_ROW_INDEX = 1048575;
|
|
295
312
|
const SER_NUM = 0x00;
|
|
296
313
|
const SER_STR = 0x01;
|
|
297
314
|
const SER_BOOL = 0x02;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
+
import { decodeUtf16le } from '../../bytes.js';
|
|
1
2
|
import { isErrorCode } from '../../core/value.js';
|
|
3
|
+
import { hex } from '../../hex.js';
|
|
2
4
|
import { XlsbParseError } from './errors.js';
|
|
3
|
-
const CHARS_PER_BATCH = 4096;
|
|
4
5
|
const NULL_STRING_LENGTH = 0xffffffff;
|
|
5
6
|
const rkScratch = new DataView(new ArrayBuffer(8));
|
|
6
7
|
export class RecordReader {
|
|
7
8
|
#data;
|
|
8
|
-
#
|
|
9
|
+
#cachedView;
|
|
9
10
|
#offset = 0;
|
|
10
11
|
constructor(data) {
|
|
11
12
|
this.#data = data;
|
|
12
|
-
|
|
13
|
+
}
|
|
14
|
+
get #view() {
|
|
15
|
+
return (this.#cachedView ??= new DataView(this.#data.buffer, this.#data.byteOffset, this.#data.byteLength));
|
|
13
16
|
}
|
|
14
17
|
get remaining() {
|
|
15
18
|
return this.#data.length - this.#offset;
|
|
@@ -89,16 +92,7 @@ export class RecordReader {
|
|
|
89
92
|
}
|
|
90
93
|
#characters(count) {
|
|
91
94
|
const start = this.#take(count * 2);
|
|
92
|
-
|
|
93
|
-
let batch = [];
|
|
94
|
-
for (let index = 0; index < count; index++) {
|
|
95
|
-
batch.push(this.#view.getUint16(start + index * 2, true));
|
|
96
|
-
if (batch.length === CHARS_PER_BATCH) {
|
|
97
|
-
text += String.fromCharCode(...batch);
|
|
98
|
-
batch = [];
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return batch.length > 0 ? text + String.fromCharCode(...batch) : text;
|
|
95
|
+
return decodeUtf16le(this.#data.subarray(start, start + count * 2));
|
|
102
96
|
}
|
|
103
97
|
#take(count) {
|
|
104
98
|
if (count > this.remaining) {
|
|
@@ -144,5 +138,5 @@ function colorByType(type, index, alpha, red, green, blue) {
|
|
|
144
138
|
}
|
|
145
139
|
}
|
|
146
140
|
function hexByte(value) {
|
|
147
|
-
return value
|
|
141
|
+
return hex(value, 2);
|
|
148
142
|
}
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
/** The index [MS-XLS] reserves for a call whose name is given by the token stream's first operand. */
|
|
2
2
|
export declare const FTAB_USER_DEFINED = 255;
|
|
3
|
-
/** Look up a built-in function name by its `iftab` index, or `undefined` if the index names none. */
|
|
4
|
-
export declare function functionNameFor(index: number): string | undefined;
|
|
5
3
|
/**
|
|
6
|
-
*
|
|
4
|
+
* One built-in function: the name an `iftab` index means, and how many arguments it takes.
|
|
7
5
|
*
|
|
8
|
-
* A `PtgFunc` token states only *which* function is called, never with
|
|
9
|
-
* token Excel emits precisely because the count is implied by the
|
|
10
|
-
* back from its two operands and one call token is impossible
|
|
11
|
-
*
|
|
12
|
-
*
|
|
6
|
+
* The arity is not decoration. A `PtgFunc` token states only *which* function is called, never with
|
|
7
|
+
* how many arguments: it is the token Excel emits precisely because the count is implied by the
|
|
8
|
+
* function. So decoding `ROUND(A1,2)` back from its two operands and one call token is impossible
|
|
9
|
+
* without it, and `'variadic'` says the call cannot be spelled with that token at all (`PtgFuncVar`
|
|
10
|
+
* carries its own count; the two token forms partition the table between them). Transcribed from the
|
|
11
|
+
* parameter grammar each function's [MS-XLS] 2.5.198.17 entry states.
|
|
13
12
|
*
|
|
14
|
-
*
|
|
13
|
+
* It used to live in a second table keyed by name, which let an entry exist in one and not the other
|
|
14
|
+
* with nothing to say so. A function whose arity was never transcribed simply read as variadic, and a
|
|
15
|
+
* `PtgFunc` citing it then took the wrong run of operands off the stack and produced a different
|
|
16
|
+
* formula, silently. Recording it beside the name makes "no arity recorded" unrepresentable: the
|
|
17
|
+
* compiler asks for it once per entry, and `'variadic'` becomes a decision written down rather than
|
|
18
|
+
* an absence that looks like one.
|
|
15
19
|
*/
|
|
16
|
-
export
|
|
20
|
+
export type FunctionEntry = readonly [name: string, arity: number | 'variadic'];
|
|
21
|
+
/** The built-in function an `iftab` index names, or `undefined` if the index names none. */
|
|
22
|
+
export declare function builtinFunctionAt(index: number): FunctionEntry | undefined;
|
|
23
|
+
/** Look up a built-in function name by its `iftab` index, or `undefined` if the index names none. */
|
|
24
|
+
export declare function functionNameFor(index: number): string | undefined;
|
|
25
|
+
export declare const FTAB: readonly (FunctionEntry | undefined)[];
|