@office-kit/xlsx 0.11.1 → 0.12.0

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 (68) hide show
  1. package/README.md +4 -1
  2. package/dist/cell/cell.d.ts +44 -9
  3. package/dist/cell/index.d.ts +1 -1
  4. package/dist/{cell-BucgGwl3.mjs → cell-Df3cKRIl.mjs} +72 -30
  5. package/dist/cell-Df3cKRIl.mjs.map +1 -0
  6. package/dist/{cell-style-DuvS_Lsg.mjs → cell-style-BFmJOmcx.mjs} +130 -93
  7. package/dist/cell-style-BFmJOmcx.mjs.map +1 -0
  8. package/dist/cell.mjs +2 -2
  9. package/dist/{coordinate-96Ecci4d.mjs → coordinate-Bt5Gni2I.mjs} +19 -8
  10. package/dist/coordinate-Bt5Gni2I.mjs.map +1 -0
  11. package/dist/{defined-names-CviWmtQg.mjs → defined-names-Ctu3F6ls.mjs} +4 -3
  12. package/dist/defined-names-Ctu3F6ls.mjs.map +1 -0
  13. package/dist/{differential-DvKU8fJt.mjs → differential-H9SjEeIU.mjs} +2 -2
  14. package/dist/{differential-DvKU8fJt.mjs.map → differential-H9SjEeIU.mjs.map} +1 -1
  15. package/dist/{drawing-BxzLuryn.mjs → drawing-ZJ3h4VHD.mjs} +2 -2
  16. package/dist/{drawing-BxzLuryn.mjs.map → drawing-ZJ3h4VHD.mjs.map} +1 -1
  17. package/dist/drawing.mjs +1 -1
  18. package/dist/{inference-BrI9uIY4.mjs → inference-BMvv9cUY.mjs} +18 -3
  19. package/dist/inference-BMvv9cUY.mjs.map +1 -0
  20. package/dist/io.mjs +2 -2
  21. package/dist/{load-Bghb1YHY.mjs → load-CJdGh50R.mjs} +6 -6
  22. package/dist/{load-Bghb1YHY.mjs.map → load-CJdGh50R.mjs.map} +1 -1
  23. package/dist/node.mjs +1 -1
  24. package/dist/{save-Bqcf8w3g.mjs → save-a0InIbtJ.mjs} +7 -5
  25. package/dist/save-a0InIbtJ.mjs.map +1 -0
  26. package/dist/streaming/write-only.d.ts +7 -13
  27. package/dist/streaming.mjs +16 -46
  28. package/dist/streaming.mjs.map +1 -1
  29. package/dist/styles/cell-style.d.ts +78 -32
  30. package/dist/styles/fonts.d.ts +10 -1
  31. package/dist/styles/index.d.ts +3 -3
  32. package/dist/styles/stylesheet.d.ts +26 -0
  33. package/dist/styles.mjs +4 -4
  34. package/dist/{stylesheet-writer-HxaX7bGy.mjs → stylesheet-writer-D7Uug85X.mjs} +31 -18
  35. package/dist/stylesheet-writer-D7Uug85X.mjs.map +1 -0
  36. package/dist/{table-1P8we2gS.mjs → table-Ccro4rrz.mjs} +11 -9
  37. package/dist/table-Ccro4rrz.mjs.map +1 -0
  38. package/dist/utils/coordinate.d.ts +30 -4
  39. package/dist/utils/formula-text.d.ts +7 -0
  40. package/dist/utils/index.d.ts +1 -1
  41. package/dist/utils.mjs +2 -2
  42. package/dist/workbook/calc-properties.d.ts +8 -1
  43. package/dist/workbook/index.d.ts +1 -1
  44. package/dist/{workbook-BlZVXiyG.mjs → workbook-B15-T4cs.mjs} +6 -6
  45. package/dist/{workbook-BlZVXiyG.mjs.map → workbook-B15-T4cs.mjs.map} +1 -1
  46. package/dist/workbook.mjs +45 -3
  47. package/dist/workbook.mjs.map +1 -1
  48. package/dist/worksheet/cell-range.d.ts +10 -3
  49. package/dist/worksheet/data-validations.d.ts +1 -1
  50. package/dist/worksheet/index.d.ts +3 -3
  51. package/dist/worksheet/table-validate.d.ts +7 -0
  52. package/dist/worksheet/table.d.ts +4 -1
  53. package/dist/worksheet/views.d.ts +5 -0
  54. package/dist/worksheet/worksheet.d.ts +106 -65
  55. package/dist/worksheet/writer.d.ts +7 -0
  56. package/dist/{worksheet-C5Ensf_j.mjs → worksheet-4xW-i8j9.mjs} +235 -51
  57. package/dist/worksheet-4xW-i8j9.mjs.map +1 -0
  58. package/dist/worksheet.mjs +3 -3
  59. package/package.json +1 -1
  60. package/dist/cell-BucgGwl3.mjs.map +0 -1
  61. package/dist/cell-style-DuvS_Lsg.mjs.map +0 -1
  62. package/dist/coordinate-96Ecci4d.mjs.map +0 -1
  63. package/dist/defined-names-CviWmtQg.mjs.map +0 -1
  64. package/dist/inference-BrI9uIY4.mjs.map +0 -1
  65. package/dist/save-Bqcf8w3g.mjs.map +0 -1
  66. package/dist/stylesheet-writer-HxaX7bGy.mjs.map +0 -1
  67. package/dist/table-1P8we2gS.mjs.map +0 -1
  68. package/dist/worksheet-C5Ensf_j.mjs.map +0 -1
