/** A1-notation helpers. Rows/cols are 0-based internally; A1 is 1-based. */ interface CellPos { row: number; col: number; } interface Rect { r1: number; c1: number; r2: number; c2: number; } /** 0 → "A", 25 → "Z", 26 → "AA", 99 → "CV". */ declare function colName(col: number): string; /** "A" → 0, "CV" → 99. Returns -1 for invalid input. */ declare function colIndex(name: string): number; /** "B3" (or "$B$3") → {row: 2, col: 1}; null when not a cell ref. */ declare function parseA1(text: string): CellPos | null; /** {row:2, col:1} → "B3". */ declare function toA1(pos: CellPos): string; /** "A1:B5" → normalized Rect (corners sorted); null when not a range. */ declare function parseRange(text: string): Rect | null; declare function normalizeRect(a: CellPos, b: CellPos): Rect; declare function rectContains(rect: Rect, row: number, col: number): boolean; declare function cellKey(row: number, col: number): string; declare function parseKey(key: string): CellPos; type HorizontalAlign = "left" | "center" | "right"; type NumberFormat = "general" | "number" | "currency" | "percent"; /** Persisted visual semantics of one spreadsheet cell; unset fields inherit defaults. */ interface CellFormat { background?: string; foreground?: string; bold?: boolean; italic?: boolean; horizontalAlign?: HorizontalAlign; numberFormat?: NumberFormat; } declare function mergeFormat(current: CellFormat, patch: CellFormat): CellFormat; interface SheetAxisMetricEntry { index: number; size: number; } type SheetAxis = "row" | "column"; interface SheetAxisMetricsSnapshot { defaultSize: number; overrides: SheetAxisMetricEntry[]; } /** Default logical sizes shared by the document and Canvas viewport adapters. */ declare const DEFAULT_ROW_SIZE = 24; declare const DEFAULT_COLUMN_SIZE = 112; /** * Sparse logical axis metrics. Default-size entries are deliberately absent so * a large sheet preserves only user-resized axes in its document snapshot. */ declare class SheetAxisMetrics { private length; private defaultSize; private readonly overrides; constructor(length: number, defaultSize: number); get axisLength(): number; get default(): number; get(index: number): number; set(index: number, size: number): void; reset(index: number): void; entries(): SheetAxisMetricEntry[]; toSnapshot(): SheetAxisMetricsSnapshot; clone(): SheetAxisMetrics; static fromSnapshot(length: number, snapshot: SheetAxisMetricsSnapshot): SheetAxisMetrics; private validateIndex; } type SheetStructureOperation = { kind: "insert"; axis: "row" | "column"; index: number; count: number; } | { kind: "delete"; axis: "row" | "column"; index: number; count: number; }; /** * Rewrite A1 references in formula source for a structural operation. This is * intentionally source-level: retaining `$` markers is required for future * fill behavior even though structure changes move absolute targets too. */ declare function transformFormulaReferences(source: string, operation: SheetStructureOperation): string; /** Transform a stored sparse cell coordinate; null means deletion removed it. */ declare function transformCellPosition(position: CellPos, operation: SheetStructureOperation): CellPos | null; /** Transform one row/column metric index with the document operation contract. */ declare function transformAxisMetricIndex(index: number, operation: SheetStructureOperation): number | null; /** * Recursive-descent parser. Precedence (low→high): `+ -` < `* /` < `^` * (right-assoc) < unary `-` < postfix `%` < primary. `%` is Sheets-style postfix * percent (50% → 0.5), NOT modulo. */ type Node = { t: "num"; v: number; } | { t: "str"; v: string; } | { t: "error"; code: "#REF!"; } | { t: "ref"; row: number; col: number; } | { t: "range"; rect: Rect; } | { t: "bin"; op: "+" | "-" | "*" | "/" | "^" | "&"; l: Node; r: Node; } | { t: "neg"; e: Node; } | { t: "pct"; e: Node; } | { t: "call"; name: string; args: Node[]; }; declare class ParseError extends Error { } declare function parse(src: string): Node; /** Error values are first-class and propagate through operators. */ interface CellError { error: "#DIV/0!" | "#VALUE!" | "#REF!" | "#NAME?" | "#CYCLE!" | "#ERROR!"; } /** `null` = empty cell (coerces to 0 in arithmetic, skipped by aggregates). */ type Value = number | string | boolean | null | CellError; declare const isErr: (v: Value) => v is CellError; declare const err: (code: CellError["error"]) => CellError; interface EvalContext { /** Resolved value of a cell (never a formula string). May throw CycleError. */ getCell(row: number, col: number): Value; } declare class CycleError extends Error { } /** Flatten an argument node into values; ranges expand to all their cells. */ declare function flatten(node: Node, ctx: EvalContext): Value[]; declare function evaluate(node: Node, ctx: EvalContext): Value; /** Collect every cell/range a parsed formula references (for the dep graph). */ declare function collectRefs(node: Node, scalars: Set, ranges: Rect[]): void; /** Serializable view of a populated sparse document cell. */ interface PopulatedCell { row: number; col: number; raw: string; format?: CellFormat; } /** Serializable, sparse document state used by structure history and codecs. */ interface SheetSnapshot { rows: number; cols: number; cells: PopulatedCell[]; rowMetrics?: SheetAxisMetricsSnapshot; columnMetrics?: SheetAxisMetricsSnapshot; } /** * Sparse spreadsheet model: a Map of only the non-empty cells, a reverse * dependency index for scalar refs, and a rect list for range refs (a range * like A1:A10000 is stored as ONE rect with containment checks — never * expanded into 10k edges). Pure TS; no canvas imports; bun-test friendly. */ declare class SheetModel { rows: number; cols: number; rowMetrics: SheetAxisMetrics; columnMetrics: SheetAxisMetrics; private cells; /** key → formula-cell keys that read it via a scalar ref. */ private scalarDependents; /** Range reads: checked by containment when a cell changes. */ private rangeDependents; private listeners; constructor(rows?: number, cols?: number); onChange(fn: () => void): () => void; private emit; /** Raw editable text of a cell ("" when empty). */ getRaw(row: number, col: number): string; /** Resolved value (null when empty). */ getValue(row: number, col: number): Value; /** Display string for the grid. */ getDisplay(row: number, col: number): string; getFormat(row: number, col: number): Readonly; hasFormat(row: number, col: number): boolean; getAxisSize(axis: SheetAxis, index: number): number; /** Set a logical row/column size without giving the document a rendering dependency. */ setAxisSize(axis: SheetAxis, index: number, size: number): void; setFormat(row: number, col: number, patch: CellFormat): void; /** Replace the complete stored format; used by transactional undo/redo. */ replaceFormat(row: number, col: number, format: CellFormat | undefined): void; /** Number of non-empty cells (for HUD/debug). */ get cellCount(): number; /** * Smallest normalized rectangle containing every populated cell, or null for * an empty document. This is a document query, not a viewport concern. */ getUsedRange(): Rect | null; /** * Enumerate only existing cells in a normalized document rectangle. This is * the safe primitive for clear/cut: selecting the complete 10,000 × 100 * sheet must not create one million empty writes. */ getCellsInRange(range: Rect): PopulatedCell[]; /** Capture only sparse records, never the full logical rectangle. */ toSnapshot(): SheetSnapshot; /** Replace document state atomically after a validated history operation. */ restoreSnapshot(snapshot: SheetSnapshot): void; /** * Move sparse records and rewrite formula source for a row/column operation. * The transformed state is rebuilt through normal parsing so dependency indexes * and calculated values cannot retain coordinates from the previous shape. */ applyStructure(operation: SheetStructureOperation): void; setCell(row: number, col: number, raw: string): void; /** Remove key's outgoing read edges (called before rewriting the cell). */ private unwireReads; /** Transitive closure of formula cells that (directly or not) read `key`. */ private collectDependents; /** * Re-evaluate the dirty set in dependency order via DFS with a visiting * state: hitting a cell that is currently being evaluated means a reference * cycle — every participant gets #CYCLE!. */ private recalculate; } interface CellWrite { row: number; col: number; raw: string; } interface CellFormatWrite { row: number; col: number; format: CellFormat; } interface AxisSizeWrite { axis: SheetAxis; index: number; size: number; } /** * Transactional undo/redo for document operations. The UI, clipboard and a * future MCP surface all submit the same `CellWrite[]` shape, never Canvas * state, so history remains deterministic and independently testable. */ declare class SheetHistory { private readonly model; private undoStack; private redoStack; constructor(model: SheetModel); get canUndo(): boolean; get canRedo(): boolean; apply(writes: CellWrite[]): void; applyFormats(writes: CellFormatWrite[]): void; applyAxisSizes(writes: AxisSizeWrite[]): void; /** Apply one structural document operation as a single undoable transaction. */ applyStructure(operation: SheetStructureOperation): void; undo(): void; redo(): void; } interface SheetBounds { rows: number; cols: number; } /** Serializes editable raw cell content into the browser spreadsheet TSV shape. */ declare function copyRange(model: SheetModel, range: Rect): string; /** Converts a tabular clipboard payload into in-bounds document writes. */ declare function pasteText(text: string, origin: { row: number; col: number; }, bounds: SheetBounds): CellWrite[]; interface WorkbookSheet { id: string; name: string; model: SheetModel; } interface WorkbookSnapshotSheet extends SheetSnapshot { id: string; name: string; } interface WorkbookSnapshot { version: 1; activeSheetId: string; sheets: WorkbookSnapshotSheet[]; } interface NewSheetOptions { name?: string; rows?: number; cols?: number; } /** * Pure ordered workbook document. It deliberately coordinates sheets without * taking ownership of rendering, browser storage, or UI interaction. */ declare class Workbook { private readonly entries; private nextId; private activeId; constructor(options?: NewSheetOptions); get sheets(): readonly WorkbookSheet[]; get activeSheetId(): string; get activeSheet(): WorkbookSheet; getSheet(id: string): WorkbookSheet; addSheet(name?: string, options?: Omit): WorkbookSheet; setActiveSheet(id: string): void; renameSheet(id: string, name: string): void; deleteSheet(id: string): WorkbookSheet; toSnapshot(): WorkbookSnapshot; static fromSnapshot(snapshot: WorkbookSnapshot): Workbook; private createEntry; private validateName; private nextSheetName; } /** Serialize only the documented, versioned document representation. */ declare function toWorkbookJson(workbook: Workbook): string; /** Reject malformed documents through Workbook's versioned snapshot contract. */ declare function parseWorkbookJson(source: string): Workbook; /** Export editable raw cell content so formulas survive a CSV round-trip. */ declare function toCsv(model: SheetModel, range: Rect): string; /** Parse RFC 4180-style quoted fields into bounded raw document writes. */ declare function fromCsv(source: string, origin: { row: number; col: number; }, bounds: SheetBounds): CellWrite[]; /** A compact starting sheet that exposes literals, formulas and range totals. */ declare function createDemoModel(): SheetModel; type Fn = (args: Node[], ctx: EvalContext) => Value; declare const FUNCTIONS: Record; /** Formula tokenizer. Input is the text AFTER the leading `=`. */ type TokenType = "num" | "str" | "ref" | "error" | "ident" | "op" | "eof"; interface Token { type: TokenType; text: string; pos: number; } declare class LexError extends Error { } declare function lex(src: string): Token[]; export { type AxisSizeWrite, type CellError, type CellFormat, type CellFormatWrite, type CellPos, type CellWrite, CycleError, DEFAULT_COLUMN_SIZE, DEFAULT_ROW_SIZE, type EvalContext, FUNCTIONS, type HorizontalAlign, LexError, type NewSheetOptions, type Node, type NumberFormat, ParseError, type PopulatedCell, type Rect, type SheetAxis, type SheetAxisMetricEntry, SheetAxisMetrics, type SheetAxisMetricsSnapshot, type SheetBounds, SheetHistory, SheetModel, type SheetSnapshot, type SheetStructureOperation, type Token, type TokenType, type Value, Workbook, type WorkbookSheet, type WorkbookSnapshot, type WorkbookSnapshotSheet, cellKey, colIndex, colName, collectRefs, copyRange, createDemoModel, err, evaluate, flatten, fromCsv, isErr, lex, mergeFormat, normalizeRect, parse, parseA1, parseKey, parseRange, parseWorkbookJson, pasteText, rectContains, toA1, toCsv, toWorkbookJson, transformAxisMetricIndex, transformCellPosition, transformFormulaReferences };