/** * xlsx STRUCTURE — merged cells, Excel tables, defined names. * * OWNERSHIP (DESIGN-P3.md): this file belongs to the STRUCTURE agent. It * imports only from `./internal.js`, `../xml/index.js`, `../opc/index.js`, * `../document/index.js` (R_NAMESPACE) and `../schema/index.js` — never * from `./index.js`, `./styles.js`, `./formula/` or `./streaming.js`. * The Integrate agent later wires these functions as methods: * * ```ts * sheet.merge('A1:C1'); // → mergeCells(sheet._internal(), 'A1:C1') * sheet.merges(); // → mergedRanges(...) * sheet.addTable('A1:D10', { name: 'Sales' }); * wb.setDefinedName('TaxRate', 'Sheet1!$B$1'); * ``` * * Design rules (normative — CONTRACTS.md §8.13–§8.15): * - All range refs are normalized A1 ('A1:C3'); XML attributes use the * two-corner form (internal.ts `formatRangeRefFull`). * - New elements are placed with `insertInSchemaOrder` (mergeCells and * tableParts position inside CT_Worksheet is the #1 repair-prompt trap). * - Table parts are created with content-type override + worksheet * relationship; tableColumn names and the header-row cell texts are * kept exactly equal (Excel repairs on mismatch). * * ASYNC NOTE (deviation from the sync stubs, per CONTRACTS.md §0.3): * `addTable` and `listTables` are `async`. Table parts are NOT eagerly * loaded by `Workbook.open`, and reading an existing table part may * decompress its zip entry — which the platform only offers async * (`DecompressionStream`). §0.3 is explicit that anything that may * decompress is async; the sync stub signatures were unimplementable. * Everything else in this module operates on eagerly-loaded DOMs * (worksheet, workbook.xml) and stays sync. */ import type { CellAddress } from './internal.js'; import { type SheetInternal, type WorkbookInternal } from './internal.js'; /** * Merge the cells of `range` ('B2:D2'; any corner order, absolute markers * accepted). The values of covered cells are left in place — Excel's file * model keeps only the top-left cell's value visible, and Excel opens * files with values in covered cells without complaint, so nothing is * destroyed (a later `unmerge` reveals them again). `setCell` on a * covered cell likewise still writes the value into the DOM; it simply * stays hidden behind the merge until unmerged — to change what the * merged area displays, write the top-left cell. Throws when `range` is a * single cell, or when it overlaps an existing merge (the message names * the overlapping range — unmerge it first). Marks the worksheet dirty. * * ```ts * sheet.merge('A1:C1'); * ``` */ export declare function mergeCells(sheet: SheetInternal, range: string): void; /** * Remove the merge whose range is exactly `range` (any corner order, * absolute markers ignored). Throws when no such merge exists — the * message lists the sheet's merges. Removes the `mergeCells` element when * it becomes empty. Marks the worksheet dirty. The values that were * covered by the merge were never cleared, so they reappear. * * ```ts * sheet.unmerge('A1:C1'); * ``` */ export declare function unmergeCells(sheet: SheetInternal, 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', 'B3:B5'] * ``` */ export declare function mergedRanges(sheet: SheetInternal): readonly string[]; /** Options for {@link addTable}. */ export interface TableOptions { /** * Table name AND displayName (Excel keeps them equal for UI-created * tables). Must start with a letter/_/backslash, contain no spaces * (' ' → suggest '_' in the error), be no longer than 255 chars, not * look like a cell reference, and be unique across the workbook * (case-insensitive). Default: 'TableN' for the smallest free N. */ readonly name?: string; /** * Header texts, left to right. Must match the range's column count. * They are WRITTEN into the header row cells (overwriting what is * there) because Excel requires header cells and tableColumn names to * agree. Omitted: existing header-row cell texts are used, blanks * become 'Column1', 'Column2', …; duplicates get numeric suffixes. */ readonly headers?: readonly string[]; /** * Table style name ('TableStyleMedium2' = Excel's default, also the * default here); null = no tableStyleInfo element (unstyled). */ readonly style?: string | null; } /** A read view of one Excel table. */ export interface TableInfo { /** table/@name (equals displayName for tables this library creates). */ readonly name: string; /** table/@displayName. */ readonly displayName: string; /** Normalized full range including header/totals rows ('A1:D10'). */ readonly range: string; /** Column names, left to right (tableColumn/@name). */ readonly columns: readonly string[]; /** True when the table shows a header row (headerRowCount ≠ 0). */ readonly headerRow: boolean; /** True when the table shows a totals row (totalsRowCount ≥ 1). */ readonly totalsRow: boolean; /** Table style name, or null when unstyled. */ readonly style: string | null; /** Absolute part name of the table XML ('/xl/tables/table1.xml'). */ readonly partName: string; /** Name of the worksheet the table lives on. */ readonly sheetName: string; } /** * Create an Excel table over `range` (first row = header row) with an * autofilter across the full range. Builds the table part * (/xl/tables/tableN.xml, smallest free N), the content-type override, * the worksheet→table relationship, and the worksheet `tableParts` entry * (in schema order). Header texts are written into the header-row cells * (see {@link TableOptions.headers}). Throws when `range` has fewer than * 2 rows (header + at least one data row), when the range overlaps an * existing table, or when the name is invalid/taken. Marks the worksheet * (and shared strings, via the header writes) dirty. * * Async because existing table parts must be read for workbook-wide * name/id uniqueness and overlap checks (CONTRACTS.md §0.3). * * ```ts * const t = await sheet.addTable('A1:D10', { name: 'Sales' }); * t.columns // → ['Region', 'Product', 'Qty', 'Revenue'] * ``` */ export declare function addTable(sheet: SheetInternal, range: string, options?: TableOptions): Promise; /** * The tables of this sheet, in worksheet `tablePart` document order. * Reads existing table parts (any producer), resolving each `r:id` * through the worksheet's relationships; a tablePart with a broken * relationship throws (never silently omitted, mirroring sheet * resolution). Async because table parts are read lazily (§0.3). * * ```ts * (await sheet.tables()).map((t) => t.name); // → ['Sales'] * ``` */ export declare function listTables(sheet: SheetInternal): Promise; /** A defined name, workbook- or sheet-scoped. */ export interface DefinedName { readonly name: string; /** The refers-to formula text, verbatim ('Sheet1!$B$1', 'OFFSET(…)'). */ readonly ref: string; /** * Scope: undefined = workbook-global; a sheet name = local to that * sheet (definedName/@localSheetId resolved through the FULL workbook * sheet list, including chartsheets). */ readonly sheet?: string; /** definedName/@hidden. */ readonly hidden: boolean; } /** Options for {@link setDefinedName} / {@link removeDefinedName}. */ export interface DefinedNameOptions { /** Scope the name to this sheet (name as shown on the tab). Omitted = * workbook scope. Unknown sheet name throws. */ readonly sheet?: string; /** Create the name hidden (setDefinedName only). Default false. */ readonly hidden?: boolean; } /** * All defined names of the workbook (both scopes), 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 }] * ``` */ export declare function definedNames(wb: WorkbookInternal): 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' * ``` */ export declare function getDefinedName(wb: WorkbookInternal, 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, and the text is otherwise stored verbatim * (no formula validation — CONTRACTS.md §8.15). Name rules per Excel: * starts with letter/_/backslash, then letters/digits/_/./?/backslash, * no spaces, ≤255 chars, must not look like a cell reference or a lone * 'R'/'C'. The `definedNames` element is created in schema order when * missing. Replacing matches by case-insensitive name + exact scope. * Marks workbook.xml dirty. * * ```ts * wb.setDefinedName('TaxRate', 'Sheet1!$B$1'); * wb.setDefinedName('LocalRange', 'Sheet2!$A$1:$A$10', { sheet: 'Sheet2' }); * ``` */ export declare function setDefinedName(wb: WorkbookInternal, name: string, ref: string, options?: DefinedNameOptions): void; /** * Remove a defined name (case-insensitive name + exact scope). Throws * when no such name exists — call `definedNames()` to list them. Removes * the `definedNames` element when it becomes empty. Marks workbook.xml * dirty. * * ```ts * wb.removeDefinedName('TaxRate'); * ``` */ export declare function removeDefinedName(wb: WorkbookInternal, name: string, options?: DefinedNameOptions): void; /** * @internal Validate an Excel defined-name / table name; throws with the * exact rule violated and a suggestion. Exposed for the implementation's * tests; not public API. */ export declare function validateXlName(name: string, kind: 'table' | 'defined name'): void; /** * @internal True when two normalized ranges intersect. Exposed for the * implementation's tests; not public API. */ export declare function rangesOverlap(a: { start: CellAddress; end: CellAddress; }, b: { start: CellAddress; end: CellAddress; }): boolean; //# sourceMappingURL=structure.d.ts.map