@@ -1,11 +1,18 @@
1
1
  import type { Cell } from '../cell/cell.js';
2
- import { type CellRangeBoundaries } from '../utils/coordinate.js';
2
+ import { type CellRangeBoundaries, type RangeRef } from '../utils/coordinate.js';
3
3
  /** Re-export under the plan's canonical name. */
4
4
  export type CellRange = CellRangeBoundaries;
5
5
  /** Build a CellRange from explicit 1-based bounds. */
6
6
  export declare function makeCellRange(minRow: number, minCol: number, maxRow: number, maxCol: number): CellRange;
7
- /** Parse a range expression — wraps {@link rangeBoundaries}. */
8
- export declare function parseRange(input: string): CellRange;
7
+ /**
8
+ * Resolve a {@link RangeRef} to numeric bounds: A1 expressions go through
9
+ * {@link rangeBoundaries}, pre-computed bounds through {@link makeCellRange}.
10
+ * Both paths validate against the grid and normalise inverted bounds, so
11
+ * `{ minRow: 5, maxRow: 1 }` behaves like `"A5:A1"` rather than iterating zero
12
+ * rows, and a fractional or off-grid bound throws here instead of half-way
13
+ * through the caller's loop.
14
+ */
15
+ export declare function parseRange(input: RangeRef): CellRange;
9
16
  /** Format a CellRange back into the canonical OOXML string. */
10
17
  export declare function rangeToString(r: CellRange): string;
11
18
  /**
@@ -45,7 +45,7 @@ export interface ValidationCommon {
45
45
  /**
46
46
  * Add a list-type dropdown validation to a range. `values` may be an inline
47
47
  * list (`['Red', 'Green', 'Blue']`) or a sheet reference
48
- * (`'=Sheet1!$A$1:$A$10'`).
48
+ * (`'Sheet1!$A$1:$A$10'`, with or without a leading `=`).
49
49
  */
50
50
  export declare const addListValidation: (ws: Worksheet, sqref: MultiCellRange | string, values: ReadonlyArray<string> | string, opts?: ValidationCommon) => DataValidation;
