@shbernal/ts-xlsx 3.0.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 (277) hide show
  1. package/README.md +34 -24
  2. package/dist/bytes.d.ts +10 -2
  3. package/dist/bytes.js +22 -0
  4. package/dist/core/address.d.ts +96 -2
  5. package/dist/core/address.js +87 -33
  6. package/dist/core/array-formula-ranges.d.ts +33 -0
  7. package/dist/core/array-formula-ranges.js +62 -0
  8. package/dist/core/autofilter.d.ts +4 -3
  9. package/dist/core/autofilter.js +31 -30
  10. package/dist/core/axis-handle.d.ts +2 -0
  11. package/dist/core/axis-handle.js +5 -2
  12. package/dist/core/cell.d.ts +4 -3
  13. package/dist/core/cell.js +4 -6
  14. package/dist/core/clone.d.ts +29 -0
  15. package/dist/core/clone.js +24 -0
  16. package/dist/core/color-resolution.js +4 -6
  17. package/dist/core/column.d.ts +1 -0
  18. package/dist/core/column.js +6 -2
  19. package/dist/core/comment-thread.d.ts +7 -3
  20. package/dist/core/comment-thread.js +2 -1
  21. package/dist/core/conditional-formatting-overlay.d.ts +11 -1
  22. package/dist/core/conditional-formatting-overlay.js +30 -3
  23. package/dist/core/conditional-formatting.d.ts +107 -11
  24. package/dist/core/conditional-formatting.js +76 -19
  25. package/dist/core/containers.d.ts +12 -0
  26. package/dist/core/containers.js +5 -0
  27. package/dist/core/data-validation-overlay.d.ts +7 -1
  28. package/dist/core/data-validation-overlay.js +19 -4
  29. package/dist/core/data-validation.d.ts +22 -0
  30. package/dist/core/data-validation.js +30 -4
  31. package/dist/core/date-format.d.ts +20 -0
  32. package/dist/core/date-format.js +170 -0
  33. package/dist/core/date.d.ts +43 -8
  34. package/dist/core/date.js +19 -3
  35. package/dist/core/formula-references.d.ts +26 -0
  36. package/dist/core/formula-references.js +173 -0
  37. package/dist/core/formula-scan.d.ts +2 -0
  38. package/dist/core/formula-scan.js +58 -0
  39. package/dist/core/formula.d.ts +76 -17
  40. package/dist/core/formula.js +87 -80
  41. package/dist/core/function-values.d.ts +4 -0
  42. package/dist/core/function-values.js +58 -0
  43. package/dist/core/future-functions.d.ts +3 -0
  44. package/dist/core/{modern-functions.js → future-functions.js} +119 -88
  45. package/dist/core/grid-edits.d.ts +30 -3
  46. package/dist/core/grid-edits.js +248 -81
  47. package/dist/core/grid-shift.d.ts +58 -9
  48. package/dist/core/grid-shift.js +26 -4
  49. package/dist/core/hyperlink.d.ts +39 -0
  50. package/dist/core/hyperlink.js +88 -0
  51. package/dist/core/image.d.ts +49 -14
  52. package/dist/core/image.js +16 -5
  53. package/dist/core/internal.d.ts +10 -2
  54. package/dist/core/limits.d.ts +25 -0
  55. package/dist/core/limits.js +4 -0
  56. package/dist/core/merge.d.ts +18 -4
  57. package/dist/core/merge.js +33 -20
  58. package/dist/core/page-setup.d.ts +26 -11
  59. package/dist/core/pivot-table.d.ts +49 -10
  60. package/dist/core/pivot-table.js +112 -60
  61. package/dist/core/protection.d.ts +66 -4
  62. package/dist/core/protection.js +6 -11
  63. package/dist/core/range.js +34 -30
  64. package/dist/core/row-input.js +2 -2
  65. package/dist/core/row.d.ts +1 -0
  66. package/dist/core/row.js +6 -2
  67. package/dist/core/structured-reference.d.ts +7 -0
  68. package/dist/core/structured-reference.js +7 -0
  69. package/dist/core/style.d.ts +85 -70
  70. package/dist/core/style.js +92 -28
  71. package/dist/core/table-style.d.ts +1 -1
  72. package/dist/core/table-style.js +4 -4
  73. package/dist/core/table.d.ts +64 -16
  74. package/dist/core/table.js +87 -40
  75. package/dist/core/theme.d.ts +2 -0
  76. package/dist/core/theme.js +9 -5
  77. package/dist/core/value.d.ts +60 -28
  78. package/dist/core/value.js +48 -43
  79. package/dist/core/workbook-media.d.ts +34 -0
  80. package/dist/core/workbook-media.js +44 -0
  81. package/dist/core/workbook-styles.d.ts +83 -1
  82. package/dist/core/workbook-styles.js +4 -0
  83. package/dist/core/workbook-theme.js +5 -3
  84. package/dist/core/workbook-vba.js +3 -2
  85. package/dist/core/workbook.d.ts +41 -3
  86. package/dist/core/workbook.js +46 -41
  87. package/dist/core/worksheet-comments.d.ts +2 -1
  88. package/dist/core/worksheet-comments.js +20 -13
  89. package/dist/core/worksheet-merges.d.ts +49 -0
  90. package/dist/core/worksheet-merges.js +65 -0
  91. package/dist/core/worksheet-model.d.ts +10 -2
  92. package/dist/core/worksheet-model.js +28 -9
  93. package/dist/core/worksheet-pictures.d.ts +3 -3
  94. package/dist/core/worksheet-pictures.js +7 -6
  95. package/dist/core/worksheet.d.ts +165 -27
  96. package/dist/core/worksheet.js +206 -89
  97. package/dist/customui/ribbon.js +2 -1
  98. package/dist/entries/core.d.ts +21 -14
  99. package/dist/entries/core.js +14 -7
  100. package/dist/entries/errors.d.ts +1 -0
  101. package/dist/entries/errors.js +1 -0
  102. package/dist/entries/xlsx.d.ts +1 -1
  103. package/dist/errors.d.ts +64 -0
  104. package/dist/errors.js +22 -0
  105. package/dist/hex.d.ts +8 -0
  106. package/dist/hex.js +3 -0
  107. package/dist/io/cell-metadata/metadata.d.ts +42 -0
  108. package/dist/io/cell-metadata/metadata.js +35 -0
  109. package/dist/io/cell-metadata/rich-values.d.ts +11 -0
  110. package/dist/io/cell-metadata/rich-values.js +80 -0
  111. package/dist/io/csv/delimiter.d.ts +21 -0
  112. package/dist/io/csv/delimiter.js +18 -0
  113. package/dist/io/csv/errors.d.ts +14 -0
  114. package/dist/io/csv/errors.js +5 -0
  115. package/dist/io/csv/read.d.ts +6 -1
  116. package/dist/io/csv/read.js +51 -22
  117. package/dist/io/csv/write.d.ts +19 -5
  118. package/dist/io/csv/write.js +24 -44
  119. package/dist/io/opc/inflate.js +14 -0
  120. package/dist/io/opc/namespaces.d.ts +16 -0
  121. package/dist/io/opc/namespaces.js +4 -0
  122. package/dist/io/opc/part-paths.d.ts +9 -0
  123. package/dist/io/opc/part-paths.js +5 -5
  124. package/dist/io/opc/read-opc.d.ts +58 -14
  125. package/dist/io/opc/read-opc.js +49 -21
  126. package/dist/io/opc/read-options.d.ts +5 -1
  127. package/dist/io/opc/sniff-format.d.ts +3 -3
  128. package/dist/io/opc/sniff-format.js +2 -2
  129. package/dist/io/opc/strict-relationships.d.ts +2 -0
  130. package/dist/io/opc/strict-relationships.js +12 -0
  131. package/dist/io/read-policy/column-budget.d.ts +26 -0
  132. package/dist/io/read-policy/column-budget.js +18 -0
  133. package/dist/io/read-policy/read-repair.d.ts +74 -0
  134. package/dist/io/read-policy/read-repair.js +119 -0
  135. package/dist/io/style/cell-style-resolution.d.ts +25 -0
  136. package/dist/io/style/cell-style-resolution.js +30 -0
  137. package/dist/io/style/xf-style.d.ts +23 -1
  138. package/dist/io/style/xf-style.js +8 -0
  139. package/dist/io/xlsb/formula.d.ts +2 -2
  140. package/dist/io/xlsb/formula.js +52 -35
  141. package/dist/io/xlsb/primitives.js +8 -14
  142. package/dist/io/xlsb/ptg-functions.d.ts +19 -10
  143. package/dist/io/xlsb/ptg-functions.js +495 -596
  144. package/dist/io/xlsb/read-metadata.d.ts +7 -0
  145. package/dist/io/xlsb/read-metadata.js +69 -0
  146. package/dist/io/xlsb/read-styles.js +45 -81
  147. package/dist/io/xlsb/read-worksheet.d.ts +26 -1
  148. package/dist/io/xlsb/read-worksheet.js +148 -106
  149. package/dist/io/xlsb/read.d.ts +6 -3
  150. package/dist/io/xlsb/read.js +70 -31
  151. package/dist/io/xlsb/record-stream.d.ts +30 -0
  152. package/dist/io/xlsb/record-stream.js +20 -0
  153. package/dist/io/xlsb/record-types.d.ts +14 -5
  154. package/dist/io/xlsb/record-types.js +14 -5
  155. package/dist/io/xlsb/sheet-protection.d.ts +20 -0
  156. package/dist/io/xlsb/sheet-protection.js +60 -0
  157. package/dist/io/xlsx/cell-accumulator.d.ts +24 -9
  158. package/dist/io/xlsx/cell-accumulator.js +74 -21
  159. package/dist/io/xlsx/cell-metadata.d.ts +39 -0
  160. package/dist/io/xlsx/cell-metadata.js +162 -0
  161. package/dist/io/xlsx/cell-value.d.ts +19 -5
  162. package/dist/io/xlsx/cell-value.js +45 -30
  163. package/dist/io/xlsx/color-xml.js +3 -2
  164. package/dist/io/xlsx/column-span.d.ts +11 -0
  165. package/dist/io/xlsx/column-span.js +9 -0
  166. package/dist/io/xlsx/comments.d.ts +9 -30
  167. package/dist/io/xlsx/comments.js +25 -83
  168. package/dist/io/xlsx/conditional-formatting.d.ts +43 -23
  169. package/dist/io/xlsx/conditional-formatting.js +437 -138
  170. package/dist/io/xlsx/data-validation.d.ts +12 -7
  171. package/dist/io/xlsx/data-validation.js +67 -53
  172. package/dist/io/xlsx/edit-vba.d.ts +7 -2
  173. package/dist/io/xlsx/edit-vba.js +52 -52
  174. package/dist/io/xlsx/font-xml.d.ts +7 -0
  175. package/dist/io/xlsx/font-xml.js +104 -0
  176. package/dist/io/xlsx/hyperlinks.d.ts +19 -21
  177. package/dist/io/xlsx/hyperlinks.js +12 -32
  178. package/dist/io/xlsx/images.d.ts +49 -16
  179. package/dist/io/xlsx/images.js +149 -50
  180. package/dist/io/xlsx/namespaces.d.ts +24 -0
  181. package/dist/io/xlsx/namespaces.js +11 -0
  182. package/dist/io/xlsx/package-plan.d.ts +60 -15
  183. package/dist/io/xlsx/package-plan.js +83 -18
  184. package/dist/io/xlsx/part-names.d.ts +6 -8
  185. package/dist/io/xlsx/part-names.js +3 -7
  186. package/dist/io/xlsx/pivot.d.ts +5 -5
  187. package/dist/io/xlsx/pivot.js +26 -24
  188. package/dist/io/xlsx/preserved-splices.d.ts +6 -0
  189. package/dist/io/xlsx/preserved-splices.js +74 -0
  190. package/dist/io/xlsx/read-comments.d.ts +29 -0
  191. package/dist/io/xlsx/read-comments.js +75 -0
  192. package/dist/io/xlsx/read-parts.d.ts +59 -0
  193. package/dist/io/xlsx/read-parts.js +259 -0
  194. package/dist/io/xlsx/read-pivot.js +11 -4
  195. package/dist/io/xlsx/{rich-runs.d.ts → read-rich-runs.d.ts} +8 -5
  196. package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +24 -4
  197. package/dist/io/xlsx/read-rows.d.ts +35 -11
  198. package/dist/io/xlsx/read-rows.js +73 -49
  199. package/dist/io/xlsx/read-shared-strings.js +3 -2
  200. package/dist/io/xlsx/read-styles.d.ts +0 -30
  201. package/dist/io/xlsx/read-styles.js +45 -105
  202. package/dist/io/xlsx/read-workbook-xml.d.ts +42 -0
  203. package/dist/io/xlsx/read-workbook-xml.js +175 -0
  204. package/dist/io/xlsx/read-worksheet.d.ts +9 -3
  205. package/dist/io/xlsx/read-worksheet.js +70 -177
  206. package/dist/io/xlsx/read.d.ts +3 -14
  207. package/dist/io/xlsx/read.js +74 -411
  208. package/dist/io/xlsx/relationships.d.ts +3 -0
  209. package/dist/io/xlsx/relationships.js +4 -0
  210. package/dist/io/xlsx/rich-text.js +1 -1
  211. package/dist/io/xlsx/row-position.d.ts +20 -0
  212. package/dist/io/xlsx/row-position.js +11 -0
  213. package/dist/io/xlsx/row-xml.d.ts +139 -0
  214. package/dist/io/xlsx/row-xml.js +222 -0
  215. package/dist/io/xlsx/shared-formulas.js +2 -2
  216. package/dist/io/xlsx/sheet-properties.d.ts +10 -1
  217. package/dist/io/xlsx/sheet-properties.js +182 -20
  218. package/dist/io/xlsx/strict-parts.d.ts +7 -0
  219. package/dist/io/xlsx/strict-parts.js +171 -0
  220. package/dist/io/xlsx/style-elements.d.ts +41 -0
  221. package/dist/io/xlsx/style-elements.js +136 -0
  222. package/dist/io/xlsx/styles.d.ts +17 -3
  223. package/dist/io/xlsx/styles.js +13 -209
  224. package/dist/io/xlsx/tables.d.ts +10 -2
  225. package/dist/io/xlsx/tables.js +55 -52
  226. package/dist/io/xlsx/theme-xml.d.ts +32 -4
  227. package/dist/io/xlsx/theme-xml.js +106 -71
  228. package/dist/io/xlsx/threaded-comments.d.ts +14 -11
  229. package/dist/io/xlsx/threaded-comments.js +16 -8
  230. package/dist/io/xlsx/workbook-xml.d.ts +45 -6
  231. package/dist/io/xlsx/workbook-xml.js +62 -54
  232. package/dist/io/xlsx/worksheet-xml.d.ts +26 -70
  233. package/dist/io/xlsx/worksheet-xml.js +69 -282
  234. package/dist/io/xlsx/write-stream.d.ts +90 -19
  235. package/dist/io/xlsx/write-stream.js +80 -25
  236. package/dist/io/xlsx/write.d.ts +12 -6
  237. package/dist/io/xlsx/write.js +226 -123
  238. package/dist/rel-type.d.ts +25 -0
  239. package/dist/rel-type.js +9 -0
  240. package/dist/token-set.d.ts +13 -0
  241. package/dist/token-set.js +4 -1
  242. package/dist/vba/bytes.d.ts +16 -5
  243. package/dist/vba/bytes.js +27 -6
  244. package/dist/vba/cfb-format.d.ts +55 -0
  245. package/dist/vba/cfb-format.js +35 -0
  246. package/dist/vba/cfb-writer.d.ts +8 -0
  247. package/dist/vba/cfb-writer.js +40 -40
  248. package/dist/vba/cfb.d.ts +21 -4
  249. package/dist/vba/cfb.js +124 -90
  250. package/dist/vba/codepage.js +2 -1
  251. package/dist/vba/dir-records.d.ts +6 -0
  252. package/dist/vba/dir-records.js +10 -2
  253. package/dist/vba/errors.d.ts +11 -4
  254. package/dist/vba/index.d.ts +0 -2
  255. package/dist/vba/index.js +0 -2
  256. package/dist/vba/ms-ovba.d.ts +6 -2
  257. package/dist/vba/ms-ovba.js +66 -22
  258. package/dist/vba/project-editor.js +129 -119
  259. package/dist/vba/project.d.ts +15 -1
  260. package/dist/vba/project.js +38 -13
  261. package/dist/vba/vba-encoding.d.ts +4 -10
  262. package/dist/vba/vba-encoding.js +3 -17
  263. package/dist/xml/xml-attrs.d.ts +37 -0
  264. package/dist/xml/xml-attrs.js +30 -0
  265. package/dist/xml/xml-chars.d.ts +40 -0
  266. package/dist/xml/xml-chars.js +12 -0
  267. package/dist/xml/xml-namespaces.d.ts +31 -0
  268. package/dist/xml/xml-namespaces.js +50 -0
  269. package/dist/xml/xml-read.d.ts +101 -11
  270. package/dist/xml/xml-read.js +150 -18
  271. package/dist/xml/xml-scan.d.ts +25 -34
  272. package/dist/xml/xml-scan.js +69 -46
  273. package/dist/xml/xml.d.ts +59 -26
  274. package/dist/xml/xml.js +45 -23
  275. package/package.json +15 -9
  276. package/skills/ts-xlsx-upstream/SKILL.md +21 -13
  277. package/dist/core/modern-functions.d.ts +0 -1
