@borgar/fx 4.13.0 → 5.0.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 (141) hide show
  1. package/dist/index-BMr6cTgc.d.cts +1444 -0
  2. package/dist/index-BMr6cTgc.d.ts +1444 -0
  3. package/dist/index.cjs +3054 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +1 -0
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.js +2984 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/xlsx/index.cjs +3120 -0
  10. package/dist/xlsx/index.cjs.map +1 -0
  11. package/dist/xlsx/index.d.cts +55 -0
  12. package/dist/xlsx/index.d.ts +55 -0
  13. package/dist/xlsx/index.js +3049 -0
  14. package/dist/xlsx/index.js.map +1 -0
  15. package/docs/API.md +2959 -718
  16. package/docs/AST_format.md +2 -2
  17. package/eslint.config.mjs +40 -0
  18. package/lib/a1.spec.ts +32 -0
  19. package/lib/a1.ts +26 -0
  20. package/lib/addA1RangeBounds.ts +50 -0
  21. package/lib/addTokenMeta.spec.ts +166 -0
  22. package/lib/{addTokenMeta.js → addTokenMeta.ts} +53 -33
  23. package/lib/astTypes.ts +211 -0
  24. package/lib/cloneToken.ts +29 -0
  25. package/lib/{constants.js → constants.ts} +6 -3
  26. package/lib/fixRanges.spec.ts +220 -0
  27. package/lib/fixRanges.ts +260 -0
  28. package/lib/fromCol.spec.ts +15 -0
  29. package/lib/{fromCol.js → fromCol.ts} +1 -1
  30. package/lib/index.spec.ts +119 -0
  31. package/lib/index.ts +76 -0
  32. package/lib/isNodeType.ts +151 -0
  33. package/lib/isType.spec.ts +208 -0
  34. package/lib/{isType.js → isType.ts} +26 -25
  35. package/lib/lexers/{advRangeOp.js → advRangeOp.ts} +1 -1
  36. package/lib/lexers/{canEndRange.js → canEndRange.ts} +2 -2
  37. package/lib/lexers/{lexBoolean.js → lexBoolean.ts} +25 -6
  38. package/lib/lexers/{lexContext.js → lexContext.ts} +14 -6
  39. package/lib/lexers/{lexError.js → lexError.ts} +3 -3
  40. package/lib/lexers/{lexFunction.js → lexFunction.ts} +3 -2
  41. package/lib/lexers/lexNameFuncCntx.ts +112 -0
  42. package/lib/lexers/{lexNamed.js → lexNamed.ts} +4 -4
  43. package/lib/lexers/{lexNewLine.js → lexNewLine.ts} +3 -2
  44. package/lib/lexers/{lexNumber.js → lexNumber.ts} +4 -3
  45. package/lib/lexers/{lexOperator.js → lexOperator.ts} +5 -4
  46. package/lib/lexers/lexRange.ts +15 -0
  47. package/lib/lexers/{lexRangeA1.js → lexRangeA1.ts} +11 -7
  48. package/lib/lexers/{lexRangeR1C1.js → lexRangeR1C1.ts} +10 -6
  49. package/lib/lexers/{lexRangeTrim.js → lexRangeTrim.ts} +3 -2
  50. package/lib/lexers/{lexRefOp.js → lexRefOp.ts} +4 -3
  51. package/lib/lexers/{lexString.js → lexString.ts} +3 -3
  52. package/lib/lexers/{lexStructured.js → lexStructured.ts} +5 -5
  53. package/lib/lexers/{lexWhitespace.js → lexWhitespace.ts} +3 -2
  54. package/lib/lexers/sets.ts +51 -0
  55. package/lib/mergeRefTokens.spec.ts +141 -0
  56. package/lib/{mergeRefTokens.js → mergeRefTokens.ts} +14 -9
  57. package/lib/nodeTypes.ts +54 -0
  58. package/lib/parse.spec.ts +1410 -0
  59. package/lib/{parser.js → parse.ts} +81 -63
  60. package/lib/parseA1Range.spec.ts +233 -0
  61. package/lib/parseA1Range.ts +206 -0
  62. package/lib/parseA1Ref.spec.ts +337 -0
  63. package/lib/parseA1Ref.ts +115 -0
  64. package/lib/parseR1C1Range.ts +191 -0
  65. package/lib/parseR1C1Ref.spec.ts +323 -0
  66. package/lib/parseR1C1Ref.ts +127 -0
  67. package/lib/parseRef.spec.ts +90 -0
  68. package/lib/parseRef.ts +240 -0
  69. package/lib/{parseSRange.js → parseSRange.ts} +15 -10
  70. package/lib/parseStructRef.spec.ts +168 -0
  71. package/lib/parseStructRef.ts +76 -0
  72. package/lib/stringifyA1Range.spec.ts +72 -0
  73. package/lib/stringifyA1Range.ts +72 -0
  74. package/lib/stringifyA1Ref.spec.ts +64 -0
  75. package/lib/stringifyA1Ref.ts +59 -0
  76. package/lib/{stringifyPrefix.js → stringifyPrefix.ts} +17 -2
  77. package/lib/stringifyR1C1Range.spec.ts +92 -0
  78. package/lib/stringifyR1C1Range.ts +73 -0
  79. package/lib/stringifyR1C1Ref.spec.ts +63 -0
  80. package/lib/stringifyR1C1Ref.ts +67 -0
  81. package/lib/stringifyStructRef.spec.ts +124 -0
  82. package/lib/stringifyStructRef.ts +113 -0
  83. package/lib/stringifyTokens.ts +15 -0
  84. package/lib/toCol.spec.ts +11 -0
  85. package/lib/{toCol.js → toCol.ts} +4 -4
  86. package/lib/tokenTypes.ts +76 -0
  87. package/lib/tokenize-srefs.spec.ts +429 -0
  88. package/lib/tokenize.spec.ts +2103 -0
  89. package/lib/tokenize.ts +346 -0
  90. package/lib/translate.spec.ts +35 -0
  91. package/lib/translateToA1.spec.ts +247 -0
  92. package/lib/translateToA1.ts +231 -0
  93. package/lib/translateToR1C1.spec.ts +227 -0
  94. package/lib/translateToR1C1.ts +145 -0
  95. package/lib/types.ts +179 -0
  96. package/lib/xlsx/index.spec.ts +27 -0
  97. package/lib/xlsx/index.ts +32 -0
  98. package/package.json +45 -31
  99. package/tsconfig.json +28 -0
  100. package/typedoc-ignore-links.ts +17 -0
  101. package/typedoc.json +41 -0
  102. package/.eslintrc +0 -22
  103. package/benchmark/benchmark.js +0 -48
  104. package/benchmark/formulas.json +0 -15677
  105. package/dist/fx.d.ts +0 -823
  106. package/dist/fx.js +0 -2
  107. package/dist/package.json +0 -1
  108. package/lib/a1.js +0 -348
  109. package/lib/a1.spec.js +0 -458
  110. package/lib/addTokenMeta.spec.js +0 -153
  111. package/lib/astTypes.js +0 -96
  112. package/lib/extraTypes.js +0 -74
  113. package/lib/fixRanges.js +0 -104
  114. package/lib/fixRanges.spec.js +0 -171
  115. package/lib/fromCol.spec.js +0 -11
  116. package/lib/index.js +0 -134
  117. package/lib/index.spec.js +0 -67
  118. package/lib/isType.spec.js +0 -168
  119. package/lib/lexer-srefs.spec.js +0 -324
  120. package/lib/lexer.js +0 -264
  121. package/lib/lexer.spec.js +0 -1953
  122. package/lib/lexers/lexRange.js +0 -8
  123. package/lib/lexers/sets.js +0 -38
  124. package/lib/mergeRefTokens.spec.js +0 -121
  125. package/lib/package.json +0 -1
  126. package/lib/parseRef.js +0 -157
  127. package/lib/parseRef.spec.js +0 -71
  128. package/lib/parseStructRef.js +0 -48
  129. package/lib/parseStructRef.spec.js +0 -164
  130. package/lib/parser.spec.js +0 -1208
  131. package/lib/rc.js +0 -341
  132. package/lib/rc.spec.js +0 -403
  133. package/lib/stringifyStructRef.js +0 -80
  134. package/lib/stringifyStructRef.spec.js +0 -182
  135. package/lib/toCol.spec.js +0 -11
  136. package/lib/translate-toA1.spec.js +0 -214
  137. package/lib/translate-toRC.spec.js +0 -197
  138. package/lib/translate.js +0 -239
  139. package/lib/translate.spec.js +0 -21
  140. package/rollup.config.mjs +0 -22
  141. package/tsd.json +0 -12
