@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
@@ -0,0 +1,171 @@
1
+ import { XmlParseError } from '../../xml/errors.js';
2
+ import { NamespaceScope } from '../../xml/xml-namespaces.js';
3
+ import { tagRanges } from '../../xml/xml-read.js';
4
+ import { localName } from '../../xml/xml-scan.js';
5
+ import { startTag } from '../../xml/xml.js';
6
+ const STRICT = 'http://purl.oclc.org/ooxml/';
7
+ const TRANSITIONAL = 'http://schemas.openxmlformats.org/';
8
+ const NAMESPACES = new Map([
9
+ 'drawingml/chart drawingml/2006/chart',
10
+ 'drawingml/chartDrawing drawingml/2006/chartDrawing',
11
+ 'drawingml/diagram drawingml/2006/diagram',
12
+ 'drawingml/lockedCanvas drawingml/2006/lockedCanvas',
13
+ 'drawingml/main drawingml/2006/main',
14
+ 'drawingml/picture drawingml/2006/picture',
15
+ 'drawingml/spreadsheetDrawing drawingml/2006/spreadsheetDrawing',
16
+ 'drawingml/wordprocessingDrawing drawingml/2006/wordprocessingDrawing',
17
+ 'officeDocument/bibliography officeDocument/2006/bibliography',
18
+ 'officeDocument/characteristics officeDocument/2006/characteristics',
19
+ 'officeDocument/customProperties officeDocument/2006/custom-properties',
20
+ 'officeDocument/customXml officeDocument/2006/customXml',
21
+ 'officeDocument/docPropsVTypes officeDocument/2006/docPropsVTypes',
22
+ 'officeDocument/extendedProperties officeDocument/2006/extended-properties',
23
+ 'officeDocument/math officeDocument/2006/math',
24
+ 'officeDocument/relationships officeDocument/2006/relationships',
25
+ 'officeDocument/sharedTypes officeDocument/2006/sharedTypes',
26
+ 'presentationml/main presentationml/2006/main',
27
+ 'schemaLibrary/main schemaLibrary/2006/main',
28
+ 'spreadsheetml/main spreadsheetml/2006/main',
29
+ 'wordprocessingml/main wordprocessingml/2006/main',
30
+ ].map((pair) => {
31
+ const [strict, transitional] = pair.split(' ');
32
+ return [`${STRICT}${strict}`, `${TRANSITIONAL}${transitional}`];
33
+ }));
34
+ const DRAWINGML = `${TRANSITIONAL}drawingml/2006/main`;
35
+ const PERCENTAGES = new Map([
36
+ [
37
+ DRAWINGML,
38
+ percentageTable(1000, {
39
+ a: 'alphaRepl',
40
+ amt: 'alphaModFix tint',
41
+ b: 'fillRect fillToRect scrgbClr srcRect tileRect',
42
+ baseline: 'defRPr endParaRPr rPr',
43
+ bright: 'lum',
44
+ contrast: 'lum',
45
+ d: 'ds',
46
+ endA: 'reflection',
47
+ endPos: 'reflection',
48
+ fontScale: 'normAutofit',
49
+ g: 'scrgbClr',
50
+ l: 'fillRect fillToRect srcRect tileRect',
51
+ lim: 'miter',
52
+ lnSpcReduction: 'normAutofit',
53
+ lum: 'hsl hslClr',
54
+ pos: 'gs',
55
+ r: 'fillRect fillToRect scrgbClr srcRect tileRect',
56
+ sat: 'hsl hslClr',
57
+ sp: 'ds',
58
+ stA: 'reflection',
59
+ stPos: 'reflection',
60
+ sx: 'outerShdw reflection tile xfrm',
61
+ sy: 'outerShdw reflection tile xfrm',
62
+ t: 'fillRect fillToRect srcRect tileRect',
63
+ thresh: 'alphaBiLevel biLevel',
64
+ tx: 'relOff',
65
+ ty: 'relOff',
66
+ val: 'alpha alphaMod alphaOff blue blueMod blueOff green greenMod greenOff hueMod lum lumMod ' +
67
+ 'lumOff red redMod redOff sat satMod satOff shade spcPct tint',
68
+ zoom: 'camera',
69
+ }),
70
+ ],
71
+ [
72
+ `${TRANSITIONAL}drawingml/2006/chart`,
73
+ percentageTable(1, {
74
+ val: 'bubbleScale depthPercent gapDepth gapWidth hPercent holeSize lblOffset overlap ' +
75
+ 'secondPieSize thickness',
76
+ }),
77
+ ],
78
+ [
79
+ `${TRANSITIONAL}drawingml/2006/diagram`,
80
+ percentageTable(1000, Object.fromEntries([
81
+ 'custLinFactNeighborX',
82
+ 'custLinFactNeighborY',
83
+ 'custLinFactX',
84
+ 'custLinFactY',
85
+ 'custRadScaleInc',
86
+ 'custRadScaleRad',
87
+ 'custScaleX',
88
+ 'custScaleY',
89
+ ].map((attribute) => [attribute, 'prSet']))),
90
+ ],
91
+ ]);
92
+ function percentageTable(scale, elementsByAttribute) {
93
+ const pairs = Object.entries(elementsByAttribute).flatMap(([attribute, elements]) => elements.split(' ').map((element) => `${element} ${attribute}`));
94
+ return { scale, pairs: new Set(pairs) };
95
+ }
96
+ const PERCENTAGE = /^-?[0-9]+(?:\.[0-9]+)?%$/;
97
+ const STRICT_BYTES = new TextEncoder().encode(STRICT);
98
+ export function transitionalPart(bytes, contentType) {
99
+ if (!isXmlContentType(contentType) || !includesBytes(bytes, STRICT_BYTES))
100
+ return bytes;
101
+ const source = new TextDecoder().decode(bytes);
102
+ let xml = '';
103
+ let copied = 0;
104
+ const scope = new NamespaceScope();
105
+ try {
106
+ for (const tag of tagRanges(source)) {
107
+ if (tag.close) {
108
+ scope.close();
109
+ continue;
110
+ }
111
+ scope.open(tag.attrs);
112
+ const translated = translatedAttributes(tag.name, tag.attrs, scope);
113
+ if (tag.selfClosing)
114
+ scope.close();
115
+ if (translated === undefined)
116
+ continue;
117
+ xml += source.slice(copied, tag.start) + startTag(tag.name, translated, tag.selfClosing);
118
+ copied = tag.end;
119
+ }
120
+ }
121
+ catch (error) {
122
+ if (error instanceof XmlParseError)
123
+ return bytes;
124
+ throw error;
125
+ }
126
+ return copied === 0 ? bytes : new TextEncoder().encode(xml + source.slice(copied));
127
+ }
128
+ function translatedAttributes(name, attrs, scope) {
129
+ let translated;
130
+ const set = (attribute, value) => {
131
+ translated ??= { ...attrs };
132
+ translated[attribute] = value;
133
+ };
134
+ const declared = scope.elementNamespace(name);
135
+ const namespace = (declared === undefined ? undefined : NAMESPACES.get(declared)) ?? declared;
136
+ const local = localName(name);
137
+ const percentages = PERCENTAGES.get(namespace ?? '');
138
+ for (const attribute in attrs) {
139
+ const value = attrs[attribute] ?? '';
140
+ if (attribute === 'xmlns' || attribute.startsWith('xmlns:')) {
141
+ const uri = NAMESPACES.get(value);
142
+ if (uri !== undefined)
143
+ set(attribute, uri);
144
+ }
145
+ else if (attribute === 'uri' && local === 'graphicData' && namespace === DRAWINGML) {
146
+ const uri = NAMESPACES.get(value);
147
+ if (uri !== undefined)
148
+ set(attribute, uri);
149
+ }
150
+ else if (percentages?.pairs.has(`${local} ${attribute}`) === true && PERCENTAGE.test(value)) {
151
+ set(attribute, String(Math.round(Number.parseFloat(value) * percentages.scale)));
152
+ }
153
+ }
154
+ return translated;
155
+ }
156
+ function isXmlContentType(contentType) {
157
+ const type = contentType.toLowerCase();
158
+ return type.endsWith('+xml') || type === 'application/xml' || type === 'text/xml';
159
+ }
160
+ function includesBytes(haystack, needle) {
161
+ const [first = 0] = needle;
162
+ const last = haystack.length - needle.length;
163
+ for (let i = haystack.indexOf(first); i !== -1 && i <= last; i = haystack.indexOf(first, i + 1)) {
164
+ let matched = 1;
165
+ while (matched < needle.length && haystack[i + matched] === needle[matched])
166
+ matched += 1;
167
+ if (matched === needle.length)
168
+ return true;
169
+ }
170
+ return false;
171
+ }
@@ -0,0 +1,41 @@
1
+ import { type Alignment, type Border, type Fill, type Protection } from '../../core/style.ts';
2
+ import type { DifferentialStyle } from '../../core/workbook-styles.ts';
3
+ export declare const CUSTOM_NUMFMT_BASE = 164;
4
+ export declare const DEFAULT_FONT_BODY = "<sz val=\"11\"/><color theme=\"1\"/><name val=\"Calibri\"/><family val=\"2\"/><scheme val=\"minor\"/>";
5
+ export declare const DEFAULT_BORDER = "<border><left/><right/><top/><bottom/><diagonal/></border>";
6
+ export interface CellFormat {
7
+ readonly fillId: number;
8
+ readonly numFmtId: number;
9
+ readonly fontId: number;
10
+ readonly borderId: number;
11
+ readonly alignment: string;
12
+ readonly protection: string;
13
+ readonly quotePrefix: boolean;
14
+ readonly xfId: number;
15
+ }
16
+ export declare const DEFAULT_FORMAT: CellFormat;
17
+ export declare function formatSignature(format: CellFormat): string;
18
+ /**
19
+ * Whether a format is the do-nothing default: no facet, General number format, no quote prefix, and
20
+ * linked to the Normal named style. Such a cellXfs entry adds nothing, so its owner needs no `s`.
21
+ *
22
+ * Asked of the signature rather than field by field, because the two questions have to be answered
23
+ * from the same field set and both answer silently when they are not. A facet the signature forgets
24
+ * makes two distinct formats intern to one entry, and every cell carrying the facet quietly loses it;
25
+ * a facet *this* forgets forces a spurious entry and an `s` attribute onto every cell in the book.
26
+ * Neither is a type error, and neither is visible in the file until someone compares two of them.
27
+ */
28
+ export declare function isDefaultFormat(format: CellFormat): boolean;
29
+ export declare function xfXml(format: CellFormat, xfId: number | null): string;
30
+ export declare function cellStyleTag(entry: {
31
+ name: string;
32
+ builtinId?: number;
33
+ xfId: number;
34
+ }): string;
35
+ export declare function alignmentAttrs(alignment: Alignment): string;
36
+ export declare function protectionAttrs(protection: Protection): string;
37
+ export declare function dxfXml(style: DifferentialStyle): string;
38
+ export declare function borderXml(border: Border): string;
39
+ export declare function patternFillXml(fill: Fill, { solidBgFallback }: {
40
+ solidBgFallback: boolean;
41
+ }): string;
@@ -0,0 +1,136 @@
1
+ import { ALIGNMENT_FACETS, isBorderStyle, isFillPatternType, } from '../../core/style.js';
2
+ import { checkedToken, escapeAttr, escapeFormatCode, nonDefaultNumAttr, numberText, } from '../../xml/xml.js';
3
+ import { colorAttrs } from './color-xml.js';
4
+ import { fontXml } from './font-xml.js';
5
+ export const CUSTOM_NUMFMT_BASE = 164;
6
+ export const DEFAULT_FONT_BODY = '<sz val="11"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/>';
7
+ export const DEFAULT_BORDER = '<border><left/><right/><top/><bottom/><diagonal/></border>';
8
+ export const DEFAULT_FORMAT = {
9
+ fillId: 0,
10
+ numFmtId: 0,
11
+ fontId: 0,
12
+ borderId: 0,
13
+ alignment: '',
14
+ protection: '',
15
+ quotePrefix: false,
16
+ xfId: 0,
17
+ };
18
+ export function formatSignature(format) {
19
+ return (`fill:${format.fillId}|numFmt:${format.numFmtId}|font:${format.fontId}|border:${format.borderId}|` +
20
+ `align:${format.alignment}|protect:${format.protection}|quote:${format.quotePrefix}|xfId:${format.xfId}`);
21
+ }
22
+ const DEFAULT_FORMAT_SIGNATURE = formatSignature(DEFAULT_FORMAT);
23
+ export function isDefaultFormat(format) {
24
+ return formatSignature(format) === DEFAULT_FORMAT_SIGNATURE;
25
+ }
26
+ export function xfXml(format, xfId) {
27
+ const applyNumberFormat = format.numFmtId !== 0 ? ' applyNumberFormat="1"' : '';
28
+ const applyFont = format.fontId !== 0 ? ' applyFont="1"' : '';
29
+ const applyFill = format.fillId !== 0 ? ' applyFill="1"' : '';
30
+ const applyBorder = format.borderId !== 0 ? ' applyBorder="1"' : '';
31
+ const applyAlignment = format.alignment !== '' ? ' applyAlignment="1"' : '';
32
+ const applyProtection = format.protection !== '' ? ' applyProtection="1"' : '';
33
+ const quotePrefix = format.quotePrefix ? ' quotePrefix="1"' : '';
34
+ const xfIdAttr = xfId === null ? '' : ` xfId="${xfId}"`;
35
+ const open = `<xf numFmtId="${format.numFmtId}" fontId="${format.fontId}" fillId="${format.fillId}" ` +
36
+ `borderId="${format.borderId}"${xfIdAttr}${quotePrefix}` +
37
+ `${applyNumberFormat}${applyFont}${applyFill}${applyBorder}${applyAlignment}${applyProtection}`;
38
+ const body = (format.alignment === '' ? '' : `<alignment ${format.alignment}/>`) +
39
+ (format.protection === '' ? '' : `<protection ${format.protection}/>`);
40
+ return body === '' ? `${open}/>` : `${open}>${body}</xf>`;
41
+ }
42
+ export function cellStyleTag(entry) {
43
+ const builtin = entry.builtinId === undefined ? '' : ` builtinId="${entry.builtinId}"`;
44
+ return `<cellStyle name="${escapeAttr(entry.name)}" xfId="${entry.xfId}"${builtin}/>`;
45
+ }
46
+ export function alignmentAttrs(alignment) {
47
+ const parts = [];
48
+ for (const facet of ALIGNMENT_FACETS) {
49
+ switch (facet.kind) {
50
+ case 'token': {
51
+ const value = alignment[facet.key];
52
+ if (value === undefined || value === facet.omit)
53
+ break;
54
+ parts.push(`${facet.key}="${checkedToken(value, facet.isValid, facet.label)}"`);
55
+ break;
56
+ }
57
+ case 'number': {
58
+ const attr = nonDefaultNumAttr(facet.key, alignment[facet.key], 0);
59
+ if (attr !== '')
60
+ parts.push(attr.trimStart());
61
+ break;
62
+ }
63
+ case 'flag':
64
+ if (alignment[facet.key])
65
+ parts.push(`${facet.key}="1"`);
66
+ break;
67
+ }
68
+ }
69
+ return parts.join(' ');
70
+ }
71
+ export function protectionAttrs(protection) {
72
+ const parts = [];
73
+ if (protection.locked === false)
74
+ parts.push('locked="0"');
75
+ if (protection.hidden === true)
76
+ parts.push('hidden="1"');
77
+ return parts.join(' ');
78
+ }
79
+ export function dxfXml(style) {
80
+ const parts = [];
81
+ if (style.font !== undefined) {
82
+ const font = fontXml(style.font);
83
+ if (font !== '')
84
+ parts.push(`<font>${font}</font>`);
85
+ }
86
+ if (typeof style.numFmt === 'string' && style.numFmt !== '') {
87
+ parts.push(`<numFmt numFmtId="${CUSTOM_NUMFMT_BASE}" formatCode="${escapeFormatCode(style.numFmt)}"/>`);
88
+ }
89
+ if (style.fill !== undefined)
90
+ parts.push(patternFillXml(style.fill, { solidBgFallback: false }));
91
+ if (style.border !== undefined)
92
+ parts.push(borderXml(style.border));
93
+ return `<dxf>${parts.join('')}</dxf>`;
94
+ }
95
+ function gradientFillXml(fill) {
96
+ const attrs = (fill.gradient === 'path' ? ' type="path"' : '') +
97
+ nonDefaultNumAttr('degree', fill.degree, 0) +
98
+ nonDefaultNumAttr('left', fill.left, 0) +
99
+ nonDefaultNumAttr('right', fill.right, 0) +
100
+ nonDefaultNumAttr('top', fill.top, 0) +
101
+ nonDefaultNumAttr('bottom', fill.bottom, 0);
102
+ const stops = fill.stops
103
+ .map((stop) => `<stop position="${numberText(stop.position)}"><color ${colorAttrs(stop.color)}/></stop>`)
104
+ .join('');
105
+ return `<gradientFill${attrs}>${stops}</gradientFill>`;
106
+ }
107
+ export function borderXml(border) {
108
+ const attrs = (border.diagonalUp ? ' diagonalUp="1"' : '') + (border.diagonalDown ? ' diagonalDown="1"' : '');
109
+ return (`<border${attrs}>` +
110
+ edgeXml('left', border.left) +
111
+ edgeXml('right', border.right) +
112
+ edgeXml('top', border.top) +
113
+ edgeXml('bottom', border.bottom) +
114
+ edgeXml('diagonal', border.diagonal) +
115
+ '</border>');
116
+ }
117
+ function edgeXml(tag, edge) {
118
+ if (edge === undefined)
119
+ return `<${tag}/>`;
120
+ const style = checkedToken(edge.style, isBorderStyle, 'border style');
121
+ if (edge.color === undefined)
122
+ return `<${tag} style="${style}"/>`;
123
+ return `<${tag} style="${style}"><color ${colorAttrs(edge.color)}/></${tag}>`;
124
+ }
125
+ export function patternFillXml(fill, { solidBgFallback }) {
126
+ if (fill.type === 'gradient')
127
+ return `<fill>${gradientFillXml(fill)}</fill>`;
128
+ const fg = fill.fgColor ? `<fgColor ${colorAttrs(fill.fgColor)}/>` : '';
129
+ const bg = fill.bgColor
130
+ ? `<bgColor ${colorAttrs(fill.bgColor)}/>`
131
+ : solidBgFallback && fill.pattern === 'solid'
132
+ ? '<bgColor indexed="64"/>'
133
+ : '';
134
+ const pattern = checkedToken(fill.pattern, isFillPatternType, 'fill pattern');
135
+ return `<fill><patternFill patternType="${pattern}">${fg}${bg}</patternFill></fill>`;
136
+ }
@@ -1,7 +1,9 @@
1
- import { type DifferentialStyle, type Font, type NamedCellStyle, type TableStyleTable } from '../../core/style.ts';
1
+ import { type Font } from '../../core/style.ts';
2
2
  import { type TableStyle } from '../../core/table-style.ts';
