@shbernal/ts-xlsx 2.1.0 → 3.1.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 (225) hide show
  1. package/README.md +4 -1
  2. package/dist/bytes.d.ts +7 -0
  3. package/dist/bytes.js +22 -0
  4. package/dist/core/address.d.ts +60 -2
  5. package/dist/core/address.js +40 -24
  6. package/dist/core/autofilter.d.ts +5 -4
  7. package/dist/core/autofilter.js +34 -35
  8. package/dist/core/axis-handle.d.ts +10 -0
  9. package/dist/core/axis-handle.js +17 -0
  10. package/dist/core/cell.d.ts +25 -0
  11. package/dist/core/cell.js +9 -3
  12. package/dist/core/clone.d.ts +29 -0
  13. package/dist/core/clone.js +24 -0
  14. package/dist/core/color-resolution.js +2 -4
  15. package/dist/core/column.d.ts +5 -1
  16. package/dist/core/column.js +34 -35
  17. package/dist/core/comment-thread.js +2 -1
  18. package/dist/core/conditional-formatting-overlay.d.ts +2 -1
  19. package/dist/core/conditional-formatting-overlay.js +2 -2
  20. package/dist/core/conditional-formatting.d.ts +14 -6
  21. package/dist/core/conditional-formatting.js +45 -43
  22. package/dist/core/containers.d.ts +12 -0
  23. package/dist/core/containers.js +5 -0
  24. package/dist/core/data-validation-overlay.d.ts +2 -1
  25. package/dist/core/data-validation-overlay.js +4 -4
  26. package/dist/core/data-validation.d.ts +9 -3
  27. package/dist/core/data-validation.js +21 -18
  28. package/dist/core/date-format.d.ts +20 -0
  29. package/dist/core/date-format.js +160 -0
  30. package/dist/core/date.d.ts +43 -8
  31. package/dist/core/date.js +18 -2
  32. package/dist/core/formula.d.ts +26 -0
  33. package/dist/core/formula.js +20 -4
  34. package/dist/core/grid-edits.d.ts +2 -3
  35. package/dist/core/grid-edits.js +69 -70
  36. package/dist/core/grid-shift.d.ts +58 -9
  37. package/dist/core/grid-shift.js +26 -4
  38. package/dist/core/image.d.ts +14 -10
  39. package/dist/core/image.js +9 -9
  40. package/dist/core/internal.d.ts +8 -2
  41. package/dist/core/limits.d.ts +23 -0
  42. package/dist/core/limits.js +4 -0
  43. package/dist/core/merge-index.d.ts +31 -0
  44. package/dist/core/merge-index.js +60 -0
  45. package/dist/core/merge.d.ts +5 -14
  46. package/dist/core/merge.js +18 -27
  47. package/dist/core/page-setup.d.ts +72 -2
  48. package/dist/core/page-setup.js +34 -8
  49. package/dist/core/pivot-table.d.ts +1 -1
  50. package/dist/core/pivot-table.js +67 -53
  51. package/dist/core/protection.js +2 -11
  52. package/dist/core/range.js +34 -30
  53. package/dist/core/row-input.js +2 -2
  54. package/dist/core/row.d.ts +5 -1
  55. package/dist/core/row.js +22 -23
  56. package/dist/core/style.d.ts +134 -75
  57. package/dist/core/style.js +112 -53
  58. package/dist/core/table-style.d.ts +1 -1
  59. package/dist/core/table-style.js +4 -4
  60. package/dist/core/table.d.ts +28 -10
  61. package/dist/core/table.js +54 -39
  62. package/dist/core/theme.js +6 -5
  63. package/dist/core/used-extent.d.ts +44 -0
  64. package/dist/core/used-extent.js +102 -0
  65. package/dist/core/value.d.ts +9 -0
  66. package/dist/core/value.js +36 -34
  67. package/dist/core/workbook-media.d.ts +34 -0
  68. package/dist/core/workbook-media.js +44 -0
  69. package/dist/core/workbook-styles.d.ts +67 -1
  70. package/dist/core/workbook-vba.js +3 -2
  71. package/dist/core/workbook.d.ts +23 -2
  72. package/dist/core/workbook.js +24 -40
  73. package/dist/core/worksheet-comments.d.ts +2 -1
  74. package/dist/core/worksheet-comments.js +20 -13
  75. package/dist/core/worksheet-merges.d.ts +44 -0
  76. package/dist/core/worksheet-merges.js +59 -0
  77. package/dist/core/worksheet-model.d.ts +9 -1
  78. package/dist/core/worksheet-model.js +24 -9
  79. package/dist/core/worksheet.d.ts +72 -12
  80. package/dist/core/worksheet.js +68 -70
  81. package/dist/customui/ribbon.js +6 -7
  82. package/dist/entries/core.d.ts +18 -13
  83. package/dist/entries/core.js +12 -6
  84. package/dist/entries/xlsx.d.ts +1 -1
  85. package/dist/errors.d.ts +64 -0
  86. package/dist/errors.js +22 -0
  87. package/dist/hex.d.ts +8 -0
  88. package/dist/hex.js +3 -0
  89. package/dist/io/csv/delimiter.d.ts +9 -0
  90. package/dist/io/csv/delimiter.js +6 -0
  91. package/dist/io/csv/read.js +11 -4
  92. package/dist/io/csv/write.d.ts +9 -2
  93. package/dist/io/csv/write.js +9 -38
  94. package/dist/io/opc/inflate.js +15 -1
  95. package/dist/io/opc/namespaces.d.ts +16 -0
  96. package/dist/io/opc/namespaces.js +4 -0
  97. package/dist/io/opc/part-paths.d.ts +10 -0
  98. package/dist/io/opc/part-paths.js +16 -1
  99. package/dist/io/opc/read-opc.d.ts +69 -10
  100. package/dist/io/opc/read-opc.js +49 -55
  101. package/dist/io/opc/read-options.d.ts +5 -1
  102. package/dist/io/opc/rels.d.ts +1 -6
  103. package/dist/io/opc/rels.js +1 -4
  104. package/dist/io/opc/sniff-format.d.ts +3 -3
  105. package/dist/io/opc/sniff-format.js +2 -2
  106. package/dist/io/style/xf-style.d.ts +48 -2
  107. package/dist/io/style/xf-style.js +14 -0
  108. package/dist/io/xlsb/formula.d.ts +2 -2
  109. package/dist/io/xlsb/formula.js +49 -34
  110. package/dist/io/xlsb/primitives.js +8 -14
  111. package/dist/io/xlsb/ptg-functions.d.ts +19 -10
  112. package/dist/io/xlsb/ptg-functions.js +385 -596
  113. package/dist/io/xlsb/read-styles.js +50 -83
  114. package/dist/io/xlsb/read-worksheet.d.ts +20 -1
  115. package/dist/io/xlsb/read-worksheet.js +73 -89
  116. package/dist/io/xlsb/read.d.ts +6 -3
  117. package/dist/io/xlsb/read.js +47 -29
  118. package/dist/io/xlsb/record-stream.d.ts +30 -0
  119. package/dist/io/xlsb/record-stream.js +20 -0
  120. package/dist/io/xlsb/record-types.d.ts +1 -5
  121. package/dist/io/xlsb/record-types.js +1 -5
  122. package/dist/io/xlsx/cell-accumulator.d.ts +9 -2
  123. package/dist/io/xlsx/cell-accumulator.js +32 -9
  124. package/dist/io/xlsx/cell-style-resolution.d.ts +25 -0
  125. package/dist/io/xlsx/cell-style-resolution.js +29 -0
  126. package/dist/io/xlsx/cell-value.d.ts +5 -3
  127. package/dist/io/xlsx/cell-value.js +13 -15
  128. package/dist/io/xlsx/color-xml.js +3 -2
  129. package/dist/io/xlsx/column-budget.d.ts +26 -0
  130. package/dist/io/xlsx/column-budget.js +22 -0
  131. package/dist/io/xlsx/comments.d.ts +6 -2
  132. package/dist/io/xlsx/comments.js +36 -31
  133. package/dist/io/xlsx/conditional-formatting.d.ts +9 -5
  134. package/dist/io/xlsx/conditional-formatting.js +51 -46
  135. package/dist/io/xlsx/data-validation.d.ts +9 -7
  136. package/dist/io/xlsx/data-validation.js +38 -35
  137. package/dist/io/xlsx/edit-vba.d.ts +7 -2
  138. package/dist/io/xlsx/edit-vba.js +15 -29
  139. package/dist/io/xlsx/font-xml.d.ts +7 -0
  140. package/dist/io/xlsx/font-xml.js +104 -0
  141. package/dist/io/xlsx/hyperlinks.d.ts +41 -7
  142. package/dist/io/xlsx/hyperlinks.js +40 -28
  143. package/dist/io/xlsx/images.js +24 -25
  144. package/dist/io/xlsx/namespaces.d.ts +16 -0
  145. package/dist/io/xlsx/namespaces.js +7 -0
  146. package/dist/io/xlsx/package-plan.d.ts +23 -3
  147. package/dist/io/xlsx/package-plan.js +66 -25
  148. package/dist/io/xlsx/part-names.d.ts +41 -0
  149. package/dist/io/xlsx/part-names.js +46 -0
  150. package/dist/io/xlsx/pivot.js +8 -7
  151. package/dist/io/xlsx/read-parts.d.ts +59 -0
  152. package/dist/io/xlsx/read-parts.js +252 -0
  153. package/dist/io/xlsx/read-pivot.js +3 -1
  154. package/dist/io/xlsx/read-repair.d.ts +26 -0
  155. package/dist/io/xlsx/read-repair.js +39 -0
  156. package/dist/io/xlsx/{rich-runs.d.ts → read-rich-runs.d.ts} +1 -1
  157. package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +7 -3
  158. package/dist/io/xlsx/read-rows.d.ts +18 -5
  159. package/dist/io/xlsx/read-rows.js +50 -37
  160. package/dist/io/xlsx/read-shared-strings.js +5 -3
  161. package/dist/io/xlsx/read-styles.d.ts +1 -6
  162. package/dist/io/xlsx/read-styles.js +65 -109
  163. package/dist/io/xlsx/read-workbook-xml.d.ts +36 -0
  164. package/dist/io/xlsx/read-workbook-xml.js +170 -0
  165. package/dist/io/xlsx/read-worksheet.d.ts +11 -1
  166. package/dist/io/xlsx/read-worksheet.js +51 -193
  167. package/dist/io/xlsx/read.d.ts +5 -13
  168. package/dist/io/xlsx/read.js +111 -436
  169. package/dist/io/xlsx/rich-text.js +1 -1
  170. package/dist/io/xlsx/row-position.d.ts +18 -0
  171. package/dist/io/xlsx/row-position.js +11 -0
  172. package/dist/io/xlsx/row-xml.d.ts +128 -0
  173. package/dist/io/xlsx/row-xml.js +203 -0
  174. package/dist/io/xlsx/shared-formulas.js +2 -2
  175. package/dist/io/xlsx/sheet-properties.d.ts +10 -1
  176. package/dist/io/xlsx/sheet-properties.js +166 -37
  177. package/dist/io/xlsx/style-elements.d.ts +43 -0
  178. package/dist/io/xlsx/style-elements.js +156 -0
  179. package/dist/io/xlsx/styles.d.ts +12 -3
  180. package/dist/io/xlsx/styles.js +5 -204
  181. package/dist/io/xlsx/tables.js +11 -14
  182. package/dist/io/xlsx/theme-xml.d.ts +26 -4
  183. package/dist/io/xlsx/theme-xml.js +107 -69
  184. package/dist/io/xlsx/threaded-comments.d.ts +8 -10
  185. package/dist/io/xlsx/threaded-comments.js +3 -1
  186. package/dist/io/xlsx/workbook-xml.d.ts +54 -4
  187. package/dist/io/xlsx/workbook-xml.js +84 -57
  188. package/dist/io/xlsx/worksheet-xml.d.ts +23 -70
  189. package/dist/io/xlsx/worksheet-xml.js +59 -242
  190. package/dist/io/xlsx/write-stream.d.ts +71 -16
  191. package/dist/io/xlsx/write-stream.js +79 -41
  192. package/dist/io/xlsx/write.d.ts +6 -2
  193. package/dist/io/xlsx/write.js +217 -153
  194. package/dist/rel-type.d.ts +16 -0
  195. package/dist/rel-type.js +6 -0
  196. package/dist/token-set.d.ts +28 -0
  197. package/dist/token-set.js +7 -0
  198. package/dist/vba/bytes.d.ts +14 -5
  199. package/dist/vba/bytes.js +16 -6
  200. package/dist/vba/cfb-format.d.ts +32 -0
  201. package/dist/vba/cfb-format.js +13 -0
  202. package/dist/vba/cfb-writer.d.ts +9 -0
  203. package/dist/vba/cfb-writer.js +28 -25
  204. package/dist/vba/cfb.d.ts +13 -1
  205. package/dist/vba/cfb.js +73 -57
  206. package/dist/vba/codepage.js +2 -1
  207. package/dist/vba/errors.d.ts +7 -0
  208. package/dist/vba/ms-ovba.js +79 -23
  209. package/dist/vba/project-editor.js +35 -40
  210. package/dist/vba/project.d.ts +11 -1
  211. package/dist/vba/project.js +40 -21
  212. package/dist/vba/vba-encoding.js +5 -6
  213. package/dist/xml/xml-attrs.d.ts +37 -0
  214. package/dist/xml/xml-attrs.js +30 -0
  215. package/dist/xml/xml-chars.d.ts +40 -0
  216. package/dist/xml/xml-chars.js +12 -0
  217. package/dist/xml/xml-namespaces.d.ts +31 -0
  218. package/dist/xml/xml-namespaces.js +50 -0
  219. package/dist/xml/xml-read.d.ts +128 -81
  220. package/dist/xml/xml-read.js +161 -178
  221. package/dist/xml/xml-scan.d.ts +78 -0
  222. package/dist/xml/xml-scan.js +180 -0
  223. package/dist/xml/xml.d.ts +29 -28
  224. package/dist/xml/xml.js +24 -24
  225. package/package.json +13 -9
