@shbernal/ts-xlsx 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/README.md +30 -23
  2. package/dist/bytes.d.ts +3 -2
  3. package/dist/core/address.d.ts +36 -0
  4. package/dist/core/address.js +47 -9
  5. package/dist/core/array-formula-ranges.d.ts +33 -0
  6. package/dist/core/array-formula-ranges.js +62 -0
  7. package/dist/core/color-resolution.js +2 -2
  8. package/dist/core/column.js +3 -2
  9. package/dist/core/comment-thread.d.ts +7 -3
  10. package/dist/core/conditional-formatting-overlay.d.ts +9 -0
  11. package/dist/core/conditional-formatting-overlay.js +28 -1
  12. package/dist/core/conditional-formatting.d.ts +98 -10
  13. package/dist/core/conditional-formatting.js +42 -1
  14. package/dist/core/data-validation-overlay.d.ts +5 -0
  15. package/dist/core/data-validation-overlay.js +15 -0
  16. package/dist/core/data-validation.d.ts +16 -0
  17. package/dist/core/data-validation.js +15 -0
  18. package/dist/core/date-format.js +14 -4
  19. package/dist/core/date.js +1 -1
  20. package/dist/core/formula-references.d.ts +26 -0
  21. package/dist/core/formula-references.js +173 -0
  22. package/dist/core/formula-scan.d.ts +2 -0
  23. package/dist/core/formula-scan.js +58 -0
  24. package/dist/core/formula.d.ts +51 -18
  25. package/dist/core/formula.js +77 -86
  26. package/dist/core/function-values.d.ts +4 -0
  27. package/dist/core/function-values.js +58 -0
  28. package/dist/core/future-functions.d.ts +3 -0
  29. package/dist/core/{modern-functions.js → future-functions.js} +119 -88
  30. package/dist/core/grid-edits.d.ts +28 -0
  31. package/dist/core/grid-edits.js +193 -25
  32. package/dist/core/hyperlink.d.ts +39 -0
  33. package/dist/core/hyperlink.js +88 -0
  34. package/dist/core/image.d.ts +36 -5
  35. package/dist/core/image.js +9 -0
  36. package/dist/core/internal.d.ts +3 -1
  37. package/dist/core/limits.d.ts +5 -3
  38. package/dist/core/merge.d.ts +13 -0
  39. package/dist/core/merge.js +15 -1
  40. package/dist/core/page-setup.d.ts +26 -11
  41. package/dist/core/pivot-table.d.ts +49 -10
  42. package/dist/core/pivot-table.js +55 -21
  43. package/dist/core/protection.d.ts +66 -4
  44. package/dist/core/protection.js +4 -0
  45. package/dist/core/row.js +3 -2
  46. package/dist/core/structured-reference.d.ts +7 -0
  47. package/dist/core/structured-reference.js +7 -0
  48. package/dist/core/table.d.ts +38 -8
  49. package/dist/core/table.js +37 -7
  50. package/dist/core/theme.d.ts +2 -0
  51. package/dist/core/theme.js +4 -1
  52. package/dist/core/value.d.ts +51 -28
  53. package/dist/core/value.js +15 -12
  54. package/dist/core/workbook-styles.d.ts +17 -1
  55. package/dist/core/workbook-styles.js +4 -0
  56. package/dist/core/workbook-theme.js +5 -3
  57. package/dist/core/workbook.d.ts +20 -3
  58. package/dist/core/workbook.js +26 -5
  59. package/dist/core/worksheet-merges.d.ts +9 -4
  60. package/dist/core/worksheet-merges.js +17 -11
  61. package/dist/core/worksheet-model.d.ts +1 -1
  62. package/dist/core/worksheet-model.js +4 -0
  63. package/dist/core/worksheet-pictures.d.ts +3 -3
  64. package/dist/core/worksheet-pictures.js +7 -6
  65. package/dist/core/worksheet.d.ts +110 -21
  66. package/dist/core/worksheet.js +174 -49
  67. package/dist/entries/core.d.ts +7 -5
  68. package/dist/entries/core.js +4 -3
  69. package/dist/entries/errors.d.ts +1 -0
  70. package/dist/entries/errors.js +1 -0
  71. package/dist/errors.js +1 -1
  72. package/dist/io/cell-metadata/metadata.d.ts +42 -0
  73. package/dist/io/cell-metadata/metadata.js +35 -0
  74. package/dist/io/cell-metadata/rich-values.d.ts +11 -0
  75. package/dist/io/cell-metadata/rich-values.js +80 -0
  76. package/dist/io/csv/delimiter.d.ts +14 -2
  77. package/dist/io/csv/delimiter.js +12 -0
  78. package/dist/io/csv/errors.d.ts +14 -0
  79. package/dist/io/csv/errors.js +5 -0
  80. package/dist/io/csv/read.d.ts +6 -1
  81. package/dist/io/csv/read.js +46 -24
  82. package/dist/io/csv/write.d.ts +10 -3
  83. package/dist/io/csv/write.js +16 -7
  84. package/dist/io/opc/part-paths.js +4 -4
  85. package/dist/io/opc/read-opc.d.ts +4 -0
  86. package/dist/io/opc/read-opc.js +10 -4
  87. package/dist/io/opc/strict-relationships.d.ts +2 -0
  88. package/dist/io/opc/strict-relationships.js +12 -0
  89. package/dist/io/read-policy/column-budget.d.ts +26 -0
  90. package/dist/io/{xlsx → read-policy}/column-budget.js +4 -8
  91. package/dist/io/read-policy/read-repair.d.ts +74 -0
  92. package/dist/io/read-policy/read-repair.js +119 -0
  93. package/dist/io/style/cell-style-resolution.d.ts +25 -0
  94. package/dist/io/style/cell-style-resolution.js +30 -0
  95. package/dist/io/xlsb/formula.js +4 -2
  96. package/dist/io/xlsb/ptg-functions.js +110 -0
  97. package/dist/io/xlsb/read-metadata.d.ts +7 -0
  98. package/dist/io/xlsb/read-metadata.js +69 -0
  99. package/dist/io/xlsb/read-worksheet.d.ts +6 -0
  100. package/dist/io/xlsb/read-worksheet.js +95 -37
  101. package/dist/io/xlsb/read.js +26 -8
  102. package/dist/io/xlsb/record-types.d.ts +13 -0
  103. package/dist/io/xlsb/record-types.js +13 -0
  104. package/dist/io/xlsb/sheet-protection.d.ts +20 -0
  105. package/dist/io/xlsb/sheet-protection.js +60 -0
  106. package/dist/io/xlsx/cell-accumulator.d.ts +20 -12
  107. package/dist/io/xlsx/cell-accumulator.js +49 -19
  108. package/dist/io/xlsx/cell-metadata.d.ts +39 -0
  109. package/dist/io/xlsx/cell-metadata.js +162 -0
  110. package/dist/io/xlsx/cell-value.d.ts +16 -4
  111. package/dist/io/xlsx/cell-value.js +38 -21
  112. package/dist/io/xlsx/color-xml.js +1 -1
  113. package/dist/io/xlsx/column-span.d.ts +11 -0
  114. package/dist/io/xlsx/column-span.js +9 -0
  115. package/dist/io/xlsx/comments.d.ts +3 -28
  116. package/dist/io/xlsx/comments.js +3 -65
  117. package/dist/io/xlsx/conditional-formatting.d.ts +42 -25
  118. package/dist/io/xlsx/conditional-formatting.js +424 -129
  119. package/dist/io/xlsx/data-validation.d.ts +12 -7
  120. package/dist/io/xlsx/data-validation.js +41 -29
  121. package/dist/io/xlsx/edit-vba.js +43 -36
  122. package/dist/io/xlsx/hyperlinks.d.ts +16 -50
  123. package/dist/io/xlsx/hyperlinks.js +8 -37
  124. package/dist/io/xlsx/images.d.ts +49 -16
  125. package/dist/io/xlsx/images.js +145 -44
  126. package/dist/io/xlsx/namespaces.d.ts +8 -0
  127. package/dist/io/xlsx/namespaces.js +4 -0
  128. package/dist/io/xlsx/package-plan.d.ts +48 -15
  129. package/dist/io/xlsx/package-plan.js +46 -9
  130. package/dist/io/xlsx/part-names.d.ts +6 -8
  131. package/dist/io/xlsx/part-names.js +3 -7
  132. package/dist/io/xlsx/pivot.d.ts +5 -5
  133. package/dist/io/xlsx/pivot.js +23 -22
  134. package/dist/io/xlsx/preserved-splices.d.ts +6 -0
  135. package/dist/io/xlsx/preserved-splices.js +74 -0
  136. package/dist/io/xlsx/read-comments.d.ts +29 -0
  137. package/dist/io/xlsx/read-comments.js +75 -0
  138. package/dist/io/xlsx/read-parts.d.ts +2 -2
  139. package/dist/io/xlsx/read-parts.js +44 -37
  140. package/dist/io/xlsx/read-pivot.js +9 -3
  141. package/dist/io/xlsx/read-rich-runs.d.ts +8 -5
  142. package/dist/io/xlsx/read-rich-runs.js +18 -1
  143. package/dist/io/xlsx/read-rows.d.ts +18 -7
  144. package/dist/io/xlsx/read-rows.js +47 -37
  145. package/dist/io/xlsx/read-styles.d.ts +0 -25
  146. package/dist/io/xlsx/read-styles.js +39 -34
  147. package/dist/io/xlsx/read-workbook-xml.d.ts +6 -0
  148. package/dist/io/xlsx/read-workbook-xml.js +9 -4
  149. package/dist/io/xlsx/read-worksheet.d.ts +8 -3
  150. package/dist/io/xlsx/read-worksheet.js +45 -23
  151. package/dist/io/xlsx/read.d.ts +0 -4
  152. package/dist/io/xlsx/read.js +17 -21
  153. package/dist/io/xlsx/relationships.d.ts +3 -0
  154. package/dist/io/xlsx/relationships.js +4 -0
  155. package/dist/io/xlsx/row-position.d.ts +3 -1
  156. package/dist/io/xlsx/row-xml.d.ts +18 -7
  157. package/dist/io/xlsx/row-xml.js +54 -35
  158. package/dist/io/xlsx/sheet-properties.js +68 -42
  159. package/dist/io/xlsx/strict-parts.d.ts +7 -0
  160. package/dist/io/xlsx/strict-parts.js +171 -0
  161. package/dist/io/xlsx/style-elements.d.ts +0 -2
  162. package/dist/io/xlsx/style-elements.js +9 -29
  163. package/dist/io/xlsx/styles.d.ts +5 -0
  164. package/dist/io/xlsx/styles.js +11 -5
  165. package/dist/io/xlsx/tables.d.ts +10 -2
  166. package/dist/io/xlsx/tables.js +49 -42
  167. package/dist/io/xlsx/theme-xml.d.ts +6 -0
  168. package/dist/io/xlsx/theme-xml.js +16 -19
  169. package/dist/io/xlsx/threaded-comments.d.ts +6 -1
  170. package/dist/io/xlsx/threaded-comments.js +14 -7
  171. package/dist/io/xlsx/workbook-xml.d.ts +13 -24
  172. package/dist/io/xlsx/workbook-xml.js +15 -33
  173. package/dist/io/xlsx/worksheet-xml.d.ts +5 -2
  174. package/dist/io/xlsx/worksheet-xml.js +37 -69
  175. package/dist/io/xlsx/write-stream.d.ts +28 -6
  176. package/dist/io/xlsx/write-stream.js +42 -17
  177. package/dist/io/xlsx/write.d.ts +11 -4
  178. package/dist/io/xlsx/write.js +153 -90
  179. package/dist/rel-type.d.ts +9 -0
  180. package/dist/rel-type.js +3 -0
  181. package/dist/vba/bytes.d.ts +2 -0
  182. package/dist/vba/bytes.js +11 -0
  183. package/dist/vba/cfb-format.d.ts +47 -0
  184. package/dist/vba/cfb-format.js +34 -0
  185. package/dist/vba/cfb-writer.d.ts +1 -2
  186. package/dist/vba/cfb-writer.js +33 -36
  187. package/dist/vba/cfb.d.ts +9 -4
  188. package/dist/vba/cfb.js +55 -43
  189. package/dist/vba/dir-records.d.ts +6 -0
  190. package/dist/vba/dir-records.js +10 -2
  191. package/dist/vba/errors.d.ts +4 -4
  192. package/dist/vba/index.d.ts +0 -2
  193. package/dist/vba/index.js +0 -2
  194. package/dist/vba/ms-ovba.d.ts +6 -2
  195. package/dist/vba/ms-ovba.js +15 -6
  196. package/dist/vba/project-editor.js +102 -87
  197. package/dist/vba/project.d.ts +4 -0
  198. package/dist/vba/project.js +12 -6
  199. package/dist/vba/vba-encoding.d.ts +4 -10
  200. package/dist/vba/vba-encoding.js +2 -15
  201. package/dist/xml/xml-read.d.ts +29 -1
  202. package/dist/xml/xml-read.js +56 -0
  203. package/dist/xml/xml-scan.d.ts +13 -0
  204. package/dist/xml/xml-scan.js +58 -7
  205. package/dist/xml/xml.d.ts +33 -1
  206. package/dist/xml/xml.js +22 -0
  207. package/package.json +5 -4
  208. package/skills/ts-xlsx-upstream/SKILL.md +21 -13
  209. package/dist/core/modern-functions.d.ts +0 -1
  210. package/dist/io/xlsx/cell-style-resolution.d.ts +0 -25
  211. package/dist/io/xlsx/cell-style-resolution.js +0 -29
  212. package/dist/io/xlsx/column-budget.d.ts +0 -26
  213. package/dist/io/xlsx/read-repair.d.ts +0 -26
  214. package/dist/io/xlsx/read-repair.js +0 -39