51
51
  /**
@@ -1,10 +1,10 @@
1
- export type { CellsByKindCounts, IterRowsOptions, Worksheet, } from './worksheet.js';
2
- export { addCellWatch, addConditionalFormatting, addDataValidation, addIgnoredError, addTable, appendRow, appendRows, applyToRange, autofitColumns, clearAllCells, clearRange, collapseColumnGroup, collapseRowGroup, copyRange, countCells, countCellsByKind, deleteCell, expandColumnGroup, expandRowGroup, findCells, freezePanes, getAutoFilter, getCell, getCellByCoord, getCellsInColumn, getCellsInRange, getCellsInRow, getColumnDimension, getDataExtent, getFreezePanes, getMaxCol, getMaxRow, getMergedCells, getMergedRangeAt, getNonEmptyCellCount, getPopulatedColumnIndices, getPopulatedRowIndices, getRangeValues, getRowDimension, getTable, groupColumns, groupRows, hideColumn, hideColumns, hideRow, hideRows, isMergedCell, isWorksheetEmpty, iterCells, iterRows, iterValues, listComments, listDataValidations, listHyperlinks, listTables, makeWorksheet, mergeCells, moveRange, removeAllComments, removeAllConditionalFormatting, removeAllDataValidations, removeAllHyperlinks, removeAllMergedRanges, removeAllTables, removeCellWatches, removeDataValidations, removeHyperlink, removeIgnoredErrors, removeTable, setAutoFilter, setCell, setCellByCoord, setColumnDimension, setColumnWidth, setColumnWidths, setComment, setDefaultColumnWidth, setDefaultRowHeight, setFreezePanes, setHyperlink, setRangeValues, setRowDimension, setRowHeight, setRowHeights, setSheetTabColor, setSheetViewMode, setSheetZoom, ungroupColumns, ungroupRows, unhideColumn, unhideColumns, unhideRow, unhideRows, unmergeCells, unmergeCellsAt, writeRange, } from './worksheet.js';
1
+ export type { AppendRowOptions, CellsByKindCounts, IterRowsOptions, Worksheet, } from './worksheet.js';
2
+ export { addCellWatch, addConditionalFormatting, addDataValidation, addIgnoredError, addTable, appendRow, appendRows, applyToRange, autofitColumns, clearAllCells, clearRange, collapseColumnGroup, collapseRowGroup, copyRange, countCells, countCellsByKind, deleteCell, ensureCell, ensureCellByCoord, expandColumnGroup, expandRowGroup, findCells, getAutoFilter, getCell, getCellByCoord, getCellsInColumn, getCellsInRange, getCellsInRow, getColumnDimension, getDataExtent, getFreezePanes, getMaxCol, getMaxRow, getMergedCells, getMergedRangeAt, getNonEmptyCellCount, getPopulatedColumnIndices, getPopulatedRowIndices, getRangeValues, getRowDimension, getTable, groupColumns, groupRows, hideColumn, hideColumns, hideRow, hideRows, isMergedCell, isWorksheetEmpty, iterCells, iterRows, iterValues, listComments, listDataValidations, listHyperlinks, listTables, makeWorksheet, mergeCells, moveRange, removeAllComments, removeAllConditionalFormatting, removeAllDataValidations, removeAllHyperlinks, removeAllMergedRanges, removeAllTables, removeCellWatches, removeDataValidations, removeHyperlink, removeIgnoredErrors, removeTable, setAutoFilter, setCell, setCellByCoord, setColumnDimension, setColumnWidth, setColumnWidths, setComment, setDefaultColumnWidth, setDefaultRowHeight, setFreezePanes, setHyperlink, setRangeValues, setRowDimension, setRowHeight, setRowHeights, setSheetTabColor, setSheetViewMode, setSheetZoom, ungroupColumns, ungroupRows, unhideColumn, unhideColumns, unhideRow, unhideRows, unmergeCells, unmergeCellsAt, writeRange, } from './worksheet.js';
3
3
  export type { MultiCellRange } from './cell-range.js';
4
4
  export { expandRangeStr, intersectionRange, isCellInRange, isRangeInRange, rangeArea, rangeContainsCell, rangeContainsRange, rangesOverlap, shiftRange, unionRange, } from './cell-range.js';
5
5
  export type { ColumnDimension, RowDimension } from './dimensions.js';
6
6
  export { makeColumnDimension, makeRowDimension } from './dimensions.js';
7
- export type { Pane, PaneState, PaneType, Selection, SheetView, SheetViewMode, } from './views.js';
7
+ export type { FreezeCounts, Pane, PaneState, PaneType, Selection, SheetView, SheetViewMode, } from './views.js';
8
8
  export { freezePaneRef, makeFreezePane, makeSheetView } from './views.js';
9
9
  export type { LegacyComment } from './comments.js';
10
10
  export { makeLegacyComment } from './comments.js';
@@ -0,0 +1,7 @@
1
+ import type { TableDefinition } from './table.js';
2
+ import type { Worksheet } from './worksheet.js';
3
+ /**
4
+ * Reject a table whose declared geometry or column names disagree with the
5
+ * sheet underneath it.
6
+ */
7
+ export declare const validateTableAgainstSheet: (ws: Worksheet, table: TableDefinition) => void;
@@ -1,6 +1,6 @@
1
1
  import type { Workbook } from '../workbook/workbook.js';
2
2
  import type { AutoFilter } from './auto-filter.js';
