@shbernal/ts-xlsx 2.1.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/README.md +4 -1
  2. package/dist/bytes.d.ts +7 -0
  3. package/dist/bytes.js +22 -0
  4. package/dist/core/address.d.ts +60 -2
  5. package/dist/core/address.js +40 -24
  6. package/dist/core/autofilter.d.ts +5 -4
  7. package/dist/core/autofilter.js +34 -35
  8. package/dist/core/axis-handle.d.ts +10 -0
  9. package/dist/core/axis-handle.js +17 -0
  10. package/dist/core/cell.d.ts +25 -0
  11. package/dist/core/cell.js +9 -3
  12. package/dist/core/clone.d.ts +29 -0
  13. package/dist/core/clone.js +24 -0
  14. package/dist/core/color-resolution.js +2 -4
  15. package/dist/core/column.d.ts +5 -1
  16. package/dist/core/column.js +34 -35
  17. package/dist/core/comment-thread.js +2 -1
  18. package/dist/core/conditional-formatting-overlay.d.ts +2 -1
  19. package/dist/core/conditional-formatting-overlay.js +2 -2
  20. package/dist/core/conditional-formatting.d.ts +14 -6
  21. package/dist/core/conditional-formatting.js +45 -43
  22. package/dist/core/containers.d.ts +12 -0
  23. package/dist/core/containers.js +5 -0
  24. package/dist/core/data-validation-overlay.d.ts +2 -1
  25. package/dist/core/data-validation-overlay.js +4 -4
  26. package/dist/core/data-validation.d.ts +9 -3
  27. package/dist/core/data-validation.js +21 -18
  28. package/dist/core/date-format.d.ts +20 -0
  29. package/dist/core/date-format.js +160 -0
  30. package/dist/core/date.d.ts +43 -8
  31. package/dist/core/date.js +18 -2
  32. package/dist/core/formula.d.ts +26 -0
  33. package/dist/core/formula.js +20 -4
  34. package/dist/core/grid-edits.d.ts +2 -3
  35. package/dist/core/grid-edits.js +69 -70
  36. package/dist/core/grid-shift.d.ts +58 -9
  37. package/dist/core/grid-shift.js +26 -4
  38. package/dist/core/image.d.ts +14 -10
  39. package/dist/core/image.js +9 -9
  40. package/dist/core/internal.d.ts +8 -2
  41. package/dist/core/limits.d.ts +23 -0
  42. package/dist/core/limits.js +4 -0
  43. package/dist/core/merge-index.d.ts +31 -0
  44. package/dist/core/merge-index.js +60 -0
  45. package/dist/core/merge.d.ts +5 -14
  46. package/dist/core/merge.js +18 -27
  47. package/dist/core/page-setup.d.ts +72 -2
  48. package/dist/core/page-setup.js +34 -8
  49. package/dist/core/pivot-table.d.ts +1 -1
  50. package/dist/core/pivot-table.js +67 -53
  51. package/dist/core/protection.js +2 -11
  52. package/dist/core/range.js +34 -30
  53. package/dist/core/row-input.js +2 -2
  54. package/dist/core/row.d.ts +5 -1
  55. package/dist/core/row.js +22 -23
  56. package/dist/core/style.d.ts +134 -75
  57. package/dist/core/style.js +112 -53
  58. package/dist/core/table-style.d.ts +1 -1
  59. package/dist/core/table-style.js +4 -4
  60. package/dist/core/table.d.ts +28 -10
  61. package/dist/core/table.js +54 -39
  62. package/dist/core/theme.js +6 -5
  63. package/dist/core/used-extent.d.ts +44 -0
  64. package/dist/core/used-extent.js +102 -0
  65. package/dist/core/value.d.ts +9 -0
  66. package/dist/core/value.js +36 -34
  67. package/dist/core/workbook-media.d.ts +34 -0
  68. package/dist/core/workbook-media.js +44 -0
  69. package/dist/core/workbook-styles.d.ts +67 -1
  70. package/dist/core/workbook-vba.js +3 -2
  71. package/dist/core/workbook.d.ts +23 -2
  72. package/dist/core/workbook.js +24 -40
  73. package/dist/core/worksheet-comments.d.ts +2 -1
  74. package/dist/core/worksheet-comments.js +20 -13
  75. package/dist/core/worksheet-merges.d.ts +44 -0
  76. package/dist/core/worksheet-merges.js +59 -0
  77. package/dist/core/worksheet-model.d.ts +9 -1
  78. package/dist/core/worksheet-model.js +24 -9
  79. package/dist/core/worksheet.d.ts +72 -12
  80. package/dist/core/worksheet.js +68 -70
  81. package/dist/customui/ribbon.js +6 -7
  82. package/dist/entries/core.d.ts +18 -13
  83. package/dist/entries/core.js +12 -6
  84. package/dist/entries/xlsx.d.ts +1 -1
  85. package/dist/errors.d.ts +64 -0
  86. package/dist/errors.js +22 -0
  87. package/dist/hex.d.ts +8 -0
  88. package/dist/hex.js +3 -0
  89. package/dist/io/csv/delimiter.d.ts +9 -0
  90. package/dist/io/csv/delimiter.js +6 -0
  91. package/dist/io/csv/read.js +11 -4
  92. package/dist/io/csv/write.d.ts +9 -2
  93. package/dist/io/csv/write.js +9 -38
  94. package/dist/io/opc/inflate.js +15 -1
  95. package/dist/io/opc/namespaces.d.ts +16 -0
  96. package/dist/io/opc/namespaces.js +4 -0
  97. package/dist/io/opc/part-paths.d.ts +10 -0
  98. package/dist/io/opc/part-paths.js +16 -1
  99. package/dist/io/opc/read-opc.d.ts +69 -10
  100. package/dist/io/opc/read-opc.js +49 -55
  101. package/dist/io/opc/read-options.d.ts +5 -1
  102. package/dist/io/opc/rels.d.ts +1 -6
  103. package/dist/io/opc/rels.js +1 -4
  104. package/dist/io/opc/sniff-format.d.ts +3 -3
  105. package/dist/io/opc/sniff-format.js +2 -2
  106. package/dist/io/style/xf-style.d.ts +48 -2
  107. package/dist/io/style/xf-style.js +14 -0
  108. package/dist/io/xlsb/formula.d.ts +2 -2
  109. package/dist/io/xlsb/formula.js +49 -34
  110. package/dist/io/xlsb/primitives.js +8 -14
  111. package/dist/io/xlsb/ptg-functions.d.ts +19 -10
  112. package/dist/io/xlsb/ptg-functions.js +385 -596
  113. package/dist/io/xlsb/read-styles.js +50 -83
  114. package/dist/io/xlsb/read-worksheet.d.ts +20 -1
  115. package/dist/io/xlsb/read-worksheet.js +73 -89
  116. package/dist/io/xlsb/read.d.ts +6 -3
  117. package/dist/io/xlsb/read.js +47 -29
  118. package/dist/io/xlsb/record-stream.d.ts +30 -0
  119. package/dist/io/xlsb/record-stream.js +20 -0
  120. package/dist/io/xlsb/record-types.d.ts +1 -5
  121. package/dist/io/xlsb/record-types.js +1 -5
  122. package/dist/io/xlsx/cell-accumulator.d.ts +9 -2
  123. package/dist/io/xlsx/cell-accumulator.js +32 -9
  124. package/dist/io/xlsx/cell-style-resolution.d.ts +25 -0
  125. package/dist/io/xlsx/cell-style-resolution.js +29 -0
  126. package/dist/io/xlsx/cell-value.d.ts +5 -3
  127. package/dist/io/xlsx/cell-value.js +13 -15
  128. package/dist/io/xlsx/color-xml.js +3 -2
  129. package/dist/io/xlsx/column-budget.d.ts +26 -0
  130. package/dist/io/xlsx/column-budget.js +22 -0
  131. package/dist/io/xlsx/comments.d.ts +6 -2
  132. package/dist/io/xlsx/comments.js +36 -31
  133. package/dist/io/xlsx/conditional-formatting.d.ts +9 -5
  134. package/dist/io/xlsx/conditional-formatting.js +51 -46
  135. package/dist/io/xlsx/data-validation.d.ts +9 -7
  136. package/dist/io/xlsx/data-validation.js +38 -35
  137. package/dist/io/xlsx/edit-vba.d.ts +7 -2
  138. package/dist/io/xlsx/edit-vba.js +15 -29
  139. package/dist/io/xlsx/font-xml.d.ts +7 -0
  140. package/dist/io/xlsx/font-xml.js +104 -0
  141. package/dist/io/xlsx/hyperlinks.d.ts +41 -7
  142. package/dist/io/xlsx/hyperlinks.js +40 -28
  143. package/dist/io/xlsx/images.js +24 -25
  144. package/dist/io/xlsx/namespaces.d.ts +16 -0
  145. package/dist/io/xlsx/namespaces.js +7 -0
  146. package/dist/io/xlsx/package-plan.d.ts +23 -3
  147. package/dist/io/xlsx/package-plan.js +66 -25
  148. package/dist/io/xlsx/part-names.d.ts +41 -0
  149. package/dist/io/xlsx/part-names.js +46 -0
  150. package/dist/io/xlsx/pivot.js +8 -7
  151. package/dist/io/xlsx/read-parts.d.ts +59 -0
  152. package/dist/io/xlsx/read-parts.js +252 -0
  153. package/dist/io/xlsx/read-pivot.js +3 -1
  154. package/dist/io/xlsx/read-repair.d.ts +26 -0
  155. package/dist/io/xlsx/read-repair.js +39 -0
  156. package/dist/io/xlsx/{rich-runs.d.ts → read-rich-runs.d.ts} +1 -1
  157. package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +7 -3
  158. package/dist/io/xlsx/read-rows.d.ts +18 -5
  159. package/dist/io/xlsx/read-rows.js +50 -37
  160. package/dist/io/xlsx/read-shared-strings.js +5 -3
  161. package/dist/io/xlsx/read-styles.d.ts +1 -6
  162. package/dist/io/xlsx/read-styles.js +65 -109
  163. package/dist/io/xlsx/read-workbook-xml.d.ts +36 -0
  164. package/dist/io/xlsx/read-workbook-xml.js +170 -0
  165. package/dist/io/xlsx/read-worksheet.d.ts +11 -1
  166. package/dist/io/xlsx/read-worksheet.js +51 -193
  167. package/dist/io/xlsx/read.d.ts +5 -13
  168. package/dist/io/xlsx/read.js +111 -436
  169. package/dist/io/xlsx/rich-text.js +1 -1
  170. package/dist/io/xlsx/row-position.d.ts +18 -0
  171. package/dist/io/xlsx/row-position.js +11 -0
  172. package/dist/io/xlsx/row-xml.d.ts +128 -0
  173. package/dist/io/xlsx/row-xml.js +203 -0
  174. package/dist/io/xlsx/shared-formulas.js +2 -2
  175. package/dist/io/xlsx/sheet-properties.d.ts +10 -1
  176. package/dist/io/xlsx/sheet-properties.js +166 -37
  177. package/dist/io/xlsx/style-elements.d.ts +43 -0
  178. package/dist/io/xlsx/style-elements.js +156 -0
  179. package/dist/io/xlsx/styles.d.ts +12 -3
  180. package/dist/io/xlsx/styles.js +5 -204
  181. package/dist/io/xlsx/tables.js +11 -14
  182. package/dist/io/xlsx/theme-xml.d.ts +26 -4
  183. package/dist/io/xlsx/theme-xml.js +107 -69
  184. package/dist/io/xlsx/threaded-comments.d.ts +8 -10
  185. package/dist/io/xlsx/threaded-comments.js +3 -1
  186. package/dist/io/xlsx/workbook-xml.d.ts +54 -4
  187. package/dist/io/xlsx/workbook-xml.js +84 -57
  188. package/dist/io/xlsx/worksheet-xml.d.ts +23 -70
  189. package/dist/io/xlsx/worksheet-xml.js +59 -242
  190. package/dist/io/xlsx/write-stream.d.ts +71 -16
  191. package/dist/io/xlsx/write-stream.js +79 -41
  192. package/dist/io/xlsx/write.d.ts +6 -2
  193. package/dist/io/xlsx/write.js +217 -153
  194. package/dist/rel-type.d.ts +16 -0
  195. package/dist/rel-type.js +6 -0
  196. package/dist/token-set.d.ts +28 -0
  197. package/dist/token-set.js +7 -0
  198. package/dist/vba/bytes.d.ts +14 -5
  199. package/dist/vba/bytes.js +16 -6
  200. package/dist/vba/cfb-format.d.ts +32 -0
  201. package/dist/vba/cfb-format.js +13 -0
  202. package/dist/vba/cfb-writer.d.ts +9 -0
  203. package/dist/vba/cfb-writer.js +28 -25
  204. package/dist/vba/cfb.d.ts +13 -1
  205. package/dist/vba/cfb.js +73 -57
  206. package/dist/vba/codepage.js +2 -1
  207. package/dist/vba/errors.d.ts +7 -0
  208. package/dist/vba/ms-ovba.js +79 -23
  209. package/dist/vba/project-editor.js +35 -40
  210. package/dist/vba/project.d.ts +11 -1
  211. package/dist/vba/project.js +40 -21
  212. package/dist/vba/vba-encoding.js +5 -6
  213. package/dist/xml/xml-attrs.d.ts +37 -0
  214. package/dist/xml/xml-attrs.js +30 -0
  215. package/dist/xml/xml-chars.d.ts +40 -0
  216. package/dist/xml/xml-chars.js +12 -0
  217. package/dist/xml/xml-namespaces.d.ts +31 -0
  218. package/dist/xml/xml-namespaces.js +50 -0
  219. package/dist/xml/xml-read.d.ts +128 -81
  220. package/dist/xml/xml-read.js +161 -178
  221. package/dist/xml/xml-scan.d.ts +78 -0
  222. package/dist/xml/xml-scan.js +180 -0
  223. package/dist/xml/xml.d.ts +29 -28
  224. package/dist/xml/xml.js +24 -24
  225. package/package.json +13 -9
