@shbernal/ts-xlsx 3.1.0 → 3.2.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 (214) hide show
  1. package/README.md +30 -23
  2. package/dist/bytes.d.ts +3 -2
  3. package/dist/core/address.d.ts +36 -0
  4. package/dist/core/address.js +47 -9
  5. package/dist/core/array-formula-ranges.d.ts +33 -0
  6. package/dist/core/array-formula-ranges.js +62 -0
  7. package/dist/core/color-resolution.js +2 -2
  8. package/dist/core/column.js +3 -2
  9. package/dist/core/comment-thread.d.ts +7 -3
  10. package/dist/core/conditional-formatting-overlay.d.ts +9 -0
  11. package/dist/core/conditional-formatting-overlay.js +28 -1
  12. package/dist/core/conditional-formatting.d.ts +98 -10
  13. package/dist/core/conditional-formatting.js +42 -1
  14. package/dist/core/data-validation-overlay.d.ts +5 -0
  15. package/dist/core/data-validation-overlay.js +15 -0
  16. package/dist/core/data-validation.d.ts +16 -0
  17. package/dist/core/data-validation.js +15 -0
  18. package/dist/core/date-format.js +14 -4
  19. package/dist/core/date.js +1 -1
  20. package/dist/core/formula-references.d.ts +26 -0
  21. package/dist/core/formula-references.js +173 -0
  22. package/dist/core/formula-scan.d.ts +2 -0
  23. package/dist/core/formula-scan.js +58 -0
  24. package/dist/core/formula.d.ts +51 -18
  25. package/dist/core/formula.js +77 -86
  26. package/dist/core/function-values.d.ts +4 -0
  27. package/dist/core/function-values.js +58 -0
  28. package/dist/core/future-functions.d.ts +3 -0
  29. package/dist/core/{modern-functions.js → future-functions.js} +119 -88
  30. package/dist/core/grid-edits.d.ts +28 -0
  31. package/dist/core/grid-edits.js +193 -25
  32. package/dist/core/hyperlink.d.ts +39 -0
  33. package/dist/core/hyperlink.js +88 -0
  34. package/dist/core/image.d.ts +36 -5
  35. package/dist/core/image.js +9 -0
  36. package/dist/core/internal.d.ts +3 -1
  37. package/dist/core/limits.d.ts +5 -3
  38. package/dist/core/merge.d.ts +13 -0
  39. package/dist/core/merge.js +15 -1
  40. package/dist/core/page-setup.d.ts +26 -11
  41. package/dist/core/pivot-table.d.ts +49 -10
  42. package/dist/core/pivot-table.js +55 -21
  43. package/dist/core/protection.d.ts +66 -4
  44. package/dist/core/protection.js +4 -0
  45. package/dist/core/row.js +3 -2
  46. package/dist/core/structured-reference.d.ts +7 -0
  47. package/dist/core/structured-reference.js +7 -0
  48. package/dist/core/table.d.ts +38 -8
  49. package/dist/core/table.js +37 -7
  50. package/dist/core/theme.d.ts +2 -0
  51. package/dist/core/theme.js +4 -1
  52. package/dist/core/value.d.ts +51 -28
  53. package/dist/core/value.js +15 -12
  54. package/dist/core/workbook-styles.d.ts +17 -1
  55. package/dist/core/workbook-styles.js +4 -0
  56. package/dist/core/workbook-theme.js +5 -3
  57. package/dist/core/workbook.d.ts +20 -3
  58. package/dist/core/workbook.js +26 -5
  59. package/dist/core/worksheet-merges.d.ts +9 -4
  60. package/dist/core/worksheet-merges.js +17 -11
  61. package/dist/core/worksheet-model.d.ts +1 -1
  62. package/dist/core/worksheet-model.js +4 -0
  63. package/dist/core/worksheet-pictures.d.ts +3 -3
  64. package/dist/core/worksheet-pictures.js +7 -6
  65. package/dist/core/worksheet.d.ts +110 -21
  66. package/dist/core/worksheet.js +174 -49
  67. package/dist/entries/core.d.ts +7 -5
  68. package/dist/entries/core.js +4 -3
  69. package/dist/entries/errors.d.ts +1 -0
  70. package/dist/entries/errors.js +1 -0
  71. package/dist/errors.js +1 -1
  72. package/dist/io/cell-metadata/metadata.d.ts +42 -0
  73. package/dist/io/cell-metadata/metadata.js +35 -0
  74. package/dist/io/cell-metadata/rich-values.d.ts +11 -0
  75. package/dist/io/cell-metadata/rich-values.js +80 -0
  76. package/dist/io/csv/delimiter.d.ts +14 -2
  77. package/dist/io/csv/delimiter.js +12 -0
  78. package/dist/io/csv/errors.d.ts +14 -0
  79. package/dist/io/csv/errors.js +5 -0
  80. package/dist/io/csv/read.d.ts +6 -1
  81. package/dist/io/csv/read.js +46 -24
  82. package/dist/io/csv/write.d.ts +10 -3
  83. package/dist/io/csv/write.js +16 -7
  84. package/dist/io/opc/part-paths.js +4 -4
  85. package/dist/io/opc/read-opc.d.ts +4 -0
  86. package/dist/io/opc/read-opc.js +10 -4
  87. package/dist/io/opc/strict-relationships.d.ts +2 -0
  88. package/dist/io/opc/strict-relationships.js +12 -0
  89. package/dist/io/read-policy/column-budget.d.ts +26 -0
  90. package/dist/io/{xlsx → read-policy}/column-budget.js +4 -8
  91. package/dist/io/read-policy/read-repair.d.ts +74 -0
  92. package/dist/io/read-policy/read-repair.js +119 -0
  93. package/dist/io/style/cell-style-resolution.d.ts +25 -0
  94. package/dist/io/style/cell-style-resolution.js +30 -0
  95. package/dist/io/xlsb/formula.js +4 -2
  96. package/dist/io/xlsb/ptg-functions.js +110 -0
  97. package/dist/io/xlsb/read-metadata.d.ts +7 -0
  98. package/dist/io/xlsb/read-metadata.js +69 -0
  99. package/dist/io/xlsb/read-worksheet.d.ts +6 -0
  100. package/dist/io/xlsb/read-worksheet.js +95 -37
  101. package/dist/io/xlsb/read.js +26 -8
  102. package/dist/io/xlsb/record-types.d.ts +13 -0
  103. package/dist/io/xlsb/record-types.js +13 -0
  104. package/dist/io/xlsb/sheet-protection.d.ts +20 -0
  105. package/dist/io/xlsb/sheet-protection.js +60 -0
  106. package/dist/io/xlsx/cell-accumulator.d.ts +20 -12
  107. package/dist/io/xlsx/cell-accumulator.js +49 -19
  108. package/dist/io/xlsx/cell-metadata.d.ts +39 -0
  109. package/dist/io/xlsx/cell-metadata.js +162 -0
  110. package/dist/io/xlsx/cell-value.d.ts +16 -4
  111. package/dist/io/xlsx/cell-value.js +38 -21
  112. package/dist/io/xlsx/color-xml.js +1 -1
  113. package/dist/io/xlsx/column-span.d.ts +11 -0
  114. package/dist/io/xlsx/column-span.js +9 -0
  115. package/dist/io/xlsx/comments.d.ts +3 -28
  116. package/dist/io/xlsx/comments.js +3 -65
  117. package/dist/io/xlsx/conditional-formatting.d.ts +42 -25
  118. package/dist/io/xlsx/conditional-formatting.js +424 -129
  119. package/dist/io/xlsx/data-validation.d.ts +12 -7
  120. package/dist/io/xlsx/data-validation.js +41 -29
  121. package/dist/io/xlsx/edit-vba.js +43 -36
  122. package/dist/io/xlsx/hyperlinks.d.ts +16 -50
  123. package/dist/io/xlsx/hyperlinks.js +8 -37
  124. package/dist/io/xlsx/images.d.ts +49 -16
  125. package/dist/io/xlsx/images.js +145 -44
  126. package/dist/io/xlsx/namespaces.d.ts +8 -0
  127. package/dist/io/xlsx/namespaces.js +4 -0
  128. package/dist/io/xlsx/package-plan.d.ts +48 -15
  129. package/dist/io/xlsx/package-plan.js +46 -9
  130. package/dist/io/xlsx/part-names.d.ts +6 -8
  131. package/dist/io/xlsx/part-names.js +3 -7
  132. package/dist/io/xlsx/pivot.d.ts +5 -5
  133. package/dist/io/xlsx/pivot.js +23 -22
  134. package/dist/io/xlsx/preserved-splices.d.ts +6 -0
  135. package/dist/io/xlsx/preserved-splices.js +74 -0
  136. package/dist/io/xlsx/read-comments.d.ts +29 -0
  137. package/dist/io/xlsx/read-comments.js +75 -0
  138. package/dist/io/xlsx/read-parts.d.ts +2 -2
  139. package/dist/io/xlsx/read-parts.js +44 -37
  140. package/dist/io/xlsx/read-pivot.js +9 -3
  141. package/dist/io/xlsx/read-rich-runs.d.ts +8 -5
  142. package/dist/io/xlsx/read-rich-runs.js +18 -1
  143. package/dist/io/xlsx/read-rows.d.ts +18 -7
  144. package/dist/io/xlsx/read-rows.js +47 -37
  145. package/dist/io/xlsx/read-styles.d.ts +0 -25
  146. package/dist/io/xlsx/read-styles.js +39 -34
  147. package/dist/io/xlsx/read-workbook-xml.d.ts +6 -0
  148. package/dist/io/xlsx/read-workbook-xml.js +9 -4
  149. package/dist/io/xlsx/read-worksheet.d.ts +8 -3
  150. package/dist/io/xlsx/read-worksheet.js +45 -23
  151. package/dist/io/xlsx/read.d.ts +0 -4
  152. package/dist/io/xlsx/read.js +17 -21
  153. package/dist/io/xlsx/relationships.d.ts +3 -0
  154. package/dist/io/xlsx/relationships.js +4 -0
  155. package/dist/io/xlsx/row-position.d.ts +3 -1
  156. package/dist/io/xlsx/row-xml.d.ts +18 -7
  157. package/dist/io/xlsx/row-xml.js +54 -35
  158. package/dist/io/xlsx/sheet-properties.js +68 -42
  159. package/dist/io/xlsx/strict-parts.d.ts +7 -0
  160. package/dist/io/xlsx/strict-parts.js +171 -0
  161. package/dist/io/xlsx/style-elements.d.ts +0 -2
  162. package/dist/io/xlsx/style-elements.js +9 -29
  163. package/dist/io/xlsx/styles.d.ts +5 -0
  164. package/dist/io/xlsx/styles.js +11 -5
  165. package/dist/io/xlsx/tables.d.ts +10 -2
  166. package/dist/io/xlsx/tables.js +49 -42
  167. package/dist/io/xlsx/theme-xml.d.ts +6 -0
  168. package/dist/io/xlsx/theme-xml.js +16 -19
  169. package/dist/io/xlsx/threaded-comments.d.ts +6 -1
  170. package/dist/io/xlsx/threaded-comments.js +14 -7
  171. package/dist/io/xlsx/workbook-xml.d.ts +13 -24
  172. package/dist/io/xlsx/workbook-xml.js +15 -33
  173. package/dist/io/xlsx/worksheet-xml.d.ts +5 -2
  174. package/dist/io/xlsx/worksheet-xml.js +37 -69
  175. package/dist/io/xlsx/write-stream.d.ts +28 -6
  176. package/dist/io/xlsx/write-stream.js +42 -17
  177. package/dist/io/xlsx/write.d.ts +11 -4
  178. package/dist/io/xlsx/write.js +153 -90
  179. package/dist/rel-type.d.ts +9 -0
  180. package/dist/rel-type.js +3 -0
  181. package/dist/vba/bytes.d.ts +2 -0
  182. package/dist/vba/bytes.js +11 -0
  183. package/dist/vba/cfb-format.d.ts +47 -0
  184. package/dist/vba/cfb-format.js +34 -0
  185. package/dist/vba/cfb-writer.d.ts +1 -2
  186. package/dist/vba/cfb-writer.js +33 -36
  187. package/dist/vba/cfb.d.ts +9 -4
  188. package/dist/vba/cfb.js +55 -43
  189. package/dist/vba/dir-records.d.ts +6 -0
  190. package/dist/vba/dir-records.js +10 -2
  191. package/dist/vba/errors.d.ts +4 -4
  192. package/dist/vba/index.d.ts +0 -2
  193. package/dist/vba/index.js +0 -2
  194. package/dist/vba/ms-ovba.d.ts +6 -2
  195. package/dist/vba/ms-ovba.js +15 -6
  196. package/dist/vba/project-editor.js +102 -87
  197. package/dist/vba/project.d.ts +4 -0
  198. package/dist/vba/project.js +12 -6
  199. package/dist/vba/vba-encoding.d.ts +4 -10
  200. package/dist/vba/vba-encoding.js +2 -15
  201. package/dist/xml/xml-read.d.ts +29 -1
  202. package/dist/xml/xml-read.js +56 -0
  203. package/dist/xml/xml-scan.d.ts +13 -0
  204. package/dist/xml/xml-scan.js +58 -7
  205. package/dist/xml/xml.d.ts +33 -1
  206. package/dist/xml/xml.js +22 -0
  207. package/package.json +5 -4
  208. package/skills/ts-xlsx-upstream/SKILL.md +21 -13
  209. package/dist/core/modern-functions.d.ts +0 -1
  210. package/dist/io/xlsx/cell-style-resolution.d.ts +0 -25
  211. package/dist/io/xlsx/cell-style-resolution.js +0 -29
  212. package/dist/io/xlsx/column-budget.d.ts +0 -26
  213. package/dist/io/xlsx/read-repair.d.ts +0 -26
  214. package/dist/io/xlsx/read-repair.js +0 -39
