- init
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Shared types for the formula engine.
|
||||
*
|
||||
* The engine is intentionally framework-agnostic: it knows nothing about Vue,
|
||||
* the store or the DOM. The host application implements {@link EngineHost} to
|
||||
* expose the current document to the evaluator.
|
||||
*/
|
||||
|
||||
/** All error values the engine can produce. They propagate to dependent cells. */
|
||||
export type ErrorCode =
|
||||
| '#REF' // invalid / deleted reference or unknown sheet name
|
||||
| '#DIV/0!' // division by zero
|
||||
| '#NAME?' // unknown function
|
||||
| '#ERR' // parse error
|
||||
| '#CIRC' // circular reference
|
||||
| '#VALUE!'; // wrong value type in arithmetic (documented extension)
|
||||
|
||||
export const ERROR_CODES: ErrorCode[] = [
|
||||
'#REF',
|
||||
'#DIV/0!',
|
||||
'#NAME?',
|
||||
'#ERR',
|
||||
'#CIRC',
|
||||
'#VALUE!',
|
||||
];
|
||||
|
||||
/** A formula error. Instances are immutable and comparable by `code`. */
|
||||
export class FormulaError {
|
||||
constructor(
|
||||
public readonly code: ErrorCode,
|
||||
public readonly detail?: string,
|
||||
) {}
|
||||
toString(): string {
|
||||
return this.code;
|
||||
}
|
||||
}
|
||||
|
||||
export function isError(v: unknown): v is FormulaError {
|
||||
return v instanceof FormulaError;
|
||||
}
|
||||
|
||||
/** A plain scalar a cell can hold once evaluated. `null` means "empty cell". */
|
||||
export type Scalar = number | string | null;
|
||||
|
||||
/** The fully evaluated value of a cell. */
|
||||
export type CellValue = Scalar | FormulaError;
|
||||
|
||||
/** 0-based cell coordinate inside a single table. */
|
||||
export interface Coord {
|
||||
col: number;
|
||||
row: number;
|
||||
}
|
||||
|
||||
/** A cell address that also carries the id of the table it lives on. */
|
||||
export interface CellRef extends Coord {
|
||||
tableId: string;
|
||||
}
|
||||
|
||||
/** Stable string key for a cell across the whole document. */
|
||||
export function keyOf(tableId: string, col: number, row: number): string {
|
||||
return `${tableId}␟${col}␟${row}`;
|
||||
}
|
||||
|
||||
export function parseKey(key: string): CellRef {
|
||||
const [tableId, col, row] = key.split('␟');
|
||||
return { tableId, col: Number(col), row: Number(row) };
|
||||
}
|
||||
|
||||
/**
|
||||
* The document as seen by the engine. Implemented by the Vue store.
|
||||
*
|
||||
* The addressable unit is a **table** (a table object on a Numbers-style
|
||||
* canvas). Table names are unique across the whole document, so a qualified
|
||||
* reference like `Umsatz!B2` / `Umsatz::B2` resolves the same no matter which
|
||||
* sheet the formula or the target table sits on.
|
||||
*/
|
||||
export interface EngineHost {
|
||||
/** Id of the table the formula currently being evaluated lives on. */
|
||||
homeTableId: string;
|
||||
/**
|
||||
* Resolve a table *name* (as written in a formula) to its id. Matching is
|
||||
* case-insensitive and tolerant of surrounding whitespace. Returns `null`
|
||||
* for an unknown / deleted table.
|
||||
*/
|
||||
resolveTableName(name: string): string | null;
|
||||
/** Dimensions of a table, used for range clamping and #REF detection. */
|
||||
tableSize(tableId: string): { cols: number; rows: number } | null;
|
||||
/**
|
||||
* Already-computed value of another cell. The recalculation driver guarantees
|
||||
* precedents are evaluated first (topological order), so this never triggers
|
||||
* a nested evaluation.
|
||||
*/
|
||||
getComputed(tableId: string, col: number, row: number): CellValue;
|
||||
}
|
||||
Reference in New Issue
Block a user