@@ -1,102 +1,201 @@
1
- import { isCfValueObjectType, isConditionalFormattingOperator, isConditionalFormattingType, isIconSetType, isCfTimePeriod, } from '../../core/conditional-formatting.js';
2
- import { stripFormulaEquals } from '../../core/formula.js';
3
- import { coerceNumericLiteral, enumToken, numFinite, numInteger } from '../../xml/xml-attrs.js';
4
- import { elementSubtrees, TextCapture, } from '../../xml/xml-read.js';
5
- import { boolPresent, boolStrict, localName } from '../../xml/xml-scan.js';
6
- import { boolAttr, checkedToken, escapeAttr, escapeText, numberText, 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';
7
10
  import { colorAttrs, parseColor } from './color-xml.js';
8
- import { CF_EXT_URI, DATABAR_LINK_EXT_URI, isExtensionElement, XM_NS } from './namespaces.js';
11
+ import { CF_EXT_URI, DATABAR_LINK_EXT_URI, isExtensionElement, isMainNamespaceElement, XM_NS, } from './namespaces.js';
9
12
  import { x14Ext } from './x14-ext.js';
10
13
  const DEFAULT_DATABAR_CFVO = [{ type: 'min' }, { type: 'max' }];
11
14
  const DEFAULT_DATABAR_COLOR = { argb: 'FF638EC6' };
15
+ const CLASSIC_ANCHOR = {
16
+ autoMin: 'min',
17
+ autoMax: 'max',
18
+ };
12
19
  function needsDataBarExt(rule) {
13
20
  return (rule.gradient !== undefined ||
21
+ rule.border !== undefined ||
22
+ rule.borderColor !== undefined ||
23
+ rule.direction !== undefined ||
14
24
  rule.negativeFillColor !== undefined ||
15
- 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));
16
31
  }