@@ -1,9 +1,11 @@
1
1
  import { assertColumnInBounds, encodeAddress, numberToColumn } from './address.js';
2
+ import { AxisHandle } from './axis-handle.js';
2
3
  import { INTERNAL } from './internal.js';
3
- export class Column {
4
+ export class Column extends AxisHandle {
4
5
  #sheet;
5
6
  index;
6
7
  constructor(sheet, index) {
8
+ super();
7
9
  assertColumnInBounds(index);
8
10
  this.#sheet = sheet;
9
11
  this.index = index;
@@ -12,73 +14,82 @@ export class Column {
12
14
  return numberToColumn(this.index);
13
15
  }
14
16
  get properties() {
17
+ return this.propertiesOf();
18
+ }
19
+ propertiesOf() {
15
20
  return this.#sheet[INTERNAL].columnPropertiesOf(this.index);
16
21
  }
22
+ ensureProperties() {
23
+ return this.#sheet[INTERNAL].ensureColumnProperties(this.index);
24
+ }
25
+ dropProperties() {
26
+ this.#sheet[INTERNAL].dropColumnProperties(this.index);
27
+ }
17
28
  get key() {
18
- return this.#read('key');
29
+ return this.read('key');
19
30
  }
20
31
  set key(key) {
21
- this.#write('key', key);
32
+ this.write('key', key);
22
33
  }
23
34
  get width() {
24
- return this.#read('width');
35
+ return this.read('width');
25
36
  }
26
37
  set width(width) {
27
- this.#write('width', width);
38
+ this.write('width', width);
28
39
  }
29
40
  get hidden() {
30
- return this.#read('hidden');
41
+ return this.read('hidden');
31
42
  }
32
43
  set hidden(hidden) {
33
- this.#write('hidden', hidden);
44
+ this.write('hidden', hidden);
34
45
  }
35
46
  get outlineLevel() {
36
- return this.#read('outlineLevel');
47
+ return this.read('outlineLevel');
37
48
  }
38
49
  set outlineLevel(outlineLevel) {
39
- this.#write('outlineLevel', outlineLevel);
50
+ this.write('outlineLevel', outlineLevel);
40
51
  }
41
52
  get collapsed() {
42
- return this.#read('collapsed');
53
+ return this.read('collapsed');
43
54
  }
44
55
  set collapsed(collapsed) {
45
- this.#write('collapsed', collapsed);
56
+ this.write('collapsed', collapsed);
46
57
  }
47
58
  get fill() {
48
- return this.#read('fill');
59
+ return this.read('fill');
49
60
  }
50
61
  set fill(fill) {
51
- this.#write('fill', fill);
62
+ this.write('fill', fill);
52
63
  }
53
64
  get numFmt() {
54
- return this.#read('numFmt');
65
+ return this.read('numFmt');
55
66
  }
56
67
  set numFmt(numFmt) {
57
- this.#write('numFmt', numFmt);
68
+ this.write('numFmt', numFmt);
58
69
  }
59
70
  get font() {
60
- return this.#read('font');
71
+ return this.read('font');
61
72
  }
62
73
  set font(font) {
63
- this.#write('font', font);
74
+ this.write('font', font);
64
75
  }
65
76
  get border() {
66
- return this.#read('border');
77
+ return this.read('border');
67
78
  }
68
79
  set border(border) {
69
- this.#write('border', border);
80
+ this.write('border', border);
70
81
  }
71
82
  get alignment() {
72
- return this.#read('alignment');
83
+ return this.read('alignment');
73
84
  }
74
85
  set alignment(alignment) {
75
- this.#write('alignment', alignment);
86
+ this.write('alignment', alignment);
76
87
  }
77
88
  get protection() {
78
- return this.#read('protection');
89
+ return this.read('protection');
79
90
  }
80
91
  set protection(protection) {
81
- this.#write('protection', protection);
92
+ this.write('protection', protection);
82
93
  }
83
94
  getCell(row) {
84
95
  return this.#sheet.getCell(encodeAddress(this.index, row));
@@ -98,16 +109,4 @@ export class Column {
98
109
  this.getCell(index + 1).value = value;
99
110
  });
100
111
  }
101
- #read(key) {
102
- return this.#sheet[INTERNAL].columnPropertiesOf(this.index)?.[key];
103
- }
104
- #write(key, value) {
105
- if (value === undefined) {
106
- const properties = this.#sheet[INTERNAL].columnPropertiesOf(this.index);
107
- if (properties !== undefined)
108
- delete properties[key];
109
- return;
110
- }
111
- this.#sheet[INTERNAL].ensureColumnProperties(this.index)[key] = value;
112
- }
113
112
  }
