/** * SpreadsheetML high-level API — a LENS over the workbook/worksheet DOMs. * * `Workbook`/`Worksheet` read and mutate the parsed XML of * /xl/workbook.xml, worksheet parts, /xl/sharedStrings.xml and * /xl/styles.xml in place. Untouched parts (charts, pivots, macros, * anything unmodeled) are preserved byte-for-byte. * * String strategy (see CONTRACTS.md §xlsx): reads resolve BOTH shared * strings (t="s") and inline strings (t="inlineStr" / t="str"); writes * always use the shared string table (matching what Excel itself writes), * creating /xl/sharedStrings.xml on demand. Deduplication is by exact * text against plain (non-rich) entries. * * Dates: SpreadsheetML stores dates as serial numbers + number format. * `setCell(ref, date)` writes the serial (1900 date system, Excel's * leap-year-bug epoch of 1899-12-30, or the 1904 system when * workbookPr/@date1904 is set) with built-in number format 14 via a * cellXf DERIVED from the cell's current xf (numFmtId overridden, all * other styling — fill/border/font/alignment — preserved), deduplicated * by structural equality. `getCell` returns a `Date` when the cell's * style uses a built-in date/time numFmtId (14–22, 45–47) or a custom * number format whose code contains date/time tokens; otherwise the * number. Symmetrically, writing a plain number into a date-styled cell * derives a General-format clone of its xf so the value reads back as * the number that was written. * * Dirty tracking: every modeled DOM lives in the document layer's cache — * parts loaded at `open()` are parsed through `OfficeDocument.xml()`, and * parts this module creates (new sheets, a new shared string table or * stylesheet, everything in `create()`) are registered via the cache's * sync priming hook. `office.xml()` therefore always returns the same * live instance the lenses mutate, and `save()` is a pure delegate to * `OfficeDocument.save()`: only dirty parts are reserialized — * everything else raw-copies (L3). */ import { OfficeDocument } from '../document/index.js'; import { XmlElement } from '../xml/index.js'; import { type CellValue, type CellAddress, type CellInfo, type PartDom, type WorkbookInternal, type SheetInternal } from './internal.js'; import { type CellStyle, type CellStyleUpdate } from './styles.js'; import { type TableOptions, type TableInfo, type DefinedName, type DefinedNameOptions } from './structure.js'; export { SML_NAMESPACE, parseCellRef, formatCellRef, parseRangeRef, formatRangeRef, } from './internal.js'; export type { CellValue, CellAddress, RangeAddress, CellType, CellInfo, } from './internal.js'; export type { BorderLineStyle, BorderEdge, CellBorders, CellFont, CellFill, CellAlignmentInfo, CellNumberFormat, CellStyle, ColorInput, BorderEdgeUpdate, BordersUpdate, CellStyleUpdate, } from './styles.js'; export type { TableOptions, TableInfo, DefinedName, DefinedNameOptions, } from './structure.js'; export { parseFormula, formulaToText, a1ToR1C1, r1c1ToA1, XLFN_FUNCTIONS, XlsxFormulaError, } from './formula/index.js'; export type { ParseFormulaOptions, FormulaTextOptions, ArrayLiteralNode, BinaryNode, BinaryOperator, BooleanLiteralNode, CallNode, CellCoord, CellRefNode, ColRangeRefNode, EmptyArgNode, ErrorLiteralNode, ErrorLiteralValue, FormulaNode, GroupNode, NameRefNode, NumberLiteralNode, PercentNode, RangeRefNode, RowRangeRefNode, SheetPrefix, StringLiteralNode, StructuredItem, StructuredRefNode, UnaryNode, } from './formula/index.js'; export { readRows } from './streaming.js'; export type { StreamedCell, StreamedRow, ReadRowsOptions } from './streaming.js'; /** * An Excel workbook (xlsx/xlsm/xltx/xltm/xlam). */ export declare class Workbook { #private; /** @internal Construct via {@link Workbook.open} / {@link Workbook.create}. */ constructor(internal?: symbol); /** * Open an existing Excel-family file. Eagerly loads the DOMs of * workbook.xml, sharedStrings.xml, styles.xml, and every worksheet part * (streaming access is a later phase; the contract here is in-memory). * Throws `Error` when the bytes are not an Excel-family package. */ static open(bytes: Uint8Array): Promise; /** * Create a new, empty xlsx that real Excel opens without repair: * [Content_Types].xml, /_rels/.rels, /xl/workbook.xml with one empty * sheet 'Sheet1', /xl/_rels/workbook.xml.rels, /xl/worksheets/ * sheet1.xml, /xl/styles.xml (minimal stylesheet). See CONTRACTS.md. */ static create(): Workbook; /** The underlying office document (escape hatch to package and parts). */ get office(): OfficeDocument; /** * All worksheets in workbook order (w:sheets order). Stable lenses. * Sheet entries that do not resolve to a part throw (never silently * omitted); entries resolving to non-worksheet parts (chartsheets, * macrosheets, dialogsheets) are excluded — those parts are * intentionally opaque and survive save untouched. */ sheets(): readonly Worksheet[]; /** * One worksheet by exact name (case-insensitive, as Excel treats sheet * names) or 0-based index into workbook order. */ sheet(nameOrIndex: string | number): Worksheet | undefined; /** * Append a new empty worksheet: new part, workbook.xml entry * (fresh sheetId + rId), content-type override, workbook rels entry. * Default name 'SheetN' for the smallest free N; throws on duplicate * or invalid (per Excel rules: empty, >31 chars, \ / ? * [ ] :) names. */ addSheet(name?: string): Worksheet; /** * All defined names of the workbook (workbook- and sheet-scoped), in * document order. Built-in names (`_xlnm.Print_Area`, …) are included — * they are ordinary defined names in the XML. * * ```ts * wb.definedNames(); // → [{ name: 'TaxRate', ref: 'Sheet1!$B$1', hidden: false }] * ``` */ definedNames(): readonly DefinedName[]; /** * One defined name by name (case-insensitive, as Excel resolves them) * and scope: with `options.sheet` only that sheet's scope is searched, * without it only workbook scope. `undefined` when absent. * * ```ts * wb.getDefinedName('TaxRate')?.ref; // → 'Sheet1!$B$1' * ``` */ getDefinedName(name: string, options?: DefinedNameOptions): DefinedName | undefined; /** * Create or replace a defined name. `ref` is the refers-to formula text * ('Sheet1!$B$1', 'Sheet1!$A$1:$C$10', or any formula); a leading '=' * is accepted and stripped, the text otherwise stored verbatim. Scope * is workbook-wide unless `options.sheet` names a sheet. Name rules per * Excel (no spaces, ≤255 chars, must not look like a cell reference); * violations throw with the exact rule and a suggestion. * * ```ts * wb.setDefinedName('TaxRate', 'Sheet1!$B$1'); * wb.setDefinedName('Data', 'Sheet2!$A$1:$C$100', { sheet: 'Sheet2' }); * ``` */ setDefinedName(name: string, ref: string, options?: DefinedNameOptions): void; /** * Remove a defined name (case-insensitive name + exact scope). Throws * when no such name exists — `definedNames()` lists the existing ones. * * ```ts * wb.removeDefinedName('TaxRate'); * ``` */ removeDefinedName(name: string, options?: DefinedNameOptions): void; /** * Serialize to file bytes — delegates to `office.save()` after making * the shared-string counts exact: when the sst part is dirty its * count/uniqueCount attributes are recounted from the live DOM (an O(n) * pass, once per save), so the §8.4 counts contract holds in the saved * bytes even if sheet DOMs were mutated behind the lens. An untouched * sst stays on the raw-copy path (L3) — nothing is marked dirty here. */ save(): Promise; /** @internal Flag a modeled part dirty (all DOMs live in the office cache). */ _markDirty(pd: PartDom): void; /** @internal True when workbookPr declares the 1904 date system. */ _date1904(): boolean; /** @internal Resolve shared string `index` to flattened text. */ _sharedString(index: number): string; /** * @internal Intern `text` in the shared string table (creating the part * on first use), deduplicating by exact text against plain entries. * Returns the si index. Marks the table dirty. */ _internString(text: string): number; /** * @internal Bring the sst count/uniqueCount attributes up to date and * mark the table dirty. Called after any mutation that changes * shared-string usage. * * `delta` is the net change in `t="s"` cells (across loaded worksheets) * caused by the mutation just performed; with it the update is O(1) — * the count is maintained incrementally (the historic full-workbook * recount per string write was the second half of the O(n²) bulk-write * problem). Without `delta` — or when the incremental total was * invalidated by a detected raw-DOM mutation — the count is recomputed * from the live DOM exactly as before (total t="s" cells across all * loaded worksheets plus the opaque macrosheet/dialogsheet parts * counted at open). `save()` always forces that full recount before a * dirty sst is serialized, so the §8.4 saved-bytes contract holds * independently of this cache. */ _updateSharedStringCounts(delta?: number): void; /** * @internal A sheet's row index detected a raw-DOM mutation (see * sheet-index.ts): the incremental t="s" total can no longer be * trusted — drop it so the next count update recounts from the DOM. */ _noteRawSheetMutation(): void; /** @internal Whether the workbook currently has a shared string table. */ _hasSharedStrings(): boolean; /** * @internal True when the cell style index `sAttr` resolves to a * date/time number format (built-in 14–22/45–47 or a custom format * whose code contains date tokens). */ _isDateStyle(sAttr: string | undefined): boolean; /** * @internal The cellXf index for writing a Date into the cell whose * current style attribute is `currentS`: the cell's current xf cloned * with numFmtId 14 (built-in short date) + applyNumberFormat, so * fill/border/font/alignment survive the write (a plain * numFmtId-14 xf when the cell has no resolvable style). Deduplicated * against existing xfs by structural equality — repeated writes reuse * one xf. Creates a minimal styles.xml when the workbook has none. */ _deriveDateStyle(currentS: string | undefined): string; /** * @internal The cellXf index for writing a plain number into a cell * whose current xf carries a date/time number format: the current xf * cloned with numFmtId 0 (General) and applyNumberFormat dropped, so * the cell stops reading back as a Date while the rest of its styling * survives (CONTRACTS.md §8.5). Deduplicated like `_deriveDateStyle` — * a date-write-then-number-write round-trip lands back on the original * xf. */ _deriveGeneralStyle(currentS: string | undefined): string; /** * @internal Remove the calculation chain (part + workbook relationship). * Called when a formula is removed: a calcChain entry pointing at a * non-formula cell makes Excel repair the file, and Excel rebuilds the * chain on demand. */ _dropCalcChain(): void; /** * @internal The capability object the Phase-3 feature modules * (styles.ts, structure.ts, formula/, streaming.ts) code against. * See `WorkbookInternal` in internal.ts for the contract. Stable per * Workbook instance. Not public API. */ _internal(): WorkbookInternal; } /** * Lens over one worksheet part (plus the shared string and style tables * it needs to interpret values). */ export declare class Worksheet { #private; /** @internal Construct via Workbook only. */ constructor(internal: symbol, wb: Workbook, sheetEl: XmlElement, pd: PartDom); /** Sheet name as shown on the tab. */ get name(): string; /** Absolute part name of the worksheet XML, e.g. '/xl/worksheets/sheet1.xml'. */ get partName(): string; /** The sheetId attribute of the workbook's `sheet` entry (NaN if absent). */ get sheetId(): number; /** The relationship id wiring this sheet to its part (e.g. 'rId1'). */ get rId(): string; /** * Read a cell by reference — 'B7' (A1 text) or {row, col} (1-based). * - empty/missing cell → null * - t="s" → resolved shared string (rich-text runs flattened to text) * - t="inlineStr"/"str" → string * - t="b" → boolean * - numeric with a date-formatted style → Date (see module doc) * - otherwise → number * Formula cells yield their cached value; the formula itself is not * evaluated (out of scope) nor returned by this method. */ getCell(ref: string | CellAddress): CellValue; /** * Rich read: cell type, decoded value, and formula text when present. * The same typing rules as {@link getCell}; cached error values (t="e") * are reported as type 'error' with the error literal (e.g. '#DIV/0!') * as a string value. */ getCellInfo(ref: string | CellAddress): CellInfo; /** * Write a cell by reference — 'B7' (A1 text) or {row, col} (1-based) — * creating row/cell elements as needed * and keeping rows and cells ordered by index (Excel requires this). * Strings go through the shared string table; null clears the value * (removes v/is children but keeps the cell if it carries a style; * otherwise removes the cell). Replaces any existing formula. Marks the * affected parts dirty. */ setCell(ref: string | CellAddress, value: CellValue): void; /** * The effective style of the cell at `ref` ('B2' or {row, col}), fully * resolved through c/@s → cellXfs → fonts/fills/borders/numFmts. A cell * with no style attribute (or a missing cell) resolves through cellXf 0; * a workbook with no styles.xml yields the documented defaults (Calibri * 11, no fill, no borders, General). * * ```ts * sheet.getCellStyle('B2').font.bold; // → true * ``` */ getCellStyle(ref: string | CellAddress): CellStyle; /** * Merge a partial, flat style update into every cell of `ref` (a single * cell 'B2', a range 'A1:D1', or {row, col}). Only the properties you * name change; explicit `null` clears one back to its default. Empty * cells in a range get style-only cell elements so the styling shows in * Excel. Fonts/fills/borders/numFmts/xfs are deduplicated by structural * equality — styling 10 000 cells the same way adds at most one element * to each styles.xml collection. * * ```ts * sheet.setCellStyle('A1:D1', { bold: true, fill: '#4472C4', color: '#FFFFFF' }); * ``` */ setCellStyle(ref: string | CellAddress, update: CellStyleUpdate): void; /** * The explicit width of a column ('B' or 1-based number) in Excel width * units (the number the Excel UI shows), or null when the column has no * explicit width (sheet default applies). * * ```ts * sheet.getColumnWidth('B'); // → 14.5 * ``` */ getColumnWidth(col: string | number): number | null; /** * Set a column's width in Excel width units (0–255); null removes the * explicit width (back to the sheet default). Other column properties * (hidden, style, …) on the same `col` run survive. * * ```ts * sheet.setColumnWidth('B', 14.5); * ``` */ setColumnWidth(col: string | number, width: number | null): void; /** * The explicit height of a 1-based row in points, or null when the row * has no explicit height (sheet default applies). * * ```ts * sheet.getRowHeight(3); // → 24 * ``` */ getRowHeight(row: number): number | null; /** * Set a row's height in points (0–409.5); null removes the explicit * height. All other row attributes and cells are untouched. * * ```ts * sheet.setRowHeight(3, 24); * ``` */ setRowHeight(row: number, height: number | null): void; /** * Merge the cells of `range` ('A1:C1'; any corner order). Covered cell * values are left in place (Excel shows the top-left one; `unmerge` * reveals the rest again — nothing is destroyed). Throws on a * single-cell range or when overlapping an existing merge (the message * names it). * * ```ts * sheet.merge('A1:C1'); * ``` */ merge(range: string): void; /** * Remove the merge whose range is exactly `range` (any corner order). * Throws when no such merge exists — the message lists the sheet's * merges. Values covered by the merge were never cleared, so they * reappear. * * ```ts * sheet.unmerge('A1:C1'); * ``` */ unmerge(range: string): void; /** * All merged ranges of the sheet, normalized ('A1:C1'), in document * order. Empty array when the sheet has none. * * ```ts * sheet.merges(); // → ['A1:C1'] * ``` */ merges(): readonly string[]; /** * Create an Excel table over `range` (first row = header row) with an * autofilter: real table part, content-type override, worksheet * relationship and `tableParts` entry. Header texts are written into * the header-row cells (from `options.headers`, or generated/uniquified * from what's there) because Excel requires header cells and column * names to agree. Throws when the range has fewer than 2 rows, overlaps * an existing table, or the name is invalid/taken. Async: existing * table parts are read for workbook-wide name/id uniqueness and overlap * checks (CONTRACTS.md §8.14). * * ```ts * const t = await sheet.addTable('A1:D10', { name: 'Sales' }); * t.columns; // → ['Region', 'Product', 'Qty', 'Revenue'] * ``` */ addTable(range: string, options?: TableOptions): Promise; /** * The tables of this sheet, in worksheet `tablePart` document order * (any producer's tables, not only ones this library created). A * tablePart with a broken relationship throws — never silently omitted. * Async: table parts are read lazily (CONTRACTS.md §8.14). * * ```ts * (await sheet.tables()).map((t) => t.name); // → ['Sales'] * ``` */ tables(): Promise; /** * Write a formula into the cell at `ref` ('D2' or {row, col}). A * leading '=' is accepted and stripped. The text is validated by the * formula parser BEFORE anything is touched (syntax errors throw with * offset and expectation) and stored canonically (`_xlfn.` prefixes * re-added for the functions that need them). Any cached value is * removed, the calc chain dropped, and calcPr/@fullCalcOnLoad set so * Excel recalculates on open. Overwriting a shared-formula group * master throws (rewriting the group is not supported yet). * * ```ts * sheet.setFormula('D2', '=SUM(B2:C2)'); * ``` */ setFormula(ref: string | CellAddress, formula: string): void; /** * The formula text of the cell at `ref`, without a leading '=', exactly * as stored; null when the cell has no formula. A dependent cell of a * shared formula group returns the group formula translated to this * cell's position (what Excel's formula bar shows). * * ```ts * sheet.getFormula('D2'); // → 'SUM(B2:C2)' * ``` */ getFormula(ref: string | CellAddress): string | null; /** * @internal The capability object the Phase-3 feature modules code * against. See `SheetInternal` in internal.ts for the contract. Stable * per Worksheet instance. Not public API. */ _internal(): SheetInternal; } //# sourceMappingURL=index.d.ts.map