@@ -1,7 +1,15 @@
1
- import { AuthoringError, quoted } from '../errors.js';
2
- import { boundedRect, decodeRange } from './address.js';
1
+ import { AuthoringError, InternalError, quoted } from '../errors.js';
2
+ import { boundedRect, decodeRange, encodeRect } from './address.js';
3
3
  import { replaceContents } from './containers.js';
4
4
  import { MergeIndex } from './merge-index.js';
5
+ function canonicalMerge(range) {
6
+ const decoded = decodeRange(range);
7
+ if (decoded.sheetName !== undefined) {
8
+ throw new SyntaxError(`merged range ${quoted(range)} names worksheet ${quoted(decoded.sheetName)}: a merge belongs to the sheet it is made on`);
9
+ }
10
+ const rect = boundedRect(decoded);
11
+ return { canonical: rect === undefined ? decoded.dimensions : encodeRect(rect), rect };
12
+ }
5
13
  export class WorksheetMerges {
6
14
  #ranges = [];
7
15
  #rects = [];
@@ -13,7 +21,7 @@ export class WorksheetMerges {
13
21
  return this.#rects;
14
22
  }
15
23
  add(range) {
16
- const rect = boundedRect(decodeRange(range));
24
+ const { canonical, rect } = canonicalMerge(range);
17
25
  if (rect !== undefined) {
18
26
  if (this.#index.overlapping(rect) !== undefined) {
19
27
  throw new AuthoringError(`merged range ${quoted(range)} overlaps an existing merged region`);
@@ -21,21 +29,22 @@ export class WorksheetMerges {
21
29
  this.#rects.push(rect);
22
30
  this.#index.note(rect);
23
31
  }
24
- this.#ranges.push(range);
32
+ this.#ranges.push(canonical);
25
33
  return rect;
26
34
  }
27
35
  remove(range) {
28
- const index = this.#ranges.indexOf(range);
36
+ const { canonical, rect } = canonicalMerge(range);
37
+ const index = this.#ranges.indexOf(canonical);
29
38
  if (index === -1)
30
39
  return { existed: false, rectsChanged: false };
31
40
  this.#ranges.splice(index, 1);
32
- const rect = boundedRect(decodeRange(range));
33
41
  if (rect === undefined)
34
42
  return { existed: true, rectsChanged: false };
35
43
  const { top, left, bottom, right } = rect;
36
44
  const at = this.#rects.findIndex((r) => r.top === top && r.left === left && r.bottom === bottom && r.right === right);
37
- if (at === -1)
38
- return { existed: true, rectsChanged: false };
45
+ if (at === -1) {
46
+ throw new InternalError(`merged range ${quoted(canonical)} was declared without its rectangle`);
47
+ }
39
48
  this.#rects.splice(at, 1);
40
49
  this.#index.invalidate();
41
50
  return { existed: true, rectsChanged: true };
@@ -48,9 +57,6 @@ export class WorksheetMerges {
48
57
  replaceContents(this.#rects, rects);
49
58
  this.#index.invalidate();
50
59
  }
51
- invalidate() {
52
- this.#index.invalidate();
53
- }
54
60
  clear() {
55
61
  this.#ranges.length = 0;
56
62
  this.#rects.length = 0;
@@ -31,7 +31,7 @@ interface ModelFacet<K extends keyof WorksheetModel = keyof WorksheetModel> {
31
31
  * load-bearing: cells are placed at their exact positions before any merge exists, so a covered
32
32
  * cell's value lands where the model says instead of being routed to a region master mid-load.
33
33
  */
34
- export declare const WORKSHEET_MODEL_FACETS: (ModelFacet<"autoFilter"> | ModelFacet<"cells"> | ModelFacet<"columnBreaks"> | ModelFacet<"columns"> | ModelFacet<"conditionalFormattings"> | ModelFacet<"dataValidations"> | ModelFacet<"headerFooter"> | ModelFacet<"merges"> | ModelFacet<"outline"> | ModelFacet<"pageMargins"> | ModelFacet<"pageSetup"> | ModelFacet<"printOptions"> | ModelFacet<"properties"> | ModelFacet<"protection"> | ModelFacet<"rowBreaks"> | ModelFacet<"rows"> | ModelFacet<"state"> | ModelFacet<"tabColor"> | ModelFacet<"tables"> | ModelFacet<"view">)[];
34
+ export declare const WORKSHEET_MODEL_FACETS: (ModelFacet<"autoFilter"> | ModelFacet<"cells"> | ModelFacet<"columnBreaks"> | ModelFacet<"columns"> | ModelFacet<"conditionalFormattings"> | ModelFacet<"dataValidations"> | ModelFacet<"headerFooter"> | ModelFacet<"hyperlinks"> | ModelFacet<"merges"> | ModelFacet<"outline"> | ModelFacet<"pageMargins"> | ModelFacet<"pageSetup"> | ModelFacet<"printOptions"> | ModelFacet<"properties"> | ModelFacet<"protection"> | ModelFacet<"rowBreaks"> | ModelFacet<"rows"> | ModelFacet<"state"> | ModelFacet<"tabColor"> | ModelFacet<"tables"> | ModelFacet<"view">)[];
35
35
  /**
36
36
  * Compile-time proof that {@link WORKSHEET_MODEL_FACETS} covers every {@link WorksheetModel} field.
37
37
  * A field added without a facet resolves this to that field's name, which does not satisfy `never`,
@@ -66,6 +66,10 @@ export const WORKSHEET_MODEL_FACETS = [
66
66
  for (const range of value)
67
67
  sheet.mergeCells(range);
68
68
  }),
69
+ facet('hyperlinks', (sheet) => sheet.hyperlinks.map((link) => ({ ...link })), (sheet, value) => {
70
+ for (const link of value)
71
+ sheet.addHyperlink(link);
72
+ }),
69
73
  facet('dataValidations', (sheet) => sheet.dataValidations.map(({ sqref, rule, extended }) => ({
70
74
  sqref,
71
75
  rule: cloneDataValidation(rule),
@@ -1,4 +1,4 @@
1
- import { type AnchoredImage, type AnchorPoint, type ImageAnchor, type ImageEditAs } from './image.ts';
1
+ import { type AnchoredImage, type AnchorPoint, type ImageAnchor, type ImageEditAs, type PictureProperties } from './image.ts';
2
2
  /** The two shapes {@link WorksheetPictures.add} accepts, in caller-facing pixel units. */
3
3
  export type PixelAnchor = {
4
4
  readonly tl: AnchorPoint;
@@ -22,8 +22,8 @@ export declare class WorksheetPictures {
22
22
  /** The anchored images, in the order they were added. */
23
23
  get anchors(): AnchoredImage[];
24
24
  get backgroundImageId(): number | undefined;
25
- add(imageId: number, anchor: PixelAnchor): void;
26
- addAnchor(imageId: number, anchor: ImageAnchor): void;
25
+ add(imageId: number, anchor: PixelAnchor, properties?: PictureProperties): void;
26
+ addAnchor(imageId: number, anchor: ImageAnchor, properties?: PictureProperties): void;
27
27
  remove(imageId: number): void;
28
28
  setBackground(imageId: number | undefined): void;
29
29
  }
@@ -1,5 +1,5 @@
1
1
  import { replaceContents } from './containers.js';
2
- import { PX_TO_EMU, resolveAnchorPoint, } from './image.js';
2
+ import { pictureProperties, PX_TO_EMU, resolveAnchorPoint, } from './image.js';
3
3
  export class WorksheetPictures {
4
4
  #metrics;
5
5
  #anchors = [];
@@ -13,7 +13,8 @@ export class WorksheetPictures {
13
13
  get backgroundImageId() {
14
14
  return this.#backgroundImageId;
15
15
  }
16
- add(imageId, anchor) {
16
+ add(imageId, anchor, properties = {}) {
17
+ const picture = pictureProperties(properties);
17
18
  const columnWidth = (col) => this.#metrics.columnWidth(col);
18
19
  const rowHeight = (row) => this.#metrics.rowHeight(row);
19
20
  if ('ext' in anchor) {
@@ -22,16 +23,16 @@ export class WorksheetPictures {
22
23
  cy: Math.round(anchor.ext.height * PX_TO_EMU),
23
24
  };
24
25
  const from = resolveAnchorPoint(anchor.tl, columnWidth, rowHeight);
25
- this.#anchors.push({ imageId, anchor: { from, ext } });
26
+ this.#anchors.push({ imageId, anchor: { from, ext }, ...picture });
26
27
  return;
27
28
  }
28
29
  const from = resolveAnchorPoint(anchor.tl, columnWidth, rowHeight);
29
30
  const to = resolveAnchorPoint(anchor.br, columnWidth, rowHeight);
30
31
  const twoCell = anchor.editAs !== undefined ? { from, to, editAs: anchor.editAs } : { from, to };
31
- this.#anchors.push({ imageId, anchor: twoCell });
32
+ this.#anchors.push({ imageId, anchor: twoCell, ...picture });
32
33
  }
33
- addAnchor(imageId, anchor) {
34
- this.#anchors.push({ imageId, anchor });
34
+ addAnchor(imageId, anchor, properties = {}) {
35
+ this.#anchors.push({ imageId, anchor, ...pictureProperties(properties) });
35
36
  }
36
37
  remove(imageId) {
37
38
  replaceContents(this.#anchors, this.#anchors.filter((image) => image.imageId !== imageId));
@@ -4,7 +4,9 @@ import { Column } from './column.ts';
4
4
  import type { CommentThread } from './comment-thread.ts';
5
5
  import type { ConditionalFormatting } from './conditional-formatting.ts';
6
6
  import type { DataValidation, DataValidationEntry } from './data-validation.ts';
7
- import type { AnchoredImage, AnchorPoint, ImageAnchor, ImageEditAs } from './image.ts';
7
+ import { type SheetSplice } from './formula-references.ts';
8
+ import { type Hyperlink } from './hyperlink.ts';
9
+ import type { AnchoredImage, AnchorPoint, ImageAnchor, ImageEditAs, PictureProperties } from './image.ts';
8
10
  import { INTERNAL } from './internal.ts';
9
11
  import type { HeaderFooter, PageBreak, PageMargins, PageSetup, PrintOptions } from './page-setup.ts';
10
12
  import { type ParsedPivotTable, PivotTable, type PivotTableOptions } from './pivot-table.ts';
@@ -14,7 +16,7 @@ import { Range } from './range.ts';
14
16
  import { Row } from './row.ts';
15
17
  import type { CellContent, CellStyle, Color, Fill } from './style.ts';
16
18
  import { Table, type TableOptions } from './table.ts';
17
- import type { CellValue } from './value.ts';
19
+ import { type CellValue } from './value.ts';
18
20
  /**
19
21
  * Whether a thing Excel can hide is showing: a sheet's tab, or the document window itself.
20
22
  *
@@ -164,6 +166,7 @@ export interface WorksheetModel {
164
166
  }[];
165
167
  cells: CellModel[];
166
168
  merges: string[];
169
+ hyperlinks: Hyperlink[];
167
170
  dataValidations: DataValidationEntry[];
168
171
  conditionalFormattings: ConditionalFormatting[];
169
172
  tables: TableOptions[];
@@ -222,15 +225,17 @@ export declare class Worksheet {
222
225
  /** Page header/footer text. Mutate in place: `sheet.headerFooter.oddHeader = '&C&"..."'`. */
223
226
  readonly headerFooter: HeaderFooter;
224
227
  /**
225
- * Manual horizontal page breaks (`<rowBreaks>`): each break's `id` is a row the print layout splits
226
- * before. Mutate in place: `sheet.rowBreaks.push({id: 3})`. Empty means no manual row breaks and the
227
- * writer emits no `<rowBreaks>` element.
228
+ * Horizontal page breaks (`<rowBreaks>`): each break's `id` is the last row before it, so
229
+ * `sheet.rowBreaks.push({id: 3})` starts a new printed page at row 4. Mutate in place. A row splice
230
+ * moves a break with the row after it. Empty means no row breaks and the writer emits no
231
+ * `<rowBreaks>` element.
228
232
  */
229
233
  readonly rowBreaks: PageBreak[];
230
234
  /**
231
- * Manual vertical page breaks (`<colBreaks>`): each break's `id` is a column the print layout splits
232
- * before. Mutate in place: `sheet.columnBreaks.push({id: 3})`. Empty means no manual column breaks and
233
- * the writer emits no `<colBreaks>` element.
235
+ * Vertical page breaks (`<colBreaks>`): each break's `id` is the last column before it, so
236
+ * `sheet.columnBreaks.push({id: 3})` starts a new printed page at column D. Mutate in place. A column
237
+ * splice moves a break with the column after it. Empty means no column breaks and the writer emits
238
+ * no `<colBreaks>` element.
234
239
  */
235
240
  readonly columnBreaks: PageBreak[];
236
241
  constructor(name: string, id: number, state?: WorksheetState['state']);
@@ -358,7 +363,8 @@ export declare class Worksheet {
358
363
  getTable(name: string): Table | undefined;
359
364
  /**
360
365
  * Add a pivot table to this (destination) sheet, summarising a source sheet's data. The source is
361
- * read once, now, so the pivot is a snapshot: later edits to the source do not change it. The
366
+ * read once, now, so the pivot is a snapshot: later edits to the source's values do not change it,
367
+ * while a row or column splice of the source sheet moves its {@link PivotTable.sourceRef}. The
362
368
  * supported shape (one summed value field, at least one row and column field) is enforced here.
363
369
  *
364
370
  * @throws {AuthoringError} if the metric, fields, or source shape are unsupported.
@@ -371,7 +377,9 @@ export declare class Worksheet {
371
377
  * read-only inspection view (source range, field roles, value field, aggregation). A pivot
372
378
  * authored on this sheet via {@link addPivotTable} does not appear here; a pivot loaded from a
373
379
  * file does not appear in {@link pivotTables}. The loaded pivots re-emit verbatim through
374
- * byte-preservation, so this collection is never itself serialised.
380
+ * byte-preservation, so this collection is never itself serialised. A row or column splice of a
381
+ * pivot's source sheet moves its {@link ParsedPivotSource.ref} here and in the cache the writer
382
+ * emits, by one rule, so the view says what is written.
375
383
  */
376
384
  get loadedPivotTables(): readonly ParsedPivotTable[];
377
385
  /**
@@ -383,7 +391,8 @@ export declare class Worksheet {
383
391
  * Every message supplies its own {@link Comment.id} and {@link Comment.date}, and names its author by
384
392
  * {@link Comment.personId} into the workbook registry ({@link Workbook.addPerson}): the writer has no
385
393
  * clock and no id generator, so nothing here is invented and the same workbook always serialises to the
386
- * same bytes. Every id is normalised to the brace-wrapped upper-case GUID form the format requires, so a
394
+ * same bytes. An author id nobody registered is refused when the workbook is written, where the
395
+ * registry is complete; a message with no `personId` is written as Excel writes an unknown author. Every id is normalised to the brace-wrapped upper-case GUID form the format requires, so a
387
396
  * `crypto.randomUUID()` is accepted as-is.
388
397
  *
389
398
  * Message ids must be unique **within this sheet**, because that is the scope in which they mean
@@ -421,25 +430,33 @@ export declare class Worksheet {
421
430
  *
422
431
  * Grid points are 0-based (`{col: 0, row: 0}` is cell A1). A later row/column splice re-pins the
423
432
  * anchor to the same logical position.
433
+ *
434
+ * `properties` gives the picture alternative text and a title, crops it, or makes it a link; see
435
+ * {@link PictureProperties}.
436
+ *
437
+ * A sheet read from a file keeps its drawing whole when the drawing holds a chart, a shape or other
438
+ * content the library does not model. A picture added to such a sheet is written into that drawing,
439
+ * beside what it holds, and read back it is part of the kept drawing rather than one of
440
+ * {@link images}.
424
441
  */
425
442
  addImage(imageId: number, anchor: {
426
443
  readonly tl: AnchorPoint;
427
444
  readonly br: AnchorPoint;
428
445
  readonly editAs?: ImageEditAs;
429
- }): void;
446
+ }, properties?: PictureProperties): void;
430
447
  addImage(imageId: number, anchor: {
431
448
  readonly tl: AnchorPoint;
432
449
  readonly ext: {
433
450
  readonly width: number;
434
451
  readonly height: number;
435
452
  };
436
- }): void;
453
+ }, properties?: PictureProperties): void;
437
454
  /**
438
455
  * Anchor an image with a pre-built model anchor in the model's own units (EMUs). This is the
439
456
  * low-level primitive {@link addImage} builds on and the reader uses to re-pin an image parsed from
440
457
  * a drawing part without a lossy pixel round-trip.
441
458
  */
442
- addImageAnchor(imageId: number, anchor: ImageAnchor): void;
459
+ addImageAnchor(imageId: number, anchor: ImageAnchor, properties?: PictureProperties): void;
443
460
  /** Drop every anchor of the given workbook image from this sheet. The image stays registered on the
444
461
  * workbook (another sheet may still show it), so only this sheet's anchors are removed; the writer
445
462
  * then omits any media no sheet anchors any longer. */
@@ -465,9 +482,16 @@ export declare class Worksheet {
465
482
  * anchor's, exactly how Excel collapses a range on merge. Leaving it would emit a populated `<c>`
466
483
  * under the `<mergeCell>` ref, the geometry Excel opens with a repair prompt. Covered-cell styles
467
484
  * survive (a border spanning the merge is legal), so only the conflicting value is cleared.
485
+ *
486
+ * The range is stored in canonical form, `$` anchors dropped and the top-left corner first, so
487
+ * merging `$B$2:$A$1` reports `A1:B2` through {@link merges}.
488
+ *
489
+ * @throws {SyntaxError} if the range is unparseable or names a worksheet: a merge belongs to the
490
+ * sheet it is made on, and a prefix naming another one used to be ignored.
491
+ * @throws {AuthoringError} if the range overlaps an already-merged region.
468
492
  */
469
493
  mergeCells(range: string): void;
470
- /** The merged ranges on this sheet, in the order they were added. */
494
+ /** The merged ranges on this sheet, in canonical form (`A1:B2`), in the order they were added. */
471
495
  get merges(): readonly string[];
472
496
  /**
473
497
  * The sheet's autofilter (its range plus any per-column criteria), or `undefined` when the sheet
@@ -484,9 +508,12 @@ export declare class Worksheet {
484
508
  get autoFilter(): AutoFilter | undefined;
485
509
  set autoFilter(filter: string | AutoFilter | undefined);
486
510
  /**
487
- * Remove a merged range previously added with {@link mergeCells}, returning whether a merge with
488
- * that exact range string existed. The covering rectangle is dropped alongside it, so a cell the
489
- * merge had masked addresses independently again. The inverse of {@link mergeCells}.
511
+ * Remove a merged range previously added with {@link mergeCells}, returning whether such a merge
512
+ * existed. The range matches however it is spelled (`$` anchors, corner order), since merges are
513
+ * stored and compared in canonical form. The covering rectangle is dropped alongside it, so a cell
514
+ * the merge had masked addresses independently again. The inverse of {@link mergeCells}.
515
+ *
516
+ * @throws {SyntaxError} if the range is unparseable or names a worksheet.
490
517
  */
491
518
  unmergeCells(range: string): boolean;
492
519
  /**
@@ -510,6 +537,8 @@ export declare class Worksheet {
510
537
  * range (`"A1:A10"`), a whole column, or several space-separated areas (`"A1:C1 A3:C3"`) sharing one
511
538
  * rule set. The block is stored once against the range, defensively copied so the getter never hands
512
539
  * back a reference into the caller's object.
540
+ *
541
+ * @throws {AuthoringError} when `formatting.ref` names no cells: empty, or no area of it decodes.
513
542
  */
514
543
  addConditionalFormatting(formatting: ConditionalFormatting): void;
515
544
  /** The conditional formattings on this sheet, each bound to its target range, in insertion order. */
@@ -519,6 +548,35 @@ export declare class Worksheet {
519
548
  * contains the cell wins, mirroring how a spreadsheet resolves overlapping validations.
520
549
  */
521
550
  dataValidationAt(reference: string): DataValidation | undefined;
551
+ /**
552
+ * Put a hyperlink on a cell or a rectangle of cells: `{ref: 'B2', target: 'https://example.com'}`,
553
+ * or `{ref: 'D1:H1', target: '#Summary!A1', tooltip: 'Back to the summary'}`. A `#`-prefixed target
554
+ * is a place in this workbook; any other is a URL or a path, written as given.
555
+ *
556
+ * A link is not part of a cell's value, so it goes on a number, a date, a formula or an empty cell as
557
+ * readily as on text, and the value stays whatever it is. A link over the same `ref` as one already
558
+ * on the sheet replaces it. One over a different range is added beside it: where two cover a cell,
559
+ * {@link hyperlinkAt} reports the later, and Excel keeps both.
560
+ *
561
+ * A row or column splice moves a link with the cells it covers, growing it when lines are inserted
562
+ * inside it and shrinking it when some of its lines are deleted, as Excel does.
563
+ *
564
+ * @throws {SyntaxError} if `ref` is not a reference.
565
+ * @throws {AuthoringError} if `ref` names a whole row or column rather than cells.
566
+ */
567
+ addHyperlink(link: Hyperlink): void;
568
+ /**
569
+ * Remove the hyperlink whose `ref` is `ref`, and report whether there was one. A link over a wider
570
+ * range that merely covers `ref` stays.
571
+ */
572
+ removeHyperlink(ref: string): boolean;
573
+ /** The hyperlinks on this sheet, in the order they were added. */
574
+ get hyperlinks(): readonly Hyperlink[];
575
+ /**
576
+ * The hyperlink a cell opens, or `undefined` when none covers it. Of two links covering the cell, the
577
+ * one added later.
578
+ */
579
+ hyperlinkAt(reference: string): Hyperlink | undefined;
522
580
  /**
523
581
  * Remove `count` rows starting at the 1-based `start`, then insert the given rows in their place.
524
582
  * Rows below the edit shift by `inserts.length - count`: a delete pulls the tail up, an insert
@@ -528,10 +586,21 @@ export declare class Worksheet {
528
586
  * silently becomes a no-op. Cells carry their full style to the shifted position, and merged ranges
529
587
  * shift with the rows they cover.
530
588
  *
589
+ * Formulas move with the rows as Excel moves them: a reference to this sheet, in any sheet's formula,
590
+ * a defined name, a data validation, a conditional format or a table's column formulas, follows the
591
+ * row it names, and one to a deleted row becomes `#REF!`. An authored pivot drawing from this sheet
592
+ * has its source range moved the same way. What the inserted rows carry is written against the sheet after the
593
+ * edit and is not moved. A dynamic array whose range the edit leaves holding another formula has its
594
+ * spill blocked, as Excel blocks it: the array formula keeps its own cell alone and caches `#SPILL!`.
595
+ *
531
596
  * @throws {RangeError} if `start` is not a positive integer or `count` is negative.
532
597
  * @throws {RangeError} if an inserted row would land past the last row of the grid. The sheet is
533
598
  * left untouched, so this is a refused edit rather than half of one: a region pushed off the edge
534
599
  * clamps and absorbs the loss, but content pushed off it is what Excel refuses outright.
600
+ * @throws {AuthoringError} if the edit would cut through a Ctrl+Shift+Enter array formula's range: an
601
+ * insert strictly inside it, or a delete taking part of it. Excel refuses the same edit, as a change
602
+ * to part of an array, and the sheet is left untouched. An edit moving or deleting the whole range,
603
+ * and any edit through a dynamic array's range, goes ahead.
535
604
  */
536
605
  spliceRows(start: number, count: number, ...inserts: RowInput[]): void;
537
606
  /**
@@ -567,7 +636,8 @@ export declare class Worksheet {
567
636
  * beneath them. `freeze(1)` pins a header row; `freeze(0, 1)` pins the first column. Passing both
568
637
  * zero clears the freeze (equivalent to {@link unfreeze}).
569
638
  *
570
- * @throws {RangeError} if either split is a negative or non-integer count.
639
+ * @throws {RangeError} if either split is a negative or non-integer count, or leaves no row or
640
+ * column of the grid to scroll. The view is left as it was.
571
641
  */
572
642
  freeze(ySplit?: number, xSplit?: number): void;
573
643
  /** Clear any frozen split, returning the sheet to a normal (fully scrolling) view. */
@@ -581,9 +651,16 @@ export declare class Worksheet {
581
651
  *
582
652
  * Each copy is a faithful duplicate of the source: its cell values, its per-cell styles, and its
583
653
  * row properties (height, hidden, outline level, row fill). It carries no merge of its own, so a
584
- * range can be merged onto a duplicated row afterwards.
654
+ * range can be merged onto a duplicated row afterwards. A formula is copied as Excel copies a row,
655
+ * its relative references moved down with it and its cached result dropped, since that was computed
656
+ * over the source's cells; an inserted copy is taken from the source as the insert left it. A copy
657
+ * landing in a dynamic array's range blocks its spill, as {@link spliceRows} says.
585
658
  *
586
- * @throws {RangeError} if `start` is not a positive integer or `count` is negative.
659
+ * @throws {RangeError} if `start` is not a positive integer or `count` is negative, or if a copy
660
+ * would land past the last row. The sheet is left untouched.
661
+ * @throws {AuthoringError} if a copy would land inside a Ctrl+Shift+Enter array formula's range, or
662
+ * replace part of one, which Excel refuses as a change to part of an array. The sheet is left
663
+ * untouched.
587
664
  */
588
665
  duplicateRow(start: number, options?: {
589
666
  count?: number;
@@ -596,11 +673,15 @@ export declare class Worksheet {
596
673
  * the right of the edit re-anchors to its new columns. Each inserted column is an array of values
597
674
  * indexed by row (index 0 → row 1); an empty array inserts a blank column.
598
675
  *
676
+ * Formulas move with the columns, by the rules {@link spliceRows} gives for rows.
677
+ *
599
678
  * @throws {RangeError} if `start` is not a positive integer or `count` is negative.
600
679
  * @throws {RangeError} if an inserted column would land past the last column, or one of its values
601
680
  * past the last row. The sheet is left untouched, so this is a refused edit rather than half of
602
681
  * one: a region pushed off the edge clamps and absorbs the loss, but content pushed off it is
603
682
  * what Excel refuses outright, and {@link addColumn} refuses the same argument identically.
683
+ * @throws {AuthoringError} if the edit would cut through a Ctrl+Shift+Enter array formula's range, by
684
+ * the rule {@link spliceRows} gives for rows. The sheet is left untouched.
604
685
  */
605
686
  spliceColumns(start: number, count: number, ...inserts: CellValue[][]): void;
606
687
  /**
@@ -709,6 +790,14 @@ export interface WorksheetInternals {
709
790
  * restores that credential verbatim rather than re-hashing.
710
791
  */
711
792
  restoreProtection(protection: SheetProtection): void;
793
+ /**
794
+ * Hand the sheet what moves the formulas beyond it, every other sheet's and the workbook's defined
795
+ * names, when a splice of this sheet moves the lines they refer to. The workbook sets it on each sheet
796
+ * it creates.
797
+ */
798
+ setFormulaHost(host: (edit: SheetSplice) => void): void;
799
+ /** Move the references this sheet's formulas make to a spliced sheet, which here is another one. */
800
+ spliceFormulas(edit: SheetSplice): void;
712
801
  /**
713
802
  * Materialise the cell at an exact 1-based position, creating it on first access. Unlike
714
803
  * {@link Worksheet.getCell} this performs no merge resolution: the cell returned is the one at