17
- function dataBarExtGuid(index) {
32
+ function inExtension(cf, rule) {
33
+ return cf.extended === true || ruleNeedsExtension(rule);
34
+ }
35
+ function extensionGuid(index) {
18
36
  return `{00000000-0000-0000-0000-${String(index + 1).padStart(12, '0')}}`;
19
37
  }
20
- export function dataBarExtLinks(formattings) {
21
- const links = new Map();
22
- let index = 0;
38
+ export function planConditionalFormatting(formattings) {
39
+ const priorities = new Map();
40
+ const extensionIds = new Map();
41
+ let next = 1;
23
42
  for (const cf of formattings) {
24
43
  for (const rule of cf.rules) {
25
- if (rule.type === 'dataBar' && needsDataBarExt(rule))
26
- 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
+ }
27
51
  }
28
52
  }
29
- 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;
30
61
  }
31
62
  const SCALE_KINDS = ['dataBar', 'colorScale', 'iconSet'];
32
63
  const SCALE_TYPES = new Set(SCALE_KINDS);
33
- export function conditionalFormattingsXml(formattings, styles, extLinks) {
34
- if (formattings.length === 0)
35
- return '';
36
- const priority = { next: 1 };
37
- 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('');
38
66
  }
39
- export function conditionalFormattingsExtXml(formattings, extLinks) {
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 anchors = dataBarAnchors(rule).map(x14Cfvo).join('');
54
- const gradient = boolAttr('gradient', rule.gradient);
55
- const negative = rule.negativeFillColor !== undefined
56
- ? `<x14:negativeFillColor ${colorAttrs(rule.negativeFillColor)}/>`
57
- : '';
58
- const axis = rule.axisColor !== undefined ? `<x14:axisColor ${colorAttrs(rule.axisColor)}/>` : '';
59
- return (`<x14:conditionalFormatting xmlns:xm="${XM_NS}">` +
60
- `<x14:cfRule type="dataBar" id="${guid}">` +
61
- `<x14:dataBar${gradient}>${anchors}${negative}${axis}</x14:dataBar>` +
62
- `</x14:cfRule><xm:sqref>${escapeText(ref)}</xm:sqref></x14:conditionalFormatting>`);
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)}"`;
63
144
  }