@@ -1,7 +1,7 @@
1
- import { AuthoringError } from '../errors.js';
1
+ import { AuthoringError, quoted } from '../errors.js';
2
2
  import { tokenSet } from '../token-set.js';
3
- import { decodeRange, encodeAddress } from './address.js';
4
- import { isDeletedSpan, shiftIndex } from './grid-shift.js';
3
+ import { boundedRect, decodeRange, encodeRect } from './address.js';
4
+ import { isDeletedSpan, shiftIndex, shiftRect } from './grid-shift.js';
5
5
  export const isCustomFilterOperator = tokenSet({
6
6
  equal: true,
7
7
  notEqual: true,
@@ -12,15 +12,16 @@ export const isCustomFilterOperator = tokenSet({
12
12
  });
13
13
  export function canonicalizeAutoFilter(input) {
14
14
  const ref = typeof input === 'string' ? input : input.ref;
15
- const { top, left, bottom, right, dimensions } = decodeRange(ref);
16
- if (top === undefined || left === undefined || bottom === undefined || right === undefined) {
17
- throw new AuthoringError(`autofilter range "${ref}" must be a bounded rectangle`);
15
+ const decoded = decodeRange(ref);
16
+ const rect = boundedRect(decoded);
17
+ if (rect === undefined) {
18
+ throw new AuthoringError(`autofilter range ${quoted(ref)} must be a bounded rectangle`);
18
19
  }
19
20
  if (typeof input === 'string')
20
- return { ref: dimensions, columns: [] };
21
- const width = right - left + 1;
21
+ return { ref: decoded.dimensions, columns: [] };
22
+ const width = rect.right - rect.left + 1;
22
23
  return {
23
- ref: dimensions,
24
+ ref: decoded.dimensions,
24
25
  columns: input.columns.map((column) => canonicalizeColumn(column, width)),
25
26
  };
26
27
  }
@@ -28,35 +29,35 @@ function canonicalizeColumn(column, width) {
28
29
  if (!Number.isInteger(column.colId) || column.colId < 0 || column.colId >= width) {
29
30
  throw new AuthoringError(`autofilter colId ${column.colId} is outside the filter range`);
30
31
  }
31
- if (column.criteria.kind === 'custom') {
32
- const count = column.criteria.predicates.length;
33
- if (count < 1 || count > 2) {
34
- throw new AuthoringError(`a custom filter needs one or two predicates, got ${count}`);
35
- }
32
+ const criteria = column.criteria;
33
+ if (criteria.kind === 'values') {
34
+ return { colId: column.colId, criteria: { ...criteria, values: [...criteria.values] } };
36
35
  }
37
- return column;
36
+ const count = criteria.predicates.length;
37
+ if (count < 1 || count > 2) {
38
+ throw new AuthoringError(`a custom filter needs one or two predicates, got ${count}`);
39
+ }
40
+ return {
41
+ colId: column.colId,
42
+ criteria: { ...criteria, predicates: criteria.predicates.map((predicate) => ({ ...predicate })) },
43
+ };
38
44
  }
39
- export function shiftAutoFilter(filter, axis, start, count, delta) {
40
- const { top, left, bottom, right } = decodeRange(filter.ref);
41
- if (top === undefined || left === undefined || bottom === undefined || right === undefined) {
45
+ export function shiftAutoFilter(filter, splice) {
46
+ const rect = boundedRect(decodeRange(filter.ref));
47
+ if (rect === undefined)
42
48
  return filter;
43
- }
44
- const [lo, hi] = axis === 'row' ? [top, bottom] : [left, right];
45
- if (isDeletedSpan(lo, hi, start, count))
49
+ const moved = shiftRect(rect, splice);
50
+ if (moved === undefined)
46
51
  return undefined;
47
- const movedLo = shiftIndex(lo, start, count, delta, axis);
48
- const movedHi = shiftIndex(hi, start, count, delta, axis);
49
- if (axis === 'row') {
50
- const ref = `${encodeAddress(left, movedLo)}:${encodeAddress(right, movedHi)}`;
52
+ const ref = encodeRect(moved);
53
+ if (splice.axis === 'row')
51
54
  return { ref, columns: filter.columns };
52
- }
53
- const ref = `${encodeAddress(movedLo, top)}:${encodeAddress(movedHi, bottom)}`;
54
55
  const columns = [];
55
56
  for (const column of filter.columns) {
56
- const absolute = left + column.colId;
57
- if (isDeletedSpan(absolute, absolute, start, count))
57
+ const absolute = rect.left + column.colId;
58
+ if (isDeletedSpan(absolute, absolute, splice))
58
59
  continue;
59
- columns.push({ ...column, colId: shiftIndex(absolute, start, count, delta, axis) - movedLo });
60
+ columns.push({ ...column, colId: shiftIndex(absolute, splice) - moved.left });
60
61
  }
61
62
  return { ref, columns };
62
63
  }
@@ -3,6 +3,8 @@ export declare abstract class AxisHandle<P extends object> {
3
3
  protected abstract propertiesOf(): P | undefined;
4
4
  /** This position's format record, created if it does not exist yet. */
5
5
  protected abstract ensureProperties(): P;
6
+ /** Remove this position's format record entirely, so nothing is left declaring the line. */
7
+ protected abstract dropProperties(): void;
6
8
  protected read<K extends keyof P>(key: K): P[K] | undefined;
7
9
  protected write<K extends keyof P>(key: K, value: P[K]): void;
8
10
  }
@@ -5,8 +5,11 @@ export class AxisHandle {
5
5
  write(key, value) {
6
6
  if (value === undefined) {
7
7
  const properties = this.propertiesOf();
8
- if (properties !== undefined)
9
- delete properties[key];
8
+ if (properties === undefined)
9
+ return;
10
+ delete properties[key];
11
+ if (Object.keys(properties).length === 0)
12
+ this.dropProperties();
10
13
  return;
11
14
  }
12
15
  this.ensureProperties()[key] = value;
@@ -139,9 +139,10 @@ export declare class Cell {
139
139
  set note(note: string | undefined);
140
140
  }
141
141
  /**
142
- * Whether a cell carries formatting of its own: one of the {@link CellStyle} facets, the quote-prefix
143
- * flag, or a link to a named style. Driven by {@link CELL_STYLE_FACETS}, so a facet added to the
144
- * tuple reaches every "is this cell blank" decision without anyone remembering to widen a literal.
142
+ * Whether a cell carries formatting of its own: any {@link CellContent} facet, which is the six shared
143
+ * style facets plus the quote-prefix flag and the link to a named style. Driven by
144
+ * {@link CELL_CONTENT_FACETS}, so a facet added to the tuple reaches every "is this cell blank"
145
+ * decision without anyone remembering to widen a literal.
145
146
  *
146
147
  * Row- and column-inherited formatting is not the cell's own and does not count. Neither does a
147
148
  * note: it lives in the comments part, not the cell's `<c>` element, so a writer deciding whether an
package/dist/core/cell.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { assertColumnInBounds, assertRowInBounds, encodeAddress } from './address.js';
2
2
  import { NAMED_STYLE_ID } from './internal.js';
3
- import { assignStyleFacets, CELL_STYLE_FACETS, } from './style.js';
3
+ import { assignContentFacets, assignStyleFacets, CELL_CONTENT_FACETS, } from './style.js';
4
4
  import { cellValueToText, coerceCellValue, detectValueType, } from './value.js';
5
5
  export class Cell {
6
6
  row;
@@ -107,9 +107,7 @@ export class Cell {
107
107
  }
108
108
  }
109
109
  export function cellHasOwnStyle(cell) {
110
- return (CELL_STYLE_FACETS.some((facet) => cell[facet] !== undefined) ||
111
- cell.quotePrefix === true ||
112
- cell[NAMED_STYLE_ID] !== undefined);
110
+ return CELL_CONTENT_FACETS.some((facet) => cell[facet] !== undefined);
113
111
  }
114
112
  export function cellCarriesContent(cell) {
115
113
  return cell.value !== null || cell.note !== undefined || cellHasOwnStyle(cell);
@@ -119,7 +117,7 @@ export function applyCellStyle(cell, style) {
119
117
  }
120
118
  export function copyCellContent(source, target) {
121
119
  target.value = source.value;
122
- applyCellStyle(target, source);
120
+ assignContentFacets(target, source);
123
121
  target.note = source.note;
124
122
  }
125
123
  export function cellToModel(cell) {
@@ -129,6 +127,6 @@ export function cellToModel(cell) {
129
127
  value: cell.value,
130
128
  note: cell.note,
131
129
  };
132
- assignStyleFacets(model, cell);
130
+ assignContentFacets(model, cell);
133
131
  return model;
134
132
  }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * How far a copy of one field goes.
3
+ *
4
+ * - `'value'`: assign it. Correct for a scalar, and for anything genuinely immutable.
5
+ * - `'record'`: `{...v}`. A flat object whose own fields are scalars.
6
+ * - `'values'`: `[...v]`. An array of scalars.
7
+ * - `'records'`: `v.map(x => ({...x}))`. An array of flat objects.
8
+ * - a function: the field's own clone, for a nested type that has a plan of its own.
9
+ */
10
+ export type CloneStrategy<V> = 'value' | 'record' | 'values' | 'records' | ((value: V) => V);
11
+ /**
12
+ * One strategy per field of `T`. The `Record` is what makes a missing field a compile error.
13
+ *
14
+ * A field's strategy sees the field's type without `undefined`, because {@link cloneWith} skips an
15
+ * absent field rather than handing it over. Under `exactOptionalPropertyTypes` a facet declared
16
+ * `font?: Font | undefined` keeps that `undefined` through `Required`, so without the exclusion a
17
+ * nested type's own clone function would not satisfy its own field's strategy.
18
+ */
19
+ export type ClonePlan<T> = {
20
+ readonly [K in keyof Required<T>]-?: CloneStrategy<Exclude<Required<T>[K], undefined>>;
21
+ };
22
+ /**
23
+ * Copy `source` according to `plan`, leaving a field absent when the source leaves it absent.
24
+ *
25
+ * Absent rather than `undefined`: every one of these types declares its optional fields under
26
+ * `exactOptionalPropertyTypes`, where a present-but-undefined key is a different shape from a missing
27
+ * one, and a round-trip that fabricated the first would report formatting a cell does not have.
28
+ */
29
+ export declare function cloneWith<T extends object>(source: T, plan: ClonePlan<T>): T;
@@ -0,0 +1,24 @@
1
+ export function cloneWith(source, plan) {
2
+ const out = {};
3
+ for (const key of Object.keys(plan)) {
4
+ const value = source[key];
5
+ if (value === undefined)
6
+ continue;
7
+ out[key] = applyStrategy(value, plan[key]);
8
+ }
9
+ return out;
10
+ }
11
+ function applyStrategy(value, strategy) {
12
+ if (typeof strategy === 'function')
13
+ return strategy(value);
14
+ switch (strategy) {
15
+ case 'value':
16
+ return value;
17
+ case 'record':
18
+ return { ...value };
19
+ case 'values':
20
+ return [...value];
21
+ case 'records':
22
+ return value.map((entry) => ({ ...entry }));
23
+ }
24
+ }
@@ -1,5 +1,6 @@
1
+ import { hex } from '../hex.js';
1
2
  import { parseArgb } from './style.js';
2
- import { DEFAULT_THEME_COLOR_SCHEME, THEME_COLOR_SLOTS } from './theme.js';
3
+ import { DEFAULT_THEME_COLOR_SCHEME, isThemeRgb, THEME_COLOR_SLOTS, } from './theme.js';
3
4
  export const DEFAULT_INDEXED_COLORS = [
4
5
  '00000000', '00FFFFFF', '00FF0000', '0000FF00', '000000FF', '00FFFF00', '00FF00FF', '0000FFFF',
5
6
  '00000000', '00FFFFFF', '00FF0000', '0000FF00', '000000FF', '00FFFF00', '00FF00FF', '0000FFFF',
@@ -31,7 +32,7 @@ function resolveBase(color, context) {
31
32
  if (slot === undefined)
32
33
  return undefined;
33
34
  const value = (context.theme ?? DEFAULT_THEME_COLOR_SCHEME)[slot];
34
- return value === undefined ? undefined : `FF${value.toUpperCase()}`;
35
+ return value !== undefined && isThemeRgb(value) ? `FF${value.toUpperCase()}` : undefined;
35
36
  }
36
37
  if (color.indexed !== undefined) {
37
38
  if (SYSTEM_INDEXED_COLORS.has(color.indexed))
@@ -102,8 +103,5 @@ function hueToChannel(p, q, offset) {
102
103
  return p;
103
104
  }
104
105
  function channelHex(value) {
105
- return Math.round(clamp01(value) * 255)
106
- .toString(16)
107
- .toUpperCase()
108
- .padStart(2, '0');
106
+ return hex(Math.round(clamp01(value) * 255), 2);
109
107
  }
@@ -21,6 +21,7 @@ export declare class Column extends AxisHandle<ColumnProperties> {
21
21
  get properties(): Readonly<ColumnProperties> | undefined;
22
22
  protected propertiesOf(): ColumnProperties | undefined;
23
23
  protected ensureProperties(): ColumnProperties;
24
+ protected dropProperties(): void;
24
25
  /**
25
26
  * Stable key naming this column so a keyed-object row (see {@link Worksheet.addRow}) can place a
26
27
  * value under it by name rather than position. In-memory only: never serialized to OOXML.
@@ -1,4 +1,4 @@
1
- import { assertColumnInBounds, encodeAddress, numberToColumn } from './address.js';
1
+ import { assertColumnInBounds, assertRowInBounds, numberToColumn } from './address.js';
2
2
  import { AxisHandle } from './axis-handle.js';
3
3
  import { INTERNAL } from './internal.js';
4
4
  export class Column extends AxisHandle {
@@ -22,6 +22,9 @@ export class Column extends AxisHandle {
22
22
  ensureProperties() {
23
23
  return this.#sheet[INTERNAL].ensureColumnProperties(this.index);
24
24
  }
25
+ dropProperties() {
26
+ this.#sheet[INTERNAL].dropColumnProperties(this.index);
27
+ }
25
28
  get key() {
26
29
  return this.read('key');
27
30
  }
@@ -89,7 +92,8 @@ export class Column extends AxisHandle {
89
92
  this.write('protection', protection);
90
93
  }
91
94
  getCell(row) {
92
- return this.#sheet.getCell(encodeAddress(this.index, row));
95
+ assertRowInBounds(row);
96
+ return this.#sheet[INTERNAL].masterAt(row, this.index);
93
97
  }
94
98
  get cells() {
95
99
  return this.#sheet[INTERNAL].columnCells(this.index);
@@ -55,11 +55,15 @@ export interface Comment {
55
55
  /** Brace-wrapped GUID identifying this message, preserved verbatim from the file. */
56
56
  readonly id: string;
57
57
  /**
58
- * Who wrote it, resolved through the workbook registry. Absent when the file recorded no author or
59
- * named an id the registry does not hold; {@link personId} distinguishes those two cases.
58
+ * Who wrote it, resolved through the workbook registry. Absent when the file recorded no author, or
59
+ * named an id the registry does not hold, which Excel treats the same way.
60
60
  */
61
61
  readonly author?: Person;
62
- /** The author's {@link Person.id} exactly as written; absent when the file recorded no author. */
62
+ /**
63
+ * The author's {@link Person.id}, which must be registered ({@link Workbook.addPerson}) by the time
64
+ * the workbook is written. Absent for a message with no recorded author, which is written under the
65
+ * null GUID Excel uses for one and shown by Excel as "Author".
66
+ */
63
67
  readonly personId?: string;
64
68
  /**
65
69
  * When it was written, verbatim. Excel writes local wall-clock with fractional seconds and no
@@ -1,9 +1,10 @@
1
+ import { quoted } from '../errors.js';
1
2
  const GUID = /^\{?([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})\}?$/i;
2
3
  export function commentThreadGuid(value, what) {
3
4
  const match = GUID.exec(value.trim());
4
5
  if (match === null) {
5
6
  throw new SyntaxError(`${what} must be a GUID: Excel writes threaded-comment ids as ` +
6
- `"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}", but got "${value}"`);
7
+ `"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}", but got ${quoted(value)}`);
7
8
  }
8
9
  return `{${match.slice(1).join('-').toUpperCase()}}`;
9
10
  }
@@ -1,4 +1,5 @@
1
1
  import { type ConditionalFormatting } from './conditional-formatting.ts';
2
+ import type { AxisSplice } from './grid-shift.ts';
2
3
  export declare class ConditionalFormattingOverlay {
3
4
  #private;
4
5
  /**
@@ -6,6 +7,10 @@ export declare class ConditionalFormattingOverlay {
6
7
  * range (`"A1:A10"`), a whole column, or several space-separated areas (`"A1:C1 A3:C3"`) sharing one
7
8
  * rule set. The block is stored once against the range, defensively copied so the getter never hands
8
9
  * back a reference into the caller's object.
10
+ *
11
+ * @throws {AuthoringError} when `formatting.ref` names no area at all. A rule set attached to
12
+ * nothing formats no cell and is written back as the same unreadable text, so it is a mistake worth
13
+ * surfacing at the call. The reader does not reach this: it drops such a block at its own boundary.
9
14
  */
10
15
  add(formatting: ConditionalFormatting): void;
11
16
  /** The conditional formattings on this sheet, each bound to its target range, in insertion order. */
@@ -14,7 +19,12 @@ export declare class ConditionalFormattingOverlay {
14
19
  * Re-anchor every rule set through a row or column splice, so a highlight keeps covering the cells
15
20
  * it was written for. A rule set whose every target area fell inside a deleted span goes with them.
16
21
  */
17
- shift(axis: 'row' | 'col', start: number, count: number, delta: number): void;
22
+ shift(splice: AxisSplice): void;
23
+ /**
24
+ * Rewrite every rule's formulae, and the value of each scale anchor whose type is `formula`, through
25
+ * `rewrite`, keeping a rule set nothing in which changed as the same object.
26
+ */
27
+ mapFormulas(rewrite: (formula: string) => string): void;
18
28
  /** Drop every conditional formatting, leaving the overlay empty. */
19
29
  clear(): void;
20
30
  }
@@ -1,23 +1,50 @@
1
+ import { AuthoringError, quoted } from '../errors.js';
1
2
  import { cloneConditionalFormatting } from './conditional-formatting.js';
2
3
  import { replaceContents } from './containers.js';
3
- import { shiftSqref } from './merge.js';
4
+ import { decodeSqrefRects, shiftSqref } from './merge.js';
4
5
  export class ConditionalFormattingOverlay {
5
6
  #entries = [];
6
7
  add(formatting) {
8
+ if (decodeSqrefRects(formatting.ref).length === 0) {
9
+ throw new AuthoringError(`conditional formatting range ${quoted(formatting.ref)} names no cells`);
10
+ }
7
11
  this.#entries.push(cloneConditionalFormatting(formatting));
8
12
  }
9
13
  get entries() {
10
14
  return this.#entries;
11
15
  }
12
- shift(axis, start, count, delta) {
16
+ shift(splice) {
13
17
  const entries = [];
14
18
  for (const entry of this.#entries) {
15
- const ref = shiftSqref(entry.ref, axis, start, count, delta);
19
+ const ref = shiftSqref(entry.ref, splice);
16
20
  if (ref !== undefined)
17
21
  entries.push({ ...entry, ref });
18
22
  }
19
23
  replaceContents(this.#entries, entries);
20
24
  }
25
+ mapFormulas(rewrite) {
26
+ for (const [index, entry] of this.#entries.entries()) {
27
+ let changed = false;
28
+ const rules = entry.rules.map((rule) => {
29
+ const formulae = rule.formulae?.map((operand) => typeof operand === 'string' ? rewrite(operand) : operand);
30
+ const cfvo = rule.cfvo?.map((anchor) => anchor.type === 'formula' && typeof anchor.value === 'string'
31
+ ? { ...anchor, value: rewrite(anchor.value) }
32
+ : anchor);
33
+ const formulaeMoved = formulae?.some((operand, i) => operand !== rule.formulae?.[i]) ?? false;
34
+ const cfvoMoved = cfvo?.some((anchor, i) => anchor.value !== rule.cfvo?.[i]?.value) ?? false;
35
+ if (!formulaeMoved && !cfvoMoved)
36
+ return rule;
37
+ changed = true;
38
+ return {
39
+ ...rule,
40
+ ...(formulae === undefined ? {} : { formulae }),
41
+ ...(cfvo === undefined ? {} : { cfvo }),
42
+ };
43
+ });
44
+ if (changed)
45
+ this.#entries[index] = { ...entry, rules };
46
+ }
47
+ }
21
48
  clear() {
22
49
  this.#entries.length = 0;
23
50
  }
@@ -1,16 +1,31 @@
1
- import type { Color, DifferentialStyle } from './style.ts';
2
- /** How a {@link CfValueObject} reads its `value`: `ST_CfvoType` verbatim. */
3
- export type CfValueObjectType = 'num' | 'percent' | 'max' | 'min' | 'percentile' | 'formula';
1
+ import { type ClonePlan } from './clone.ts';
2
+ import type { AssertNever } from './internal.ts';
3
+ import { type Color } from './style.ts';
4
+ import type { DifferentialStyle } from './workbook-styles.ts';
5
+ /**
6
+ * How a {@link CfValueObject} reads its `value`: `ST_CfvoType` verbatim, with the `autoMin` and
7
+ * `autoMax` the 2009 extension adds.
8
+ */
9
+ export type CfValueObjectType = 'num' | 'percent' | 'max' | 'min' | 'percentile' | 'formula' | 'autoMin' | 'autoMax';
4
10
  /** Narrow a raw `<cfvo type>` token to a known {@link CfValueObjectType}. */
5
11
  export declare const isCfValueObjectType: (value: string) => value is CfValueObjectType;
6
12
  /**
7
13
  * One anchor of a colour-scale, data-bar, or icon-set scale: a "conditional format value object".
8
14
  * `type` names how `value` is read: a literal `num`, a `percent`/`percentile` of the range, a
9
15
  * `formula`, or the range's own `min`/`max` (which carry no value).
16
+ *
17
+ * `autoMin` and `autoMax` are the automatic anchors Excel 2010 gives a new data bar, and carry no value
18
+ * either. Only the extension form spells them, so a data bar using one is written with its extension,
19
+ * its classic element saying `min` or `max` in their place as Excel's does.
10
20
  */
11
21
  export interface CfValueObject {
12
22
  type: CfValueObjectType;
13
23
  value?: number | string;
24
+ /**
25
+ * Whether a value equal to this threshold reaches it. `false` makes an icon set's threshold a strict
26
+ * `>` rather than the `>=` the schema defaults to.
27
+ */
28
+ gte?: boolean;
14
29
  }
15
30
  /**
16
31
  * What a rule tests, as `<cfRule type>` carries it: `ST_CfType` verbatim.
@@ -37,21 +52,49 @@ export declare const isConditionalFormattingOperator: (value: string) => value i
37
52
  export type CfTimePeriod = 'today' | 'yesterday' | 'tomorrow' | 'last7Days' | 'thisMonth' | 'lastMonth' | 'nextMonth' | 'thisWeek' | 'lastWeek' | 'nextWeek';
38
53
  /** Narrow a raw `<cfRule timePeriod>` token to a known {@link CfTimePeriod}. */
39
54
  export declare const isCfTimePeriod: (value: string) => value is CfTimePeriod;
55
+ /**
56
+ * Which way a data bar grows, as `ST_DataBarDirection` enumerates it: `context` follows the sheet's
57
+ * reading direction.
58
+ */
59
+ export type DataBarDirection = 'context' | 'leftToRight' | 'rightToLeft';
60
+ /** Narrow a raw `<x14:dataBar direction>` token to a known {@link DataBarDirection}. */
61
+ export declare const isDataBarDirection: (value: string) => value is DataBarDirection;
62
+ /**
63
+ * Where a data bar draws the axis between its negative and positive bars, as `ST_DataBarAxisPosition`
64
+ * enumerates it: where the values put it, at the middle of the cell, or nowhere, which grows a
65
+ * negative bar the way a positive one grows.
66
+ */
67
+ export type DataBarAxisPosition = 'automatic' | 'middle' | 'none';
68
+ /** Narrow a raw `<x14:dataBar axisPosition>` token to a known {@link DataBarAxisPosition}. */
69
+ export declare const isDataBarAxisPosition: (value: string) => value is DataBarAxisPosition;
40
70
  /**
41
71
  * The named icon family an `iconSet` rule draws from, as `ST_IconSetType` enumerates it. The leading
42
72
  * digit is the number of icons, which is also how many {@link CfValueObject} anchors the rule needs.
43
73
  *
44
- * The 2009 extension adds three more families (`3Stars`, `3Triangles`, `5Boxes`) under its own
45
- * namespace. They are absent here because the classic `<iconSet>` element this list types cannot
46
- * carry them; a file using one states it in the extension, which the library round-trips verbatim.
74
+ * `3Stars`, `3Triangles` and `5Boxes` are the families the 2009 extension added. The classic
75
+ * `<iconSet>` element cannot name them, so a rule drawing from one is written in the extension form.
47
76
  */
48
- export type IconSetType = '3Arrows' | '3ArrowsGray' | '3Flags' | '3TrafficLights1' | '3TrafficLights2' | '3Signs' | '3Symbols' | '3Symbols2' | '4Arrows' | '4ArrowsGray' | '4RedToBlack' | '4Rating' | '4TrafficLights' | '5Arrows' | '5ArrowsGray' | '5Rating' | '5Quarters';
77
+ export type IconSetType = '3Arrows' | '3ArrowsGray' | '3Flags' | '3TrafficLights1' | '3TrafficLights2' | '3Signs' | '3Symbols' | '3Symbols2' | '4Arrows' | '4ArrowsGray' | '4RedToBlack' | '4Rating' | '4TrafficLights' | '5Arrows' | '5ArrowsGray' | '5Rating' | '5Quarters' | '3Stars' | '3Triangles' | '5Boxes';
49
78
  /** Narrow a raw `<iconSet iconSet>` token to a known {@link IconSetType}. */
50
79
  export declare const isIconSetType: (value: string) => value is IconSetType;
80
+ /** The families only the 2009 extension can name: a rule drawing from one is written there. */
81
+ export declare function isExtensionIconSet(iconSet: IconSetType): boolean;
82
+ /** The family a custom icon comes from: any {@link IconSetType}, or `NoIcons` for a threshold showing none. */
83
+ export type CfIconSetType = IconSetType | 'NoIcons';
84
+ /** Narrow a raw `<x14:cfIcon iconSet>` token to a known {@link CfIconSetType}. */
85
+ export declare function isCfIconSetType(value: string): value is CfIconSetType;
86
+ /** One threshold's icon in a custom icon set: icon number `iconId`, from 0, of the family `iconSet`. */
87
+ export interface CfIcon {
88
+ iconSet: CfIconSetType;
89
+ iconId: number;
90
+ }
51
91
  /**
52
92
  * A single conditional-formatting rule. `type` is the OOXML cfRule type; the remaining fields carry
53
93
  * the operands that type needs and are absent otherwise. A rule the library does not model in depth
54
94
  * still preserves `type`, `priority`, `operator`, `formulae`, and `dxfId` across a round-trip.
95
+ *
96
+ * A data bar's facets marked as x14 properties have no place in the classic `<dataBar>` element, so a
97
+ * bar carrying any of them, or an automatic anchor, is written with a linked `<x14:dataBar>` as well.
55
98
  */
56
99
  export interface ConditionalFormattingRule {
57
100
  type: ConditionalFormattingType;
@@ -75,14 +118,48 @@ export interface ConditionalFormattingRule {
75
118
  color?: Color;
76
119
  /** A colorScale's colours, one per {@link cfvo}. */
77
120
  colors?: Color[];
78
- /** A dataBar's gradient-fill flag. Lives only in the x14 extension, not the classic element. */
121
+ /** A dataBar's shortest bar, as a percentage of the cell. */
122
+ minLength?: number;
123
+ /** A dataBar's longest bar, as a percentage of the cell. */
124
+ maxLength?: number;
125
+ /** A dataBar's gradient-fill flag. An x14 property. */
79
126
  gradient?: boolean;
80
- /** A dataBar's fill colour for negative values. An x14 extension property. */
127
+ /** Whether a dataBar has a border, in {@link borderColor}. An x14 property. */
128
+ border?: boolean;
129
+ /** A dataBar's border colour. An x14 property. */
130
+ borderColor?: Color;
131
+ /** Which way a dataBar grows. An x14 property. */
132
+ direction?: DataBarDirection;
133
+ /** A dataBar's fill colour for negative values. An x14 property. */
81
134
  negativeFillColor?: Color;
135
+ /** A dataBar's border colour for negative values. An x14 property. */
136
+ negativeBorderColor?: Color;
137
+ /**
138
+ * Whether a dataBar fills a negative bar in its positive colour rather than
139
+ * {@link negativeFillColor}. An x14 property.
140
+ */
141
+ negativeBarColorSameAsPositive?: boolean;
142
+ /**
143
+ * Whether a dataBar borders a negative bar in its positive border colour rather than
144
+ * {@link negativeBorderColor}. An x14 property.
145
+ */
146
+ negativeBarBorderColorSameAsPositive?: boolean;
147
+ /** Where a dataBar draws the axis between negative and positive bars. An x14 property. */
148
+ axisPosition?: DataBarAxisPosition;
82
149
  /** A dataBar's axis colour (the zero line between positive and negative bars). An x14 property. */
83
150
  axisColor?: Color;
84
151
  /** An iconSet's named icon family (e.g. `3TrafficLights1`). */
85
152
  iconSet?: IconSetType;
153
+ /**
154
+ * A custom iconSet's icons, one per {@link cfvo} threshold in order, each replacing the icon
155
+ * {@link iconSet} would show there. Only the extension form carries them, so a rule with icons is
156
+ * written in it.
157
+ */
158
+ icons?: CfIcon[];
159
+ /** iconSet: the icons in reverse order, the highest threshold showing the family's first icon. */
160
+ reverse?: boolean;
161
+ /** dataBar / iconSet: whether the cell still shows its value beside the bar or icon. */
162
+ showValue?: boolean;
86
163
  /** top10 rank cutoff. */
87
164
  rank?: number;
88
165
  /** top10: the rank is a percentage rather than a count. */
@@ -98,13 +175,32 @@ export interface ConditionalFormattingRule {
98
175
  /** timePeriod window (`today`, `lastWeek`, …). */
99
176
  timePeriod?: CfTimePeriod;
100
177
  }
101
- /** A set of rules bound to the range(s) they cover. `ref` is an OOXML `sqref`: one or more
178
+ /**
179
+ * A set of rules bound to the range(s) they cover. `ref` is an OOXML `sqref`: one or more
102
180
  * space-separated areas (`"A1:C1 A3:C3 A5:C5"`), the shape Excel writes when one rule is applied to
103
- * several non-contiguous selections at once. */
181
+ * several non-contiguous selections at once.
182
+ *
183
+ * `extended` marks a set stored in the 2009 extension form (`<x14:conditionalFormatting>` inside the
184
+ * worksheet `<extLst>`), where Excel puts a rule whose formula reaches another sheet. The reader sets
185
+ * it for a set found in that form so a round-trip writes the set back there. A rule only that form can
186
+ * express, one drawing from a 2009 icon family or carrying custom icons, is written there whatever the
187
+ * flag says.
188
+ */
104
189
  export interface ConditionalFormatting {
105
190
  ref: string;
106
191
  rules: ConditionalFormattingRule[];
192
+ extended?: boolean;
107
193
  }
108
194
  /** A defensive deep copy, so a stored conditional formatting never aliases the caller's object nor
109
195
  * any of its nested arrays (rules, formulae, cfvo, colours) or the differential style. */
110
196
  export declare function cloneConditionalFormatting(cf: ConditionalFormatting): ConditionalFormatting;
197
+ /**
198
+ * Whether a rule needs the extension form: it names a family or custom icons the classic element has
199
+ * no way to spell.
200
+ */
201
+ export declare function ruleNeedsExtension(rule: ConditionalFormattingRule): boolean;
202
+ declare const RULE_CLONE: ClonePlan<ConditionalFormattingRule>;
203
+ export type EveryRuleFieldIsCloned = AssertNever<Exclude<keyof Required<ConditionalFormattingRule>, keyof typeof RULE_CLONE>>;
204
+ declare const STYLE_CLONE: ClonePlan<DifferentialStyle>;
205
+ export type EveryDifferentialStyleFieldIsCloned = AssertNever<Exclude<keyof Required<DifferentialStyle>, keyof typeof STYLE_CLONE>>;
206
+ export {};