@guiexpert/table 1.1.98 → 1.1.100

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.
Files changed (99) hide show
  1. package/README.md +9 -0
  2. package/css/main.css +296 -0
  3. package/css/table-clipboard.css +41 -0
  4. package/css/table-color-vars.css +56 -0
  5. package/css/table-sheet-editing.css +149 -0
  6. package/css/table-spreadsheet.css +50 -0
  7. package/index.cjs +46 -59
  8. package/index.d.ts +46 -0
  9. package/index.js +18934 -11624
  10. package/lib/table/action/action-id.type.d.ts +1 -1
  11. package/lib/table/action/shortcut.service.d.ts +9 -0
  12. package/lib/table/aria/aria-texts.d.ts +26 -0
  13. package/lib/table/aria/aria-texts.if.d.ts +196 -0
  14. package/lib/table/batch-edit/batch-edit-service.d.ts +22 -0
  15. package/lib/table/batch-edit/cell-change.if.d.ts +6 -2
  16. package/lib/table/batch-edit/pending-cell-changes.d.ts +7 -0
  17. package/lib/table/batch-edit/write-row-value.d.ts +14 -0
  18. package/lib/table/calc/column-values.d.ts +2 -0
  19. package/lib/table/clipboard/clipboard-html.d.ts +41 -0
  20. package/lib/table/clipboard/clipboard-keymap.d.ts +18 -0
  21. package/lib/table/clipboard/clipboard-options.d.ts +30 -0
  22. package/lib/table/clipboard/clipboard-options.if.d.ts +67 -0
  23. package/lib/table/clipboard/clipboard-service.d.ts +122 -0
  24. package/lib/table/clipboard/input-pipes.d.ts +59 -0
  25. package/lib/table/clipboard/paste-plan.d.ts +96 -0
  26. package/lib/table/clipboard/tsv.d.ts +31 -0
  27. package/lib/table/data/common/event/ge-edit-event.d.ts +46 -0
  28. package/lib/table/data/common/event/ge-row-drag-event.d.ts +2 -2
  29. package/lib/table/data/common/event/ge-undo-event.d.ts +29 -0
  30. package/lib/table/data/options/table-options.d.ts +28 -0
  31. package/lib/table/data/options/table-options.if.d.ts +99 -1
  32. package/lib/table/data/tablemodel/areamodel/abstract-area-model.d.ts +11 -2
  33. package/lib/table/data/tablemodel/areamodel/area-model-array-of-arrays.d.ts +14 -0
  34. package/lib/table/data/tablemodel/areamodel/area-model-object-array.d.ts +14 -0
  35. package/lib/table/data/tablemodel/areamodel/area-model.if.d.ts +11 -0
  36. package/lib/table/data/tablemodel/column/column-def.d.ts +13 -0
  37. package/lib/table/data/tablemodel/column/column-def.if.d.ts +36 -1
  38. package/lib/table/data/tablemodel/column/default-editable.d.ts +18 -0
  39. package/lib/table/event-adapter.d.ts +6 -0
  40. package/lib/table/event-listener-hub.d.ts +10 -0
  41. package/lib/table/event-listener.if.d.ts +16 -0
  42. package/lib/table/factory/pivot-factory.d.ts +1 -1
  43. package/lib/table/factory/row-group-factory.d.ts +1 -1
  44. package/lib/table/factory/table-factory.d.ts +14 -0
  45. package/lib/table/formula/formula-ast.if.d.ts +32 -2
  46. package/lib/table/formula/formula-error.d.ts +4 -2
  47. package/lib/table/formula/parser.d.ts +5 -2
  48. package/lib/table/formula/tokenizer.d.ts +5 -2
  49. package/lib/table/input-handler.d.ts +8 -0
  50. package/lib/table/master-detail/master-detail-service.d.ts +9 -0
  51. package/lib/table/render-scope.d.ts +40 -0
  52. package/lib/table/row-drag/row-drag-service.d.ts +3 -2
  53. package/lib/table/selection/selection-service.d.ts +48 -0
  54. package/lib/table/service/excel-export-options.if.d.ts +6 -0
  55. package/lib/table/service/excel-service.d.ts +4 -0
  56. package/lib/table/service/excel-service.if.d.ts +35 -0
  57. package/lib/table/sheet/cell-address.d.ts +100 -0
  58. package/lib/table/sheet/cell-formula-options.d.ts +27 -0
  59. package/lib/table/sheet/cell-formula-options.if.d.ts +27 -0
  60. package/lib/table/sheet/excel-formula.d.ts +20 -0
  61. package/lib/table/sheet/format-formula.d.ts +19 -0
  62. package/lib/table/sheet/sheet-cells.if.d.ts +17 -0
  63. package/lib/table/sheet/sheet-compiler.d.ts +47 -0
  64. package/lib/table/sheet/sheet-engine.d.ts +207 -0
  65. package/lib/table/sheet/sheet-function-info.d.ts +25 -0
  66. package/lib/table/sheet/sheet-functions.d.ts +27 -0
  67. package/lib/table/sheet/sheet-values.d.ts +154 -0
  68. package/lib/table/sheet/shift-formula.d.ts +71 -0
  69. package/lib/table/sheet/table-sheet.d.ts +214 -0
  70. package/lib/table/sheet-editing/cell-editor-service.d.ts +105 -0
  71. package/lib/table/sheet-editing/cell-editor.if.d.ts +110 -0
  72. package/lib/table/sheet-editing/editing-keymap.d.ts +17 -0
  73. package/lib/table/sheet-editing/editing-options.d.ts +34 -0
  74. package/lib/table/sheet-editing/editing-options.if.d.ts +49 -0
  75. package/lib/table/sheet-editing/editors/date-cell-editor.d.ts +23 -0
  76. package/lib/table/sheet-editing/editors/number-cell-editor.d.ts +18 -0
  77. package/lib/table/sheet-editing/editors/select-cell-editor.d.ts +36 -0
  78. package/lib/table/sheet-editing/editors/text-cell-editor.d.ts +35 -0
  79. package/lib/table/sheet-editing/formula-assist.d.ts +103 -0
  80. package/lib/table/sheet-editing/formula-text.d.ts +61 -0
  81. package/lib/table/sheet-editing/sheet-navigation.d.ts +26 -0
  82. package/lib/table/spreadsheet/area-model-sheet.d.ts +170 -0
  83. package/lib/table/spreadsheet/formula-bar.d.ts +53 -0
  84. package/lib/table/spreadsheet/spreadsheet-factory.d.ts +111 -0
  85. package/lib/table/spreadsheet/spreadsheet-options.if.d.ts +28 -0
  86. package/lib/table/spreadsheet/spreadsheet-preset.d.ts +37 -0
  87. package/lib/table/spreadsheet/structure-edit.d.ts +35 -0
  88. package/lib/table/table-api.d.ts +511 -2
  89. package/lib/table/table-scope.d.ts +294 -1
  90. package/lib/table/undo/cell-changes-undoable.d.ts +34 -0
  91. package/lib/table/undo/model-rows.d.ts +17 -0
  92. package/lib/table/undo/pending-changes-undoable.d.ts +35 -0
  93. package/lib/table/undo/undo-keymap.d.ts +17 -0
  94. package/lib/table/undo/undo-options.d.ts +26 -0
  95. package/lib/table/undo/undo-options.if.d.ts +30 -0
  96. package/lib/table/undo/undo-service.d.ts +103 -0
  97. package/lib/table/undo/undo-stack.d.ts +62 -0
  98. package/lib/table/undo/undoable.if.d.ts +36 -0
  99. 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;