@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,92 +1,201 @@
1
- import { isCfValueObjectType, isConditionalFormattingOperator, isConditionalFormattingType, isIconSetType, isCfTimePeriod, } from '../../core/conditional-formatting.js';
2
- import { elementSubtrees, TextCapture, } from '../../xml/xml-read.js';
3
- import { boolPresent, boolStrict, coerceNumericLiteral, enumToken, localName, numFinite, numInteger, } from '../../xml/xml-scan.js';
4
- import { boolAttr, checkedToken, escapeAttr, escapeText, numberText, stripFormulaEquals, textAttr, } from '../../xml/xml.js';
1
+ import { isCfIconSetType, isCfTimePeriod, isCfValueObjectType, isConditionalFormattingOperator, isConditionalFormattingType, isDataBarAxisPosition, isDataBarDirection, isIconSetType, ruleNeedsExtension, } from '../../core/conditional-formatting.js';
2
+ import { mangleFormula, stripFormulaEquals, unmangleFunctions } from '../../core/formula.js';
3
+ import { decodeSqrefRects } from '../../core/merge.js';
4
+ import { InternalError } from '../../errors.js';
5
+ import { coerceNumericLiteral, enumToken, numInteger } from '../../xml/xml-attrs.js';
6
+ import { elementRange, TextCapture, } from '../../xml/xml-read.js';
7
+ import { boolStrict, boolTristate, localName } from '../../xml/xml-scan.js';
8
+ import { boolAttr, checkedToken, escapeAttr, escapeText, intAttr, numberText, textAttr, } from '../../xml/xml.js';
9
+ import { admitting } from '../read-policy/read-repair.js';
5
10
  import { colorAttrs, parseColor } from './color-xml.js';
6
- import { CF_EXT_URI, DATABAR_LINK_EXT_URI, XM_NS } from './namespaces.js';
11
+ import { CF_EXT_URI, DATABAR_LINK_EXT_URI, isExtensionElement, isMainNamespaceElement, XM_NS, } from './namespaces.js';
7
12
  import { x14Ext } from './x14-ext.js';
8
13
  const DEFAULT_DATABAR_CFVO = [{ type: 'min' }, { type: 'max' }];
9
14
  const DEFAULT_DATABAR_COLOR = { argb: 'FF638EC6' };
15
+ const CLASSIC_ANCHOR = {
16
+ autoMin: 'min',
17
+ autoMax: 'max',
18
+ };
10
19
  function needsDataBarExt(rule) {
11
20
  return (rule.gradient !== undefined ||
21
+ rule.border !== undefined ||
22
+ rule.borderColor !== undefined ||
23
+ rule.direction !== undefined ||
12
24
  rule.negativeFillColor !== undefined ||
13
- rule.axisColor !== undefined);
25
+ rule.negativeBorderColor !== undefined ||
26
+ rule.negativeBarColorSameAsPositive !== undefined ||
27
+ rule.negativeBarBorderColorSameAsPositive !== undefined ||
28
+ rule.axisPosition !== undefined ||
29
+ rule.axisColor !== undefined ||
30
+ (rule.cfvo ?? []).some((anchor) => CLASSIC_ANCHOR[anchor.type] !== undefined));
14
31
  }