@@ -1,19 +1,35 @@
1
- import { MAX_COLUMN, numberToColumn } from '../../core/address.js';
2
- import { quoteSheetName } from '../../core/formula.js';
1
+ import { MAX_COLUMN, MAX_COLUMN_INDEX, MAX_ROW_INDEX, numberToColumn } from '../../core/address.js';
2
+ import { formulaNumberLiteral, quoteSheetName } from '../../core/formula.js';
3
+ import { REF_ERROR } from '../../core/value.js';
4
+ import { XlsbParseError } from './errors.js';
3
5
  import { errorCodeFor, RecordReader } from './primitives.js';
4
- import { FTAB_USER_DEFINED, fixedArityFor, functionNameFor } from './ptg-functions.js';
6
+ import { builtinFunctionAt, FTAB_USER_DEFINED, functionNameFor } from './ptg-functions.js';
5
7
  export function decodeFormula(rgce, rgcb, scope) {
6
- const tokens = new RecordReader(rgce);
7
- const extra = new RecordReader(rgcb);
8
+ try {
9
+ return decodeTokens(rgce, rgcb, scope);
10
+ }
11
+ catch (error) {
12
+ if (error instanceof XlsbParseError)
13
+ return undefined;
14
+ throw error;
15
+ }
16
+ }
17
+ function decodeTokens(rgce, rgcb, scope) {
8
18
  const stack = [];
9
- const push = (text) => {
10
- if (text === undefined)
11
- return false;
12
- stack.push(text);
13
- return true;
19
+ const decode = {
20
+ tokens: new RecordReader(rgce),
21
+ extra: new RecordReader(rgcb),
22
+ stack,
23
+ scope,
24
+ push: (text) => {
25
+ if (text === undefined)
26
+ return false;
27
+ stack.push(text);
28
+ return true;
29
+ },
14
30
  };
15
- while (!tokens.done) {
16
- if (!step(tokens.u8(), tokens, extra, stack, scope, push))
31
+ while (!decode.tokens.done) {
32
+ if (!step(decode.tokens.u8(), decode))
17
33
  return undefined;
18
34
  }
19
35
  return stack.length === 1 ? stack[0] : undefined;
@@ -29,7 +45,8 @@ export function formulaAnchor(rgce, rgcb) {
29
45
  return undefined;
30
46
  return { row, column: extra.u32() };
31
47
  }
32
- function step(ptg, tokens, extra, stack, scope, push) {
48
+ function step(ptg, decode) {
49
+ const { tokens, stack, push } = decode;
33
50
  const binary = BINARY_OPERATORS.get(ptg);
34
51
  if (binary !== undefined) {
35
52
  const right = stack.pop();
@@ -54,33 +71,33 @@ function step(ptg, tokens, extra, stack, scope, push) {
54
71
  case PTG.Str:
55
72
  return push(quoteString(tokens.shortString()));
56
73
  case PTG.Attr:
57
- return attribute(tokens, stack, push);
74
+ return attribute(decode);
58
75
  case PTG.Err:
59
76
  return push(errorCodeFor(tokens.u8()));
60
77
  case PTG.Bool:
61
78
  return push(tokens.u8() !== 0 ? 'TRUE' : 'FALSE');
62
79
  case PTG.Int:
63
- return push(String(tokens.u16()));
80
+ return push(numberLiteral(tokens.u16()));
64
81
  case PTG.Num:
65
- return push(numberText(tokens.f64()));
82
+ return push(numberLiteral(tokens.f64()));
66
83
  default:
67
84
  return ptg >= CLASSED_TOKEN_FLOOR
68
- ? operand((ptg & CLASSED_TOKEN_MASK) | CLASSED_TOKEN_FLOOR, tokens, extra, stack, scope, push)
85
+ ? operand((ptg & CLASSED_TOKEN_MASK) | CLASSED_TOKEN_FLOOR, decode)
69
86
  : false;
70
87
  }
71
88
  }
72
- function operand(base, tokens, extra, stack, scope, push) {
89
+ function operand(base, decode) {
90
+ const { tokens, extra, stack, scope, push } = decode;
73
91
  switch (base) {
74
92
  case PTG.Array:
75
93
  tokens.skip(14);
76
94
  return push(arrayConstant(extra));
77
95
  case PTG.Func: {
78
- const name = functionNameFor(tokens.u16());
79
- const arity = name === undefined ? undefined : fixedArityFor(name);
80
- return name !== undefined && arity !== undefined && push(call(name, arity, stack));
96
+ const fn = builtinFunctionAt(tokens.u16());
97
+ return fn !== undefined && fn[1] !== 'variadic' && push(call(fn[0], fn[1], stack));
81
98
  }
82
99
  case PTG.FuncVar:
83
- return variadicCall(tokens, stack, push);
100
+ return variadicCall(decode);
84
101
  case PTG.Name: {
85
102
  return push(scope.names[tokens.u32() - 1]);
86
103
  }
@@ -100,16 +117,16 @@ function operand(base, tokens, extra, stack, scope, push) {
100
117
  }
101
118
  case PTG.RefErr:
102
119
  tokens.skip(6);
103
- return push(REFERENCE_ERROR);
120
+ return push(REF_ERROR);
104
121
  case PTG.AreaErr:
105
122
  tokens.skip(12);
106
- return push(REFERENCE_ERROR);
123
+ return push(REF_ERROR);
107
124
  case PTG.RefErr3d:
108
125
  tokens.skip(8);
109
- return push(REFERENCE_ERROR);
126
+ return push(REF_ERROR);
110
127
  case PTG.AreaErr3d:
111
128
  tokens.skip(14);
112
- return push(REFERENCE_ERROR);
129
+ return push(REF_ERROR);
113
130
  case PTG.MemArea:
114
131
  tokens.skip(6);
115
132
  return skipExtraRanges(extra);
@@ -117,7 +134,7 @@ function operand(base, tokens, extra, stack, scope, push) {
117
134
  return false;
118
135
  }
119
136
  }
120
- function attribute(tokens, stack, push) {
137
+ function attribute({ tokens, stack, push }) {
121
138
  const flags = tokens.u8();
122
139
  const data = tokens.u16();
123
140
  if ((flags & ATTR_CHOOSE) !== 0) {
@@ -128,7 +145,7 @@ function attribute(tokens, stack, push) {
128
145
  return push(call('SUM', 1, stack));
129
146
  return true;
130
147
  }
131
- function variadicCall(tokens, stack, push) {
148
+ function variadicCall({ tokens, stack, push }) {
132
149
  const count = tokens.u8() & FUNCVAR_PARAM_MASK;
133
150
  const index = tokens.u16() & FUNCVAR_INDEX_MASK;
134
151
  if (index !== FTAB_USER_DEFINED) {
@@ -167,7 +184,7 @@ function arrayConstant(extra) {
167
184
  function arrayElement(extra) {
168
185
  switch (extra.u8()) {
169
186
  case SER_NUM:
170
- return numberText(extra.f64());
187
+ return numberLiteral(extra.f64());
171
188
  case SER_STR:
172
189
  return quoteString(extra.shortString());
173
190
  case SER_BOOL:
@@ -212,7 +229,7 @@ function rangeText(rowFirst, rowLast, packedFirst, packedLast) {
212
229
  const last = columnOnly(packedLast);
213
230
  return first === undefined || last === undefined ? undefined : `${first}:${last}`;
214
231
  }
215
- if ((packedFirst & COLUMN_MASK) === 0 && (packedLast & COLUMN_MASK) === MAX_COLUMN - 1) {
232
+ if ((packedFirst & COLUMN_MASK) === 0 && (packedLast & COLUMN_MASK) === MAX_COLUMN_INDEX) {
216
233
  return rowFirst > MAX_ROW_INDEX || rowLast > MAX_ROW_INDEX
217
234
  ? undefined
218
235
  : `${rowOnly(rowFirst, packedFirst)}:${rowOnly(rowLast, packedLast)}`;
@@ -233,10 +250,9 @@ function rowOnly(row, packedColumn) {
233
250
  function quoteString(text) {
234
251
  return `"${text.replace(/"/g, '""')}"`;
235
252
  }
236
- function numberText(value) {
237
- return String(value).toUpperCase();
253
+ function numberLiteral(value) {
254
+ return Number.isFinite(value) ? formulaNumberLiteral(value) : undefined;
238
255
  }
239
- const REFERENCE_ERROR = '#REF!';
240
256
  const BINARY_OPERATORS = new Map([
241
257
  [0x03, '+'],
242
258
  [0x04, '-'],
@@ -291,7 +307,6 @@ const FUNCVAR_INDEX_MASK = 0x7fff;
291
307
  const COLUMN_MASK = 0x3fff;
292
308
  const COLUMN_RELATIVE = 0x4000;
293
309
  const ROW_RELATIVE = 0x8000;
294
- const MAX_ROW_INDEX = 1048575;
295
310
  const SER_NUM = 0x00;
296
311
  const SER_STR = 0x01;
297
312
  const SER_BOOL = 0x02;
@@ -1,15 +1,18 @@
1
+ import { decodeUtf16le } from '../../bytes.js';
1
2
  import { isErrorCode } from '../../core/value.js';
3
+ import { hex } from '../../hex.js';
2
4
  import { XlsbParseError } from './errors.js';
3
- const CHARS_PER_BATCH = 4096;
4
5
  const NULL_STRING_LENGTH = 0xffffffff;
5
6
  const rkScratch = new DataView(new ArrayBuffer(8));
6
7
  export class RecordReader {
7
8
  #data;
8
- #view;
9
+ #cachedView;
9
10
  #offset = 0;
10
11
  constructor(data) {
11
12
  this.#data = data;
12
- this.#view = new DataView(data.buffer, data.byteOffset, data.byteLength);
13
+ }
14
+ get #view() {
15
+ return (this.#cachedView ??= new DataView(this.#data.buffer, this.#data.byteOffset, this.#data.byteLength));
13
16
  }
14
17
  get remaining() {
15
18
  return this.#data.length - this.#offset;
@@ -89,16 +92,7 @@ export class RecordReader {
89
92
  }
90
93
  #characters(count) {
91
94
  const start = this.#take(count * 2);
92
- let text = '';
93
- let batch = [];
94
- for (let index = 0; index < count; index++) {
95
- batch.push(this.#view.getUint16(start + index * 2, true));
96
- if (batch.length === CHARS_PER_BATCH) {
97
- text += String.fromCharCode(...batch);
98
- batch = [];
99
- }
100
- }
101
- return batch.length > 0 ? text + String.fromCharCode(...batch) : text;
95
+ return decodeUtf16le(this.#data.subarray(start, start + count * 2));
102
96
  }
103
97
  #take(count) {
104
98
  if (count > this.remaining) {
@@ -144,5 +138,5 @@ function colorByType(type, index, alpha, red, green, blue) {
144
138
  }
145
139
  }
146
140
  function hexByte(value) {
147
- return value.toString(16).toUpperCase().padStart(2, '0');
141
+ return hex(value, 2);
148
142
  }
@@ -1,16 +1,25 @@
1
1
  /** The index [MS-XLS] reserves for a call whose name is given by the token stream's first operand. */
2
2
  export declare const FTAB_USER_DEFINED = 255;
3
- /** Look up a built-in function name by its `iftab` index, or `undefined` if the index names none. */
4
- export declare function functionNameFor(index: number): string | undefined;
5
3
  /**
6
- * How many arguments a fixed-arity function takes, or `undefined` for one whose argument count varies.
4
+ * One built-in function: the name an `iftab` index means, and how many arguments it takes.
7
5
  *
8
- * A `PtgFunc` token states only *which* function is called, never with how many arguments: it is the
9
- * token Excel emits precisely because the count is implied by the function. So decoding `ROUND(A1,2)`
10
- * back from its two operands and one call token is impossible without this: the arity is the only
11
- * thing that says which operands on the stack belong to the call. (`PtgFuncVar` carries its own count
12
- * and needs none of this; the two token forms partition the table between them.)
6
+ * The arity is not decoration. A `PtgFunc` token states only *which* function is called, never with
7
+ * how many arguments: it is the token Excel emits precisely because the count is implied by the
8
+ * function. So decoding `ROUND(A1,2)` back from its two operands and one call token is impossible
9
+ * without it, and `'variadic'` says the call cannot be spelled with that token at all (`PtgFuncVar`
10
+ * carries its own count; the two token forms partition the table between them). Transcribed from the
11
+ * parameter grammar each function's [MS-XLS] 2.5.198.17 entry states.
13
12
  *
14
- * Transcribed from the parameter grammar each function's [MS-XLS] 2.5.198.17 entry states.
13
+ * It used to live in a second table keyed by name, which let an entry exist in one and not the other
14
+ * with nothing to say so. A function whose arity was never transcribed simply read as variadic, and a
15
+ * `PtgFunc` citing it then took the wrong run of operands off the stack and produced a different
16
+ * formula, silently. Recording it beside the name makes "no arity recorded" unrepresentable: the
17
+ * compiler asks for it once per entry, and `'variadic'` becomes a decision written down rather than
18
+ * an absence that looks like one.
15
19
  */
16
- export declare function fixedArityFor(name: string): number | undefined;
20
+ export type FunctionEntry = readonly [name: string, arity: number | 'variadic'];
21
+ /** The built-in function an `iftab` index names, or `undefined` if the index names none. */
22
+ export declare function builtinFunctionAt(index: number): FunctionEntry | undefined;
23
+ /** Look up a built-in function name by its `iftab` index, or `undefined` if the index names none. */
24
+ export declare function functionNameFor(index: number): string | undefined;
25
+ export declare const FTAB: readonly (FunctionEntry | undefined)[];