@@ -0,0 +1,15 @@
1
+ import type { Token } from '../types.ts';
2
+ import { lexRangeA1 } from './lexRangeA1.ts';
3
+ import { lexRangeR1C1 } from './lexRangeR1C1.ts';
4
+
5
+ type LexRangeOptions = {
6
+ allowTernary: boolean,
7
+ mergeRefs: boolean,
8
+ r1c1: boolean
9
+ };
10
+
11
+ export function lexRange (str: string, pos: number, options: LexRangeOptions): Token | undefined {
12
+ return options.r1c1
13
+ ? lexRangeR1C1(str, pos, options)
14
+ : lexRangeA1(str, pos, options);
15
+ }
@@ -1,9 +1,9 @@
1
- /* eslint-disable no-mixed-operators */
2
- import { REF_RANGE, REF_BEAM, REF_TERNARY, MAX_COLS, MAX_ROWS } from '../constants.js';
3
- import { advRangeOp } from './advRangeOp.js';
4
- import { canEndRange, canEndPartialRange } from './canEndRange.js';
1
+ import { REF_RANGE, REF_BEAM, REF_TERNARY, MAX_COLS, MAX_ROWS } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
3
+ import { advRangeOp } from './advRangeOp.ts';
4
+ import { canEndRange, canEndPartialRange } from './canEndRange.ts';
5
5
 