3
- import type { Worksheet } from './worksheet.js';
3
+ import { type Worksheet } from './worksheet.js';
4
4
  export interface TableColumn {
5
5
  /** 1-based column id (per-table). */
6
6
  id: number;
@@ -65,6 +65,9 @@ export declare function makeTableDefinition(opts: {
65
65
  * in one call. Auto-assigns the workbook-unique `id`, derives `displayName`
66
66
  * from the supplied `name`, and constructs `TableColumn` records (1-based ids)
67
67
  * from a string-array shorthand.
68
+ *
69
+ * Goes through {@link addTable}, so the definition is checked against the sheet
70
+ * before it lands. Pass `headerRowCount: 0` for a genuinely header-less table.
68
71
  */
69
72
  export declare const addExcelTable: (wb: Workbook, ws: Worksheet, opts: {
70
73
  name: string;
@@ -35,6 +35,11 @@ export interface SheetView {
35
35
  }
36
36
  /** Build a SheetView with sensible defaults. */
37
37
  export declare function makeSheetView(opts?: Partial<SheetView>): SheetView;
38
+ /** How many rows / columns a freeze holds in place, counted from the top-left. */
39
+ export interface FreezeCounts {
40
+ rows: number;
41
+ cols: number;
42
+ }
38
43
  /**
39
44
  * Build a frozen Pane from a top-left coordinate. Per Excel semantics:
40
45
  * - "B2" → freeze 1 row + 1 col → xSplit=1, ySplit=1, activePane='bottomRight'
@@ -1,8 +1,8 @@
1
1
  import type { CellValue } from '../cell/cell.js';
2
2
  import { type Cell } from '../cell/cell.js';
3
- import { type InlineFont, type TextRun } from '../cell/rich-text.js';
4
3
  import type { Drawing } from '../drawing/drawing.js';
5
4
  import { type Color } from '../styles/colors.js';
5
+ import { type CellCoordinateNumeric, type RangeRef } from '../utils/coordinate.js';
6
6
  import type { AutoFilter } from './auto-filter.js';
7
7
  import { type CellRange } from './cell-range.js';
8
8
  import type { LegacyComment } from './comments.js';
@@ -21,7 +21,7 @@ import type { SortState } from './sort-state.js';
21
21
  import type { WebPublishItem, WorksheetCustomProperty } from './web-publish.js';
22
22
  import { type Hyperlink } from './hyperlinks.js';
23
23
  import type { TableDefinition } from './table.js';
24
- import { type SheetView } from './views.js';
24
+ import { type FreezeCounts, type SheetView } from './views.js';
25
25
  export interface Worksheet {
26
26
  title: string;
27
27
  /** Sparse store: row index → (col index → Cell). */
@@ -232,10 +232,29 @@ export declare function makeWorksheet(title: string): Worksheet;
232
232
  /** Resolve a 1-based or "A1" coordinate; returns the populated Cell or undefined. */
233
233
  export declare function getCell(ws: Worksheet, row: number, col: number): Cell | undefined;
234
234
  /**
235
- * Create or update a Cell at (row, col). Existing cells keep their styleId /
236
- * hyperlinkId / commentId unless explicitly overridden.
235
+ * Write a Cell at (row, col), creating it when the coordinate is empty.
236
+ * `value` always lands on the cell, so an existing value is replaced. Use
237
+ * {@link ensureCell} to reach a cell without writing to it. An existing cell
238
+ * keeps its styleId / hyperlinkId / commentId unless `styleId` is passed.
239
+ *
240
+ * `null` is the explicit empty value: it clears the value and leaves the cell
241
+ * in the sheet with its fill, border and number format, the way Excel's
242
+ * Delete key does. {@link deleteCell} drops the cell entirely, formatting
243
+ * included, and {@link clearRange} does the same across a rectangle.
244
+ */
245
+ export declare function setCell(ws: Worksheet, row: number, col: number, value: CellValue, styleId?: number): Cell;
246
+ /**
247
+ * Get the Cell at (row, col), allocating an empty one when the coordinate is
248
+ * not populated yet. An existing cell is returned untouched, value and all,
249
+ * which makes this the way to reach a cell you are about to style or attach a
250
+ * formula to.
251
+ *
252
+ * {@link mergeCells} drops the cells underneath a merge; reaching one of those
253
+ * coordinates allocates it again, and the written `<sheetData>` then carries a
254
+ * blank `<c>` under the merge. A merged block's value lives on its top-left
255
+ * cell, so address that coordinate when the block is what you mean.
237
256
  */
238
- export declare function setCell(ws: Worksheet, row: number, col: number, value?: CellValue, styleId?: number): Cell;
257
+ export declare function ensureCell(ws: Worksheet, row: number, col: number): Cell;
239
258
  /** Delete a single cell from the sheet. Empty rows are pruned. */
240
259
  export declare function deleteCell(ws: Worksheet, row: number, col: number): void;
241
260
  /**
@@ -243,28 +262,51 @@ export declare function deleteCell(ws: Worksheet, row: number, col: number): voi
243
262
  * removed. Row maps that go empty are pruned. Column / row dimensions, merges,
244
263
  * comments etc. are left untouched.
245
264
  */
246
- export declare function clearRange(ws: Worksheet, range: string): number;
265
+ export declare function clearRange(ws: Worksheet, range: RangeRef): number;
247
266
  /**
248
267
  * Wipe every populated cell on the worksheet, leaving styles, dimensions,
249
268
  * merges, comments, hyperlinks etc. intact. Returns the count of cells removed.
250
269
  * Useful when a sheet should be re-filled from scratch but its formatting kept.
251
270
  */
252
271
  export declare function clearAllCells(ws: Worksheet): number;
272
+ export interface AppendRowOptions {
273
+ /**
274
+ * Style ids to apply per column, positionally aligned with `values`. Build
275
+ * the ids once with `registerCellStyle` from `@office-kit/xlsx/styles` and
276
+ * reuse them for every row.
277
+ *
278
+ * A column carrying a style id is written even when its value is empty, so a
279
+ * bordered-but-blank input column survives the append. Ids past the end of
280
+ * `values` therefore materialise styled blank cells, widening the sheet: a
281
+ * 4-value row with 5 ids occupies 5 columns, and `getMaxCol`, the
282
+ * `<dimension>` ref and `iterRows` all see the fifth. For ragged rows that
283
+ * should stop at their own last value, trim the array per row:
284
+ * `{ styleIds: columnStyles.slice(0, values.length) }`.
285
+ */
286
+ styleIds?: ReadonlyArray<number | undefined>;
287
+ }
253
288
  /**
254
289
  * Append a row of values starting at the next empty row. Returns the row index
255
290
  * (1-based). Mirrors openpyxl's `Worksheet.append`. `null` / `undefined`
256
- * entries leave the cell empty.
291
+ * entries leave the cell empty unless `opts.styleIds` names a style for that
292
+ * column.
257
293
  */
258
- export declare function appendRow(ws: Worksheet, values: ReadonlyArray<CellValue | undefined>): number;
294
+ export declare function appendRow(ws: Worksheet, values: ReadonlyArray<CellValue | undefined>, opts?: AppendRowOptions): number;
259
295
  /**
260
296
  * Bulk version of {@link appendRow}: append a 2D array of values one row at a
261
- * time. Returns `{firstRow, lastRow}` both 1-based, inclusive. An empty input
262
- * returns `{firstRow, lastRow: firstRow - 1}` so callers can detect the no-op
263
- * without throwing.
297
+ * time. Returns `{firstRow, lastRow}`, both 1-based and inclusive. An empty
298
+ * input returns `{firstRow, lastRow: firstRow - 1}` so callers can detect the
299
+ * no-op without throwing.
264
300
  *
265
301
  * Common usage: `appendRows(ws, csvParsedRows)` for fast import.
302
+ *
303
+ * `opts` is column-indexed, not row-indexed: the same
304
+ * {@link AppendRowOptions.styleIds} apply to every row, which is the point when
305
+ * a column has one format down the whole table. Rows shorter than `styleIds`
306
+ * still get the trailing styled blanks described there, so trim per row when
307
+ * the input is ragged.
266
308
  */
267
- export declare function appendRows(ws: Worksheet, rows: ReadonlyArray<ReadonlyArray<CellValue | undefined>>): {
309
+ export declare function appendRows(ws: Worksheet, rows: ReadonlyArray<ReadonlyArray<CellValue | undefined>>, opts?: AppendRowOptions): {
268
310
  firstRow: number;
269
311
  lastRow: number;
270
312
  };
@@ -282,7 +324,7 @@ export declare function appendRows(ws: Worksheet, rows: ReadonlyArray<ReadonlyAr
282
324
  * coordinates. An empty rows array returns `undefined` rather than an invalid
283
325
  * zero-area range.
284
326
  */
285
- export declare function writeRange(ws: Worksheet, startRef: string, values: ReadonlyArray<ReadonlyArray<CellValue | undefined>>): {
327
+ export declare function writeRange(ws: Worksheet, startRef: string | CellCoordinateNumeric, values: ReadonlyArray<ReadonlyArray<CellValue | undefined>>): {
286
328
  minRow: number;
287
329
  maxRow: number;
288
330
  minCol: number;
@@ -386,10 +428,11 @@ export declare function getCellAddress(ws: Worksheet, c: Cell): string;
386
428
  * Sheet-qualified A1 range address — `'Sheet1!A1:B5'` for plain titles,
387
429
  * `'\'Quarter 1\'!A1:B5'` for titles needing quoting. Pass any A1-style range
388
430
  * string (single cell `'A1'`, rectangle `'A1:B5'`, row span `'1:5'`, column
389
- * span `'A:E'`); the helper does no validation on `range` itself — that's the
390
- * caller's responsibility.
431
+ * span `'A:E'`), which is forwarded verbatim without validation, or numeric
432
+ * bounds, which are validated and normalised into a rectangle so the address
433
+ * names the region the other range helpers would operate on.
391
434
  */
392
- export declare function getRangeAddress(ws: Worksheet, range: string): string;
435
+ export declare function getRangeAddress(ws: Worksheet, range: RangeRef): string;
393
436
  /**
394
437
  * True iff the worksheet has zero non-empty cells. Equivalent to
395
438
  * `getNonEmptyCellCount(ws) === 0` but short-circuits on the first non-null
@@ -450,57 +493,41 @@ export declare function replaceCellValues(ws: Worksheet, search: string | ((valu
450
493
  * predicate over every populated cell), but only cells inside the rectangular
451
494
  * `range` are visited. Returns the count changed.
452
495
  */
453
- export declare function replaceInRange(ws: Worksheet, range: string, search: string | ((value: CellValue, cell: Cell) => boolean), replacement: CellValue): number;
496
+ export declare function replaceInRange(ws: Worksheet, range: RangeRef, search: string | ((value: CellValue, cell: Cell) => boolean), replacement: CellValue): number;
454
497
  /**
455
498
  * Iterate the populated cells inside a rectangular range. Cells that don't
456
499
  * exist in the sparse store are skipped (no auto-allocate). Use {@link
457
500
  * applyToRange} when you need every coordinate visited regardless of
458
501
  * population.
459
502
  */
460
- export declare function getCellsInRange(ws: Worksheet, range: string): IterableIterator<Cell>;
503
+ export declare function getCellsInRange(ws: Worksheet, range: RangeRef): IterableIterator<Cell>;
461
504
  /**
462
- * Set a cell's value to a rich-text run array. Accepts either a pre-built
463
- * `RichText` (frozen array of TextRun) or a fresh `Array<{ text, font? }>`
464
- * shape `makeRichText` normalises and freezes the runs in either case.
465
- * Returns the cell.
505
+ * A1-addressed {@link setCell}: resolves `coord` to a numeric (row, col) and
506
+ * writes `value` there. Throws `OpenXmlSchemaError` when `coord` is not a
507
+ * plain A1 reference.
466
508
  */
467
- export declare function setCellRichText(ws: Worksheet, row: number, col: number, runs: ReadonlyArray<TextRun | {
468
- text: string;
469
- font?: InlineFont;
470
- }>, styleId?: number): Cell;
471
- /**
472
- * Set a cell's value to a normal Excel formula. Combines `setCell` with
473
- * `setFormula`. The leading `=` is stripped if present so callers can pass
474
- * `'=A1+1'` or `'A1+1'` interchangeably.
475
- */
476
- export declare function setCellFormula(ws: Worksheet, row: number, col: number, formula: string, opts?: {
477
- cachedValue?: number | string | boolean;
478
- styleId?: number;
479
- }): Cell;
480
- /**
481
- * Set a cell's value to an array (CSE) formula spanning `ref`. Lands the
482
- * formula on the top-left cell of the range — Excel reads the `ref` attribute
483
- * to know how far the result spreads. Equivalent to `setCell` +
484
- * `setArrayFormula`. Leading `=` is stripped.
485
- */
486
- export declare function setCellArrayFormula(ws: Worksheet, row: number, col: number, ref: string, formula: string, opts?: {
487
- cachedValue?: number | string | boolean;
488
- styleId?: number;
489
- }): Cell;
490
- /** Resolve an "A1" coordinate to a numeric (col, row) pair on the sheet. */
491
- export declare function setCellByCoord(ws: Worksheet, coord: string, value?: CellValue, styleId?: number): Cell;
509
+ export declare function setCellByCoord(ws: Worksheet, coord: string, value: CellValue, styleId?: number): Cell;
492
510
  /** Convenience getter accepting an "A1" coordinate. */
493
511
  export declare function getCellByCoord(ws: Worksheet, coord: string): Cell | undefined;
512
+ /**
513
+ * A1-addressed {@link ensureCell}. Throws `OpenXmlSchemaError` when `coord` is
514
+ * not a plain A1 reference.
515
+ */
516
+ export declare function ensureCellByCoord(ws: Worksheet, coord: string): Cell;
494
517
  /**
495
518
  * Merge a range. The top-left cell keeps its value; every other cell in the
496
519
  * range is dropped from `ws.rows` so the on-wire `<sheetData>` won't carry
497
520
  * phantom cells underneath the merge. Mirrors openpyxl's
498
521
  * `MergedCellRange.format()`. Idempotent for an identical range, throws when
499
522
  * the range overlaps an existing merge.
523
+ *
524
+ * The registered range is a validated, normalised copy of `refOrRange`, so
525
+ * mutating a bounds object afterwards can't rewrite a merge that is already on
526
+ * the sheet.
500
527
  */
501
- export declare function mergeCells(ws: Worksheet, refOrRange: string | CellRange): CellRange;
528
+ export declare function mergeCells(ws: Worksheet, refOrRange: RangeRef): CellRange;
502
529
  /** Drop a previously-merged range. No-op if the range isn't registered. */
503
- export declare function unmergeCells(ws: Worksheet, refOrRange: string | CellRange): boolean;
530
+ export declare function unmergeCells(ws: Worksheet, refOrRange: RangeRef): boolean;
504
531
  /** Read-only iterator over the worksheet's merged ranges. */
505
532
  export declare function getMergedCells(ws: Worksheet): ReadonlyArray<CellRange>;
506
533
  /** True iff (row, col) sits inside any merged range — top-left included. */
@@ -524,26 +551,28 @@ export declare function unmergeCellsAt(ws: Worksheet, row: number, col: number):
524
551
  */
525
552
  export declare function removeAllMergedRanges(ws: Worksheet): number;
526
553
  /**
527
- * Freeze rows / columns above + left of `topLeftRef` ("B2" 1 row + 1 col).
554
+ * Freeze rows / columns above + left of the given top-left cell. Takes either
555
+ * the A1 ref of the first unfrozen cell (`"B2"` freezes 1 row + 1 column) or
556
+ * the counts directly (`{ rows: 1, cols: 0 }` freezes the header row alone).
528
557
  * Pass `undefined` to clear any existing freeze. Targets the workbook's primary
529
558
  * SheetView (`ws.views[0]`); creates one if absent.
530
559
  */
531
- export declare function setFreezePanes(ws: Worksheet, topLeftRef: string | undefined): void;
560
+ export declare function setFreezePanes(ws: Worksheet, topLeft: string | FreezeCounts | undefined): void;
532
561
  /** Inverse of {@link setFreezePanes}; returns the top-left ref or undefined when no freeze is active. */
533
562
  export declare function getFreezePanes(ws: Worksheet): string | undefined;
534
563
  /**
535
- * Freeze the top `count` rows. Equivalent to `setFreezePanes(ws, "A${count +
536
- * 1}")` Excel's "Freeze Top Row" is `freezeRows(ws, 1)`.
564
+ * Freeze the top `count` rows. Equivalent to `setFreezePanes(ws, { rows: count,
565
+ * cols: 0 })`, and Excel's "Freeze Top Row" is `freezeRows(ws, 1)`. Rejects 0,
566
+ * which the counts form accepts: {@link unfreezePanes} is how a freeze is
567
+ * cleared.
537
568
  */
538
569
  export declare function freezeRows(ws: Worksheet, count: number): void;
539
570
  /**
540
- * Freeze the leftmost `count` columns. Equivalent to `setFreezePanes(ws,
541
- * "${columnLetter(count + 1)}1")` Excel's "Freeze First Column" is
542
- * `freezeColumns(ws, 1)`.
571
+ * Freeze the leftmost `count` columns. Equivalent to `setFreezePanes(ws, {
572
+ * rows: 0, cols: count })`, and Excel's "Freeze First Column" is
573
+ * `freezeColumns(ws, 1)`. Rejects 0 for the same reason as {@link freezeRows}.
543
574
  */
544
575
  export declare function freezeColumns(ws: Worksheet, count: number): void;
545
- /** Freeze both top `rows` rows AND left `cols` columns. */
546
- export declare function freezePanes(ws: Worksheet, rows: number, cols: number): void;
547
576
  /** Drop the freeze pane on the primary view. */
548
577
  export declare const unfreezePanes: (ws: Worksheet) => void;
549
578
  /**
@@ -560,7 +589,7 @@ export declare const freezeFirstColumn: (ws: Worksheet) => void;
560
589
  /**
561
590
  * Freeze both row 1 and column A so the header row + label column stay visible.
562
591
  * Equivalent to selecting B2 and "View → Freeze Panes". Shortcut for
563
- * `freezePanes(ws, 1, 1)`.
592
+ * `setFreezePanes(ws, { rows: 1, cols: 1 })`.
564
593
  */
565
594
  export declare const freezeFirstRowAndColumn: (ws: Worksheet) => void;
566
595
  /**
@@ -605,19 +634,24 @@ export declare function setSelectedRange(ws: Worksheet, sqref: string): void;
605
634
  * down starting at the top-left of `range`; subsequent rows follow. `null` /
606
635
  * `undefined` entries skip the cell. Useful for dropping a header + data block
607
636
  * in one call.
637
+ *
638
+ * Values past the range's bottom or right edge are dropped rather than written
639
+ * outside it, the way {@link copyRange} clips to its target extent. Use
640
+ * {@link writeRange} for the unbounded form, which takes an anchor and grows to
641
+ * fit the array.
608
642
  */
609
- export declare function setRangeValues(ws: Worksheet, range: string, rows: ReadonlyArray<ReadonlyArray<CellValue | null | undefined>>): void;
643
+ export declare function setRangeValues(ws: Worksheet, range: RangeRef, rows: ReadonlyArray<ReadonlyArray<CellValue | null | undefined>>): void;
610
644
  /**
611
645
  * Iterate over every cell coordinate in a range, calling `visit` once per (row,
612
646
  * col). Allocates the cell on first touch so callers can mutate it freely.
613
647
  */
614
- export declare function applyToRange(ws: Worksheet, range: string, visit: (cell: Cell, row: number, col: number) => void): void;
648
+ export declare function applyToRange(ws: Worksheet, range: RangeRef, visit: (cell: Cell, row: number, col: number) => void): void;
615
649
  /**
616
650
  * Read a rectangular range as a dense 2-D array of values. Empty cells yield
617
651
  * `null`. The shape is `[maxRow - minRow + 1] × [maxCol - minCol + 1]`. Inverse
618
652
  * of {@link setRangeValues}.
619
653
  */
620
- export declare function getRangeValues(ws: Worksheet, range: string): (CellValue | null)[][];
654
+ export declare function getRangeValues(ws: Worksheet, range: RangeRef): (CellValue | null)[][];
621
655
  /**
622
656
  * Copy every populated cell from `source` to `target` (within the same
623
657
  * worksheet, or across worksheets via `targetWs`). Cells are shallow-cloned:
@@ -632,7 +666,7 @@ export declare function getRangeValues(ws: Worksheet, range: string): (CellValue
632
666
  *
633
667
  * Returns the number of cells copied.
634
668
  */
635
- export declare function copyRange(ws: Worksheet, source: string, target: string, opts?: {
669
+ export declare function copyRange(ws: Worksheet, source: RangeRef, target: RangeRef, opts?: {
636
670
  targetWs?: Worksheet;
637
671
  }): number;
638
672
  /**
@@ -643,7 +677,7 @@ export declare function copyRange(ws: Worksheet, source: string, target: string,
643
677
  * cells aren't overwritten before they've been read. Returns the number of
644
678
  * cells moved.
645
679
  */
646
- export declare function moveRange(ws: Worksheet, source: string, target: string, opts?: {
680
+ export declare function moveRange(ws: Worksheet, source: RangeRef, target: RangeRef, opts?: {
647
681
  targetWs?: Worksheet;
648
682
  }): number;
649
683
  /**
@@ -890,7 +924,14 @@ export declare function removeAllDataValidations(ws: Worksheet): number;
890
924
  export declare function setAutoFilter(ws: Worksheet, filter: AutoFilter | undefined): void;
891
925
  /** Read the current AutoFilter, if any. */
892
926
  export declare function getAutoFilter(ws: Worksheet): AutoFilter | undefined;
893
- /** Append a table. The id and displayName must be workbook-unique — the caller is responsible. */
927
+ /**
928
+ * Append a table, rejecting one whose geometry or column names disagree with
929
+ * the cells under it: the column count has to match the width of `ref`, `ref`
930
+ * has to contain the header and totals rows, column names have
931
+ * to be unique and non-empty, and every header cell has to hold its column's
932
+ * name as text. The id and displayName must be workbook-unique, and stay the
933
+ * caller's responsibility: neither is visible from a single sheet.
934
+ */
894
935
  export declare function addTable(ws: Worksheet, table: TableDefinition): TableDefinition;
895
936
  /** Look up a table by displayName. */
896
937
  export declare function getTable(ws: Worksheet, displayName: string): TableDefinition | undefined;
@@ -1,5 +1,6 @@
1
1
  import { type Cell } from '../cell/cell.js';
2
2
  import type { Relationships } from '../packaging/relationships.js';
3
+ import type { Stylesheet } from '../styles/stylesheet.js';
3
4
  import type { SharedStringsTable } from '../workbook/shared-strings.js';
4
5
  import type { HeaderFooter, PageMargins, PageSetup } from './page-setup.js';
5
6
  import type { WebPublishItem } from './web-publish.js';
@@ -7,6 +8,12 @@ import type { Worksheet } from './worksheet.js';
7
8
  export interface WorksheetWriteContext {
8
9
  /** Accumulator the writer mutates as it emits string cells. */
9
10
  sharedStrings: SharedStringsTable;
11
+ /**
12
+ * Stylesheet the sheet's cells resolve their `styleId` against. Held live
13
+ * rather than as a count, because the write-only path grows the pool while
14
+ * rows stream out.
15
+ */
16
+ styles: Stylesheet;
10
17
  /**
11
18
  * Workbook epoch for `Date` / `{kind:'duration'}` cell serialisation. `true`
12
19
  * = Mac 1904 epoch; `false` (default) = Windows 1900 epoch. Modern Excel