@guiexpert/table 1.1.98 → 1.1.99
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 +9 -0
- package/css/main.css +296 -0
- package/css/table-clipboard.css +41 -0
- package/css/table-color-vars.css +56 -0
- package/css/table-sheet-editing.css +149 -0
- package/css/table-spreadsheet.css +50 -0
- package/index.cjs +46 -59
- package/index.d.ts +46 -0
- package/index.js +18934 -11624
- package/lib/table/action/action-id.type.d.ts +1 -1
- package/lib/table/action/shortcut.service.d.ts +9 -0
- package/lib/table/aria/aria-texts.d.ts +26 -0
- package/lib/table/aria/aria-texts.if.d.ts +196 -0
- package/lib/table/batch-edit/batch-edit-service.d.ts +22 -0
- package/lib/table/batch-edit/cell-change.if.d.ts +6 -2
- package/lib/table/batch-edit/pending-cell-changes.d.ts +7 -0
- package/lib/table/batch-edit/write-row-value.d.ts +14 -0
- package/lib/table/calc/column-values.d.ts +2 -0
- package/lib/table/clipboard/clipboard-html.d.ts +41 -0
- package/lib/table/clipboard/clipboard-keymap.d.ts +18 -0
- package/lib/table/clipboard/clipboard-options.d.ts +30 -0
- package/lib/table/clipboard/clipboard-options.if.d.ts +67 -0
- package/lib/table/clipboard/clipboard-service.d.ts +122 -0
- package/lib/table/clipboard/input-pipes.d.ts +59 -0
- package/lib/table/clipboard/paste-plan.d.ts +96 -0
- package/lib/table/clipboard/tsv.d.ts +31 -0
- package/lib/table/data/common/event/ge-edit-event.d.ts +46 -0
- package/lib/table/data/common/event/ge-row-drag-event.d.ts +2 -2
- package/lib/table/data/common/event/ge-undo-event.d.ts +29 -0
- package/lib/table/data/options/table-options.d.ts +28 -0
- package/lib/table/data/options/table-options.if.d.ts +99 -1
- package/lib/table/data/tablemodel/areamodel/abstract-area-model.d.ts +11 -2
- package/lib/table/data/tablemodel/areamodel/area-model-array-of-arrays.d.ts +14 -0
- package/lib/table/data/tablemodel/areamodel/area-model-object-array.d.ts +14 -0
- package/lib/table/data/tablemodel/areamodel/area-model.if.d.ts +11 -0
- package/lib/table/data/tablemodel/column/column-def.d.ts +13 -0
- package/lib/table/data/tablemodel/column/column-def.if.d.ts +36 -1
- package/lib/table/data/tablemodel/column/default-editable.d.ts +18 -0
- package/lib/table/event-adapter.d.ts +6 -0
- package/lib/table/event-listener-hub.d.ts +10 -0
- package/lib/table/event-listener.if.d.ts +16 -0
- package/lib/table/factory/pivot-factory.d.ts +1 -1
- package/lib/table/factory/row-group-factory.d.ts +1 -1
- package/lib/table/factory/table-factory.d.ts +14 -0
- package/lib/table/formula/formula-ast.if.d.ts +32 -2
- package/lib/table/formula/formula-error.d.ts +4 -2
- package/lib/table/formula/parser.d.ts +5 -2
- package/lib/table/formula/tokenizer.d.ts +5 -2
- package/lib/table/input-handler.d.ts +8 -0
- package/lib/table/master-detail/master-detail-service.d.ts +9 -0
- package/lib/table/render-scope.d.ts +40 -0
- package/lib/table/row-drag/row-drag-service.d.ts +3 -2
- package/lib/table/selection/selection-service.d.ts +48 -0
- package/lib/table/service/excel-export-options.if.d.ts +6 -0
- package/lib/table/service/excel-service.d.ts +4 -0
- package/lib/table/service/excel-service.if.d.ts +35 -0
- package/lib/table/sheet/cell-address.d.ts +100 -0
- package/lib/table/sheet/cell-formula-options.d.ts +27 -0
- package/lib/table/sheet/cell-formula-options.if.d.ts +27 -0
- package/lib/table/sheet/excel-formula.d.ts +20 -0
- package/lib/table/sheet/format-formula.d.ts +19 -0
- package/lib/table/sheet/sheet-cells.if.d.ts +17 -0
- package/lib/table/sheet/sheet-compiler.d.ts +47 -0
- package/lib/table/sheet/sheet-engine.d.ts +207 -0
- package/lib/table/sheet/sheet-function-info.d.ts +25 -0
- package/lib/table/sheet/sheet-functions.d.ts +27 -0
- package/lib/table/sheet/sheet-values.d.ts +154 -0
- package/lib/table/sheet/shift-formula.d.ts +71 -0
- package/lib/table/sheet/table-sheet.d.ts +214 -0
- package/lib/table/sheet-editing/cell-editor-service.d.ts +105 -0
- package/lib/table/sheet-editing/cell-editor.if.d.ts +110 -0
- package/lib/table/sheet-editing/editing-keymap.d.ts +17 -0
- package/lib/table/sheet-editing/editing-options.d.ts +34 -0
- package/lib/table/sheet-editing/editing-options.if.d.ts +49 -0
- package/lib/table/sheet-editing/editors/date-cell-editor.d.ts +23 -0
- package/lib/table/sheet-editing/editors/number-cell-editor.d.ts +18 -0
- package/lib/table/sheet-editing/editors/select-cell-editor.d.ts +36 -0
- package/lib/table/sheet-editing/editors/text-cell-editor.d.ts +35 -0
- package/lib/table/sheet-editing/formula-assist.d.ts +103 -0
- package/lib/table/sheet-editing/formula-text.d.ts +61 -0
- package/lib/table/sheet-editing/sheet-navigation.d.ts +26 -0
- package/lib/table/spreadsheet/area-model-sheet.d.ts +170 -0
- package/lib/table/spreadsheet/formula-bar.d.ts +53 -0
- package/lib/table/spreadsheet/spreadsheet-factory.d.ts +111 -0
- package/lib/table/spreadsheet/spreadsheet-options.if.d.ts +28 -0
- package/lib/table/spreadsheet/spreadsheet-preset.d.ts +37 -0
- package/lib/table/spreadsheet/structure-edit.d.ts +35 -0
- package/lib/table/table-api.d.ts +511 -2
- package/lib/table/table-scope.d.ts +294 -1
- package/lib/table/undo/cell-changes-undoable.d.ts +34 -0
- package/lib/table/undo/model-rows.d.ts +17 -0
- package/lib/table/undo/pending-changes-undoable.d.ts +35 -0
- package/lib/table/undo/undo-keymap.d.ts +17 -0
- package/lib/table/undo/undo-options.d.ts +26 -0
- package/lib/table/undo/undo-options.if.d.ts +30 -0
- package/lib/table/undo/undo-service.d.ts +103 -0
- package/lib/table/undo/undo-stack.d.ts +62 -0
- package/lib/table/undo/undoable.if.d.ts +36 -0
- package/package.json +1 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/** Rows of a sheet (like Excel): 1 … 1 048 576. */
|
|
2
|
+
export declare const SHEET_MAX_ROWS = 1048576;
|
|
3
|
+
/** Columns of a sheet (like Excel): A … XFD = 16 384. */
|
|
4
|
+
export declare const SHEET_MAX_COLUMNS = 16384;
|
|
5
|
+
/**
|
|
6
|
+
* The letters of a column (0-based): 0 → `"A"`, 25 → `"Z"`, 26 → `"AA"`, 16 383 → `"XFD"`.
|
|
7
|
+
*
|
|
8
|
+
* @param {number} columnIndex - 0-based column
|
|
9
|
+
* @returns {string} the letters (`""` for an index outside 0 … 16 383)
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* columnLetter(27); // "AB"
|
|
13
|
+
*
|
|
14
|
+
* @category Spreadsheet
|
|
15
|
+
* @since 1.1.99
|
|
16
|
+
*/
|
|
17
|
+
export declare function columnLetter(columnIndex: number): string;
|
|
18
|
+
/**
|
|
19
|
+
* The 0-based column of letters: `"A"` → 0, `"ab"` → 27 (case does not matter).
|
|
20
|
+
*
|
|
21
|
+
* @param {string} letters - column letters
|
|
22
|
+
* @returns {number} the column, `-1` if invalid or beyond `XFD`
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* columnIndexOfLetter("XFD"); // 16383
|
|
26
|
+
*
|
|
27
|
+
* @category Spreadsheet
|
|
28
|
+
* @since 1.1.99
|
|
29
|
+
*/
|
|
30
|
+
export declare function columnIndexOfLetter(letters: string): number;
|
|
31
|
+
/**
|
|
32
|
+
* A parsed cell address: 0-based row and column, `$` = absolute.
|
|
33
|
+
*
|
|
34
|
+
* @category Spreadsheet
|
|
35
|
+
* @since 1.1.99
|
|
36
|
+
*/
|
|
37
|
+
export interface CellAddressIf {
|
|
38
|
+
row: number;
|
|
39
|
+
col: number;
|
|
40
|
+
absRow: boolean;
|
|
41
|
+
absCol: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The address of a cell: `toCellAddress(2, 1)` → `"B3"`, with `$` for absolute parts.
|
|
45
|
+
*
|
|
46
|
+
* @param {number} row - 0-based row
|
|
47
|
+
* @param {number} col - 0-based column
|
|
48
|
+
* @param {{ absRow?: boolean, absCol?: boolean }} [abs] - `$` before the row / column
|
|
49
|
+
* @returns {string} the address, `"#REF!"` outside the sheet
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* toCellAddress(0, 5, { absRow: true, absCol: true }); // "$F$1"
|
|
53
|
+
*
|
|
54
|
+
* @category Spreadsheet
|
|
55
|
+
* @since 1.1.99
|
|
56
|
+
*/
|
|
57
|
+
export declare function toCellAddress(row: number, col: number, abs?: {
|
|
58
|
+
absRow?: boolean;
|
|
59
|
+
absCol?: boolean;
|
|
60
|
+
}): string;
|
|
61
|
+
/**
|
|
62
|
+
* Parses a cell address like `"B3"`, `"$B$3"`, `"b$3"`.
|
|
63
|
+
*
|
|
64
|
+
* @param {string} address - the address
|
|
65
|
+
* @returns {CellAddressIf | undefined} row, column (0-based) and the absolute parts; `undefined` if invalid
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* parseCellAddress("$B3"); // { row: 2, col: 1, absRow: false, absCol: true }
|
|
69
|
+
*
|
|
70
|
+
* @category Spreadsheet
|
|
71
|
+
* @since 1.1.99
|
|
72
|
+
*/
|
|
73
|
+
export declare function parseCellAddress(address: string): CellAddressIf | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* A parsed range: first and last cell (0-based, inclusive). A whole column (`"A:A"`) has the rows 0 … 1 048 575 and
|
|
76
|
+
* `wholeColumns: true`, a whole row (`"3:3"`) the columns 0 … 16 383 and `wholeRows: true`.
|
|
77
|
+
*
|
|
78
|
+
* @category Spreadsheet
|
|
79
|
+
* @since 1.1.99
|
|
80
|
+
*/
|
|
81
|
+
export interface RangeAddressIf {
|
|
82
|
+
from: CellAddressIf;
|
|
83
|
+
to: CellAddressIf;
|
|
84
|
+
wholeColumns?: boolean;
|
|
85
|
+
wholeRows?: boolean;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Parses a range like `"A1:B5"`, `"$A$1:B5"`, `"A:A"`, `"B:D"`, `"3:3"` or a single cell `"C7"`. The corners are
|
|
89
|
+
* sorted (`"B5:A1"` = `"A1:B5"`).
|
|
90
|
+
*
|
|
91
|
+
* @param {string} address - the range
|
|
92
|
+
* @returns {RangeAddressIf | undefined} the range; `undefined` if invalid
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* parseRangeAddress("A:A")?.to.row; // 1048575
|
|
96
|
+
*
|
|
97
|
+
* @category Spreadsheet
|
|
98
|
+
* @since 1.1.99
|
|
99
|
+
*/
|
|
100
|
+
export declare function parseRangeAddress(address: string): RangeAddressIf | undefined;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { FormulaFunction } from '../formula/formula-options.if.js';
|
|
2
|
+
import { CellFormulaOptionsIf } from './cell-formula-options.if.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The defaults of {@link CellFormulaOptionsIf} (cell formulas).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* CellFormulaOptions.create(true)?.maxRangeCells; // 10000000
|
|
9
|
+
*
|
|
10
|
+
* @category Spreadsheet
|
|
11
|
+
* @since 1.1.99
|
|
12
|
+
*/
|
|
13
|
+
export declare class CellFormulaOptions implements CellFormulaOptionsIf {
|
|
14
|
+
functions: Record<string, FormulaFunction>;
|
|
15
|
+
isoDatesAsDates: boolean;
|
|
16
|
+
maxRangeCells: number;
|
|
17
|
+
rejectInvalidFormulas: boolean;
|
|
18
|
+
columns?: string[];
|
|
19
|
+
/**
|
|
20
|
+
* The options of {@link TableOptionsIf.cellFormulas}: `undefined`/`false` = off, `true` = the defaults, an object =
|
|
21
|
+
* the defaults overridden by its values (`undefined` keeps the default).
|
|
22
|
+
*
|
|
23
|
+
* @param {boolean | Partial<CellFormulaOptionsIf>} [option] - the option
|
|
24
|
+
* @returns {CellFormulaOptionsIf | undefined} complete options, `undefined` if off
|
|
25
|
+
*/
|
|
26
|
+
static create(option?: boolean | Partial<CellFormulaOptionsIf>): CellFormulaOptionsIf | undefined;
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { FormulaFunction } from '../formula/formula-options.if.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cell formulas like in Excel ({@link TableOptionsIf.cellFormulas}, {@link SheetEngine}): `=B2*C2`, `=SUM(D2:D100)`.
|
|
5
|
+
* `cellFormulas: true` uses the defaults of {@link CellFormulaOptions}; an object overrides single values.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const engine = SheetEngine.fromArrays(data, { functions: { VAT: (net) => Number(net) * 0.19 } });
|
|
9
|
+
*
|
|
10
|
+
* @category Spreadsheet
|
|
11
|
+
* @since 1.1.99
|
|
12
|
+
*/
|
|
13
|
+
export interface CellFormulaOptionsIf {
|
|
14
|
+
/**
|
|
15
|
+
* Own functions by name (case-insensitive); they may replace built-in ones. A range argument (`A1:B5`) arrives as
|
|
16
|
+
* {@link FormulaRange}, a date as its serial number.
|
|
17
|
+
*/
|
|
18
|
+
functions: Record<string, FormulaFunction>;
|
|
19
|
+
/** ISO text (`"2026-10-16"`) counts as date in arithmetic (`=A2+1`) and date functions. Default `true`. */
|
|
20
|
+
isoDatesAsDates: boolean;
|
|
21
|
+
/** Larger ranges are `#ERROR!` (`A1:XFD1048576`). Default `10_000_000`. */
|
|
22
|
+
maxRangeCells: number;
|
|
23
|
+
/** The table refuses formulas with a syntax error instead of storing them (`#ERROR!`). Default `false`. */
|
|
24
|
+
rejectInvalidFormulas: boolean;
|
|
25
|
+
/** Only these properties hold formulas (the other columns keep `=…` as text). Default: every data column. */
|
|
26
|
+
columns?: string[];
|
|
27
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Where the data of the sheet lie in the file: rows above, columns in front, and their number. */
|
|
2
|
+
export interface ExcelSheetPlacementIf {
|
|
3
|
+
dRow: number;
|
|
4
|
+
dCol: number;
|
|
5
|
+
rows: number;
|
|
6
|
+
cols: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The formula of a cell formula for an Excel file: all references moved by the offset of the sheet (header rows,
|
|
10
|
+
* leading columns – also absolute parts), whole columns/rows bounded to the data (the file holds headers and totals
|
|
11
|
+
* around them), newer functions with `_xlfn.`. `undefined` for a formula Excel cannot read: a syntax error or a field
|
|
12
|
+
* (`[price]`). Text without `=`.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} input - the cell formula (with `=`)
|
|
15
|
+
* @param {ExcelSheetPlacementIf} at - where the data are in the file
|
|
16
|
+
* @returns {string | undefined} the Excel formula
|
|
17
|
+
*
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export declare function toExcelFormula(input: string, at: ExcelSheetPlacementIf): string | undefined;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FormulaNode, FormulaRefNode } from '../formula/formula-ast.if.js';
|
|
2
|
+
|
|
3
|
+
/** A reference as text: `B3`, `$B$3`; whole columns/rows in ranges. */
|
|
4
|
+
export declare function formatRef(ref: FormulaRefNode): string;
|
|
5
|
+
/**
|
|
6
|
+
* The canonical text of a formula AST (without `=`): functions and references in capitals, `,` between arguments,
|
|
7
|
+
* texts with `""` for a quotation mark, parentheses only where needed. Used for moving formulas and the Excel export.
|
|
8
|
+
*
|
|
9
|
+
* @param {FormulaNode} ast - the syntax tree
|
|
10
|
+
* @returns {string} the formula text
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* formatFormula({ kind: "binary", op: "*", left: { kind: "ref", row: 1, col: 1, absRow: false, absCol: false },
|
|
14
|
+
* right: { kind: "literal", value: 2 } }); // "B2*2"
|
|
15
|
+
*
|
|
16
|
+
* @category Spreadsheet
|
|
17
|
+
* @since 1.1.99
|
|
18
|
+
*/
|
|
19
|
+
export declare function formatFormula(ast: FormulaNode): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The link between the body model and the cell formulas of a table ({@link TableOptionsIf.cellFormulas}): the model
|
|
3
|
+
* asks it for the value of every text input – an `=…` cell of a formula column gives its result. Set by the table.
|
|
4
|
+
*
|
|
5
|
+
* @category Internals
|
|
6
|
+
* @since 1.1.99
|
|
7
|
+
*/
|
|
8
|
+
export interface SheetCellsIf {
|
|
9
|
+
/** The value of a cell of an array row (`AreaModelArrayOfArrays`): the result for a formula, otherwise `input`. */
|
|
10
|
+
valueAt(row: unknown, columnIndex: number, input: string): unknown;
|
|
11
|
+
/** The value of a property of a row object: the result for a formula, otherwise `input`. */
|
|
12
|
+
valueOfProperty(row: unknown, property: string, input: string): unknown;
|
|
13
|
+
/** True if the column of this property may hold formulas. */
|
|
14
|
+
isFormulaProperty(property: string): boolean;
|
|
15
|
+
/** True if the column may hold formulas. */
|
|
16
|
+
isFormulaColumnIndex(columnIndex: number): boolean;
|
|
17
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { FormulaFunction } from '../formula/formula-options.if.js';
|
|
2
|
+
import { FormulaError } from '../formula/formula-error.js';
|
|
3
|
+
import { SheetFnContext } from './sheet-functions.js';
|
|
4
|
+
import { SheetValue } from './sheet-values.js';
|
|
5
|
+
|
|
6
|
+
/** A range a formula reads (0-based, inclusive, already cut to the sheet). */
|
|
7
|
+
export interface RangeRef {
|
|
8
|
+
r1: number;
|
|
9
|
+
c1: number;
|
|
10
|
+
r2: number;
|
|
11
|
+
c2: number;
|
|
12
|
+
}
|
|
13
|
+
/** What the compiled formula of a cell needs from the engine. */
|
|
14
|
+
export interface SheetCompileEnv {
|
|
15
|
+
/** The value of a cell (formula result or data). */
|
|
16
|
+
read(row: number, col: number): SheetValue;
|
|
17
|
+
/** Rows of the data (ranges are cut there). */
|
|
18
|
+
rowCount(): number;
|
|
19
|
+
/** The column of a data field (`[price]`), -1 if it is none. */
|
|
20
|
+
fieldColumn(name: string): number;
|
|
21
|
+
/** Own functions (upper case names). */
|
|
22
|
+
functions: Map<string, FormulaFunction>;
|
|
23
|
+
/** Largest range (cells) – larger ones are #ERROR!. */
|
|
24
|
+
maxRangeCells: number;
|
|
25
|
+
fn: SheetFnContext;
|
|
26
|
+
}
|
|
27
|
+
/** A compiled cell formula: evaluation and the cells it reads. */
|
|
28
|
+
export interface CompiledCellFormula {
|
|
29
|
+
evaluate(): SheetValue;
|
|
30
|
+
/** Single cells read (`row * 16384 + col`). */
|
|
31
|
+
readonly singles: number[];
|
|
32
|
+
readonly ranges: RangeRef[];
|
|
33
|
+
readonly volatile: boolean;
|
|
34
|
+
/** Syntax error or unknown function – the evaluation returns it. */
|
|
35
|
+
readonly error?: FormulaError;
|
|
36
|
+
}
|
|
37
|
+
/** The key of a cell in maps. */
|
|
38
|
+
export declare function cellKey(row: number, col: number): number;
|
|
39
|
+
/**
|
|
40
|
+
* Compiles the formula of a cell (`=B2*C2`) into closures over the engine – no `eval`, no `new Function`.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} source - the formula with `=`
|
|
43
|
+
* @param {number} row - the row of the cell (for `[field]`)
|
|
44
|
+
* @param {SheetCompileEnv} env - the engine
|
|
45
|
+
* @returns {CompiledCellFormula} the compiled formula
|
|
46
|
+
*/
|
|
47
|
+
export declare function compileCellFormula(source: string, row: number, env: SheetCompileEnv): CompiledCellFormula;
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { CellRange } from '../data/common/cell-range.js';
|
|
2
|
+
import { SheetStructureEditIf } from './shift-formula.js';
|
|
3
|
+
import { CellFormulaOptionsIf } from './cell-formula-options.if.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The data a {@link SheetEngine} computes on: inputs by **physical** row and column (0-based) – values or formula texts
|
|
7
|
+
* (`"=B2*C2"`). The table has adapters for its models; `SheetEngine.fromArrays` uses a 2-D array.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* const source: SheetDataSourceIf = {
|
|
11
|
+
* getRowCount: () => data.length,
|
|
12
|
+
* getColumnCount: () => 4,
|
|
13
|
+
* getInput: (row, col) => data[row][col],
|
|
14
|
+
* };
|
|
15
|
+
*
|
|
16
|
+
* @category Spreadsheet
|
|
17
|
+
* @since 1.1.99
|
|
18
|
+
*/
|
|
19
|
+
export interface SheetDataSourceIf {
|
|
20
|
+
getRowCount(): number;
|
|
21
|
+
getColumnCount(): number;
|
|
22
|
+
/** The input of a cell: a value or a formula text with `=`. */
|
|
23
|
+
getInput(row: number, col: number): unknown;
|
|
24
|
+
/** False for a column whose `=…` texts are plain text (`ColumnDef.cellFormulas: false`). Default: true. */
|
|
25
|
+
isFormulaColumn?(col: number): boolean;
|
|
26
|
+
/** The column of a data field for `[field]` in a cell formula, -1 if it is none. */
|
|
27
|
+
getFieldColumn?(field: string): number;
|
|
28
|
+
/**
|
|
29
|
+
* Optional, for sparse data (a sheet with a million empty rows): calls `fn` for every cell that may hold an input –
|
|
30
|
+
* `rebuild()` then reads only these instead of rows × columns.
|
|
31
|
+
*/
|
|
32
|
+
forEachInput?(fn: (row: number, col: number, input: unknown) => void): void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* What a (re)calculation did.
|
|
36
|
+
*
|
|
37
|
+
* @category Spreadsheet
|
|
38
|
+
* @since 1.1.99
|
|
39
|
+
*/
|
|
40
|
+
export interface SheetRecalcResultIf {
|
|
41
|
+
/** Formula cells whose result changed (row, column). */
|
|
42
|
+
readonly changedCells: ReadonlyArray<readonly [number, number]>;
|
|
43
|
+
/** Formula cells evaluated. */
|
|
44
|
+
readonly evaluated: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* True for a formula input: text starting with `=` (more than `=`). `'=…` is text.
|
|
48
|
+
*
|
|
49
|
+
* @param {unknown} input - a cell input
|
|
50
|
+
* @returns {boolean} true for a formula text
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* isFormulaText("=B2*C2"); // true
|
|
54
|
+
* isFormulaText("'=1+1"); // false – text "=1+1"
|
|
55
|
+
*
|
|
56
|
+
* @category Spreadsheet
|
|
57
|
+
* @since 1.1.99
|
|
58
|
+
*/
|
|
59
|
+
export declare function isFormulaText(input: unknown): input is string;
|
|
60
|
+
/**
|
|
61
|
+
* The spreadsheet engine of cell formulas (DOM-free): compiles the formula texts of the data (`"=SUM(D2:D4)"`), keeps a
|
|
62
|
+
* dependency graph (single cells and range nodes) and recalculates **only the dependent cells** after a change – in
|
|
63
|
+
* topological order (Kahn), cycles (Tarjan) become `#CIRC!`. No `eval`, no `new Function`. Volatile functions (`TODAY`,
|
|
64
|
+
* `NOW`, `RAND`, `RANDBETWEEN`) are recomputed on every recalculation.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* const engine = SheetEngine.fromArrays([
|
|
68
|
+
* ["Laptop", 1299, 2, "=B1*C1"],
|
|
69
|
+
* ["Mouse", 25, 10, "=B2*C2"],
|
|
70
|
+
* [null, null, null, "=SUM(D1:D2)"],
|
|
71
|
+
* ]);
|
|
72
|
+
* engine.getValue(2, 3); // 2848
|
|
73
|
+
*
|
|
74
|
+
* @category Spreadsheet
|
|
75
|
+
* @since 1.1.99
|
|
76
|
+
*/
|
|
77
|
+
export declare class SheetEngine {
|
|
78
|
+
private readonly source;
|
|
79
|
+
readonly options: CellFormulaOptionsIf;
|
|
80
|
+
private readonly formulas;
|
|
81
|
+
private readonly singleDependents;
|
|
82
|
+
private readonly rangeNodes;
|
|
83
|
+
private readonly rangesByColumn;
|
|
84
|
+
private readonly wideRanges;
|
|
85
|
+
private readonly volatileCells;
|
|
86
|
+
/** Formula cells per column – a read in a column without formulas skips the map lookup. */
|
|
87
|
+
private readonly formulaColumns;
|
|
88
|
+
private readonly env;
|
|
89
|
+
private readonly fieldColumns;
|
|
90
|
+
/**
|
|
91
|
+
* @param {SheetDataSourceIf} source - the data
|
|
92
|
+
* @param {Partial<CellFormulaOptionsIf> & { now?: () => Date, random?: () => number }} [options] - own functions
|
|
93
|
+
* and limits; `now`/`random` for tests
|
|
94
|
+
*/
|
|
95
|
+
constructor(source: SheetDataSourceIf, options?: Partial<CellFormulaOptionsIf> & {
|
|
96
|
+
now?: () => Date;
|
|
97
|
+
random?: () => number;
|
|
98
|
+
});
|
|
99
|
+
/**
|
|
100
|
+
* An engine over a 2-D array (rows of cells) – without a table.
|
|
101
|
+
*
|
|
102
|
+
* @param {unknown[][]} data - the cells; formula texts start with `=`
|
|
103
|
+
* @param {Partial<CellFormulaOptionsIf>} [options] - own functions and limits
|
|
104
|
+
* @returns {SheetEngine} the engine, already calculated
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* SheetEngine.fromArrays([[1, 2, "=A1+B1"]]).getValue(0, 2); // 3
|
|
108
|
+
*/
|
|
109
|
+
static fromArrays(data: unknown[][], options?: Partial<CellFormulaOptionsIf>): SheetEngine;
|
|
110
|
+
/**
|
|
111
|
+
* Reads all inputs again and calculates every formula (start, `setRows`, other columns).
|
|
112
|
+
*
|
|
113
|
+
* @returns {SheetRecalcResultIf} what was calculated
|
|
114
|
+
*/
|
|
115
|
+
rebuild(): SheetRecalcResultIf;
|
|
116
|
+
/**
|
|
117
|
+
* The inputs of cells changed (written by the table): formulas are compiled again, the dependent cells recalculated.
|
|
118
|
+
*
|
|
119
|
+
* @param {ReadonlyArray<readonly [number, number]>} cells - physical row and column of each changed cell
|
|
120
|
+
* @returns {SheetRecalcResultIf} what was recalculated
|
|
121
|
+
*/
|
|
122
|
+
inputsChanged(cells: ReadonlyArray<readonly [number, number]>): SheetRecalcResultIf;
|
|
123
|
+
/**
|
|
124
|
+
* Recalculates the volatile formulas (`TODAY`, `NOW`, `RAND`) and their dependents.
|
|
125
|
+
*
|
|
126
|
+
* @returns {SheetRecalcResultIf} what was recalculated
|
|
127
|
+
*/
|
|
128
|
+
recalculate(): SheetRecalcResultIf;
|
|
129
|
+
/**
|
|
130
|
+
* The value of a cell: the result of its formula or its data value (`Date` for dates, a {@link FormulaError} for an
|
|
131
|
+
* error, `'=…` without the quote).
|
|
132
|
+
*
|
|
133
|
+
* @param {number} row - physical row (0-based)
|
|
134
|
+
* @param {number} col - column (0-based)
|
|
135
|
+
* @returns {unknown} the value
|
|
136
|
+
*/
|
|
137
|
+
getValue(row: number, col: number): unknown;
|
|
138
|
+
/**
|
|
139
|
+
* True if the cell holds a formula.
|
|
140
|
+
*
|
|
141
|
+
* @param {number} row - physical row
|
|
142
|
+
* @param {number} col - column
|
|
143
|
+
* @returns {boolean} true for a formula cell
|
|
144
|
+
*/
|
|
145
|
+
isFormula(row: number, col: number): boolean;
|
|
146
|
+
/** @returns {number} the number of formula cells */
|
|
147
|
+
getFormulaCount(): number;
|
|
148
|
+
/**
|
|
149
|
+
* Evaluates a formula once (not stored), e.g. for a formula bar preview.
|
|
150
|
+
*
|
|
151
|
+
* @param {string} source - the formula (`"=SUM(D2:D4)"`, the `=` is optional)
|
|
152
|
+
* @param {[number, number]} [at] - the cell it is evaluated in (for `[field]`)
|
|
153
|
+
* @returns {unknown} the result
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* engine.evaluate("=SUM(D2:D4)"); // 3895
|
|
157
|
+
*/
|
|
158
|
+
evaluate(source: string, at?: readonly [number, number]): unknown;
|
|
159
|
+
/**
|
|
160
|
+
* The cells and ranges a formula reads.
|
|
161
|
+
*
|
|
162
|
+
* @param {number} row - physical row
|
|
163
|
+
* @param {number} col - column
|
|
164
|
+
* @returns {CellRange[]} its precedents (empty for a value cell)
|
|
165
|
+
*/
|
|
166
|
+
getPrecedents(row: number, col: number): CellRange[];
|
|
167
|
+
/**
|
|
168
|
+
* The formula cells that read a cell directly.
|
|
169
|
+
*
|
|
170
|
+
* @param {number} row - physical row
|
|
171
|
+
* @param {number} col - column
|
|
172
|
+
* @returns {Array<[number, number]>} row and column of each dependent
|
|
173
|
+
*/
|
|
174
|
+
getDependents(row: number, col: number): Array<[number, number]>;
|
|
175
|
+
/**
|
|
176
|
+
* The new formula texts after rows or columns were inserted or deleted (or cells moved) – the caller writes them
|
|
177
|
+
* (the engine only reads the data). Cells are given at their position **after** the edit.
|
|
178
|
+
*
|
|
179
|
+
* @param {SheetStructureEditIf} edit - what changed
|
|
180
|
+
* @returns {Array<{ row: number, col: number, input: string }>} changed formula texts
|
|
181
|
+
*/
|
|
182
|
+
adjustForStructureChange(edit: SheetStructureEditIf): Array<{
|
|
183
|
+
row: number;
|
|
184
|
+
col: number;
|
|
185
|
+
input: string;
|
|
186
|
+
}>;
|
|
187
|
+
private read;
|
|
188
|
+
/** A value cell: `""` is blank (a cleared cell), `'=…` is the text `=…`. */
|
|
189
|
+
private dataValue;
|
|
190
|
+
private fieldColumn;
|
|
191
|
+
private add;
|
|
192
|
+
private remove;
|
|
193
|
+
/** Calls `fn` for every formula that reads the cell (single references and ranges; a formula may come twice). */
|
|
194
|
+
private forEachDependent;
|
|
195
|
+
private dependentsOfKey;
|
|
196
|
+
/**
|
|
197
|
+
* Recalculates the formulas reachable from the seeds: BFS over the dependents → Kahn (topological) → the rest are
|
|
198
|
+
* cycles (Tarjan → #CIRC!) and cells behind them (a second Kahn pass, they inherit the error). Iterative – a chain
|
|
199
|
+
* of 100 000 cells does not overflow the stack. The dependents of a cell are looked up once per recalculation.
|
|
200
|
+
*
|
|
201
|
+
* Cost: the graph part is linear in the dependents; the evaluation reads every cell of every range again – a
|
|
202
|
+
* running sum `=SUM($B$2:B2)` copied down n rows is O(n²) per change (as in Excel; `=C1+B2` is linear).
|
|
203
|
+
*/
|
|
204
|
+
private recalc;
|
|
205
|
+
/** The cells of `nodes` that lie on a cycle (strongly connected components > 1 or a self reference) – iterative Tarjan. */
|
|
206
|
+
private cycles;
|
|
207
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A built-in function of cell formulas: name, signature and a short English description – for function suggestions
|
|
3
|
+
* and help texts.
|
|
4
|
+
*
|
|
5
|
+
* @category Spreadsheet
|
|
6
|
+
* @since 1.1.99
|
|
7
|
+
*/
|
|
8
|
+
export interface FormulaFunctionInfoIf {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
/** e.g. `"SUM(number1, [number2], …)"` */
|
|
11
|
+
readonly signature: string;
|
|
12
|
+
readonly description: string;
|
|
13
|
+
readonly group: "Math" | "Conditional" | "Logic" | "Lookup" | "Text" | "Date" | "Info";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The built-in functions of cell formulas (Excel signatures and semantics), sorted by name.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* FORMULA_FUNCTION_INFO.filter(i => i.name.startsWith("SU")).map(i => i.signature);
|
|
20
|
+
* // ["SUBSTITUTE(text, old_text, new_text, [instance])", "SUM(number1, [number2], …)", …]
|
|
21
|
+
*
|
|
22
|
+
* @category Spreadsheet
|
|
23
|
+
* @since 1.1.99
|
|
24
|
+
*/
|
|
25
|
+
export declare const FORMULA_FUNCTION_INFO: readonly FormulaFunctionInfoIf[];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { numberToText, SheetValue, ValueOptions } from './sheet-values.js';
|
|
2
|
+
|
|
3
|
+
/** What a function of a cell formula may use besides its arguments. */
|
|
4
|
+
export interface SheetFnContext extends ValueOptions {
|
|
5
|
+
/** The serial number of now (TODAY, NOW). */
|
|
6
|
+
now(): number;
|
|
7
|
+
/** A random number 0 … 1 (RAND). */
|
|
8
|
+
random(): number;
|
|
9
|
+
}
|
|
10
|
+
/** A built-in function of cell formulas. */
|
|
11
|
+
export interface SheetFunctionSpec {
|
|
12
|
+
readonly min: number;
|
|
13
|
+
readonly max: number;
|
|
14
|
+
/** Recomputed on every recalculation (TODAY, NOW, RAND). */
|
|
15
|
+
readonly volatile?: boolean;
|
|
16
|
+
/** Gets error arguments (ISERROR …) instead of returning the first one. */
|
|
17
|
+
readonly acceptsErrors?: boolean;
|
|
18
|
+
/** Arguments evaluated on demand (IF, IFERROR …). */
|
|
19
|
+
readonly lazy?: (args: Array<() => SheetValue>, ctx: SheetFnContext) => SheetValue;
|
|
20
|
+
readonly fn?: (args: SheetValue[], ctx: SheetFnContext) => SheetValue;
|
|
21
|
+
}
|
|
22
|
+
/** A criterion of SUMIF/COUNTIF: `5`, `">5"`, `"<>x"`, `"M*"`, `""` (blank). */
|
|
23
|
+
export declare function makeCriterion(criterion: SheetValue, o: ValueOptions): (v: SheetValue) => boolean;
|
|
24
|
+
/** The built-in functions of cell formulas (Excel signatures and semantics). */
|
|
25
|
+
export declare const SHEET_FUNCTIONS: Record<string, SheetFunctionSpec>;
|
|
26
|
+
/** The text of a number for messages and TEXT. */
|
|
27
|
+
export { numberToText };
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { FormulaError } from '../formula/formula-error.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A date in a cell formula: the Excel serial number (1900 date system: 1 = 1900-01-01, with Excel's 1900-02-29;
|
|
5
|
+
* the fraction is the time of day). It counts as a number (arithmetic, `ISNUMBER`) and stays a date through `=A2`,
|
|
6
|
+
* `IF`, lookups and date ± number; `MIN`/`MAX` and other arithmetic give a number (like Excel's values). The table
|
|
7
|
+
* shows it as `Date`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* dateToSerial(new Date(2026, 9, 16)); // 46311
|
|
11
|
+
*
|
|
12
|
+
* @category Spreadsheet
|
|
13
|
+
* @since 1.1.99
|
|
14
|
+
*/
|
|
15
|
+
export declare class SheetDate {
|
|
16
|
+
readonly serial: number;
|
|
17
|
+
/** Marker (works across copies of the core). */
|
|
18
|
+
readonly type = "SheetDate";
|
|
19
|
+
/** @param {number} serial - the Excel serial number */
|
|
20
|
+
constructor(serial: number);
|
|
21
|
+
/** @returns {Date} the date (local time) */
|
|
22
|
+
toDate(): Date;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* True for a {@link SheetDate}.
|
|
26
|
+
*
|
|
27
|
+
* @param {unknown} v - any value
|
|
28
|
+
* @returns {boolean} true for a sheet date
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* isSheetDate(new SheetDate(1)); // true
|
|
32
|
+
*
|
|
33
|
+
* @category Spreadsheet
|
|
34
|
+
* @since 1.1.99
|
|
35
|
+
*/
|
|
36
|
+
export declare function isSheetDate(v: unknown): v is SheetDate;
|
|
37
|
+
/**
|
|
38
|
+
* The Excel serial number of a date (local calendar date and time, no time zone shift – like Excel).
|
|
39
|
+
*
|
|
40
|
+
* @param {Date} date - a date
|
|
41
|
+
* @returns {number} the serial number (`NaN` for an invalid date)
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* dateToSerial(new Date(1900, 0, 1)); // 1
|
|
45
|
+
*
|
|
46
|
+
* @category Spreadsheet
|
|
47
|
+
* @since 1.1.99
|
|
48
|
+
*/
|
|
49
|
+
export declare function dateToSerial(date: Date): number;
|
|
50
|
+
/**
|
|
51
|
+
* The date of an Excel serial number (local time); serial 60 (Excel's 1900-02-29) becomes 1900-03-01.
|
|
52
|
+
*
|
|
53
|
+
* @param {number} serial - the serial number
|
|
54
|
+
* @returns {Date} the date
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* serialToDate(46311); // 2026-10-16 00:00 local
|
|
58
|
+
*
|
|
59
|
+
* @category Spreadsheet
|
|
60
|
+
* @since 1.1.99
|
|
61
|
+
*/
|
|
62
|
+
export declare function serialToDate(serial: number): Date;
|
|
63
|
+
/** The serial of a calendar date like Excel's DATE (months and days may overflow). */
|
|
64
|
+
export declare function serialOf(year: number, month: number, day: number): number;
|
|
65
|
+
/** Year, month (1–12), day of a serial number. */
|
|
66
|
+
export declare function partsOfSerial(serial: number): {
|
|
67
|
+
y: number;
|
|
68
|
+
m: number;
|
|
69
|
+
d: number;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* A rectangle of cells passed to a function (`SUM(A1:B5)`): read lazily, row by row.
|
|
73
|
+
*
|
|
74
|
+
* @category Spreadsheet
|
|
75
|
+
* @since 1.1.99
|
|
76
|
+
*/
|
|
77
|
+
export declare class FormulaRange {
|
|
78
|
+
readonly row: number;
|
|
79
|
+
readonly col: number;
|
|
80
|
+
readonly rows: number;
|
|
81
|
+
readonly cols: number;
|
|
82
|
+
private readonly read;
|
|
83
|
+
/** Marker (works across copies of the core). */
|
|
84
|
+
readonly type = "FormulaRange";
|
|
85
|
+
/**
|
|
86
|
+
* @param {number} row - first row (0-based)
|
|
87
|
+
* @param {number} col - first column
|
|
88
|
+
* @param {number} rows - number of rows (cut at the rows of the data)
|
|
89
|
+
* @param {number} cols - number of columns
|
|
90
|
+
* @param {(row: number, col: number) => SheetValue} read - reads a cell (sheet coordinates)
|
|
91
|
+
*/
|
|
92
|
+
constructor(row: number, col: number, rows: number, cols: number, read: (row: number, col: number) => SheetValue);
|
|
93
|
+
/**
|
|
94
|
+
* The value at a position inside the range.
|
|
95
|
+
*
|
|
96
|
+
* @param {number} r - row inside the range (0-based)
|
|
97
|
+
* @param {number} c - column inside the range
|
|
98
|
+
* @returns {SheetValue} the value (blank = `null`)
|
|
99
|
+
*/
|
|
100
|
+
get(r: number, c: number): SheetValue;
|
|
101
|
+
/** @returns {SheetValue[]} all values, row by row */
|
|
102
|
+
values(): SheetValue[];
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* True for a {@link FormulaRange}.
|
|
106
|
+
*
|
|
107
|
+
* @param {unknown} v - any value
|
|
108
|
+
* @returns {boolean} true for a range
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* if (isFormulaRange(arg)) console.log(arg.rows, arg.cols);
|
|
112
|
+
*
|
|
113
|
+
* @category Spreadsheet
|
|
114
|
+
* @since 1.1.99
|
|
115
|
+
*/
|
|
116
|
+
export declare function isFormulaRange(v: unknown): v is FormulaRange;
|
|
117
|
+
/**
|
|
118
|
+
* A value inside a cell formula: number, text, boolean, blank (`null`), error, date or – only as argument – a range.
|
|
119
|
+
*
|
|
120
|
+
* @category Spreadsheet
|
|
121
|
+
* @since 1.1.99
|
|
122
|
+
*/
|
|
123
|
+
export type SheetValue = number | string | boolean | null | FormulaError | SheetDate | FormulaRange;
|
|
124
|
+
/** Rounds to 15 significant digits like Excel (`0.1 + 0.2` = `0.3`); -0 → 0. */
|
|
125
|
+
export declare function round15(n: number): number;
|
|
126
|
+
/** A number result: not finite → #NUM!, rounded to 15 digits. */
|
|
127
|
+
export declare function num(n: number): number | FormulaError;
|
|
128
|
+
/** The serial number of ISO text (`2026-10-16`, with time), `undefined` if it is none. */
|
|
129
|
+
export declare function isoTextToSerial(text: string): number | undefined;
|
|
130
|
+
/** Options the conversions need. */
|
|
131
|
+
export interface ValueOptions {
|
|
132
|
+
isoDatesAsDates: boolean;
|
|
133
|
+
}
|
|
134
|
+
/** A value of the data as sheet value: `Date` → {@link SheetDate}, objects → #VALUE!, `NaN` → blank. */
|
|
135
|
+
export declare function fromCellData(v: unknown): SheetValue;
|
|
136
|
+
/** A scalar (a range → #VALUE! – no implicit intersection). */
|
|
137
|
+
export declare function scalar(v: SheetValue): Exclude<SheetValue, FormulaRange>;
|
|
138
|
+
/** A value as number for arithmetic: blank 0, TRUE 1, numeric text, ISO date text (option), date serial. */
|
|
139
|
+
export declare function toNum(v: SheetValue, o: ValueOptions): number | FormulaError;
|
|
140
|
+
/** A number as text like Excel's general format: 15 significant digits, exponent from 1E+21 on. */
|
|
141
|
+
export declare function numberToText(n: number): string;
|
|
142
|
+
/** A value as text: numbers in general format, TRUE/FALSE, a date as its serial number (like Excel). */
|
|
143
|
+
export declare function toStr(v: SheetValue): string | FormulaError;
|
|
144
|
+
/** A value as boolean: numbers ≠ 0, "TRUE"/"FALSE", blank FALSE. */
|
|
145
|
+
export declare function toBool(v: SheetValue): boolean | FormulaError;
|
|
146
|
+
/**
|
|
147
|
+
* Compares like Excel: numbers (and dates) numerically (15 digits), texts case-insensitively, different types by type
|
|
148
|
+
* (number < text < boolean, `"3" = 3` is FALSE); blank is 0, `""` or FALSE – whatever the other side is.
|
|
149
|
+
*/
|
|
150
|
+
export declare function compareSheet(a: SheetValue, b: SheetValue): number | FormulaError;
|
|
151
|
+
/** True for blank and `""`. */
|
|
152
|
+
export declare function isEmpty(v: SheetValue): boolean;
|
|
153
|
+
/** A sheet value for the table: SheetDate → Date, ranges → #VALUE!. */
|
|
154
|
+
export declare function toExternal(v: SheetValue): unknown;
|