6
- function advA1Col (str, pos) {
6
+ function advA1Col (str: string, pos: number): number {
7
7
  // [A-Z]{1,3}
8
8
  const start = pos;
9
9
  if (str.charCodeAt(pos) === 36) { // $
@@ -29,7 +29,7 @@ function advA1Col (str, pos) {
29
29
  return (col && col <= MAX_COLS + 1) ? pos - start : 0;
30
30
  }
31
31
 
32
- function advA1Row (str, pos) {
32
+ function advA1Row (str: string, pos: number): number {
33
33
  // [1-9][0-9]{0,6}
34
34
  const start = pos;
35
35
  if (str.charCodeAt(pos) === 36) { // $
@@ -56,7 +56,11 @@ function advA1Row (str, pos) {
56
56
  return (row && row <= MAX_ROWS + 1) ? pos - start : 0;
57
57
  }
58
58
 
59
- export function lexRangeA1 (str, pos, options) {
59
+ export function lexRangeA1 (
60
+ str: string,
61
+ pos: number,
62
+ options: { mergeRefs: boolean, allowTernary: boolean }
63
+ ): Token | undefined {
60
64
  let p = pos;
61
65
  const left = advA1Col(str, p);
62
66
  let right = 0;
@@ -1,7 +1,7 @@
1
- /* eslint-disable no-mixed-operators */
2
- import { REF_RANGE, REF_BEAM, REF_TERNARY, MAX_COLS, MAX_ROWS } from '../constants.js';
3
- import { advRangeOp } from './advRangeOp.js';
4
- import { canEndRange } from './canEndRange.js';
1
+ import { REF_RANGE, REF_BEAM, REF_TERNARY, MAX_COLS, MAX_ROWS } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
3
+ import { advRangeOp } from './advRangeOp.ts';
4
+ import { canEndRange } from './canEndRange.ts';
5
5
 
6
6
  const BR_OPEN = 91; // [
7
7
  const BR_CLOSE = 93; // ]
@@ -18,7 +18,7 @@ const MINUS = 45;
18
18
  // R
19
19
  // R\[[+-]?\d+\]
20
20
  // R[1-9][0-9]{0,6}
21
- function lexR1C1Part (str, pos, isRow = false) {
21
+ function lexR1C1Part (str: string, pos: number, isRow: boolean = false): number {
22
22
  const start = pos;
23
23
  const c0 = str.charCodeAt(pos);
24
24
  if ((isRow ? c0 === UC_R || c0 === LC_R : c0 === UC_C || c0 === LC_C)) {
@@ -78,7 +78,11 @@ function lexR1C1Part (str, pos, isRow = false) {
78
78
  return 0;
79
79
  }
80
80
 
81
- export function lexRangeR1C1 (str, pos, options) {
81
+ export function lexRangeR1C1 (
82
+ str: string,
83
+ pos: number,
84
+ options: { allowTernary: boolean }
85
+ ): Token | undefined {
82
86
  let p = pos;
83
87
  // C1
84
88
  // C1:C1
@@ -1,9 +1,10 @@
1
- import { OPERATOR_TRIM } from '../constants.js';
1
+ import { OPERATOR_TRIM } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
2
3
 
3
4
  const PERIOD = 46;
4
5
  const COLON = 58;
5
6
 
6
- export function lexRangeTrim (str, pos) {
7
+ export function lexRangeTrim (str: string, pos: number): Token | undefined {
7
8
  const c0 = str.charCodeAt(pos);
8
9
  if (c0 === PERIOD || c0 === COLON) {
9
10
  const c1 = str.charCodeAt(pos + 1);
@@ -1,9 +1,10 @@
1
- import { OPERATOR } from '../constants.js';
2
- import { advRangeOp } from './advRangeOp.js';
1
+ import { OPERATOR } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
3
+ import { advRangeOp } from './advRangeOp.ts';
3
4
 
4
5
  const EXCL = 33; // !
5
6
 
6
- export function lexRefOp (str, pos, opts) {
7
+ export function lexRefOp (str: string, pos: number, opts: { r1c1: boolean }): Token | undefined {
7
8
  // in R1C1 mode we only allow [ '!' ]
8
9
  if (str.charCodeAt(pos) === EXCL) {
9
10
  return { type: OPERATOR, value: str[pos] };
@@ -1,9 +1,9 @@
1
- /* eslint-disable no-mixed-operators */
2
- import { STRING } from '../constants.js';
1
+ import { STRING } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
3
3
 
4
4
  const QUOT = 34;
5
5
 
6
- export function lexString (str, pos) {
6
+ export function lexString (str: string, pos: number): Token | undefined {
7
7
  const start = pos;
8
8
  if (str.charCodeAt(pos) === QUOT) {
9
9
  pos++;
@@ -1,11 +1,11 @@
1
- /* eslint-disable no-mixed-operators */
2
- import { parseSRange } from '../parseSRange.js';
3
- import { REF_STRUCT } from '../constants.js';
4
- import { isWS } from './lexWhitespace.js';
1
+ import { parseSRange } from '../parseSRange.ts';
2
+ import { REF_STRUCT } from '../constants.ts';
3
+ import { isWS } from './lexWhitespace.ts';
4
+ import type { Token } from '../types.ts';
5
5
 
6
6
  const EXCL = 33; // !
7
7
 
8
- export function lexStructured (str, pos) {
8
+ export function lexStructured (str: string, pos: number): Token | undefined {
9
9
  const structData = parseSRange(str, pos);
10
10
  if (structData && structData.length) {
11
11
  // we have a match for a valid SR
@@ -1,4 +1,5 @@
1
- import { WHITESPACE } from '../constants.js';
1
+ import { WHITESPACE } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
2
3
 
3
4
  export function isWS (c) {
4
5
  return (
@@ -19,7 +20,7 @@ export function isWS (c) {
19
20
  );
20
21
  }
21
22
 
22
- export function lexWhitespace (str, pos) {
23
+ export function lexWhitespace (str: string, pos: number): Token | undefined {
23
24
  const start = pos;
24
25
  while (isWS(str.charCodeAt(pos))) {
25
26
  pos++;
@@ -0,0 +1,51 @@
1
+ import { lexError } from './lexError.ts';
2
+ import { lexRangeTrim } from './lexRangeTrim.ts';
3
+ import { lexOperator } from './lexOperator.ts';
4
+ import { lexBoolean } from './lexBoolean.ts';
5
+ import { lexNewLine } from './lexNewLine.ts';
6
+ import { lexWhitespace } from './lexWhitespace.ts';
7
+ import { lexString } from './lexString.ts';
8
+ import { lexContextQuoted, lexContextUnquoted } from './lexContext.ts';
9
+ import { lexRange } from './lexRange.ts';
10
+ import { lexStructured } from './lexStructured.ts';
11
+ import { lexNumber } from './lexNumber.ts';
12
+ import { lexNamed } from './lexNamed.ts';
13
+ import { lexRefOp } from './lexRefOp.ts';
14
+ import { lexNameFuncCntx } from './lexNameFuncCntx.ts';
15
+ import type { Token } from '../types.ts';
16
+
17
+ export type PartLexer = (
18
+ str: string,
19
+ pos: number,
20
+ options?: Partial<{
21
+ xlsx: boolean,
22
+ allowTerniary: boolean,
23
+ allowTernary: boolean,
24
+ mergeRefs: boolean,
25
+ r1c1: boolean
26
+ }>
27
+ ) => Token | undefined;
28
+
29
+ export const lexers: PartLexer[] = [
30
+ lexError,
31
+ lexRangeTrim,
32
+ lexOperator,
33
+ lexNewLine,
34
+ lexWhitespace,
35
+ lexString,
36
+ lexRange,
37
+ lexNumber,
38
+ lexBoolean,
39
+ lexContextQuoted,
40
+ lexNameFuncCntx,
41
+ lexStructured
42
+ ];
43
+
44
+ export const lexersRefs = [
45
+ lexRefOp,
46
+ lexContextQuoted,
47
+ lexContextUnquoted,
48
+ lexRange,
49
+ lexStructured,
50
+ lexNamed
51
+ ];
@@ -0,0 +1,141 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import { CONTEXT, FUNCTION, FX_PREFIX, OPERATOR, REF_RANGE, REF_BEAM, REF_NAMED, REF_TERNARY, UNKNOWN } from './constants.ts';
3
+ import { mergeRefTokens } from './mergeRefTokens.ts';
4
+ import { tokenize } from './tokenize.ts';
5
+
6
+ describe('mergeRefTokens', () => {
7
+ test('merges reference tokens and preserves metadata', () => {
8
+ const list = tokenize('=SUM([Wb1]Sheet1!A1:B2)', { mergeRefs: false, withLocation: true });
9
+
10
+ expect(list).toEqual([
11
+ { type: FX_PREFIX, value: '=', loc: [ 0, 1 ] },
12
+ { type: FUNCTION, value: 'SUM', loc: [ 1, 4 ] },
13
+ { type: OPERATOR, value: '(', loc: [ 4, 5 ] },
14
+
15
+ { type: CONTEXT, value: '[Wb1]Sheet1', loc: [ 5, 16 ] },
16
+ { type: OPERATOR, value: '!', loc: [ 16, 17 ] },
17
+ { type: REF_RANGE, value: 'A1', loc: [ 17, 19 ] },
18
+ { type: OPERATOR, value: ':', loc: [ 19, 20 ] },
19
+ { type: REF_RANGE, value: 'B2', loc: [ 20, 22 ] },
20
+
21
+ { type: OPERATOR, value: ')', loc: [ 22, 23 ] }
22
+ ]);
23
+
24
+ // set IDs on all tokens about to be joined
25
+ list[3].id = 'id1';
26
+ list[4].id = 'id2';
27
+ list[5].id = 'id3';
28
+ list[6].id = 'id4';
29
+ list[7].id = 'id5';
30
+
31
+ const mergedList = mergeRefTokens(list);
32
+ expect(mergedList).toEqual([
33
+ { type: FX_PREFIX, value: '=', loc: [ 0, 1 ] },
34
+ { type: FUNCTION, value: 'SUM', loc: [ 1, 4 ] },
35
+ { type: OPERATOR, value: '(', loc: [ 4, 5 ] },
36
+ { type: REF_RANGE,
37
+ id: 'id5', // token has the id of the first one
38
+ value: '[Wb1]Sheet1!A1:B2',
39
+ loc: [ 5, 22 ] },
40
+ { type: OPERATOR, value: ')', loc: [ 22, 23 ] }
41
+ ]);
42
+ });
43
+
44
+ describe('tokenize with mergeRefs enabled', () => {
45
+ const opts = { mergeRefs: true, allowTernary: true };
46
+
47
+ test('basic cell references', () => {
48
+ expect(tokenize('A1', opts)).toEqual([
49
+ { type: REF_RANGE, value: 'A1' }
50
+ ]);
51
+
52
+ expect(tokenize('A1:A1', opts)).toEqual([
53
+ { type: REF_RANGE, value: 'A1:A1' }
54
+ ]);
55
+ });
56
+
57
+ test('beam references', () => {
58
+ expect(tokenize('A:A', opts)).toEqual([
59
+ { type: REF_BEAM, value: 'A:A' }
60
+ ]);
61
+ });
62
+
63
+ test('ternary references', () => {
64
+ expect(tokenize('A1:A', opts)).toEqual([
65
+ { type: REF_TERNARY, value: 'A1:A' }
66
+ ]);
67
+ });
68
+
69
+ test('quoted sheet references', () => {
70
+ expect(tokenize('\'Sheet1\'!A1', opts)).toEqual([
71
+ { type: REF_RANGE, value: '\'Sheet1\'!A1' }
72
+ ]);
73
+
74
+ expect(tokenize('\'Sheet1\'!A:A', opts)).toEqual([
75
+ { type: REF_BEAM, value: '\'Sheet1\'!A:A' }
76
+ ]);
77
+
78
+ expect(tokenize('\'Sheet1\'!A1:A', opts)).toEqual([
79
+ { type: REF_TERNARY, value: '\'Sheet1\'!A1:A' }
80
+ ]);
81
+ });
82
+
83
+ test('unquoted sheet references', () => {
84
+ expect(tokenize('Sheet1!A1', opts)).toEqual([
85
+ { type: REF_RANGE, value: 'Sheet1!A1' }
86
+ ]);
87
+
88
+ expect(tokenize('Sheet1!A:A', opts)).toEqual([
89
+ { type: REF_BEAM, value: 'Sheet1!A:A' }
90
+ ]);
91
+
92
+ expect(tokenize('Sheet1!A1:A', opts)).toEqual([
93
+ { type: REF_TERNARY, value: 'Sheet1!A1:A' }
94
+ ]);
95
+ });
96
+
97
+ test('workbook references', () => {
98
+ expect(tokenize('[WB]Sheet1!A1', opts)).toEqual([
99
+ { type: REF_RANGE, value: '[WB]Sheet1!A1' }
100
+ ]);
101
+
102
+ expect(tokenize('[WB]Sheet1!A:A', opts)).toEqual([
103
+ { type: REF_BEAM, value: '[WB]Sheet1!A:A' }
104
+ ]);
105
+
106
+ expect(tokenize('[WB]Sheet1!A1:A', opts)).toEqual([
107
+ { type: REF_TERNARY, value: '[WB]Sheet1!A1:A' }
108
+ ]);
109
+
110
+ expect(tokenize('[WB]Sheet1!A1.:.C3', opts)).toEqual([
111
+ { type: REF_RANGE, value: '[WB]Sheet1!A1.:.C3' }
112
+ ]);
113
+ });
114
+
115
+ test('named references', () => {
116
+ expect(tokenize('foo', opts)).toEqual([
117
+ { type: REF_NAMED, value: 'foo' }
118
+ ]);
119
+
120
+ expect(tokenize('\'quoted\'!foo', opts)).toEqual([
121
+ { type: REF_NAMED, value: '\'quoted\'!foo' }
122
+ ]);
123
+
124
+ expect(tokenize('Sheet1!foo', opts)).toEqual([
125
+ { type: REF_NAMED, value: 'Sheet1!foo' }
126
+ ]);
127
+ });
128
+
129
+ test('path references with different formats', () => {
130
+ expect(tokenize('[path]!foo', opts)).toEqual([
131
+ { type: UNKNOWN, value: '[path]' },
132
+ { type: OPERATOR, value: '!' },
133
+ { type: REF_NAMED, value: 'foo' }
134
+ ]);
135
+
136
+ expect(tokenize('[path]prefix!foo', opts)).toEqual([
137
+ { type: REF_NAMED, value: '[path]prefix!foo' }
138
+ ]);
139
+ });
140
+ });
141
+ });
@@ -1,4 +1,5 @@
1
- import { CONTEXT, CONTEXT_QUOTE, REF_RANGE, REF_NAMED, REF_BEAM, REF_TERNARY, OPERATOR, REF_STRUCT } from './constants.js';
1
+ import { CONTEXT, CONTEXT_QUOTE, REF_RANGE, REF_NAMED, REF_BEAM, REF_TERNARY, OPERATOR, REF_STRUCT } from './constants.ts';
2
+ import type { Token } from './types.ts';
2
3
 
3
4
  const END = '$';
4
5
 
@@ -33,13 +34,17 @@ const validRunsMerge = [
33
34
  [ CONTEXT_QUOTE, '!', REF_NAMED, REF_STRUCT ]
34
35
  ];
35
36
 
37
+ type TypeNode = {
38
+ [key: string]: TypeNode | boolean;
39
+ };
40
+
36
41
  // valid token runs are converted to a tree structure
37
- const refPartsTree = {};
38
- function packList (f, node) {
42
+ const refPartsTree: TypeNode = {};
43
+ function packList (f: string[], node: TypeNode) {
39
44
  if (f.length) {
40
45
  const key = f[0];
41
- node[key] = node[key] || {};
42
- packList(f.slice(1), node[key]);
46
+ if (!node[key]) { node[key] = {}; }
47
+ packList(f.slice(1), node[key] as TypeNode);
43
48
  }
44
49
  else {
45
50
  node[END] = true;
@@ -49,7 +54,7 @@ validRunsMerge.forEach(run => packList(run.concat().reverse(), refPartsTree));
49
54
 
50
55
  // attempt to match a backwards run of tokens from a given point
51
56
  // to a path in the tree
52
- const matcher = (tokens, currNode, anchorIndex, index = 0) => {
57
+ const matcher = (tokens: Token[], currNode, anchorIndex, index = 0) => {
53
58
  let i = index;
54
59
  let node = currNode;
55
60
  const max = tokens.length - index;
@@ -76,10 +81,10 @@ const matcher = (tokens, currNode, anchorIndex, index = 0) => {
76
81
  * as whole references (`Sheet1!A1:B2`) rather than separate tokens for each
77
82
  * part: (`Sheet1`,`!`,`A1`,`:`,`B2`).
78
83
  *
79
- * @param {Array<Token>} tokenlist An array of tokens (from `tokenize()`)
80
- * @returns {Array<Token>} A new list of tokens with range parts merged.
84
+ * @param tokenlist An array of tokens.
85
+ * @returns A new list of tokens with range parts merged.
81
86
  */
82
- export function mergeRefTokens (tokenlist) {
87
+ export function mergeRefTokens (tokenlist: Token[]): Token[] {
83
88
  const finalTokens = [];
84
89
  // this seeks backwards because it's really the range part
85
90
  // that controls what can be joined.
@@ -0,0 +1,54 @@
1
+ import {
2
+ // AST types
3
+ UNARY,
4
+ BINARY,
5
+ REFERENCE,
6
+ LITERAL,
7
+ ERROR_LITERAL,
8
+ CALL,
9
+ ARRAY,
10
+ IDENTIFIER,
11
+ LAMBDA,
12
+ LET,
13
+ LET_DECL
14
+ } from './constants.ts';
15
+
16
+ /**
17
+ * A dictionary of the types used to identify AST node variants.
18
+ *
19
+ * @prop UNARY - A unary operation (`10%`)
20
+ * @prop BINARY - A binary operation (`10+10`)
21
+ * @prop REFERENCE - A range identifier (`A1`)
22
+ * @prop LITERAL - A literal (number, string, or boolean) (`123`, `"foo"`, `false`)
23
+ * @prop ERROR - An error literal (`#VALUE!`)
24
+ * @prop CALL - A function call expression (`SUM(1,2)`)
25
+ * @prop ARRAY - An array expression (`{1,2;3,4}`)
26
+ * @prop IDENTIFIER - A function name identifier (`SUM`)
27
+ * @prop LAMBDA - A LAMBDA expression (`LAMBDA(x,y,x*y)``)
28
+ * @prop LET - A LET expression (`LET(a,A1*10,b,SUM(F:F),a*b)`)
29
+ * @prop LET_DECL - A LET declaration (LET(`a,A1*10`...)
30
+ */
31
+ export const nodeTypes = Object.freeze({
32
+ /** A unary operation (`10%`) */
33
+ UNARY,
34
+ /** A binary operation (`10+10`) */
35
+ BINARY,
36
+ /** A range identifier (`A1`) */
37
+ REFERENCE,
38
+ /** A literal (number, string, or boolean) (`123`, `"foo"`, `false`) */
39
+ LITERAL,
40
+ /** An error literal (`#VALUE!`) */
41
+ ERROR: ERROR_LITERAL,
42
+ /** A function call expression (`SUM(1,2)`) */
43
+ CALL,
44
+ /** An array expression (`{1,2;3,4}`) */
45
+ ARRAY,
46
+ /** A function name identifier (`SUM`) */
47
+ IDENTIFIER,
48
+ /** A LAMBDA expression (`LAMBDA(x,y,x*y)``) */
49
+ LAMBDA,
50
+ /** A LET expression (`LET(a,A1*10,b,SUM(F:F),a*b)`) */
51
+ LET,
52
+ /** A LET declaration (LET(`a,A1*10`...)*/
53
+ LET_DECL
54
+ });