@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,27 +1,23 @@
1
1
  import { encodeAddress, tryDecodeRange } from '../../core/address.js';
2
- import { isTotalsRowFunction, } from '../../core/table.js';
2
+ import { mangleFormula, unmangleFunctions } from '../../core/formula.js';
3
+ import { isTotalsRowFunction, TABLE_STYLE_FLAGS, } from '../../core/table.js';
4
+ import { numInteger } from '../../xml/xml-attrs.js';
3
5
  import { parseXml, TextCapture } from '../../xml/xml-read.js';
4
- import { boolPresent, localName, numInteger } from '../../xml/xml-scan.js';
5
- import { boolAttr, escapeAttr, escapeText, XML_DECLARATION } from '../../xml/xml.js';
6
+ import { boolTristate, localName } from '../../xml/xml-scan.js';
7
+ import { boolAttr, checkedToken, escapeAttr, escapeText, XML_DECLARATION } from '../../xml/xml.js';
6
8
  import { NS } from './relationships.js';
7
- export function tableXml(table, id) {
9
+ export function tableXml(table, id, formulaNames) {
8
10
  const name = escapeAttr(table.name);
9
- const displayName = escapeAttr(table.displayName);
10
11
  const headerRowCount = table.headerRow ? '' : ' headerRowCount="0"';
11
- let totals;
12
- if (table.totalsRow) {
13
- totals = ' totalsRowCount="1"';
14
- }
15
- else if (table.totalsRowShown !== undefined) {
16
- totals = ` totalsRowShown="${table.totalsRowShown ? '1' : '0'}"`;
17
- }
18
- else {
19
- totals = '';
20
- }
12
+ const totals = table.totalsRow
13
+ ? ' totalsRowCount="1"'
14
+ : boolAttr('totalsRowShown', table.totalsRowShown);
21
15
  const autoFilter = table.autoFilterRef !== undefined ? `<autoFilter ref="${table.autoFilterRef}"/>` : '';
22
- const columns = table.columns.map((column, i) => tableColumnXml(column, i + 1)).join('');
16
+ const columns = table.columns
17
+ .map((column, i) => tableColumnXml(column, i + 1, formulaNames))
18
+ .join('');
23
19
  return (XML_DECLARATION +
24
- `<table xmlns="${NS.main}" id="${id}" name="${name}" displayName="${displayName}" ` +
20
+ `<table xmlns="${NS.main}" id="${id}" name="${name}" displayName="${name}" ` +
25
21
  `ref="${table.range}"${headerRowCount}${totals}>` +
26
22
  autoFilter +
27
23
  `<tableColumns count="${table.columns.length}">${columns}</tableColumns>` +
@@ -36,29 +32,32 @@ function tableStyleInfoXml(style) {
36
32
  let attrs = '';
37
33
  if (style.name !== undefined)
38
34
  attrs += ` name="${escapeAttr(style.name)}"`;
39
- attrs +=
40
- boolAttr('showFirstColumn', style.showFirstColumn) +
41
- boolAttr('showLastColumn', style.showLastColumn) +
42
- boolAttr('showRowStripes', style.showRowStripes) +
43
- boolAttr('showColumnStripes', style.showColumnStripes);
35
+ attrs += TABLE_STYLE_FLAGS.map((flag) => boolAttr(flag, style[flag])).join('');
44
36
  return `<tableStyleInfo${attrs}/>`;
45
37
  }
46
- function tableColumnXml(column, id) {
38
+ function tableColumnXml(column, id, formulaNames) {
47
39
  let attrs = `id="${id}" name="${escapeAttr(column.name)}"`;
48
40
  if (column.totalsRowLabel !== undefined) {
49
41
  attrs += ` totalsRowLabel="${escapeAttr(column.totalsRowLabel)}"`;
50
42
  }
51
43
  if (column.totalsRowFunction !== undefined) {
52
- attrs += ` totalsRowFunction="${escapeAttr(column.totalsRowFunction)}"`;
44
+ attrs += ` totalsRowFunction="${checkedToken(column.totalsRowFunction, isTotalsRowFunction, 'totals row function')}"`;
45
+ }
46
+ let children = '';
47
+ if (column.calculatedColumnFormula !== undefined) {
48
+ const stored = mangleFormula(column.calculatedColumnFormula, formulaNames);
49
+ children += `<calculatedColumnFormula>${escapeText(stored)}</calculatedColumnFormula>`;
53
50
  }
54
51
  if (column.totalsRowFormula !== undefined) {
55
- return `<tableColumn ${attrs}><totalsRowFormula>${escapeText(column.totalsRowFormula)}</totalsRowFormula></tableColumn>`;
52
+ const stored = mangleFormula(column.totalsRowFormula, formulaNames);
53
+ children += `<totalsRowFormula>${escapeText(stored)}</totalsRowFormula>`;
56
54
  }
57
- return `<tableColumn ${attrs}/>`;
55
+ return children === ''
56
+ ? `<tableColumn ${attrs}/>`
57
+ : `<tableColumn ${attrs}>${children}</tableColumn>`;
58
58
  }
59
- export function parseTable(xml) {
59
+ export function parseTable(xml, definedNames) {
60
60
  let name;
61
- let displayName;
62
61
  let ref;
63
62
  let headerRowCount = 1;
64
63
  let totalsRowCount = 0;
@@ -66,18 +65,17 @@ export function parseTable(xml) {
66
65
  let style;
67
66
  let hasAutoFilter = false;
68
67
  const columns = [];
69
- const totalsFormula = new TextCapture('totalsRowFormula');
68
+ let currentColumn;
69
+ const formula = new TextCapture(['totalsRowFormula', 'calculatedColumnFormula']);
70
70
  parseXml(xml, {
71
71
  onOpen(elementName, attrs, selfClosing) {
72
72
  switch (localName(elementName)) {
73
73
  case 'table':
74
- name = attrs.name ?? attrs.displayName;
75
- displayName = attrs.displayName ?? attrs.name;
74
+ name = attrs.displayName ?? attrs.name;
76
75
  ref = attrs.ref;
77
76
  headerRowCount = numInteger(attrs.headerRowCount, 0) ?? headerRowCount;
78
77
  totalsRowCount = numInteger(attrs.totalsRowCount, 0) ?? totalsRowCount;
79
- if (attrs.totalsRowShown !== undefined)
80
- totalsRowShown = boolPresent(attrs.totalsRowShown);
78
+ totalsRowShown = boolTristate(attrs.totalsRowShown);
81
79
  break;
82
80
  case 'autoFilter':
83
81
  hasAutoFilter = true;
@@ -86,22 +84,21 @@ export function parseTable(xml) {
86
84
  const captured = {};
87
85
  if (attrs.name !== undefined)
88
86
  captured.name = attrs.name;
89
- if (attrs.showFirstColumn !== undefined)
90
- captured.showFirstColumn = boolPresent(attrs.showFirstColumn);
91
- if (attrs.showLastColumn !== undefined)
92
- captured.showLastColumn = boolPresent(attrs.showLastColumn);
93
- if (attrs.showRowStripes !== undefined)
94
- captured.showRowStripes = boolPresent(attrs.showRowStripes);
95
- if (attrs.showColumnStripes !== undefined) {
96
- captured.showColumnStripes = boolPresent(attrs.showColumnStripes);
87
+ for (const flag of TABLE_STYLE_FLAGS) {
88
+ const value = boolTristate(attrs[flag]);
89
+ if (value !== undefined)
90
+ captured[flag] = value;
97
91
  }
98
92
  style = captured;
99
93
  break;
100
94
  }
101
95
  case 'tableColumn': {
102
- if (attrs.name === undefined)
96
+ if (attrs.name === undefined) {
97
+ currentColumn = undefined;
103
98
  break;
99
+ }
104
100
  const column = { name: attrs.name };
101
+ currentColumn = column;
105
102
  if (attrs.totalsRowLabel !== undefined)
106
103
  column.totalsRowLabel = attrs.totalsRowLabel;
107
104
  if (attrs.totalsRowFunction !== undefined &&
@@ -112,20 +109,24 @@ export function parseTable(xml) {
112
109
  break;
113
110
  }
114
111
  case 'totalsRowFormula':
115
- totalsFormula.open('totalsRowFormula', selfClosing);
112
+ case 'calculatedColumnFormula':
113
+ formula.open(localName(elementName), selfClosing);
116
114
  break;
117
115
  }
118
116
  },
119
117
  onText(text) {
120
- totalsFormula.text(text);
118
+ formula.text(text);
121
119
  },
122
120
  onClose(elementName) {
123
- const formula = totalsFormula.close(localName(elementName));
124
- if (formula === undefined)
121
+ const local = localName(elementName);
122
+ const text = formula.close(local);
123
+ if (text === undefined || currentColumn === undefined)
125
124
  return;
126
- const column = columns[columns.length - 1];
127
- if (column !== undefined)
128
- column.totalsRowFormula = formula;
125
+ const formulaText = unmangleFunctions(text, definedNames);
126
+ if (local === 'totalsRowFormula')
127
+ currentColumn.totalsRowFormula = formulaText;
128
+ else
129
+ currentColumn.calculatedColumnFormula = formulaText;
129
130
  },
130
131
  });
131
132
  if (name === undefined || ref === undefined || columns.length === 0)
@@ -133,15 +134,17 @@ export function parseTable(xml) {
133
134
  const decoded = tryDecodeRange(ref);
134
135
  if (decoded === undefined)
135
136
  return undefined;
136
- const { top, left, bottom } = decoded;
137
- if (top === undefined || left === undefined || bottom === undefined)
137
+ const { top, left, bottom, right } = decoded;
138
+ if (top === undefined || left === undefined || bottom === undefined || right === undefined) {
139
+ return undefined;
140
+ }
141
+ if (columns.length !== right - left + 1)
138
142
  return undefined;
139
143
  const headerRow = headerRowCount !== 0;
140
144
  const totalsRow = totalsRowCount > 0;
141
145
  const dataRows = bottom - top + 1 - (headerRow ? 1 : 0) - (totalsRow ? 1 : 0);
142
146
  const options = {
143
147
  name,
144
- displayName: displayName ?? name,
145
148
  ref: encodeAddress(left, top),
146
149
  columns,
147
150
  rowCount: Math.max(0, dataRows),
@@ -1,16 +1,35 @@
1
- import { type ThemeColorScheme, type ThemeFontScheme, type ThemeOverrides } from '../../core/theme.ts';
1
+ import type { AssertNever } from '../../core/internal.ts';
2
+ import { type ThemeColorScheme, type ThemeColorSlot, type ThemeFontScheme, type ThemeOverrides } from '../../core/theme.ts';
2
3
  /**
3
4
  * Extract the colour scheme from a theme part. Returns only the slots the part actually declares in a
4
5
  * colour model this reader understands; an unrecognised one is dropped rather than guessed at, so a
5
6
  * caller can tell "the theme says nothing here" from "the theme says black".
6
7
  *
7
- * Reads the `<a:clrScheme>` block alone. A theme carries a font scheme and a format scheme too, but
8
- * neither participates in resolving a colour, and scanning the whole part would let a `<a:srgbClr>`
8
+ * Reads the `<clrScheme>` block alone. A theme carries a font scheme and a format scheme too, but
9
+ * neither participates in resolving a colour, and scanning the whole part would let an `<srgbClr>`
9
10
  * buried in a gradient stop masquerade as a scheme slot.
10
11
  */
11
12
  export declare function parseThemeColorScheme(themeXml: string): ThemeColorScheme;
12
- /** Extract the major/minor latin typefaces from a theme part's `<a:fontScheme>`. */
13
+ /** Extract the major/minor latin typefaces from a theme part's `<fontScheme>`. */
13
14
  export declare function parseThemeFontScheme(themeXml: string): ThemeFontScheme;
15
+ /** {@link parseThemeColorScheme} and {@link parseThemeFontScheme} from one scan of the part, for the
16
+ * reader, which wants both. */
17
+ export declare function parseThemeSchemes(themeXml: string): {
18
+ readonly colors: ThemeColorScheme;
19
+ readonly fonts: ThemeFontScheme;
20
+ };
21
+ declare const SCHEME_ELEMENT_ORDER: readonly ["dk1", "lt1", "dk2", "lt2", "accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "hlink", "folHlink"];
22
+ /**
23
+ * The half of the proof the list above owes: `satisfies` covers "no invented slot", this covers "no
24
+ * omission". A slot missing here is not a slot written in the wrong place -- it is a slot dropped
25
+ * from every rewritten `<a:clrScheme>`, verbatim source element and all, so a caller who authored it
26
+ * gets back a theme that silently does not carry it.
27
+ *
28
+ * This is the one list in the library where the schema order and the index order differ, which makes
29
+ * it the one a new slot is least likely to be added to by hand. `DEFAULT_THEME_COLOR_SCHEME` proves
30
+ * the same completeness on the model side.
31
+ */
32
+ export type EverySlotIsInSchemaOrder = AssertNever<Exclude<ThemeColorSlot, (typeof SCHEME_ELEMENT_ORDER)[number]>>;
14
33
  /**
15
34
  * Apply authored colour/font overrides to a theme part, returning the new part text.
16
35
  *
@@ -24,6 +43,14 @@ export declare function parseThemeFontScheme(themeXml: string): ThemeFontScheme;
24
43
  * its value. That matters for `dk1`/`lt1`, which Excel writes as `<a:sysClr val="windowText"
25
44
  * lastClr="000000"/>`: rewriting those as `<a:srgbClr>` would pin them to one machine's resolved
26
45
  * window colours and break dark-mode following.
46
+ *
47
+ * The edit is made by *offset*, not by pattern. What it replaces was three container-scanning regular
48
+ * expressions in the one file whose own header condemns that pattern, on a path a preserved source
49
+ * theme's bytes reach: `[\s\S]*?` terminated on a `</clrScheme>` inside a comment, `[^>]*` missed a
50
+ * `<latin typeface="X"></latin>` and dropped the override silently, and the DrawingML prefix -- read
51
+ * out of the part's own root element, where an NCName may legally contain `.` and `-` -- was
52
+ * interpolated into the pattern unescaped. {@link elementRange} answers the same question with the
53
+ * scanner, and splicing at its offsets is what makes an unoverridden part come back byte for byte.
27
54
  */
28
55
  export declare function applyThemeOverrides(baseXml: string, overrides: ThemeOverrides): string;
29
56
  /**
@@ -35,3 +62,4 @@ export declare function applyThemeOverrides(baseXml: string, overrides: ThemeOve
35
62
  * built from scratch rather than read from a file.
36
63
  */
37
64
  export declare const DEFAULT_THEME_XML: string;
65
+ export {};
@@ -1,41 +1,82 @@
1
- import { DEFAULT_THEME_COLOR_SCHEME, isThemeColorSlot, normalizeThemeColor, } from '../../core/theme.js';
2
- import { decodeEntities } from '../../xml/xml-scan.js';
3
- import { escapeAttr } from '../../xml/xml.js';
4
- const SCHEME_SLOT = new RegExp('<a:(dk1|lt1|dk2|lt2|accent[1-6]|hlink|folHlink)\\b[^>]*>' + '\\s*<a:(srgbClr|sysClr)\\b([^>]*)>', 'g');
5
- export function parseThemeColorScheme(themeXml) {
6
- const block = /<a:clrScheme\b[^>]*>([\s\S]*?)<\/a:clrScheme>/.exec(themeXml);
7
- if (block === null)
8
- return {};
1
+ import { DEFAULT_THEME_COLOR_SCHEME, isThemeColorSlot, isThemeRgb, } from '../../core/theme.js';
2
+ import { elementRange, parseXml } from '../../xml/xml-read.js';
3
+ import { localName } from '../../xml/xml-scan.js';
4
+ import { startTag } from '../../xml/xml.js';
5
+ const COLOR_ELEMENTS = new Set(['srgbClr', 'sysClr']);
6
+ function readThemeScheme(themeXml) {
7
+ const colors = {};
8
+ const elements = {};
9
+ const fonts = {};
10
+ let prefix = '';
11
+ let container;
12
+ let slot;
13
+ let fontSlot;
14
+ parseXml(themeXml, {
15
+ onOpen(name, attrs) {
16
+ const local = localName(name);
17
+ if (local === 'theme') {
18
+ const colon = name.indexOf(':');
19
+ prefix = colon === -1 ? '' : name.slice(0, colon + 1);
20
+ return;
21
+ }
22
+ if (local === 'clrScheme' || local === 'fontScheme') {
23
+ container = local;
24
+ return;
25
+ }
26
+ if (container === 'clrScheme') {
27
+ if (isThemeColorSlot(local)) {
28
+ slot = local;
29
+ }
30
+ else if (slot !== undefined && COLOR_ELEMENTS.has(local)) {
31
+ const value = local === 'sysClr' ? attrs.lastClr : attrs.val;
32
+ if (value !== undefined && isThemeRgb(value))
33
+ colors[slot] = value.toUpperCase();
34
+ elements[slot] = startTag(name, attrs, true);
35
+ slot = undefined;
36
+ }
37
+ return;
38
+ }
39
+ if (container === 'fontScheme') {
40
+ if (local === 'majorFont')
41
+ fontSlot = 'major';
42
+ else if (local === 'minorFont')
43
+ fontSlot = 'minor';
44
+ else if (local === 'latin' && fontSlot !== undefined && attrs.typeface !== undefined) {
45
+ fonts[fontSlot] ??= attrs.typeface;
46
+ }
47
+ }
48
+ },
49
+ onClose(name) {
50
+ const local = localName(name);
51
+ if (local === 'clrScheme' || local === 'fontScheme') {
52
+ container = undefined;
53
+ slot = undefined;
54
+ fontSlot = undefined;
55
+ }
56
+ else if (local === 'majorFont' || local === 'minorFont') {
57
+ fontSlot = undefined;
58
+ }
59
+ else if (slot !== undefined && local === slot) {
60
+ slot = undefined;
61
+ }
62
+ },
63
+ });
9
64
  const scheme = {};
10
- for (const match of (block[1] ?? '').matchAll(SCHEME_SLOT)) {
11
- const slot = match[1];
12
- if (slot === undefined || !isThemeColorSlot(slot))
13
- continue;
14
- const attrs = match[3] ?? '';
15
- const source = match[2] === 'sysClr' ? /\blastClr="([^"]*)"/ : /\bval="([^"]*)"/;
16
- const value = source.exec(attrs)?.[1];
17
- if (value !== undefined && /^[0-9a-fA-F]{6}$/.test(value))
18
- scheme[slot] = value;
19
- }
20
- return scheme;
65
+ if (fonts.major !== undefined)
66
+ scheme.major = fonts.major;
67
+ if (fonts.minor !== undefined)
68
+ scheme.minor = fonts.minor;
69
+ return { colors, elements, fonts: scheme, prefix };
70
+ }
71
+ export function parseThemeColorScheme(themeXml) {
72
+ return readThemeScheme(themeXml).colors;
21
73
  }
22
74
  export function parseThemeFontScheme(themeXml) {
23
- const block = /<a:fontScheme\b[^>]*>([\s\S]*?)<\/a:fontScheme>/.exec(themeXml);
24
- if (block === null)
25
- return {};
26
- const face = (which) => {
27
- const font = new RegExp(`<a:${which}\\b[^>]*>([\\s\\S]*?)</a:${which}>`).exec(block[1] ?? '');
28
- const typeface = /<a:latin\b[^>]*\btypeface="([^"]*)"/.exec(font?.[1] ?? '')?.[1];
29
- return typeface === undefined ? undefined : decodeEntities(typeface);
30
- };
31
- const scheme = {};
32
- const major = face('majorFont');
33
- const minor = face('minorFont');
34
- if (major !== undefined)
35
- scheme.major = major;
36
- if (minor !== undefined)
37
- scheme.minor = minor;
38
- return scheme;
75
+ return readThemeScheme(themeXml).fonts;
76
+ }
77
+ export function parseThemeSchemes(themeXml) {
78
+ const { colors, fonts } = readThemeScheme(themeXml);
79
+ return { colors, fonts };
39
80
  }
40
81
  const SCHEME_ELEMENT_ORDER = [
41
82
  'dk1',
@@ -52,49 +93,43 @@ const SCHEME_ELEMENT_ORDER = [
52
93
  'folHlink',
53
94
  ];
54
95
  export function applyThemeOverrides(baseXml, overrides) {
55
- let xml = baseXml;
96
+ const { elements: sourceElements, prefix } = readThemeScheme(baseXml);
97
+ const edits = [];
56
98
  const colors = overrides.colors ?? {};
57
99
  if (Object.keys(colors).length > 0) {
58
- const sourceElements = parseThemeColorElements(baseXml);
59
- const body = SCHEME_ELEMENT_ORDER.map((slot) => {
60
- const authored = colors[slot];
61
- const inner = authored !== undefined
62
- ? `<a:srgbClr val="${normalizeThemeColor(authored)}"/>`
63
- : (sourceElements[slot] ?? `<a:srgbClr val="${DEFAULT_THEME_COLOR_SCHEME[slot]}"/>`);
64
- return `<a:${slot}>${inner}</a:${slot}>`;
65
- }).join('');
66
- xml = replaceBlockBody(xml, 'clrScheme', body);
100
+ const scheme = elementRange(baseXml, ['clrScheme']);
101
+ if (scheme !== undefined) {
102
+ const body = SCHEME_ELEMENT_ORDER.map((slot) => {
103
+ const authored = colors[slot];
104
+ const inner = authored !== undefined
105
+ ? `<${prefix}srgbClr val="${authored}"/>`
106
+ : (sourceElements[slot] ??
107
+ `<${prefix}srgbClr val="${DEFAULT_THEME_COLOR_SCHEME[slot]}"/>`);
108
+ return `<${prefix}${slot}>${inner}</${prefix}${slot}>`;
109
+ }).join('');
110
+ edits.push({ start: scheme.contentStart, end: scheme.contentEnd, text: body });
111
+ }
67
112
  }
68
113
  const { major, minor } = overrides.fonts ?? {};
114
+ const latin = (which, typeface) => {
115
+ const found = elementRange(baseXml, [which, 'latin']);
116
+ if (found === undefined)
117
+ return;
118
+ edits.push({
119
+ start: found.start,
120
+ end: found.end,
121
+ text: startTag(found.name, { ...found.attrs, typeface }, true),
122
+ });
123
+ };
69
124
  if (major !== undefined)
70
- xml = replaceLatinTypeface(xml, 'majorFont', major);
125
+ latin('majorFont', major);
71
126
  if (minor !== undefined)
72
- xml = replaceLatinTypeface(xml, 'minorFont', minor);
73
- return xml;
74
- }
75
- function parseThemeColorElements(themeXml) {
76
- const block = /<a:clrScheme\b[^>]*>([\s\S]*?)<\/a:clrScheme>/.exec(themeXml);
77
- if (block === null)
78
- return {};
79
- const elements = {};
80
- const pattern = /<a:(dk1|lt1|dk2|lt2|accent[1-6]|hlink|folHlink)>([\s\S]*?)<\/a:\1>|<a:(dk1|lt1|dk2|lt2|accent[1-6]|hlink|folHlink)\/>/g;
81
- for (const match of (block[1] ?? '').matchAll(pattern)) {
82
- const slot = match[1] ?? match[3];
83
- if (slot === undefined || !isThemeColorSlot(slot))
84
- continue;
85
- const inner = match[2];
86
- if (inner !== undefined && inner !== '')
87
- elements[slot] = inner;
127
+ latin('minorFont', minor);
128
+ let xml = baseXml;
129
+ for (const edit of edits.sort((a, b) => b.start - a.start)) {
130
+ xml = xml.slice(0, edit.start) + edit.text + xml.slice(edit.end);
88
131
  }
89
- return elements;
90
- }
91
- function replaceBlockBody(xml, name, body) {
92
- const pattern = new RegExp(`(<a:${name}\\b[^>]*>)[\\s\\S]*?(</a:${name}>)`);
93
- return xml.replace(pattern, (_all, open, close) => `${open}${body}${close}`);
94
- }
95
- function replaceLatinTypeface(xml, which, typeface) {
96
- const pattern = new RegExp(`(<a:${which}\\b[^>]*>[\\s\\S]*?<a:latin\\b)[^>]*(/>)`);
97
- return xml.replace(pattern, (_all, open, close) => `${open} typeface="${escapeAttr(typeface)}"${close}`);
132
+ return xml;
98
133
  }
99
134
  export const DEFAULT_THEME_XML = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n' +
100
135
  '<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme">' +
@@ -1,14 +1,12 @@
1
1
  import { type CommentThread, type MentionRef, type Person } from '../../core/comment-thread.ts';
2
- /** A registered author of threaded comments: one `<person>` of `xl/persons/person.xml`. */
3
- export interface ParsedPerson {
4
- /** Brace-wrapped GUID a message's `personId` points at. */
5
- readonly id: string;
6
- readonly displayName: string;
7
- /** Identity-provider handle, `S::<email>::<tenant-guid>` for an AzureAD account. */
8
- readonly userId?: string;
9
- /** Identity provider, e.g. `AD`. */
10
- readonly providerId?: string;
11
- }
2
+ /**
3
+ * A registered author of threaded comments: one `<person>` of `xl/persons/person.xml`, which is the
4
+ * model's own {@link Person} with nothing added. Declared as an alias for the same reason
5
+ * {@link ParsedMention} is: this file's write half already emits `Person` directly, so re-declaring
6
+ * the four fields here made one feature module name one shape two ways, with nothing keeping the two
7
+ * in step.
8
+ */
9
+ export type ParsedPerson = Person;
12
10
  /**
13
11
  * One `<mention>` of a message's `<mentions>` block: the model's own {@link MentionRef}, which is
14
12
  * exactly the four wire attributes with nothing resolved yet. Declaring it a second time here would
@@ -80,8 +78,13 @@ export declare function buildCommentThreads(messages: readonly ParsedThreadedCom
80
78
  *
81
79
  * A thread with no messages writes nothing: it has neither text to say nor a head id for its replies and
82
80
  * its legacy fallback to hang off.
81
+ *
82
+ * A message with no author is written under the null GUID, Excel's own spelling for one. `personById` is
83
+ * the workbook's registry, and a message naming an id it does not hold is refused.
84
+ *
85
+ * @throws {AuthoringError} if a message's author is not a registered person.
83
86
  */
84
- export declare function threadedCommentsXml(threads: readonly CommentThread[]): string;
87
+ export declare function threadedCommentsXml(threads: readonly CommentThread[], personById: (id: string) => Person | undefined): string;
85
88
  /**
86
89
  * Serialise the workbook's identity registry into `xl/persons/person.xml`: singular and unnumbered,
87
90
  * unlike the per-sheet thread parts.
@@ -1,7 +1,9 @@
1
1
  import { encodeAddress, tryDecodeCellRef } from '../../core/address.js';
2
2
  import { MENTION_OFFSET_MAX, } from '../../core/comment-thread.js';
3
+ import { AuthoringError, quoted } from '../../errors.js';
4
+ import { decodeSpreadsheetText, numInteger } from '../../xml/xml-attrs.js';
3
5
  import { parseXml, TextCapture } from '../../xml/xml-read.js';
4
- import { boolStrict, decodeSpreadsheetText, localName, numInteger, } from '../../xml/xml-scan.js';
6
+ import { boolStrict, localName } from '../../xml/xml-scan.js';
5
7
  import { escapeAttr, escapeSpreadsheetText, textAttr, XML_DECLARATION } from '../../xml/xml.js';
6
8
  import { THREADED_COMMENTS_NS } from './namespaces.js';
7
9
  export function parsePersons(xml) {
@@ -131,8 +133,7 @@ function commentFrom(message, personById) {
131
133
  id: message.id,
132
134
  text: message.text,
133
135
  mentions: message.mentions.map((mention) => mentionOf(mention, personById)),
134
- ...(author !== undefined ? { author } : {}),
135
- ...(message.personId !== undefined ? { personId: message.personId } : {}),
136
+ ...(author !== undefined ? { author, personId: author.id } : {}),
136
137
  ...(message.date !== undefined ? { date: message.date } : {}),
137
138
  };
138
139
  }
@@ -146,27 +147,34 @@ function mentionOf(mention, personById) {
146
147
  ...(mention.mentionId !== undefined ? { mentionId: mention.mentionId } : {}),
147
148
  };
148
149
  }
149
- export function threadedCommentsXml(threads) {
150
+ export function threadedCommentsXml(threads, personById) {
150
151
  const messages = threads.flatMap((thread) => {
151
152
  const [head, ...replies] = thread.comments;
152
153
  if (head === undefined)
153
154
  return [];
154
155
  return [
155
- threadedCommentXml(thread.ref, head, thread.resolved ? ' done="1"' : ''),
156
- ...replies.map((reply) => threadedCommentXml(thread.ref, reply, ` parentId="${escapeAttr(head.id)}"`)),
156
+ threadedCommentXml(thread.ref, head, thread.resolved ? ' done="1"' : '', personById),
157
+ ...replies.map((reply) => threadedCommentXml(thread.ref, reply, ` parentId="${escapeAttr(head.id)}"`, personById)),
157
158
  ];
158
159
  });
159
160
  return (XML_DECLARATION +
160
161
  `<ThreadedComments xmlns="${THREADED_COMMENTS_NS}">${messages.join('')}</ThreadedComments>`);
161
162
  }
162
- function threadedCommentXml(ref, comment, tail) {
163
+ function threadedCommentXml(ref, comment, tail, personById) {
163
164
  const date = textAttr('dT', comment.date);
164
- const person = textAttr('personId', comment.personId);
165
+ const personId = comment.personId ?? UNKNOWN_AUTHOR;
166
+ if (personId !== UNKNOWN_AUTHOR && personById(personId) === undefined) {
167
+ throw new AuthoringError(`cannot write the threaded comment ${quoted(comment.id)}: its author ${quoted(personId)} is not ` +
168
+ 'a registered person. Register it with Workbook.addPerson, or leave personId out for a ' +
169
+ 'comment with no recorded author');
170
+ }
171
+ const person = textAttr('personId', personId);
165
172
  return (`<threadedComment ref="${escapeAttr(ref)}"${date}${person} id="${escapeAttr(comment.id)}"${tail}>` +
166
173
  `<text>${escapeSpreadsheetText(comment.text)}</text>` +
167
174
  mentionsXml(comment.mentions) +
168
175
  '</threadedComment>');
169
176
  }
177
+ const UNKNOWN_AUTHOR = '{00000000-0000-0000-0000-000000000000}';
170
178
  function mentionsXml(mentions) {
171
179
  const entries = mentions.flatMap(({ personId, mentionId, startIndex, length }) => {
172
180
  if (mentionId === undefined)
@@ -1,12 +1,51 @@
1
1
  import type { Workbook, WorkbookProperties } from '../../core/workbook.ts';
2
- import type { PivotPlan, PreservedPartPlan, PreservedRootReferencePlan, PreservedWorkbookReferencePlan, TablePlan } from './package-plan.ts';
2
+ import type { PivotPlan, PlannedRelationship, PreservedPartPlan, PreservedWorkbookReferencePlan, TablePlan } from './package-plan.ts';
3
3
  export type PreservedWorkbookRel = PreservedWorkbookReferencePlan & {
4
4
  readonly relId: string;
5
5
  };
6
- export declare function contentTypesXml(sheetCount: number, tables: readonly TablePlan[], commentNumbers: readonly number[], drawingNumbers: readonly number[], printerSettingsNumbers: readonly number[], mediaExtensions: readonly string[], hasSharedStrings: boolean, preservedParts: readonly PreservedPartPlan[], pivots: readonly PivotPlan[], preservedWorkbookRefs: readonly PreservedWorkbookReferencePlan[], threadedCommentNumbers: readonly number[], hasPersons: boolean): string;
7
- export declare function rootRelsXml(rootRefs: readonly PreservedRootReferencePlan[]): string;
8
- export declare function workbookXml(workbook: Workbook, preservedRels: readonly PreservedWorkbookRel[], pivots: readonly PivotPlan[]): string;
9
- export declare const FIXED_WORKBOOK_REL_COUNT = 2;
10
- export declare function workbookRelsXml(sheetCount: number, hasSharedStrings: boolean, personsRelId: string | null, preservedRels: readonly PreservedWorkbookRel[], pivots: readonly PivotPlan[]): string;
6
+ /**
7
+ * The workbook part's relationships, recorded once by the writer's `planWorkbookRelationships`, with
8
+ * the ids the workbook body cites picked out of them.
9
+ *
10
+ * Declared here because the body is the consumer of the ids: it references them from `<sheet r:id>`.
11
+ * The body used to spell that reference `rId${i + 1}`, which agreed with the allocator only because
12
+ * sheets happen to be the first ids it hands out. Anything laid ahead of them would have re-pointed
13
+ * every sheet at the wrong part, and the package would have stayed schema-valid while doing it -- a
14
+ * class of corruption no validator catches and no round-trip through this library notices, because
15
+ * the reader resolves the same wrong ids consistently.
16
+ */
17
+ export interface WorkbookRelPlan {
18
+ readonly sheetRelIds: readonly string[];
19
+ readonly preservedWorkbookRels: readonly PreservedWorkbookRel[];
20
+ /** Every relationship the workbook's `.rels` part declares, in id order. */
21
+ readonly relationships: readonly PlannedRelationship[];
22
+ }
23
+ /**
24
+ * What `[Content_Types].xml` needs to know about a package: every part family it declares.
25
+ *
26
+ * One object rather than twelve positional parameters, eight of them arrays and four of those bare
27
+ * `readonly number[]`, which two adjacent ones could be silently transposed between. That is the same
28
+ * hazard `SheetReferences`, `SheetPlan` and `WorksheetXmlInputs` remove elsewhere in this writer, and
29
+ * it travels the whole way down: the two functions that render from this take it as it stands rather
30
+ * than re-scattering its fields across their own parameter lists.
31
+ */
32
+ export interface ContentTypeInputs {
33
+ readonly sheetCount: number;
34
+ readonly tables: readonly TablePlan[];
35
+ readonly commentNumbers: readonly number[];
36
+ readonly drawingNumbers: readonly number[];
37
+ readonly printerSettingsNumbers: readonly number[];
38
+ readonly mediaExtensions: readonly string[];
39
+ readonly hasSharedStrings: boolean;
40
+ readonly preservedParts: readonly PreservedPartPlan[];
41
+ readonly pivots: readonly PivotPlan[];
42
+ readonly preservedWorkbookRefs: readonly PreservedWorkbookReferencePlan[];
43
+ readonly threadedCommentNumbers: readonly number[];
44
+ readonly hasPersons: boolean;
45
+ readonly hasCellMetadata: boolean;
46
+ readonly hasRichValues: boolean;
47
+ }
48
+ export declare function contentTypesXml(inputs: ContentTypeInputs): string;
49
+ export declare function workbookXml(workbook: Workbook, plan: WorkbookRelPlan, pivots: readonly PivotPlan[]): string;
11
50
  export declare function corePropsXml(properties: WorkbookProperties): string;
12
51
  export declare function appPropsXml(properties: WorkbookProperties): string;