64
145
  function dataBarAnchors(rule) {
65
146
  return rule.cfvo && rule.cfvo.length > 0 ? rule.cfvo : DEFAULT_DATABAR_CFVO;
66
147
  }
67
- function cfvoWriter(form) {
148
+ function cfvoWriter(form, formulaNames) {
68
149
  return (cfvo) => {
69
- const type = checkedToken(cfvo.type, isCfValueObjectType, 'conditional format value type');
150
+ const checked = checkedToken(cfvo.type, isCfValueObjectType, 'conditional format value type');
151
+ const type = form === 'classic' ? (CLASSIC_ANCHOR[cfvo.type] ?? checked) : checked;
70
152
  const tag = form === 'classic' ? 'cfvo' : 'x14:cfvo';
153
+ const gte = cfvo.gte === false ? ' gte="0"' : '';
71
154
  if (cfvo.value === undefined)
72
- return `<${tag} type="${type}"/>`;
73
- const value = String(cfvo.value);
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;
74
161
  return form === 'classic'
75
- ? `<${tag} type="${type}"${textAttr('val', value)}/>`
76
- : `<${tag} type="${type}"><xm:f>${escapeText(value)}</xm:f></${tag}>`;
162
+ ? `<${tag} type="${type}"${textAttr('val', value)}${gte}/>`
163
+ : `<${tag} type="${type}"${gte}><xm:f>${escapeText(value)}</xm:f></${tag}>`;
77
164
  };
78
165
  }
79
- const cfvoXml = cfvoWriter('classic');
80
- const x14Cfvo = cfvoWriter('x14');
81
166
  function cfRuleExtLinkXml(guid) {
82
167
  return `<extLst>${x14Ext(DATABAR_LINK_EXT_URI, `<x14:id>${guid}</x14:id>`)}</extLst>`;
83
168
  }
84
- function blockXml(cf, styles, priority, extLinks) {
85
- 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('');
86
174
  if (rules === '')
87
175
  return '';
88
176
  return `<conditionalFormatting sqref="${escapeAttr(cf.ref)}">${rules}</conditionalFormatting>`;
89
177
  }
90
- function ruleXml(rule, styles, priority, extLinks) {
91
- const p = rule.priority ?? priority.next;
92
- priority.next = Math.max(priority.next, p) + 1;
93
- const attrs = [
94
- `type="${checkedToken(rule.type, isConditionalFormattingType, 'conditional formatting type')}"`,
95
- ];
178
+ function ruleXml(rule, styles, plan, formulaNames) {
179
+ const attrs = [typeAttr(rule)];
96
180
  const dxfId = resolveDxfId(rule, styles);
97
181
  if (dxfId !== undefined)
98
182
  attrs.push(`dxfId="${dxfId}"`);
99
- 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 = [];
100
199
  if (rule.stopIfTrue)
101
200
  attrs.push('stopIfTrue="1"');
102
201
  if (rule.aboveAverage === false)
@@ -116,16 +215,10 @@ function ruleXml(rule, styles, priority, extLinks) {
116
215
  attrs.push(`timePeriod="${checkedToken(rule.timePeriod, isCfTimePeriod, 'time period')}"`);
117
216
  }
118
217
  if (rule.rank !== undefined)
119
- attrs.push(`rank="${numberText(rule.rank)}"`);
218
+ attrs.push(intAttr('rank', rule.rank, 0).trim());
120
219
  if (rule.stdDev !== undefined)
121
- attrs.push(`stdDev="${numberText(rule.stdDev)}"`);
122
- let body = SCALE_TYPES.has(rule.type) ? scaleXml(rule) : formulaeXml(rule.formulae);
123
- const extGuid = extLinks.get(rule);
124
- if (extGuid !== undefined)
125
- body += cfRuleExtLinkXml(extGuid);
126
- return body === ''
127
- ? `<cfRule ${attrs.join(' ')}/>`
128
- : `<cfRule ${attrs.join(' ')}>${body}</cfRule>`;
220
+ attrs.push(intAttr('stdDev', rule.stdDev).trim());
221
+ return attrs;
129
222
  }
130
223
  function resolveDxfId(rule, styles) {
131
224
  if (SCALE_TYPES.has(rule.type))
@@ -137,66 +230,221 @@ function resolveDxfId(rule, styles) {
137
230
  return styles.differentialStyleId(rule.style);
138
231
  return undefined;
139
232
  }
140
- function formulaeXml(formulae) {
233
+ function operandsXml(formulae, tag, formulaNames) {
141
234
  if (formulae === undefined)
142
235
  return '';
143
- 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('');
144
239
  }
145
- function scaleXml(rule) {
240
+ function scaleXml(rule, formulaNames, linked) {
241
+ const cfvoXml = cfvoWriter('classic', formulaNames);
146
242
  if (rule.type === 'dataBar')
147
- return dataBarXml(rule);
243
+ return dataBarXml(rule, cfvoXml, linked);
148
244
  if (rule.type === 'colorScale')
149
- return colorScaleXml(rule);
150
- return iconSetXml(rule);
245
+ return colorScaleXml(rule, cfvoXml);
246
+ return iconSetXml(rule, cfvoXml, 'classic');
151
247
  }
152
- function dataBarXml(rule) {
248
+ function dataBarXml(rule, cfvoXml, linked) {
153
249
  const color = rule.color ?? DEFAULT_DATABAR_COLOR;
154
250
  const anchors = dataBarAnchors(rule).map(cfvoXml).join('');
155
- return `<dataBar>${anchors}<color ${colorAttrs(color)}/></dataBar>`;
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>`;
156
256
  }
157
- function colorScaleXml(rule) {
257
+ function colorScaleXml(rule, cfvoXml) {
158
258
  const anchors = (rule.cfvo ?? []).map(cfvoXml).join('');
159
259
  const colors = (rule.colors ?? []).map((c) => `<color ${colorAttrs(c)}/>`).join('');
160
260
  return `<colorScale>${anchors}${colors}</colorScale>`;
161
261
  }
162
- function iconSetXml(rule) {
163
- const name = rule.iconSet === undefined
164
- ? ''
165
- : ` 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"' : '');
166
269
  const anchors = (rule.cfvo ?? []).map(cfvoXml).join('');
167
- return `<iconSet${name}>${anchors}</iconSet>`;
270
+ return `<${tag}${attrs}>${anchors}${icons.map(cfIconXml).join('')}</${tag}>`;
271
+ }
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
+ }
168
312
  }
169
- export function conditionalFormattingPass() {
313
+ export function conditionalFormattingPass(definedNames, adoptDifferentialStyle) {
170
314
  const blocks = [];
171
315
  let block;
172
316
  let draft;
173
317
  let scale;
174
318
  const formulaCapture = new TextCapture('formula');
175
319
  const linked = [];
320
+ const linkedIds = new Set();
176
321
  const extById = new Map();
177
- let x14Ext;
178
- let x14ExtId;
179
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
+ };
180
439
  const handlers = {
181
440
  onOpen(name, attrs, selfClosing, scope) {
441
+ if (dxf !== undefined) {
442
+ dxf.open(name, attrs, selfClosing, scope);
443
+ return;
444
+ }
182
445
  const ln = localName(name);
183
446
  if (isExtensionElement(scope, name)) {
184
- if (ln === 'id' && draft !== undefined) {
185
- x14IdCapture.open(ln, selfClosing);
186
- }
187
- else if (ln === 'cfRule') {
188
- x14Ext = attrs.type === 'dataBar' && attrs.id !== undefined ? emptyExt() : undefined;
189
- x14ExtId = attrs.id;
190
- }
191
- else if (x14Ext !== undefined && ln === 'dataBar') {
192
- x14Ext.gradient = boolPresent(attrs.gradient);
193
- }
194
- else if (x14Ext !== undefined && ln === 'negativeFillColor') {
195
- x14Ext.negativeFillColor = parseColor(attrs);
196
- }
197
- else if (x14Ext !== undefined && ln === 'axisColor') {
198
- x14Ext.axisColor = parseColor(attrs);
199
- }
447
+ openExtension(ln, attrs, selfClosing);
200
448
  return;
201
449
  }
202
450
  if (ln === 'conditionalFormatting') {
@@ -217,10 +465,12 @@ export function conditionalFormattingPass() {
217
465
  (ln === 'dataBar' || ln === 'colorScale' || ln === 'iconSet')) {
218
466
  scale = ln;
219
467
  if (ln === 'iconSet')
220
- draft.iconSet = enumToken(attrs.iconSet, isIconSetType);
468
+ readIconSetAttrs(draft, attrs);
469
+ else if (ln === 'dataBar')
470
+ readDataBarAttrs(draft, attrs);
221
471
  }
222
472
  else if (draft !== undefined && ln === 'cfvo') {
223
- draft.cfvo.push(parseCfvo(attrs));
473
+ draft.cfvo.push(parseCfvo(attrs, definedNames));
224
474
  }
225
475
  else if (draft !== undefined && ln === 'color') {
226
476
  const color = parseColor(attrs);
@@ -236,26 +486,27 @@ export function conditionalFormattingPass() {
236
486
  onText(chunk) {
237
487
  formulaCapture.text(chunk);
238
488
  x14IdCapture.text(chunk);
489
+ extCapture.text(chunk);
239
490
  },
240
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;
497
+ }
498
+ return;
499
+ }
241
500
  const ln = localName(name);
242
501
  if (isExtensionElement(scope, name)) {
243
- const id = x14IdCapture.close(ln);
244
- if (id !== undefined) {
245
- if (draft !== undefined)
246
- draft.x14Id = id;
247
- }
248
- else if (ln === 'cfRule' && x14Ext !== undefined && x14ExtId !== undefined) {
249
- extById.set(x14ExtId, x14Ext);
250
- x14Ext = undefined;
251
- x14ExtId = undefined;
252
- }
502
+ closeExtension(ln);
253
503
  return;
254
504
  }
255
505
  const formula = formulaCapture.close(ln);
256
506
  if (formula !== undefined) {
257
- if (draft !== undefined)
258
- draft.formulae.push(coerceNumericLiteral(formula));
507
+ if (draft !== undefined) {
508
+ draft.formulae.push(coerceNumericLiteral(unmangleFunctions(formula, definedNames)));
509
+ }
259
510
  }
260
511
  else if (ln === 'dataBar' || ln === 'colorScale' || ln === 'iconSet') {
261
512
  scale = undefined;
@@ -265,8 +516,10 @@ export function conditionalFormattingPass() {
265
516
  if (rule !== undefined) {
266
517
  if (block !== undefined)
267
518
  block.rules.push(rule);
268
- if (draft.x14Id !== undefined)
519
+ if (draft.x14Id !== undefined) {
269
520
  linked.push({ rule, id: draft.x14Id });
521
+ linkedIds.add(draft.x14Id);
522
+ }
270
523
  }
271
524
  draft = undefined;
272
525
  }
@@ -281,47 +534,77 @@ export function conditionalFormattingPass() {
281
534
  const ext = extById.get(id);
282
535
  if (ext === undefined)
283
536
  continue;
284
- if (ext.gradient !== undefined)
285
- rule.gradient = ext.gradient;
286
- if (ext.negativeFillColor !== undefined)
287
- rule.negativeFillColor = ext.negativeFillColor;
288
- if (ext.axisColor !== undefined)
289
- rule.axisColor = ext.axisColor;
537
+ Object.assign(rule, ext.bar);
538
+ if (ext.cfvo.length > 0)
539
+ rule.cfvo = [...ext.cfvo];
290
540
  }
291
541
  return blocks;
292
542
  };
293
543
  return { handlers, result };
294
544
  }
295
- function emptyExt() {
296
- return { gradient: undefined, negativeFillColor: undefined, axisColor: undefined };
297
- }
298
- export function parseDxfs(stylesXml) {
299
- const { fragments } = elementSubtrees(stylesXml, new Map([['dxfs', 'dxf']]));
300
- 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
+ }
301
553
  }
302
554
  function newDraft(attrs) {
303
555
  return {
304
556
  type: enumToken(attrs.type, isConditionalFormattingType),
305
- priority: numFinite(attrs.priority),
557
+ priority: numInteger(attrs.priority),
306
558
  stopIfTrue: boolStrict(attrs.stopIfTrue),
307
559
  operator: enumToken(attrs.operator, isConditionalFormattingOperator),
308
560
  text: attrs.text,
309
561
  timePeriod: enumToken(attrs.timePeriod, isCfTimePeriod),
310
- rank: numFinite(attrs.rank),
311
- stdDev: numFinite(attrs.stdDev),
562
+ rank: numInteger(attrs.rank, 0),
563
+ stdDev: numInteger(attrs.stdDev),
312
564
  percent: boolStrict(attrs.percent),
313
565
  bottom: boolStrict(attrs.bottom),
314
- aboveAverage: attrs.aboveAverage === undefined ? undefined : boolPresent(attrs.aboveAverage),
566
+ aboveAverage: boolTristate(attrs.aboveAverage),
315
567
  equalAverage: boolStrict(attrs.equalAverage),
316
568
  dxfId: parseIndexAttr(attrs.dxfId),
317
569
  iconSet: undefined,
570
+ icons: [],
571
+ reverse: false,
572
+ showValue: undefined,
318
573
  formulae: [],
319
574
  cfvo: [],
320
575
  colors: [],
321
576
  color: undefined,
577
+ bar: {},
322
578
  x14Id: undefined,
579
+ dxf: undefined,
323
580
  };
324
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
+ }
325
608
  function dxfIndex(value) {
326
609
  return numInteger(value, 0);
327
610
  }
@@ -358,6 +641,12 @@ function finalizeRule(draft) {
358
641
  rule.dxfId = draft.dxfId;
359
642
  if (draft.iconSet !== undefined)
360
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;
361
650
  if (draft.formulae.length > 0)
362
651
  rule.formulae = draft.formulae;
363
652
  if (draft.cfvo.length > 0)
@@ -366,14 +655,20 @@ function finalizeRule(draft) {
366
655
  rule.colors = draft.colors;
367
656
  if (draft.color !== undefined)
368
657
  rule.color = draft.color;
658
+ if (draft.type === 'dataBar')
659
+ Object.assign(rule, draft.bar);
369
660
  return rule;
370
661
  }
371
- function parseCfvo(attrs) {
662
+ function parseCfvo(attrs, definedNames) {
372
663
  const raw = attrs.type;
373
664
  const type = raw !== undefined && isCfValueObjectType(raw) ? raw : 'num';
374
665
  const cfvo = { type };
375
- if (attrs.val !== undefined) {
376
- cfvo.value = type === 'formula' ? attrs.val : coerceNumericLiteral(attrs.val);
377
- }
666
+ if (attrs.val !== undefined)
667
+ cfvo.value = anchorValue(type, attrs.val, definedNames);
668
+ if (boolTristate(attrs.gte) === false)
669
+ cfvo.gte = false;
378
670
  return cfvo;
379
671
  }
672
+ function anchorValue(type, text, definedNames) {
673
+ return type === 'formula' ? unmangleFunctions(text, definedNames) : coerceNumericLiteral(text);
674
+ }