3
+ import type { DifferentialStyle, NamedCellStyle, TableStyleTable } from '../../core/workbook-styles.ts';
3
4
  import type { XfStyle } from '../style/xf-style.ts';
4
- /** What a {@link StyleRegistry} needs from its workbook before any style is interned. */
5
+ /** What a {@link StyleRegistry} needs from its workbook before any style is interned.
6
+ */
5
7
  export interface StyleRegistryOptions {
6
8
  /**
7
9
  * The font every cell naming none of its own renders in, emitted as id 0. Take it from
@@ -22,6 +24,14 @@ export interface StyleRegistryOptions {
22
24
  */
23
25
  readonly declaredDefaultFont?: Font;
24
26
  }
27
+ /**
28
+ * The interned style table one written package is built against: every distinct fill, number format,
29
+ * font, border and xf, each handed back as the stable index a cell's `s` attribute names.
30
+ *
31
+ * One workbook, one registry. The streaming writer is why that is worth saying: it interns a row's
32
+ * styles at the moment the row is flushed, long before `xl/styles.xml` is emitted, so the ids already
33
+ * baked into those rows are only correct if the very same registry emits the part.
34
+ */
25
35
  export declare class StyleRegistry {
26
36
  #private;
27
37
  constructor(options?: StyleRegistryOptions);
@@ -91,7 +101,11 @@ export declare class StyleRegistry {
91
101
  * keeps every preserved reference pointing where it did.
92
102
  */
93
103
  differentialStyleId(style: DifferentialStyle): number;
104
+ /**
105
+ * The `<dxf>` fragment at a differential-style index, or `undefined` past the end of the table: what
106
+ * a conditional format in the extension form writes inline, since that form names no `dxfId`.
107
+ */
108
+ differentialStyleFragment(id: number): string | undefined;
94
109
  /** Serialise the accumulated table into a complete, valid styles.xml part. */
95
110
  toXml(): string;
96
111
  }
97
- export declare function fontXml(font: Font, nameTag?: 'name' | 'rFont'): string;
@@ -1,25 +1,12 @@
1
- import { ALIGNMENT_FACETS, isBorderStyle, isFillPatternType, isFontScheme, isFontVerticalAlignment, isNamedUnderlineStyle, } from '../../core/style.js';
1
+ import {} from '../../core/style.js';
2
2
  import { TABLE_STYLE_ELEMENT_TYPES } from '../../core/table-style.js';
3
- import { decodeEntities } from '../../xml/xml-scan.js';
4
- import { assertRepresentable, checkedToken, escapeAttr, numberText, XML_DECLARATION, } from '../../xml/xml.js';
5
- import { colorAttrs } from './color-xml.js';
3
+ import { escapeAttr, escapeFormatCode, nonDefaultNumAttr, XML_DECLARATION } from '../../xml/xml.js';
4
+ import { fontXml } from './font-xml.js';
6
5
  import { MARKUP_COMPATIBILITY_NS, SPREADSHEETML_NS } from './namespaces.js';
6
+ import { alignmentAttrs, borderXml, cellStyleTag, CUSTOM_NUMFMT_BASE, DEFAULT_BORDER, DEFAULT_FONT_BODY, DEFAULT_FORMAT, dxfXml, formatSignature, isDefaultFormat, patternFillXml, protectionAttrs, xfXml, } from './style-elements.js';
7
7
  const RESERVED_FILL_COUNT = 2;
8
8
  const RESERVED_FONT_COUNT = 1;
9
- const CUSTOM_NUMFMT_BASE = 164;
10
9
  const RESERVED_BORDER_COUNT = 1;
11
- const DEFAULT_FONT_BODY = '<sz val="11"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/>';
12
- const DEFAULT_BORDER = '<border><left/><right/><top/><bottom/><diagonal/></border>';
13
- const DEFAULT_FORMAT = {
14
- fillId: 0,
15
- numFmtId: 0,
16
- fontId: 0,
17
- borderId: 0,
18
- alignment: '',
19
- protection: '',
20
- quotePrefix: false,
21
- xfId: 0,
22
- };
23
10
  class InternTable {
24
11
  #entries = [];
25
12
  #idByKey = new Map();
@@ -137,7 +124,7 @@ export class StyleRegistry {
137
124
  const element = style.elements[type];
138
125
  if (element === undefined)
139
126
  return [];
140
- const size = element.size !== undefined && element.size !== 1 ? ` size="${element.size}"` : '';
127
+ const size = nonDefaultNumAttr('size', element.size, 1);
141
128
  return [
142
129
  `<tableStyleElement type="${type}"${size} dxfId="${this.differentialStyleId(element)}"/>`,
143
130
  ];
@@ -150,8 +137,12 @@ export class StyleRegistry {
150
137
  const fragment = dxfXml(style);
151
138
  return this.#dxfs.intern(fragment, fragment);
152
139
  }
140
+ differentialStyleFragment(id) {
141
+ return this.#dxfs.entries[id];
142
+ }
153
143
  #internFill(fill) {
154
- return this.#fills.intern(fillSignature(fill), patternFillXml(fill, { solidBgFallback: true }));
144
+ const xml = patternFillXml(fill, { solidBgFallback: true });
145
+ return this.#fills.intern(xml, xml);
155
146
  }
156
147
  #internNumFmt(code) {
157
148
  return this.#numFmts.intern(code, code);
@@ -206,7 +197,9 @@ export class StyleRegistry {
206
197
  #tableStylesXml() {
207
198
  const { defaultTableStyle, defaultPivotStyle } = this.#tableStyles;
208
199
  const authored = this.#authoredTableStyles;
209
- const preserved = this.#tableStyles.styles.filter((fragment) => !authored.has(tableStyleName(fragment)));
200
+ const preserved = this.#tableStyles.styles
201
+ .filter((style) => !authored.has(style.name))
202
+ .map((style) => style.xml);
210
203
  const styles = [...preserved, ...authored.values()];
211
204
  if (styles.length === 0 && defaultTableStyle === undefined && defaultPivotStyle === undefined) {
212
205
  return '';
@@ -245,192 +238,3 @@ export class StyleRegistry {
245
238
  return `<numFmts count="${this.#numFmts.size}">${entries}</numFmts>`;
246
239
  }
247
240
  }
248
- function isDefaultFormat(format) {
249
- return (format.fillId === 0 &&
250
- format.numFmtId === 0 &&
251
- format.fontId === 0 &&
252
- format.borderId === 0 &&
253
- format.alignment === '' &&
254
- format.protection === '' &&
255
- !format.quotePrefix &&
256
- format.xfId === 0);
257
- }
258
- function formatSignature(format) {
259
- return (`fill:${format.fillId}|numFmt:${format.numFmtId}|font:${format.fontId}|border:${format.borderId}|` +
260
- `align:${format.alignment}|protect:${format.protection}|quote:${format.quotePrefix}|xfId:${format.xfId}`);
261
- }
262
- function xfXml(format, xfId) {
263
- const applyNumberFormat = format.numFmtId !== 0 ? ' applyNumberFormat="1"' : '';
264
- const applyFont = format.fontId !== 0 ? ' applyFont="1"' : '';
265
- const applyFill = format.fillId !== 0 ? ' applyFill="1"' : '';
266
- const applyBorder = format.borderId !== 0 ? ' applyBorder="1"' : '';
267
- const applyAlignment = format.alignment !== '' ? ' applyAlignment="1"' : '';
268
- const applyProtection = format.protection !== '' ? ' applyProtection="1"' : '';
269
- const quotePrefix = format.quotePrefix ? ' quotePrefix="1"' : '';
270
- const xfIdAttr = xfId === null ? '' : ` xfId="${xfId}"`;
271
- const open = `<xf numFmtId="${format.numFmtId}" fontId="${format.fontId}" fillId="${format.fillId}" ` +
272
- `borderId="${format.borderId}"${xfIdAttr}${quotePrefix}` +
273
- `${applyNumberFormat}${applyFont}${applyFill}${applyBorder}${applyAlignment}${applyProtection}`;
274
- const body = (format.alignment === '' ? '' : `<alignment ${format.alignment}/>`) +
275
- (format.protection === '' ? '' : `<protection ${format.protection}/>`);
276
- return body === '' ? `${open}/>` : `${open}>${body}</xf>`;
277
- }
278
- function cellStyleTag(entry) {
279
- const builtin = entry.builtinId === undefined ? '' : ` builtinId="${entry.builtinId}"`;
280
- return `<cellStyle name="${escapeAttr(entry.name)}" xfId="${entry.xfId}"${builtin}/>`;
281
- }
282
- function alignmentAttrs(alignment) {
283
- const parts = [];
284
- for (const facet of ALIGNMENT_FACETS) {
285
- switch (facet.kind) {
286
- case 'token': {
287
- const value = alignment[facet.key];
288
- if (value === undefined || value === facet.omit)
289
- break;
290
- parts.push(`${facet.key}="${checkedToken(value, facet.isValid, facet.label)}"`);
291
- break;
292
- }
293
- case 'number': {
294
- const value = alignment[facet.key];
295
- if (value === undefined || value === 0)
296
- break;
297
- parts.push(`${facet.key}="${numberText(value)}"`);
298
- break;
299
- }
300
- case 'flag':
301
- if (alignment[facet.key])
302
- parts.push(`${facet.key}="1"`);
303
- break;
304
- }
305
- }
306
- return parts.join(' ');
307
- }
308
- function protectionAttrs(protection) {
309
- const parts = [];
310
- if (protection.locked === false)
311
- parts.push('locked="0"');
312
- if (protection.hidden === true)
313
- parts.push('hidden="1"');
314
- return parts.join(' ');
315
- }
316
- function tableStyleName(fragment) {
317
- return decodeEntities(/<tableStyle\b[^>]*\bname="([^"]*)"/.exec(fragment)?.[1] ?? '');
318
- }
319
- export function fontXml(font, nameTag = 'name') {
320
- const parts = [];
321
- if (font.bold)
322
- parts.push('<b/>');
323
- if (font.italic)
324
- parts.push('<i/>');
325
- if (font.strike)
326
- parts.push('<strike/>');
327
- if (font.outline)
328
- parts.push('<outline/>');
329
- const underline = underlineXml(font.underline);
330
- if (underline !== '')
331
- parts.push(underline);
332
- if (font.vertAlign !== undefined) {
333
- parts.push(`<vertAlign val="${checkedToken(font.vertAlign, isFontVerticalAlignment, 'font vertical alignment')}"/>`);
334
- }
335
- if (font.size !== undefined)
336
- parts.push(`<sz val="${numberText(font.size)}"/>`);
337
- if (font.color !== undefined)
338
- parts.push(`<color ${colorAttrs(font.color)}/>`);
339
- if (font.name !== undefined)
340
- parts.push(`<${nameTag} val="${escapeAttr(font.name)}"/>`);
341
- if (font.family !== undefined)
342
- parts.push(`<family val="${numberText(font.family)}"/>`);
343
- if (font.charset !== undefined)
344
- parts.push(`<charset val="${numberText(font.charset)}"/>`);
345
- if (font.scheme !== undefined && font.scheme !== 'none')
346
- parts.push(`<scheme val="${checkedToken(font.scheme, isFontScheme, 'font scheme')}"/>`);
347
- return parts.join('');
348
- }
349
- function dxfXml(style) {
350
- const parts = [];
351
- if (style.font !== undefined) {
352
- const font = fontXml(style.font);
353
- if (font !== '')
354
- parts.push(`<font>${font}</font>`);
355
- }
356
- if (typeof style.numFmt === 'string' && style.numFmt !== '') {
357
- parts.push(`<numFmt numFmtId="${CUSTOM_NUMFMT_BASE}" formatCode="${escapeFormatCode(style.numFmt)}"/>`);
358
- }
359
- if (style.fill !== undefined)
360
- parts.push(patternFillXml(style.fill, { solidBgFallback: false }));
361
- if (style.border !== undefined)
362
- parts.push(borderXml(style.border));
363
- return `<dxf>${parts.join('')}</dxf>`;
364
- }
365
- function gradientFillXml(fill) {
366
- const attrs = (fill.gradient === 'path' ? ' type="path"' : '') +
367
- (fill.degree ? ` degree="${numberText(fill.degree)}"` : '') +
368
- insetAttr('left', fill.left) +
369
- insetAttr('right', fill.right) +
370
- insetAttr('top', fill.top) +
371
- insetAttr('bottom', fill.bottom);
372
- const stops = fill.stops
373
- .map((stop) => `<stop position="${numberText(stop.position)}"><color ${colorAttrs(stop.color)}/></stop>`)
374
- .join('');
375
- return `<gradientFill${attrs}>${stops}</gradientFill>`;
376
- }
377
- function insetAttr(name, value) {
378
- return value ? ` ${name}="${numberText(value)}"` : '';
379
- }
380
- function underlineXml(underline) {
381
- if (underline === undefined || underline === false || underline === 'none')
382
- return '';
383
- if (underline === true || underline === 'single')
384
- return '<u/>';
385
- return `<u val="${checkedToken(underline, isNamedUnderlineStyle, 'underline style')}"/>`;
386
- }
387
- function borderXml(border) {
388
- const attrs = (border.diagonalUp ? ' diagonalUp="1"' : '') + (border.diagonalDown ? ' diagonalDown="1"' : '');
389
- return (`<border${attrs}>` +
390
- edgeXml('left', border.left) +
391
- edgeXml('right', border.right) +
392
- edgeXml('top', border.top) +
393
- edgeXml('bottom', border.bottom) +
394
- edgeXml('diagonal', border.diagonal) +
395
- '</border>');
396
- }
397
- function edgeXml(tag, edge) {
398
- if (edge === undefined)
399
- return `<${tag}/>`;
400
- const style = checkedToken(edge.style, isBorderStyle, 'border style');
401
- if (edge.color === undefined)
402
- return `<${tag} style="${style}"/>`;
403
- return `<${tag} style="${style}"><color ${colorAttrs(edge.color)}/></${tag}>`;
404
- }
405
- function escapeFormatCode(code) {
406
- assertRepresentable(code);
407
- return code
408
- .replace(/&/g, '&amp;')
409
- .replace(/</g, '&lt;')
410
- .replace(/>/g, '&gt;')
411
- .replace(/"/g, '&quot;');
412
- }
413
- function fillSignature(fill) {
414
- if (fill.type === 'gradient') {
415
- const stops = fill.stops.map((s) => `${s.position}:${colorSignature(s.color)}`).join(',');
416
- return `grad|${fill.gradient}|${fill.degree ?? ''}|${fill.left ?? ''}/${fill.right ?? ''}/${fill.top ?? ''}/${fill.bottom ?? ''}|${stops}`;
417
- }
418
- return `${fill.pattern}|${colorSignature(fill.fgColor)}|${colorSignature(fill.bgColor)}`;
419
- }
420
- function colorSignature(color) {
421
- if (color === undefined)
422
- return '';
423
- return `${color.argb ?? ''}/${color.theme ?? ''}/${color.tint ?? ''}/${color.indexed ?? ''}`;
424
- }
425
- function patternFillXml(fill, { solidBgFallback }) {
426
- if (fill.type === 'gradient')
427
- return `<fill>${gradientFillXml(fill)}</fill>`;
428
- const fg = fill.fgColor ? `<fgColor ${colorAttrs(fill.fgColor)}/>` : '';
429
- const bg = fill.bgColor
430
- ? `<bgColor ${colorAttrs(fill.bgColor)}/>`
431
- : solidBgFallback && fill.pattern === 'solid'
432
- ? '<bgColor indexed="64"/>'
433
- : '';
434
- const pattern = checkedToken(fill.pattern, isFillPatternType, 'fill pattern');
435
- return `<fill><patternFill patternType="${pattern}">${fg}${bg}</patternFill></fill>`;
436
- }
@@ -1,9 +1,17 @@
1
1
  import { type Table, type TableOptions } from '../../core/table.ts';
2
- export declare function tableXml(table: Table, id: number): string;
2
+ /**
3
+ * The table part. A column's calculated and totals formulas are stored with the function prefixes a
4
+ * cell formula takes, as Excel stores them; `formulaNames` is `formulaNamesInScope` for the table's
5
+ * sheet.
6
+ */
7
+ export declare function tableXml(table: Table, id: number, formulaNames: ReadonlySet<string>): string;
3
8
  /**
4
9
  * Parse a `<table>` part into the options that reconstruct it, or `undefined` when the XML is not a
5
10
  * usable table (no name, no ref, or no columns: Excel treats such a part as corrupt, so we drop it
6
11
  * rather than fabricate a degenerate table). Duplicate column names are not resolved here, since the
7
12
  * {@link Table} constructor disambiguates them, so authoring and loading share one implementation.
13
+ *
14
+ * A column's formulas shed their function prefixes as a cell formula's do, against `definedNames`,
15
+ * the workbook's names as `definedNameKeys` spells them.
8
16
  */
9
- export declare function parseTable(xml: string): TableOptions | undefined;
17
+ export declare function parseTable(xml: string, definedNames: ReadonlySet<string>): TableOptions | undefined;