@@ -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
  /**
@@ -14,7 +15,7 @@ export declare class ConditionalFormattingOverlay {
14
15
  * Re-anchor every rule set through a row or column splice, so a highlight keeps covering the cells
15
16
  * it was written for. A rule set whose every target area fell inside a deleted span goes with them.
16
17
  */
17
- shift(axis: 'row' | 'col', start: number, count: number, delta: number): void;
18
+ shift(splice: AxisSplice): void;
18
19
  /** Drop every conditional formatting, leaving the overlay empty. */
19
20
  clear(): void;
20
21
  }
@@ -9,10 +9,10 @@ export class ConditionalFormattingOverlay {
9
9
  get entries() {
10
10
  return this.#entries;
11
11
  }
12
- shift(axis, start, count, delta) {
12
+ shift(splice) {
13
13
  const entries = [];
14
14
  for (const entry of this.#entries) {
15
- const ref = shiftSqref(entry.ref, axis, start, count, delta);
15
+ const ref = shiftSqref(entry.ref, splice);
16
16
  if (ref !== undefined)
17
17
  entries.push({ ...entry, ref });
18
18
  }
@@ -1,8 +1,11 @@
1
- import type { Color, DifferentialStyle } from './style.ts';
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';
2
5
  /** How a {@link CfValueObject} reads its `value`: `ST_CfvoType` verbatim. */
3
6
  export type CfValueObjectType = 'num' | 'percent' | 'max' | 'min' | 'percentile' | 'formula';
4
7
  /** Narrow a raw `<cfvo type>` token to a known {@link CfValueObjectType}. */
5
- export declare function isCfValueObjectType(value: string): value is CfValueObjectType;
8
+ export declare const isCfValueObjectType: (value: string) => value is CfValueObjectType;
6
9
  /**
7
10
  * One anchor of a colour-scale, data-bar, or icon-set scale: a "conditional format value object".
8
11
  * `type` names how `value` is read: a literal `num`, a `percent`/`percentile` of the range, a
@@ -22,7 +25,7 @@ export interface CfValueObject {
22
25
  */
23
26
  export type ConditionalFormattingType = 'expression' | 'cellIs' | 'colorScale' | 'dataBar' | 'iconSet' | 'top10' | 'uniqueValues' | 'duplicateValues' | 'containsText' | 'notContainsText' | 'beginsWith' | 'endsWith' | 'containsBlanks' | 'notContainsBlanks' | 'containsErrors' | 'notContainsErrors' | 'timePeriod' | 'aboveAverage';
24
27
  /** Narrow a raw `<cfRule type>` token to a known {@link ConditionalFormattingType}. */
25
- export declare function isConditionalFormattingType(value: string): value is ConditionalFormattingType;
28
+ export declare const isConditionalFormattingType: (value: string) => value is ConditionalFormattingType;
26
29
  /**
27
30
  * How a `cellIs` or text rule compares, as `ST_ConditionalFormattingOperator` enumerates it.
28
31
  *
@@ -32,11 +35,11 @@ export declare function isConditionalFormattingType(value: string): value is Con
32
35
  */
33
36
  export type ConditionalFormattingOperator = 'lessThan' | 'lessThanOrEqual' | 'equal' | 'notEqual' | 'greaterThanOrEqual' | 'greaterThan' | 'between' | 'notBetween' | 'containsText' | 'notContains' | 'beginsWith' | 'endsWith';
34
37
  /** Narrow a raw `<cfRule operator>` token to a known {@link ConditionalFormattingOperator}. */
35
- export declare function isConditionalFormattingOperator(value: string): value is ConditionalFormattingOperator;
38
+ export declare const isConditionalFormattingOperator: (value: string) => value is ConditionalFormattingOperator;
36
39
  /** The window a `timePeriod` rule matches against, relative to the day the sheet is recalculated. */
37
40
  export type CfTimePeriod = 'today' | 'yesterday' | 'tomorrow' | 'last7Days' | 'thisMonth' | 'lastMonth' | 'nextMonth' | 'thisWeek' | 'lastWeek' | 'nextWeek';
38
41
  /** Narrow a raw `<cfRule timePeriod>` token to a known {@link CfTimePeriod}. */
39
- export declare function isCfTimePeriod(value: string): value is CfTimePeriod;
42
+ export declare const isCfTimePeriod: (value: string) => value is CfTimePeriod;
40
43
  /**
41
44
  * The named icon family an `iconSet` rule draws from, as `ST_IconSetType` enumerates it. The leading
42
45
  * digit is the number of icons, which is also how many {@link CfValueObject} anchors the rule needs.
@@ -47,7 +50,7 @@ export declare function isCfTimePeriod(value: string): value is CfTimePeriod;
47
50
  */
48
51
  export type IconSetType = '3Arrows' | '3ArrowsGray' | '3Flags' | '3TrafficLights1' | '3TrafficLights2' | '3Signs' | '3Symbols' | '3Symbols2' | '4Arrows' | '4ArrowsGray' | '4RedToBlack' | '4Rating' | '4TrafficLights' | '5Arrows' | '5ArrowsGray' | '5Rating' | '5Quarters';
49
52
  /** Narrow a raw `<iconSet iconSet>` token to a known {@link IconSetType}. */
50
- export declare function isIconSetType(value: string): value is IconSetType;
53
+ export declare const isIconSetType: (value: string) => value is IconSetType;
51
54
  /**
52
55
  * A single conditional-formatting rule. `type` is the OOXML cfRule type; the remaining fields carry
53
56
  * the operands that type needs and are absent otherwise. A rule the library does not model in depth
@@ -108,3 +111,8 @@ export interface ConditionalFormatting {
108
111
  /** A defensive deep copy, so a stored conditional formatting never aliases the caller's object nor
109
112
  * any of its nested arrays (rules, formulae, cfvo, colours) or the differential style. */
110
113
  export declare function cloneConditionalFormatting(cf: ConditionalFormatting): ConditionalFormatting;
114
+ declare const RULE_CLONE: ClonePlan<ConditionalFormattingRule>;
115
+ export type EveryRuleFieldIsCloned = AssertNever<Exclude<keyof Required<ConditionalFormattingRule>, keyof typeof RULE_CLONE>>;
116
+ declare const STYLE_CLONE: ClonePlan<DifferentialStyle>;
117
+ export type EveryDifferentialStyleFieldIsCloned = AssertNever<Exclude<keyof Required<DifferentialStyle>, keyof typeof STYLE_CLONE>>;
118
+ export {};
@@ -1,15 +1,15 @@
1
- const CF_VALUE_OBJECT_TYPES = {
1
+ import { tokenSet } from '../token-set.js';
2
+ import { cloneWith } from './clone.js';
3
+ import { cloneBorder, cloneFill, cloneFont } from './style.js';
4
+ export const isCfValueObjectType = tokenSet({
2
5
  num: true,
3
6
  percent: true,
4
7
  max: true,
5
8
  min: true,
6
9
  percentile: true,
7
10
  formula: true,
8
- };
9
- export function isCfValueObjectType(value) {
10
- return Object.hasOwn(CF_VALUE_OBJECT_TYPES, value);
11
- }
12
- const CONDITIONAL_FORMATTING_TYPES = {
11
+ });
12
+ export const isConditionalFormattingType = tokenSet({
13
13
  expression: true,
14
14
  cellIs: true,
15
15
  colorScale: true,
@@ -28,11 +28,8 @@ const CONDITIONAL_FORMATTING_TYPES = {
28
28
  notContainsErrors: true,
29
29
  timePeriod: true,
30
30
  aboveAverage: true,
31
- };
32
- export function isConditionalFormattingType(value) {
33
- return Object.hasOwn(CONDITIONAL_FORMATTING_TYPES, value);
34
- }
35
- const CONDITIONAL_FORMATTING_OPERATORS = {
31
+ });
32
+ export const isConditionalFormattingOperator = tokenSet({
36
33
  lessThan: true,
37
34
  lessThanOrEqual: true,
38
35
  equal: true,
@@ -45,11 +42,8 @@ const CONDITIONAL_FORMATTING_OPERATORS = {
45
42
  notContains: true,
46
43
  beginsWith: true,
47
44
  endsWith: true,
48
- };
49
- export function isConditionalFormattingOperator(value) {
50
- return Object.hasOwn(CONDITIONAL_FORMATTING_OPERATORS, value);
51
- }
52
- const CF_TIME_PERIODS = {
45
+ });
46
+ export const isCfTimePeriod = tokenSet({
53
47
  today: true,
54
48
  yesterday: true,
55
49
  tomorrow: true,
@@ -60,11 +54,8 @@ const CF_TIME_PERIODS = {
60
54
  thisWeek: true,
61
55
  lastWeek: true,
62
56
  nextWeek: true,
63
- };
64
- export function isCfTimePeriod(value) {
65
- return Object.hasOwn(CF_TIME_PERIODS, value);
66
- }
67
- const ICON_SET_TYPES = {
57
+ });
58
+ export const isIconSetType = tokenSet({
68
59
  '3Arrows': true,
69
60
  '3ArrowsGray': true,
70
61
  '3Flags': true,
@@ -82,32 +73,43 @@ const ICON_SET_TYPES = {
82
73
  '5ArrowsGray': true,
83
74
  '5Rating': true,
84
75
  '5Quarters': true,
85
- };
86
- export function isIconSetType(value) {
87
- return Object.hasOwn(ICON_SET_TYPES, value);
88
- }
76
+ });
89
77
  export function cloneConditionalFormatting(cf) {
90
78
  return { ref: cf.ref, rules: cf.rules.map(cloneRule) };
91
79
  }
80
+ const RULE_CLONE = {
81
+ type: 'value',
82
+ priority: 'value',
83
+ stopIfTrue: 'value',
84
+ operator: 'value',
85
+ formulae: 'values',
86
+ text: 'value',
87
+ style: cloneStyle,
88
+ dxfId: 'value',
89
+ cfvo: 'records',
90
+ color: 'record',
91
+ colors: 'records',
92
+ gradient: 'value',
93
+ negativeFillColor: 'record',
94
+ axisColor: 'record',
95
+ iconSet: 'value',
96
+ rank: 'value',
97
+ percent: 'value',
98
+ bottom: 'value',
99
+ aboveAverage: 'value',
100
+ equalAverage: 'value',
101
+ stdDev: 'value',
102
+ timePeriod: 'value',
103
+ };
92
104
  function cloneRule(rule) {
93
- return {
94
- ...rule,
95
- ...(rule.formulae !== undefined ? { formulae: [...rule.formulae] } : {}),
96
- ...(rule.cfvo !== undefined ? { cfvo: rule.cfvo.map((v) => ({ ...v })) } : {}),
97
- ...(rule.color !== undefined ? { color: { ...rule.color } } : {}),
98
- ...(rule.negativeFillColor !== undefined
99
- ? { negativeFillColor: { ...rule.negativeFillColor } }
100
- : {}),
101
- ...(rule.axisColor !== undefined ? { axisColor: { ...rule.axisColor } } : {}),
102
- ...(rule.colors !== undefined ? { colors: rule.colors.map((c) => ({ ...c })) } : {}),
103
- ...(rule.style !== undefined ? { style: cloneStyle(rule.style) } : {}),
104
- };
105
+ return cloneWith(rule, RULE_CLONE);
105
106
  }
107
+ const STYLE_CLONE = {
108
+ font: cloneFont,
109
+ fill: cloneFill,
110
+ border: cloneBorder,
111
+ numFmt: 'value',
112
+ };
106
113
  function cloneStyle(style) {
107
- return {
108
- ...style,
109
- ...(style.font !== undefined ? { font: { ...style.font } } : {}),
110
- ...(style.fill !== undefined ? { fill: { ...style.fill } } : {}),
111
- ...(style.border !== undefined ? { border: { ...style.border } } : {}),
112
- };
114
+ return cloneWith(style, STYLE_CLONE);
113
115
  }
@@ -1,2 +1,14 @@
1
1
  export declare function overwrite<T extends object>(target: T, source: T): void;
2
2
  export declare function replaceContents<T>(array: T[], next: readonly T[]): void;
3
+ /**
4
+ * Copy one key from `source` onto `target`, leaving `target` untouched when `source` omits it.
5
+ *
6
+ * One key at a time is the whole point, and the reason is a limit of the checker rather than a
7
+ * preference: over a union key the compiler cannot correlate `source[key]`'s type with `target[key]`'s,
8
+ * so a version taking the union needs a cast, and that cast is the one place a facet could be written
9
+ * into the wrong slot with nothing to notice. Bound to a single member here, the assignment is checked.
10
+ *
11
+ * Generic over the object as well as the key because these two lines had been written out once for a
12
+ * cell's formatting and once for a cell's content, each under its own paragraph making this point.
13
+ */
14
+ export declare function copyKeyIfPresent<T extends object, K extends keyof T>(target: T, source: Readonly<T>, key: K): void;
@@ -8,3 +8,8 @@ export function replaceContents(array, next) {
8
8
  for (const item of next)
9
9
  array.push(item);
10
10
  }
11
+ export function copyKeyIfPresent(target, source, key) {
12
+ const value = source[key];
13
+ if (value !== undefined)
14
+ target[key] = value;
15
+ }
@@ -1,4 +1,5 @@
1
1
  import { type DataValidation, type DataValidationEntry } from './data-validation.ts';
2
+ import type { AxisSplice } from './grid-shift.ts';
2
3
  export declare class DataValidationOverlay {
3
4
  #private;
4
5
  /**
@@ -33,7 +34,7 @@ export declare class DataValidationOverlay {
33
34
  * attached to rather than on whatever moved into their place. A rule whose every target area fell
34
35
  * inside a deleted span is dropped with them.
35
36
  */
36
- shift(axis: 'row' | 'col', start: number, count: number, delta: number): void;
37
+ shift(splice: AxisSplice): void;
37
38
  /** Drop every validation, leaving the overlay empty. */
38
39
  clear(): void;
39
40
  }
@@ -1,4 +1,4 @@
1
- import { AuthoringError } from '../errors.js';
1
+ import { AuthoringError, quoted } from '../errors.js';
2
2
  import { replaceContents } from './containers.js';
3
3
  import { cloneDataValidation, } from './data-validation.js';
4
4
  import { decodeSqrefRects, shiftSqref } from './merge.js';
@@ -8,7 +8,7 @@ export class DataValidationOverlay {
8
8
  add(sqref, rule, options = {}) {
9
9
  const rects = decodeSqrefRects(sqref);
10
10
  if (rects.length === 0) {
11
- throw new AuthoringError(`data validation range "${sqref}" names no cells`);
11
+ throw new AuthoringError(`data validation range ${quoted(sqref)} names no cells`);
12
12
  }
13
13
  const stored = cloneDataValidation(rule);
14
14
  const entry = { sqref, rule: stored };
@@ -30,11 +30,11 @@ export class DataValidationOverlay {
30
30
  }
31
31
  return undefined;
32
32
  }
33
- shift(axis, start, count, delta) {
33
+ shift(splice) {
34
34
  const entries = [];
35
35
  const rects = [];
36
36
  for (const entry of this.#entries) {
37
- const sqref = shiftSqref(entry.sqref, axis, start, count, delta);
37
+ const sqref = shiftSqref(entry.sqref, splice);
38
38
  if (sqref === undefined)
39
39
  continue;
40
40
  entries.push({ ...entry, sqref });
@@ -1,18 +1,20 @@
1
+ import { type ClonePlan } from './clone.ts';
2
+ import type { AssertNever } from './internal.ts';
1
3
  /** The kind of constraint a validation enforces. `list` is a dropdown; `custom` is an arbitrary
2
4
  * boolean formula; `none` constrains nothing and exists only to carry the rule's messages; the rest
3
5
  * bound a typed value (`whole`/`decimal`/`date`/`time`/`textLength`). */
4
6
  export type DataValidationType = 'none' | 'list' | 'whole' | 'decimal' | 'date' | 'time' | 'textLength' | 'custom';
5
7
  /** Narrow a raw `<dataValidation type>` token to a known {@link DataValidationType}. */
6
- export declare function isDataValidationType(value: string): value is DataValidationType;
8
+ export declare const isDataValidationType: (value: string) => value is DataValidationType;
7
9
  /** How a typed validation compares its operand(s). Absent on a `list`/`custom` rule; defaults to
8
10
  * `between` on a typed rule (the value Excel omits from the XML). */
9
11
  export type DataValidationOperator = 'between' | 'notBetween' | 'equal' | 'notEqual' | 'greaterThan' | 'lessThan' | 'greaterThanOrEqual' | 'lessThanOrEqual';
10
12
  /** Narrow a raw `<dataValidation operator>` token to a known {@link DataValidationOperator}. */
11
- export declare function isDataValidationOperator(value: string): value is DataValidationOperator;
13
+ export declare const isDataValidationOperator: (value: string) => value is DataValidationOperator;
12
14
  /** How Excel reacts to input that fails the rule. */
13
15
  export type DataValidationErrorStyle = 'stop' | 'warning' | 'information';
14
16
  /** Narrow a raw `<dataValidation errorStyle>` token to a known {@link DataValidationErrorStyle}. */
15
- export declare function isDataValidationErrorStyle(value: string): value is DataValidationErrorStyle;
17
+ export declare const isDataValidationErrorStyle: (value: string) => value is DataValidationErrorStyle;
16
18
  /** One validation rule. `formulae` holds the operand(s), `formula1` then optional `formula2`: a
17
19
  * numeric literal is stored as a number, while a cell reference, defined name, or list source keeps
18
20
  * its verbatim string. */
@@ -42,4 +44,8 @@ export interface DataValidationEntry {
42
44
  }
43
45
  /** A defensive copy of a rule, so a stored validation never aliases the caller's object (nor its
44
46
  * `formulae` array). */
47
+ declare const RULE_CLONE: ClonePlan<DataValidation>;
48
+ /** The proof that {@link RULE_CLONE} names every field of the rule. */
49
+ export type EveryDataValidationFieldIsCloned = AssertNever<Exclude<keyof Required<DataValidation>, keyof typeof RULE_CLONE>>;
45
50
  export declare function cloneDataValidation(rule: DataValidation): DataValidation;
51
+ export {};
@@ -1,4 +1,6 @@
1
- const DATA_VALIDATION_TYPES = {
1
+ import { tokenSet } from '../token-set.js';
2
+ import { cloneWith } from './clone.js';
3
+ export const isDataValidationType = tokenSet({
2
4
  none: true,
3
5
  list: true,
4
6
  whole: true,
@@ -7,11 +9,8 @@ const DATA_VALIDATION_TYPES = {
7
9
  time: true,
8
10
  textLength: true,
9
11
  custom: true,
10
- };
11
- export function isDataValidationType(value) {
12
- return Object.hasOwn(DATA_VALIDATION_TYPES, value);
13
- }
14
- const DATA_VALIDATION_OPERATORS = {
12
+ });
13
+ export const isDataValidationOperator = tokenSet({
15
14
  between: true,
16
15
  notBetween: true,
17
16
  equal: true,
@@ -20,21 +19,25 @@ const DATA_VALIDATION_OPERATORS = {
20
19
  lessThan: true,
21
20
  greaterThanOrEqual: true,
22
21
  lessThanOrEqual: true,
23
- };
24
- export function isDataValidationOperator(value) {
25
- return Object.hasOwn(DATA_VALIDATION_OPERATORS, value);
26
- }
27
- const DATA_VALIDATION_ERROR_STYLES = {
22
+ });
23
+ export const isDataValidationErrorStyle = tokenSet({
28
24
  stop: true,
29
25
  warning: true,
30
26
  information: true,
27
+ });
28
+ const RULE_CLONE = {
29
+ type: 'value',
30
+ operator: 'value',
31
+ formulae: 'values',
32
+ allowBlank: 'value',
33
+ showInputMessage: 'value',
34
+ showErrorMessage: 'value',
35
+ errorStyle: 'value',
36
+ error: 'value',
37
+ errorTitle: 'value',
38
+ prompt: 'value',
39
+ promptTitle: 'value',
31
40
  };
32
- export function isDataValidationErrorStyle(value) {
33
- return Object.hasOwn(DATA_VALIDATION_ERROR_STYLES, value);
34
- }
35
41
  export function cloneDataValidation(rule) {
36
- return {
37
- ...rule,
38
- ...(rule.formulae !== undefined ? { formulae: [...rule.formulae] } : {}),
39
- };
42
+ return cloneWith(rule, RULE_CLONE);
40
43
  }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Render a `Date` through an Excel number-format code: `yyyy-mm-dd`, `d mmm yy`, `hh:mm:ss`.
3
+ *
4
+ * The one vocabulary this library speaks for dates. `Cell.numFmt` holds a code, `DEFAULT_DATE_NUMFMT`
5
+ * is one, `isDateFormat` classifies one, and the CSV writer's `dateFormat` used to be a moment.js
6
+ * token set instead -- case-sensitive, with `mm` meaning minutes and the month spelled `MM` -- so
7
+ * `writeCsv(wb, {dateFormat: cell.numFmt})`, the obvious thing to write, rendered every date cell as
8
+ * `2024-45-dd` with no throw and no warning. A library with two public date-format properties
9
+ * speaking different languages has no defensible answer to "which one is this".
10
+ *
11
+ * Codes are case-insensitive, as Excel's are. What is *not* covered, deliberately: the elapsed-time
12
+ * forms (`[h]`, `[mm]`), which measure a duration rather than name a moment, and the locale directive
13
+ * (`[$-409]`), which is dropped rather than honoured -- month and weekday names render in English.
14
+ * Both are recorded in ADR 0041.
15
+ *
16
+ * @param utc read the date's fields in UTC rather than in the runner's local time. A serial carries
17
+ * no timezone, so a `Date` that came from one is UTC wall-clock and this should be `true`; a `Date`
18
+ * a caller assigned may mean either.
19
+ */
20
+ export declare function formatSerialDate(date: Date, code: string, utc: boolean): string;