15
- function dataBarExtGuid(index) {
32
+ function inExtension(cf, rule) {
33
+ return cf.extended === true || ruleNeedsExtension(rule);
34
+ }
35
+ function extensionGuid(index) {
16
36
  return `{00000000-0000-0000-0000-${String(index + 1).padStart(12, '0')}}`;
17
37
  }
18
- function dataBarExtLinks(formattings) {
19
- const links = new Map();
20
- let index = 0;
38
+ export function planConditionalFormatting(formattings) {
39
+ const priorities = new Map();
40
+ const extensionIds = new Map();
41
+ let next = 1;
21
42
  for (const cf of formattings) {
22
43
  for (const rule of cf.rules) {
23
- if (rule.type === 'dataBar' && needsDataBarExt(rule))
24
- links.set(rule, dataBarExtGuid(index++));
44
+ const priority = rule.priority ?? next;
45
+ intAttr('priority', priority);
46
+ next = Math.max(next, priority) + 1;
47
+ priorities.set(rule, priority);
48
+ if (inExtension(cf, rule) || (rule.type === 'dataBar' && needsDataBarExt(rule))) {
49
+ extensionIds.set(rule, extensionGuid(extensionIds.size));
50
+ }
25
51
  }
26
52
  }
27
- return links;
53
+ return { priorities, extensionIds };
54
+ }
55
+ function priorityOf(plan, rule) {
56
+ const priority = plan.priorities.get(rule);
57
+ if (priority === undefined) {
58
+ throw new InternalError('a conditional format rule reached a serialiser unplanned');
59
+ }
60
+ return priority;
28
61
  }
29
62
  const SCALE_KINDS = ['dataBar', 'colorScale', 'iconSet'];
30
63
  const SCALE_TYPES = new Set(SCALE_KINDS);
31
- export function conditionalFormattingsXml(formattings, styles) {
32
- if (formattings.length === 0)
33
- return '';
34
- const priority = { next: 1 };
35
- const extLinks = dataBarExtLinks(formattings);
36
- return formattings.map((cf) => blockXml(cf, styles, priority, extLinks)).join('');
64
+ export function conditionalFormattingsXml(formattings, styles, plan, formulaNames) {
65
+ return formattings.map((cf) => blockXml(cf, styles, plan, formulaNames)).join('');
37
66
  }
38
- export function conditionalFormattingsExtXml(formattings) {
39
- const extLinks = dataBarExtLinks(formattings);
67
+ export function conditionalFormattingsExtXml(formattings, styles, plan, formulaNames) {
40
68
  const items = [];
41
69
  for (const cf of formattings) {
70
+ const whole = cf.rules.filter((rule) => inExtension(cf, rule));
71
+ if (whole.length > 0) {
72
+ const rules = whole.map((rule) => extensionRuleXml(rule, styles, plan, formulaNames));
73
+ items.push(extensionBlockXml(cf.ref, rules.join('')));
74
+ }
42
75
  for (const rule of cf.rules) {
43
- const guid = extLinks.get(rule);
44
- if (guid !== undefined)
45
- items.push(x14DataBarXml(cf.ref, rule, guid));
76
+ const guid = plan.extensionIds.get(rule);
77
+ if (guid === undefined || inExtension(cf, rule))
78
+ continue;
79
+ items.push(extensionBlockXml(cf.ref, `<x14:cfRule type="dataBar" id="${guid}">${x14DataBarXml(rule, formulaNames, false)}</x14:cfRule>`));
46
80
  }
47
81
  }
48
82
  if (items.length === 0)
49
83
  return '';
50
84
  return x14Ext(CF_EXT_URI, `<x14:conditionalFormattings>${items.join('')}</x14:conditionalFormattings>`);
51
85
  }
52
- function x14DataBarXml(ref, rule, guid) {
53
- const cfvo = rule.cfvo && rule.cfvo.length > 0 ? rule.cfvo : DEFAULT_DATABAR_CFVO;
54
- const anchors = cfvo.map(x14CfvoXml).join('');
55
- const gradient = boolAttr('gradient', rule.gradient);
56
- const negative = rule.negativeFillColor !== undefined
57
- ? `<x14:negativeFillColor ${colorAttrs(rule.negativeFillColor)}/>`
58
- : '';
59
- const axis = rule.axisColor !== undefined ? `<x14:axisColor ${colorAttrs(rule.axisColor)}/>` : '';
60
- return (`<x14:conditionalFormatting xmlns:xm="${XM_NS}">` +
61
- `<x14:cfRule type="dataBar" id="${guid}">` +
62
- `<x14:dataBar${gradient}>${anchors}${negative}${axis}</x14:dataBar>` +
63
- `</x14:cfRule><xm:sqref>${escapeText(ref)}</xm:sqref></x14:conditionalFormatting>`);
64
- }
65
- function x14CfvoXml(cfvo) {
66
- const type = checkedToken(cfvo.type, isCfValueObjectType, 'conditional format value type');
67
- if (cfvo.value === undefined)
68
- return `<x14:cfvo type="${type}"/>`;
69
- return `<x14:cfvo type="${type}"><xm:f>${escapeText(String(cfvo.value))}</xm:f></x14:cfvo>`;
86
+ function extensionBlockXml(ref, rules) {
87
+ return (`<x14:conditionalFormatting xmlns:xm="${XM_NS}">${rules}` +
88
+ `<xm:sqref>${escapeText(ref)}</xm:sqref></x14:conditionalFormatting>`);
89
+ }
90
+ function extensionRuleXml(rule, styles, plan, formulaNames) {
91
+ const attrs = [typeAttr(rule), `priority="${priorityOf(plan, rule)}"`, ...ruleFlagAttrs(rule)];
92
+ const id = plan.extensionIds.get(rule);
93
+ if (id !== undefined)
94
+ attrs.push(`id="${id}"`);
95
+ const body = (SCALE_TYPES.has(rule.type)
96
+ ? extensionScaleXml(rule, formulaNames)
97
+ : operandsXml(rule.formulae, 'xm:f', formulaNames)) + inlineDxfXml(rule, styles);
98
+ return body === ''
99
+ ? `<x14:cfRule ${attrs.join(' ')}/>`
100
+ : `<x14:cfRule ${attrs.join(' ')}>${body}</x14:cfRule>`;
101
+ }
102
+ function inlineDxfXml(rule, styles) {
103
+ const id = resolveDxfId(rule, styles);
104
+ const fragment = id === undefined ? undefined : styles.differentialStyleFragment(id);
105
+ const range = fragment === undefined ? undefined : elementRange(fragment, ['dxf']);
106
+ if (fragment === undefined || range === undefined)
107
+ return '';
108
+ return `<x14:dxf>${fragment.slice(range.contentStart, range.contentEnd)}</x14:dxf>`;
109
+ }
110
+ function extensionScaleXml(rule, formulaNames) {
111
+ if (rule.type === 'dataBar')
112
+ return x14DataBarXml(rule, formulaNames, true);
113
+ const cfvoXml = cfvoWriter('x14', formulaNames);
114
+ if (rule.type === 'colorScale') {
115
+ const anchors = (rule.cfvo ?? []).map(cfvoXml).join('');
116
+ const colors = (rule.colors ?? []).map((c) => `<x14:color ${colorAttrs(c)}/>`).join('');
117
+ return `<x14:colorScale>${anchors}${colors}</x14:colorScale>`;
118
+ }
119
+ return iconSetXml(rule, cfvoXml, 'x14');
120
+ }
121
+ function x14DataBarXml(rule, formulaNames, whole) {
122
+ const attrs = intAttr('minLength', rule.minLength, 0) +
123
+ intAttr('maxLength', rule.maxLength, 0) +
124
+ (whole && rule.showValue === false ? ' showValue="0"' : '') +
125
+ boolAttr('border', rule.border) +
126
+ boolAttr('gradient', rule.gradient) +
127
+ tokenAttr('direction', rule.direction, isDataBarDirection, 'data bar direction') +
128
+ boolAttr('negativeBarColorSameAsPositive', rule.negativeBarColorSameAsPositive) +
129
+ boolAttr('negativeBarBorderColorSameAsPositive', rule.negativeBarBorderColorSameAsPositive) +
130
+ tokenAttr('axisPosition', rule.axisPosition, isDataBarAxisPosition, 'data bar axis position');
131
+ const children = dataBarAnchors(rule).map(cfvoWriter('x14', formulaNames)).join('') +
132
+ (whole ? x14ColorXml('fillColor', rule.color ?? DEFAULT_DATABAR_COLOR) : '') +
133
+ x14ColorXml('borderColor', rule.borderColor) +
134
+ x14ColorXml('negativeFillColor', rule.negativeFillColor) +
135
+ x14ColorXml('negativeBorderColor', rule.negativeBorderColor) +
136
+ x14ColorXml('axisColor', rule.axisColor);
137
+ return `<x14:dataBar${attrs}>${children}</x14:dataBar>`;
138
+ }
139
+ function x14ColorXml(name, color) {
140
+ return color === undefined ? '' : `<x14:${name} ${colorAttrs(color)}/>`;
141
+ }
142
+ function tokenAttr(name, value, isValid, kind) {
143
+ return value === undefined ? '' : ` ${name}="${checkedToken(value, isValid, kind)}"`;
144
+ }
145
+ function dataBarAnchors(rule) {
146
+ return rule.cfvo && rule.cfvo.length > 0 ? rule.cfvo : DEFAULT_DATABAR_CFVO;
147
+ }
148
+ function cfvoWriter(form, formulaNames) {
149
+ return (cfvo) => {
150
+ const checked = checkedToken(cfvo.type, isCfValueObjectType, 'conditional format value type');
151
+ const type = form === 'classic' ? (CLASSIC_ANCHOR[cfvo.type] ?? checked) : checked;
152
+ const tag = form === 'classic' ? 'cfvo' : 'x14:cfvo';
153
+ const gte = cfvo.gte === false ? ' gte="0"' : '';
154
+ if (cfvo.value === undefined)
155
+ return `<${tag} type="${type}"${gte}/>`;
156
+ const value = typeof cfvo.value === 'number'
157
+ ? numberText(cfvo.value)
158
+ : type === 'formula'
159
+ ? mangleFormula(cfvo.value, formulaNames)
160
+ : cfvo.value;
161
+ return form === 'classic'
162
+ ? `<${tag} type="${type}"${textAttr('val', value)}${gte}/>`
163
+ : `<${tag} type="${type}"${gte}><xm:f>${escapeText(value)}</xm:f></${tag}>`;
164
+ };
70
165
  }
71
166
  function cfRuleExtLinkXml(guid) {
72
167
  return `<extLst>${x14Ext(DATABAR_LINK_EXT_URI, `<x14:id>${guid}</x14:id>`)}</extLst>`;
73
168
  }
74
- function blockXml(cf, styles, priority, extLinks) {
75
- const rules = cf.rules.map((rule) => ruleXml(rule, styles, priority, extLinks)).join('');
169
+ function blockXml(cf, styles, plan, formulaNames) {
170
+ const rules = cf.rules
171
+ .filter((rule) => !inExtension(cf, rule))
172
+ .map((rule) => ruleXml(rule, styles, plan, formulaNames))
173
+ .join('');
76
174
  if (rules === '')
77
175
  return '';
78
176
  return `<conditionalFormatting sqref="${escapeAttr(cf.ref)}">${rules}</conditionalFormatting>`;
79
177
  }
80
- function ruleXml(rule, styles, priority, extLinks) {
81
- const p = rule.priority ?? priority.next;
82
- priority.next = Math.max(priority.next, p) + 1;
83
- const attrs = [
84
- `type="${checkedToken(rule.type, isConditionalFormattingType, 'conditional formatting type')}"`,
85
- ];
178
+ function ruleXml(rule, styles, plan, formulaNames) {
179
+ const attrs = [typeAttr(rule)];
86
180
  const dxfId = resolveDxfId(rule, styles);
87
181
  if (dxfId !== undefined)
88
182
  attrs.push(`dxfId="${dxfId}"`);
89
- attrs.push(`priority="${p}"`);
183
+ attrs.push(`priority="${priorityOf(plan, rule)}"`, ...ruleFlagAttrs(rule));
184
+ const extGuid = plan.extensionIds.get(rule);
185
+ let body = SCALE_TYPES.has(rule.type)
186
+ ? scaleXml(rule, formulaNames, extGuid !== undefined)
187
+ : operandsXml(rule.formulae, 'formula', formulaNames);
188
+ if (extGuid !== undefined)
189
+ body += cfRuleExtLinkXml(extGuid);
190
+ return body === ''
191
+ ? `<cfRule ${attrs.join(' ')}/>`
192
+ : `<cfRule ${attrs.join(' ')}>${body}</cfRule>`;
193
+ }
194
+ function typeAttr(rule) {
195
+ return `type="${checkedToken(rule.type, isConditionalFormattingType, 'conditional formatting type')}"`;
196
+ }
197
+ function ruleFlagAttrs(rule) {
198
+ const attrs = [];
90
199
  if (rule.stopIfTrue)
91
200
  attrs.push('stopIfTrue="1"');
92
201
  if (rule.aboveAverage === false)
@@ -106,16 +215,10 @@ function ruleXml(rule, styles, priority, extLinks) {
106
215
  attrs.push(`timePeriod="${checkedToken(rule.timePeriod, isCfTimePeriod, 'time period')}"`);
107
216
  }
108
217
  if (rule.rank !== undefined)
109
- attrs.push(`rank="${numberText(rule.rank)}"`);
218
+ attrs.push(intAttr('rank', rule.rank, 0).trim());
110
219
  if (rule.stdDev !== undefined)
111
- attrs.push(`stdDev="${numberText(rule.stdDev)}"`);
112
- let body = SCALE_TYPES.has(rule.type) ? scaleXml(rule) : formulaeXml(rule.formulae);
113
- const extGuid = extLinks.get(rule);
114
- if (extGuid !== undefined)
115
- body += cfRuleExtLinkXml(extGuid);
116
- return body === ''
117
- ? `<cfRule ${attrs.join(' ')}/>`
118
- : `<cfRule ${attrs.join(' ')}>${body}</cfRule>`;
220
+ attrs.push(intAttr('stdDev', rule.stdDev).trim());
221
+ return attrs;
119
222
  }
120
223
  function resolveDxfId(rule, styles) {
121
224
  if (SCALE_TYPES.has(rule.type))
@@ -127,72 +230,221 @@ function resolveDxfId(rule, styles) {
127
230
  return styles.differentialStyleId(rule.style);
128
231
  return undefined;
129
232
  }
130
- function formulaeXml(formulae) {
233
+ function operandsXml(formulae, tag, formulaNames) {
131
234
  if (formulae === undefined)
132
235
  return '';
133
- return formulae.map((f) => `<formula>${escapeText(stripFormulaEquals(f))}</formula>`).join('');
236
+ return formulae
237
+ .map((f) => `<${tag}>${escapeText(mangleFormula(stripFormulaEquals(f), formulaNames))}</${tag}>`)
238
+ .join('');
134
239
  }
135
- function scaleXml(rule) {
240
+ function scaleXml(rule, formulaNames, linked) {
241
+ const cfvoXml = cfvoWriter('classic', formulaNames);
136
242
  if (rule.type === 'dataBar')
137
- return dataBarXml(rule);
243
+ return dataBarXml(rule, cfvoXml, linked);
138
244
  if (rule.type === 'colorScale')
139
- return colorScaleXml(rule);
140
- return iconSetXml(rule);
245
+ return colorScaleXml(rule, cfvoXml);
246
+ return iconSetXml(rule, cfvoXml, 'classic');
141
247
  }
142
- function dataBarXml(rule) {
143
- const cfvo = rule.cfvo && rule.cfvo.length > 0 ? rule.cfvo : DEFAULT_DATABAR_CFVO;
248
+ function dataBarXml(rule, cfvoXml, linked) {
144
249
  const color = rule.color ?? DEFAULT_DATABAR_COLOR;
145
- const anchors = cfvo.map(cfvoXml).join('');
146
- return `<dataBar>${anchors}<color ${colorAttrs(color)}/></dataBar>`;
250
+ const anchors = dataBarAnchors(rule).map(cfvoXml).join('');
251
+ const lengths = linked
252
+ ? ''
253
+ : intAttr('minLength', rule.minLength, 0) + intAttr('maxLength', rule.maxLength, 0);
254
+ const showValue = rule.showValue === false ? ' showValue="0"' : '';
255
+ return `<dataBar${lengths}${showValue}>${anchors}<color ${colorAttrs(color)}/></dataBar>`;
147
256
  }
148
- function colorScaleXml(rule) {
257
+ function colorScaleXml(rule, cfvoXml) {
149
258
  const anchors = (rule.cfvo ?? []).map(cfvoXml).join('');
150
259
  const colors = (rule.colors ?? []).map((c) => `<color ${colorAttrs(c)}/>`).join('');
151
260
  return `<colorScale>${anchors}${colors}</colorScale>`;
152
261
  }
153
- function iconSetXml(rule) {
154
- const name = rule.iconSet === undefined
155
- ? ''
156
- : ` iconSet="${checkedToken(rule.iconSet, isIconSetType, 'icon set')}"`;
262
+ function iconSetXml(rule, cfvoXml, form) {
263
+ const tag = form === 'classic' ? 'iconSet' : 'x14:iconSet';
264
+ const icons = form === 'x14' ? (rule.icons ?? []) : [];
265
+ const attrs = tokenAttr('iconSet', rule.iconSet, isIconSetType, 'icon set') +
266
+ (rule.showValue === false ? ' showValue="0"' : '') +
267
+ (rule.reverse ? ' reverse="1"' : '') +
268
+ (icons.length > 0 ? ' custom="1"' : '');
157
269
  const anchors = (rule.cfvo ?? []).map(cfvoXml).join('');
158
- return `<iconSet${name}>${anchors}</iconSet>`;
270
+ return `<${tag}${attrs}>${anchors}${icons.map(cfIconXml).join('')}</${tag}>`;
159
271
  }
160
- function cfvoXml(cfvo) {
161
- const type = checkedToken(cfvo.type, isCfValueObjectType, 'conditional format value type');
162
- const val = cfvo.value === undefined ? '' : textAttr('val', String(cfvo.value));
163
- return `<cfvo type="${type}"${val}/>`;
272
+ function cfIconXml(icon) {
273
+ const iconSet = checkedToken(icon.iconSet, isCfIconSetType, 'custom icon set');
274
+ return `<x14:cfIcon iconSet="${iconSet}"${intAttr('iconId', icon.iconId, 0)}/>`;
275
+ }
276
+ class DxfCapture {
277
+ #xml = '<dxf>';
278
+ #depth = 0;
279
+ #skippingFrom;
280
+ open(name, attrs, selfClosing, scope) {
281
+ const local = localName(name);
282
+ if (this.#skippingFrom === undefined) {
283
+ if (isMainNamespaceElement(scope, name) && local !== 'extLst') {
284
+ const attributes = Object.entries(attrs)
285
+ .filter(([key]) => key !== 'xmlns' && !key.includes(':'))
286
+ .map(([key, value]) => ` ${key}="${escapeAttr(value)}"`)
287
+ .join('');
288
+ this.#xml += `<${local}${attributes}${selfClosing ? '/>' : '>'}`;
289
+ }
290
+ else if (!selfClosing) {
291
+ this.#skippingFrom = this.#depth;
292
+ }
293
+ }
294
+ if (!selfClosing)
295
+ this.#depth += 1;
296
+ }
297
+ close(name) {
298
+ if (this.#depth === 0) {
299
+ this.#xml += '</dxf>';
300
+ return true;
301
+ }
302
+ this.#depth -= 1;
303
+ if (this.#skippingFrom === undefined)
304
+ this.#xml += `</${localName(name)}>`;
305
+ else if (this.#skippingFrom === this.#depth)
306
+ this.#skippingFrom = undefined;
307
+ return false;
308
+ }
309
+ get fragment() {
310
+ return this.#xml;
311
+ }
164
312
  }
165
- export function conditionalFormattingPass() {
313
+ export function conditionalFormattingPass(definedNames, adoptDifferentialStyle) {
166
314
  const blocks = [];
167
315
  let block;
168
316
  let draft;
169
317
  let scale;
170
318
  const formulaCapture = new TextCapture('formula');
171
319
  const linked = [];
320
+ const linkedIds = new Set();
172
321
  const extById = new Map();
173
- let x14Ext;
174
- let x14ExtId;
175
322
  const x14IdCapture = new TextCapture('id');
323
+ let extRules;
324
+ let extRule;
325
+ let extCfvo;
326
+ let extSqref = '';
327
+ const extCapture = new TextCapture(['f', 'sqref']);
328
+ let dxf;
329
+ const closeExtensionRule = () => {
330
+ if (extRule === undefined)
331
+ return;
332
+ const { draft: ruleDraft, id } = extRule;
333
+ extRule = undefined;
334
+ extCfvo = undefined;
335
+ if (id !== undefined && linkedIds.has(id)) {
336
+ extById.set(id, { bar: ruleDraft.bar, cfvo: ruleDraft.cfvo });
337
+ return;
338
+ }
339
+ if (ruleDraft.dxf !== undefined)
340
+ ruleDraft.dxfId = String(adoptDifferentialStyle(ruleDraft.dxf));
341
+ const rule = finalizeRule(ruleDraft);
342
+ if (rule !== undefined)
343
+ extRules?.push(rule);
344
+ };
345
+ const openExtension = (ln, attrs, selfClosing) => {
346
+ if (ln === 'id' && draft !== undefined) {
347
+ x14IdCapture.open(ln, selfClosing);
348
+ }
349
+ else if (ln === 'conditionalFormatting') {
350
+ extRules = [];
351
+ extSqref = '';
352
+ }
353
+ else if (ln === 'cfRule') {
354
+ extRule = { draft: newDraft(attrs), id: attrs.id };
355
+ if (selfClosing)
356
+ closeExtensionRule();
357
+ }
358
+ else if (extRule === undefined) {
359
+ if (extRules !== undefined && ln === 'sqref')
360
+ extCapture.open(ln, selfClosing);
361
+ }
362
+ else {
363
+ readExtensionRuleChild(extRule.draft, ln, attrs, selfClosing);
364
+ }
365
+ };
366
+ const readExtensionRuleChild = (rule, ln, attrs, selfClosing) => {
367
+ switch (ln) {
368
+ case 'dataBar':
369
+ readDataBarAttrs(rule, attrs);
370
+ break;
371
+ case 'iconSet':
372
+ readIconSetAttrs(rule, attrs);
373
+ break;
374
+ case 'cfvo':
375
+ extCfvo = parseCfvo(attrs, definedNames);
376
+ rule.cfvo.push(extCfvo);
377
+ if (selfClosing)
378
+ extCfvo = undefined;
379
+ break;
380
+ case 'f':
381
+ extCapture.open(ln, selfClosing);
382
+ break;
383
+ case 'color':
384
+ rule.colors.push(parseColor(attrs));
385
+ break;
386
+ case 'fillColor':
387
+ rule.color = parseColor(attrs);
388
+ break;
389
+ case 'borderColor':
390
+ case 'negativeFillColor':
391
+ case 'negativeBorderColor':
392
+ case 'axisColor':
393
+ rule.bar[ln] = parseColor(attrs);
394
+ break;
395
+ case 'cfIcon': {
396
+ const icon = parseCfIcon(attrs);
397
+ if (icon === undefined)
398
+ rule.icons = undefined;
399
+ else
400
+ rule.icons?.push(icon);
401
+ break;
402
+ }
403
+ case 'dxf':
404
+ if (selfClosing)
405
+ rule.dxf = '<dxf/>';
406
+ else
407
+ dxf = new DxfCapture();
408
+ break;
409
+ }
410
+ };
411
+ const closeExtension = (ln) => {
412
+ const id = x14IdCapture.close(ln);
413
+ if (id !== undefined) {
414
+ if (draft !== undefined)
415
+ draft.x14Id = id;
416
+ return;
417
+ }
418
+ const text = extCapture.close(ln);
419
+ if (text !== undefined) {
420
+ if (ln === 'sqref')
421
+ extSqref = text;
422
+ else if (extCfvo !== undefined)
423
+ extCfvo.value = anchorValue(extCfvo.type, text, definedNames);
424
+ else
425
+ extRule?.draft.formulae.push(coerceNumericLiteral(unmangleFunctions(text, definedNames)));
426
+ }
427
+ else if (ln === 'cfvo') {
428
+ extCfvo = undefined;
429
+ }
430
+ else if (ln === 'cfRule') {
431
+ closeExtensionRule();
432
+ }
433
+ else if (ln === 'conditionalFormatting' && extRules !== undefined) {
434
+ if (extRules.length > 0)
435
+ blocks.push({ ref: extSqref, rules: extRules, extended: true });
436
+ extRules = undefined;
437
+ }
438
+ };
176
439
  const handlers = {
177
- onOpen(name, attrs, selfClosing) {
440
+ onOpen(name, attrs, selfClosing, scope) {
441
+ if (dxf !== undefined) {
442
+ dxf.open(name, attrs, selfClosing, scope);
443
+ return;
444
+ }
178
445
  const ln = localName(name);
179
- if (name.includes(':')) {
180
- if (ln === 'id' && draft !== undefined) {
181
- x14IdCapture.open(ln, selfClosing);
182
- }
183
- else if (ln === 'cfRule') {
184
- x14Ext = attrs.type === 'dataBar' && attrs.id !== undefined ? emptyExt() : undefined;
185
- x14ExtId = attrs.id;
186
- }
187
- else if (x14Ext !== undefined && ln === 'dataBar') {
188
- x14Ext.gradient = boolPresent(attrs.gradient);
189
- }
190
- else if (x14Ext !== undefined && ln === 'negativeFillColor') {
191
- x14Ext.negativeFillColor = parseColor(attrs);
192
- }
193
- else if (x14Ext !== undefined && ln === 'axisColor') {
194
- x14Ext.axisColor = parseColor(attrs);
195
- }
446
+ if (isExtensionElement(scope, name)) {
447
+ openExtension(ln, attrs, selfClosing);
196
448
  return;
197
449
  }
198
450
  if (ln === 'conditionalFormatting') {
@@ -213,10 +465,12 @@ export function conditionalFormattingPass() {
213
465
  (ln === 'dataBar' || ln === 'colorScale' || ln === 'iconSet')) {
214
466
  scale = ln;
215
467
  if (ln === 'iconSet')
216
- draft.iconSet = enumToken(attrs.iconSet, isIconSetType);
468
+ readIconSetAttrs(draft, attrs);
469
+ else if (ln === 'dataBar')
470
+ readDataBarAttrs(draft, attrs);
217
471
  }
218
472
  else if (draft !== undefined && ln === 'cfvo') {
219
- draft.cfvo.push(parseCfvo(attrs));
473
+ draft.cfvo.push(parseCfvo(attrs, definedNames));
220
474
  }
221
475
  else if (draft !== undefined && ln === 'color') {
222
476
  const color = parseColor(attrs);
@@ -232,26 +486,27 @@ export function conditionalFormattingPass() {
232
486
  onText(chunk) {
233
487
  formulaCapture.text(chunk);
234
488
  x14IdCapture.text(chunk);
489
+ extCapture.text(chunk);
235
490
  },
236
- onClose(name) {
237
- const ln = localName(name);
238
- if (name.includes(':')) {
239
- const id = x14IdCapture.close(ln);
240
- if (id !== undefined) {
241
- if (draft !== undefined)
242
- draft.x14Id = id;
243
- }
244
- else if (ln === 'cfRule' && x14Ext !== undefined && x14ExtId !== undefined) {
245
- extById.set(x14ExtId, x14Ext);
246
- x14Ext = undefined;
247
- x14ExtId = undefined;
491
+ onClose(name, scope) {
492
+ if (dxf !== undefined) {
493
+ if (dxf.close(name)) {
494
+ if (extRule !== undefined)
495
+ extRule.draft.dxf = dxf.fragment;
496
+ dxf = undefined;
248
497
  }
249
498
  return;
250
499
  }
500
+ const ln = localName(name);
501
+ if (isExtensionElement(scope, name)) {
502
+ closeExtension(ln);
503
+ return;
504
+ }
251
505
  const formula = formulaCapture.close(ln);
252
506
  if (formula !== undefined) {
253
- if (draft !== undefined)
254
- draft.formulae.push(coerceNumericLiteral(formula));
507
+ if (draft !== undefined) {
508
+ draft.formulae.push(coerceNumericLiteral(unmangleFunctions(formula, definedNames)));
509
+ }
255
510
  }
256
511
  else if (ln === 'dataBar' || ln === 'colorScale' || ln === 'iconSet') {
257
512
  scale = undefined;
@@ -261,8 +516,10 @@ export function conditionalFormattingPass() {
261
516
  if (rule !== undefined) {
262
517
  if (block !== undefined)
263
518
  block.rules.push(rule);
264
- if (draft.x14Id !== undefined)
519
+ if (draft.x14Id !== undefined) {
265
520
  linked.push({ rule, id: draft.x14Id });
521
+ linkedIds.add(draft.x14Id);
522
+ }
266
523
  }
267
524
  draft = undefined;
268
525
  }
@@ -277,47 +534,77 @@ export function conditionalFormattingPass() {
277
534
  const ext = extById.get(id);
278
535
  if (ext === undefined)
279
536
  continue;
280
- if (ext.gradient !== undefined)
281
- rule.gradient = ext.gradient;
282
- if (ext.negativeFillColor !== undefined)
283
- rule.negativeFillColor = ext.negativeFillColor;
284
- if (ext.axisColor !== undefined)
285
- rule.axisColor = ext.axisColor;
537
+ Object.assign(rule, ext.bar);
538
+ if (ext.cfvo.length > 0)
539
+ rule.cfvo = [...ext.cfvo];
286
540
  }
287
541
  return blocks;
288
542
  };
289
543
  return { handlers, result };
290
544
  }
291
- function emptyExt() {
292
- return { gradient: undefined, negativeFillColor: undefined, axisColor: undefined };
293
- }
294
- export function parseDxfs(stylesXml) {
295
- const { fragments } = elementSubtrees(stylesXml, new Map([['dxfs', 'dxf']]));
296
- return [...(fragments.get('dxfs') ?? [])];
545
+ export function applyConditionalFormattings(sheet, blocks) {
546
+ for (const block of blocks) {
547
+ if (decodeSqrefRects(block.ref).length === 0)
548
+ continue;
549
+ admitting(() => {
550
+ sheet.addConditionalFormatting(block);
551
+ });
552
+ }
297
553
  }
298
554
  function newDraft(attrs) {
299
555
  return {
300
556
  type: enumToken(attrs.type, isConditionalFormattingType),
301
- priority: numFinite(attrs.priority),
557
+ priority: numInteger(attrs.priority),
302
558
  stopIfTrue: boolStrict(attrs.stopIfTrue),
303
559
  operator: enumToken(attrs.operator, isConditionalFormattingOperator),
304
560
  text: attrs.text,
305
561
  timePeriod: enumToken(attrs.timePeriod, isCfTimePeriod),
306
- rank: numFinite(attrs.rank),
307
- stdDev: numFinite(attrs.stdDev),
562
+ rank: numInteger(attrs.rank, 0),
563
+ stdDev: numInteger(attrs.stdDev),
308
564
  percent: boolStrict(attrs.percent),
309
565
  bottom: boolStrict(attrs.bottom),
310
- aboveAverage: attrs.aboveAverage === undefined ? undefined : boolPresent(attrs.aboveAverage),
566
+ aboveAverage: boolTristate(attrs.aboveAverage),
311
567
  equalAverage: boolStrict(attrs.equalAverage),
312
568
  dxfId: parseIndexAttr(attrs.dxfId),
313
569
  iconSet: undefined,
570
+ icons: [],
571
+ reverse: false,
572
+ showValue: undefined,
314
573
  formulae: [],
315
574
  cfvo: [],
316
575
  colors: [],
317
576
  color: undefined,
577
+ bar: {},
318
578
  x14Id: undefined,
579
+ dxf: undefined,
319
580
  };
320
581
  }
582
+ function readIconSetAttrs(draft, attrs) {
583
+ draft.iconSet = enumToken(attrs.iconSet, isIconSetType);
584
+ draft.showValue = boolTristate(attrs.showValue);
585
+ draft.reverse = boolStrict(attrs.reverse);
586
+ }
587
+ function readDataBarAttrs(draft, attrs) {
588
+ const { bar } = draft;
589
+ draft.showValue = boolTristate(attrs.showValue);
590
+ setDefined(bar, 'minLength', numInteger(attrs.minLength, 0));
591
+ setDefined(bar, 'maxLength', numInteger(attrs.maxLength, 0));
592
+ setDefined(bar, 'border', boolTristate(attrs.border));
593
+ setDefined(bar, 'gradient', boolTristate(attrs.gradient));
594
+ setDefined(bar, 'direction', enumToken(attrs.direction, isDataBarDirection));
595
+ setDefined(bar, 'negativeBarColorSameAsPositive', boolTristate(attrs.negativeBarColorSameAsPositive));
596
+ setDefined(bar, 'negativeBarBorderColorSameAsPositive', boolTristate(attrs.negativeBarBorderColorSameAsPositive));
597
+ setDefined(bar, 'axisPosition', enumToken(attrs.axisPosition, isDataBarAxisPosition));
598
+ }
599
+ function setDefined(bar, key, value) {
600
+ if (value !== undefined)
601
+ bar[key] = value;
602
+ }
603
+ function parseCfIcon(attrs) {
604
+ const iconSet = enumToken(attrs.iconSet, isCfIconSetType);
605
+ const iconId = numInteger(attrs.iconId, 0);
606
+ return iconSet === undefined || iconId === undefined ? undefined : { iconSet, iconId };
607
+ }
321
608
  function dxfIndex(value) {
322
609
  return numInteger(value, 0);
323
610
  }
@@ -354,6 +641,12 @@ function finalizeRule(draft) {
354
641
  rule.dxfId = draft.dxfId;
355
642
  if (draft.iconSet !== undefined)
356
643
  rule.iconSet = draft.iconSet;
644
+ if (draft.icons !== undefined && draft.icons.length > 0)
645
+ rule.icons = draft.icons;
646
+ if (draft.reverse)
647
+ rule.reverse = true;
648
+ if (draft.showValue === false)
649
+ rule.showValue = false;
357
650
  if (draft.formulae.length > 0)
358
651
  rule.formulae = draft.formulae;
359
652
  if (draft.cfvo.length > 0)
@@ -362,14 +655,20 @@ function finalizeRule(draft) {
362
655
  rule.colors = draft.colors;
363
656
  if (draft.color !== undefined)
364
657
  rule.color = draft.color;
658
+ if (draft.type === 'dataBar')
659
+ Object.assign(rule, draft.bar);
365
660
  return rule;
366
661
  }
367
- function parseCfvo(attrs) {
662
+ function parseCfvo(attrs, definedNames) {
368
663
  const raw = attrs.type;
369
664
  const type = raw !== undefined && isCfValueObjectType(raw) ? raw : 'num';
370
665
  const cfvo = { type };
371
- if (attrs.val !== undefined) {
372
- cfvo.value = type === 'formula' ? attrs.val : coerceNumericLiteral(attrs.val);
373
- }
666
+ if (attrs.val !== undefined)
667
+ cfvo.value = anchorValue(type, attrs.val, definedNames);
668
+ if (boolTristate(attrs.gte) === false)
669
+ cfvo.gte = false;
374
670
  return cfvo;
375
671
  }
672
+ function anchorValue(type, text, definedNames) {
673
+ return type === 'formula' ? unmangleFunctions(text, definedNames) : coerceNumericLiteral(text);
674
+ }