@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,208 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import {
3
+ REF_RANGE, REF_BEAM, REF_NAMED, REF_TERNARY, REF_STRUCT,
4
+ FX_PREFIX, WHITESPACE, NEWLINE,
5
+ FUNCTION, OPERATOR,
6
+ ERROR, STRING, NUMBER, BOOLEAN
7
+ } from './constants.ts';
8
+ import { isRange, isReference, isLiteral, isError, isWhitespace, isFunction, isFxPrefix, isOperator } from './isType.ts';
9
+
10
+ describe('isRange', () => {
11
+ test('returns false for non-range types', () => {
12
+ expect(isRange(null)).toBe(false);
13
+ // @ts-expect-error -- testing invalid input
14
+ expect(isRange({})).toBe(false);
15
+ expect(isRange({ type: BOOLEAN })).toBe(false);
16
+ expect(isRange({ type: ERROR })).toBe(false);
17
+ expect(isRange({ type: FUNCTION })).toBe(false);
18
+ expect(isRange({ type: FX_PREFIX })).toBe(false);
19
+ expect(isRange({ type: NEWLINE })).toBe(false);
20
+ expect(isRange({ type: NUMBER })).toBe(false);
21
+ expect(isRange({ type: OPERATOR })).toBe(false);
22
+ expect(isRange({ type: REF_NAMED })).toBe(false);
23
+ expect(isRange({ type: REF_STRUCT })).toBe(false);
24
+ expect(isRange({ type: STRING })).toBe(false);
25
+ expect(isRange({ type: WHITESPACE })).toBe(false);
26
+ });
27
+
28
+ test('returns true for range types', () => {
29
+ expect(isRange({ type: REF_BEAM })).toBe(true);
30
+ expect(isRange({ type: REF_RANGE })).toBe(true);
31
+ expect(isRange({ type: REF_TERNARY })).toBe(true);
32
+ });
33
+ });
34
+
35
+ describe('isReference', () => {
36
+ test('returns false for non-reference types', () => {
37
+ expect(isReference(null)).toBe(false);
38
+ // @ts-expect-error -- testing invalid input
39
+ expect(isReference({})).toBe(false);
40
+ expect(isReference({ type: BOOLEAN })).toBe(false);
41
+ expect(isReference({ type: ERROR })).toBe(false);
42
+ expect(isReference({ type: FUNCTION })).toBe(false);
43
+ expect(isReference({ type: FX_PREFIX })).toBe(false);
44
+ expect(isReference({ type: NEWLINE })).toBe(false);
45
+ expect(isReference({ type: NUMBER })).toBe(false);
46
+ expect(isReference({ type: OPERATOR })).toBe(false);
47
+ expect(isReference({ type: STRING })).toBe(false);
48
+ expect(isReference({ type: WHITESPACE })).toBe(false);
49
+ });
50
+
51
+ test('returns true for reference types', () => {
52
+ expect(isReference({ type: REF_BEAM })).toBe(true);
53
+ expect(isReference({ type: REF_NAMED })).toBe(true);
54
+ expect(isReference({ type: REF_RANGE })).toBe(true);
55
+ expect(isReference({ type: REF_STRUCT })).toBe(true);
56
+ expect(isReference({ type: REF_TERNARY })).toBe(true);
57
+ });
58
+ });
59
+
60
+ describe('isLiteral', () => {
61
+ test('returns false for non-literal types', () => {
62
+ expect(isLiteral(null)).toBe(false);
63
+ // @ts-expect-error -- testing invalid input
64
+ expect(isLiteral({})).toBe(false);
65
+ expect(isLiteral({ type: FUNCTION })).toBe(false);
66
+ expect(isLiteral({ type: FX_PREFIX })).toBe(false);
67
+ expect(isLiteral({ type: NEWLINE })).toBe(false);
68
+ expect(isLiteral({ type: OPERATOR })).toBe(false);
69
+ expect(isLiteral({ type: REF_BEAM })).toBe(false);
70
+ expect(isLiteral({ type: REF_NAMED })).toBe(false);
71
+ expect(isLiteral({ type: REF_RANGE })).toBe(false);
72
+ expect(isLiteral({ type: REF_STRUCT })).toBe(false);
73
+ expect(isLiteral({ type: REF_TERNARY })).toBe(false);
74
+ expect(isLiteral({ type: WHITESPACE })).toBe(false);
75
+ });
76
+
77
+ test('returns true for literal types', () => {
78
+ expect(isLiteral({ type: BOOLEAN })).toBe(true);
79
+ expect(isLiteral({ type: ERROR })).toBe(true);
80
+ expect(isLiteral({ type: NUMBER })).toBe(true);
81
+ expect(isLiteral({ type: STRING })).toBe(true);
82
+ });
83
+ });
84
+
85
+ describe('isError', () => {
86
+ test('returns false for non-error types', () => {
87
+ expect(isError(null)).toBe(false);
88
+ // @ts-expect-error -- testing invalid input
89
+ expect(isError({})).toBe(false);
90
+ expect(isError({ type: BOOLEAN })).toBe(false);
91
+ expect(isError({ type: FUNCTION })).toBe(false);
92
+ expect(isError({ type: FX_PREFIX })).toBe(false);
93
+ expect(isError({ type: NEWLINE })).toBe(false);
94
+ expect(isError({ type: NUMBER })).toBe(false);
95
+ expect(isError({ type: OPERATOR })).toBe(false);
96
+ expect(isError({ type: REF_BEAM })).toBe(false);
97
+ expect(isError({ type: REF_NAMED })).toBe(false);
98
+ expect(isError({ type: REF_RANGE })).toBe(false);
99
+ expect(isError({ type: REF_STRUCT })).toBe(false);
100
+ expect(isError({ type: REF_TERNARY })).toBe(false);
101
+ expect(isError({ type: STRING })).toBe(false);
102
+ expect(isError({ type: WHITESPACE })).toBe(false);
103
+ });
104
+
105
+ test('returns true for error type', () => {
106
+ expect(isError({ type: ERROR })).toBe(true);
107
+ });
108
+ });
109
+
110
+ describe('isWhitespace', () => {
111
+ test('returns false for non-whitespace types', () => {
112
+ expect(isWhitespace(null)).toBe(false);
113
+ // @ts-expect-error -- testing invalid input
114
+ expect(isWhitespace({})).toBe(false);
115
+ expect(isWhitespace({ type: BOOLEAN })).toBe(false);
116
+ expect(isWhitespace({ type: ERROR })).toBe(false);
117
+ expect(isWhitespace({ type: FUNCTION })).toBe(false);
118
+ expect(isWhitespace({ type: FX_PREFIX })).toBe(false);
119
+ expect(isWhitespace({ type: NUMBER })).toBe(false);
120
+ expect(isWhitespace({ type: OPERATOR })).toBe(false);
121
+ expect(isWhitespace({ type: REF_BEAM })).toBe(false);
122
+ expect(isWhitespace({ type: REF_NAMED })).toBe(false);
123
+ expect(isWhitespace({ type: REF_RANGE })).toBe(false);
124
+ expect(isWhitespace({ type: REF_STRUCT })).toBe(false);
125
+ expect(isWhitespace({ type: REF_TERNARY })).toBe(false);
126
+ expect(isWhitespace({ type: STRING })).toBe(false);
127
+ });
128
+
129
+ test('returns true for whitespace types', () => {
130
+ expect(isWhitespace({ type: NEWLINE })).toBe(true);
131
+ expect(isWhitespace({ type: WHITESPACE })).toBe(true);
132
+ });
133
+ });
134
+
135
+ describe('isFunction', () => {
136
+ test('returns false for non-function types', () => {
137
+ expect(isFunction(null)).toBe(false);
138
+ // @ts-expect-error -- testing invalid input
139
+ expect(isFunction({})).toBe(false);
140
+ expect(isFunction({ type: BOOLEAN })).toBe(false);
141
+ expect(isFunction({ type: ERROR })).toBe(false);
142
+ expect(isFunction({ type: FX_PREFIX })).toBe(false);
143
+ expect(isFunction({ type: NEWLINE })).toBe(false);
144
+ expect(isFunction({ type: NUMBER })).toBe(false);
145
+ expect(isFunction({ type: OPERATOR })).toBe(false);
146
+ expect(isFunction({ type: REF_BEAM })).toBe(false);
147
+ expect(isFunction({ type: REF_NAMED })).toBe(false);
148
+ expect(isFunction({ type: REF_RANGE })).toBe(false);
149
+ expect(isFunction({ type: REF_STRUCT })).toBe(false);
150
+ expect(isFunction({ type: REF_TERNARY })).toBe(false);
151
+ expect(isFunction({ type: STRING })).toBe(false);
152
+ expect(isFunction({ type: WHITESPACE })).toBe(false);
153
+ });
154
+
155
+ test('returns true for function type', () => {
156
+ expect(isFunction({ type: FUNCTION })).toBe(true);
157
+ });
158
+ });
159
+
160
+ describe('isFxPrefix', () => {
161
+ test('returns false for non-prefix types', () => {
162
+ expect(isFxPrefix(null)).toBe(false);
163
+ // @ts-expect-error -- testing invalid input
164
+ expect(isFxPrefix({})).toBe(false);
165
+ expect(isFxPrefix({ type: BOOLEAN })).toBe(false);
166
+ expect(isFxPrefix({ type: ERROR })).toBe(false);
167
+ expect(isFxPrefix({ type: FUNCTION })).toBe(false);
168
+ expect(isFxPrefix({ type: NEWLINE })).toBe(false);
169
+ expect(isFxPrefix({ type: NUMBER })).toBe(false);
170
+ expect(isFxPrefix({ type: OPERATOR })).toBe(false);
171
+ expect(isFxPrefix({ type: REF_BEAM })).toBe(false);
172
+ expect(isFxPrefix({ type: REF_NAMED })).toBe(false);
173
+ expect(isFxPrefix({ type: REF_RANGE })).toBe(false);
174
+ expect(isFxPrefix({ type: REF_STRUCT })).toBe(false);
175
+ expect(isFxPrefix({ type: REF_TERNARY })).toBe(false);
176
+ expect(isFxPrefix({ type: STRING })).toBe(false);
177
+ expect(isFxPrefix({ type: WHITESPACE })).toBe(false);
178
+ });
179
+
180
+ test('returns true for FX_PREFIX type', () => {
181
+ expect(isFxPrefix({ type: FX_PREFIX })).toBe(true);
182
+ });
183
+ });
184
+
185
+ describe('isOperator', () => {
186
+ test('returns false for non-operator types', () => {
187
+ expect(isOperator(null)).toBe(false);
188
+ // @ts-expect-error -- testing invalid input
189
+ expect(isOperator({})).toBe(false);
190
+ expect(isOperator({ type: BOOLEAN })).toBe(false);
191
+ expect(isOperator({ type: ERROR })).toBe(false);
192
+ expect(isOperator({ type: FUNCTION })).toBe(false);
193
+ expect(isOperator({ type: FX_PREFIX })).toBe(false);
194
+ expect(isOperator({ type: NEWLINE })).toBe(false);
195
+ expect(isOperator({ type: NUMBER })).toBe(false);
196
+ expect(isOperator({ type: REF_BEAM })).toBe(false);
197
+ expect(isOperator({ type: REF_NAMED })).toBe(false);
198
+ expect(isOperator({ type: REF_RANGE })).toBe(false);
199
+ expect(isOperator({ type: REF_STRUCT })).toBe(false);
200
+ expect(isOperator({ type: REF_TERNARY })).toBe(false);
201
+ expect(isOperator({ type: STRING })).toBe(false);
202
+ expect(isOperator({ type: WHITESPACE })).toBe(false);
203
+ });
204
+
205
+ test('returns true for operator type', () => {
206
+ expect(isOperator({ type: OPERATOR })).toBe(true);
207
+ });
208
+ });
@@ -3,7 +3,8 @@ import {
3
3
  FX_PREFIX, WHITESPACE, NEWLINE,
4
4
  FUNCTION, OPERATOR,
5
5
  ERROR, STRING, NUMBER, BOOLEAN
6
- } from './constants.js';
6
+ } from './constants.ts';
7
+ import type { Token } from './types.ts';
7
8
 
8
9
  /**
9
10
  * Determines whether the specified token is a range.
@@ -12,10 +13,10 @@ import {
12
13
  * (`A1` or `A1:B2`), REF_TERNARY (`A1:A`, `A1:1`, `1:A1`, or `A:A1`), or
13
14
  * REF_BEAM (`A:A` or `1:1`). In all other cases `false` is returned.
14
15
  *
15
- * @param {any} token A token
16
- * @returns {boolean} True if the specified token is range, False otherwise.
16
+ * @param token A token
17
+ * @returns True if the specified token is range, False otherwise.
17
18
  */
18
- export function isRange (token) {
19
+ export function isRange (token?: Pick<Token, 'type'> | null): boolean {
19
20
  return !!token && (
20
21
  token.type === REF_RANGE ||
21
22
  token.type === REF_BEAM ||
@@ -30,10 +31,10 @@ export function isRange (token) {
30
31
  * REF_TERNARY (`A1:A`, `A1:1`, `1:A1`, or `A:A1`), REF_BEAM (`A:A` or `1:1`),
31
32
  * or REF_NAMED (`myrange`). In all other cases `false` is returned.
32
33
  *
33
- * @param {any} token The token
34
- * @returns {boolean} True if the specified token is reference, False otherwise.
34
+ * @param token The token
35
+ * @returns True if the specified token is reference, False otherwise.
35
36
  */
36
- export function isReference (token) {
37
+ export function isReference (token?: Pick<Token, 'type'> | null): boolean {
37
38
  return !!token && (
38
39
  token.type === REF_RANGE ||
39
40
  token.type === REF_BEAM ||
@@ -50,10 +51,10 @@ export function isReference (token) {
50
51
  * ERROR (`#VALUE!`), NUMBER (123.4), or STRING (`"lorem ipsum"`). In all other
51
52
  * cases `false` is returned.
52
53
  *
53
- * @param {any} token The token
54
- * @returns {boolean} True if the specified token is literal, False otherwise.
54
+ * @param token The token
55
+ * @returns True if the specified token is literal, False otherwise.
55
56
  */
56
- export function isLiteral (token) {
57
+ export function isLiteral (token?: Pick<Token, 'type'> | null): boolean {
57
58
  return !!token && (
58
59
  token.type === BOOLEAN ||
59
60
  token.type === ERROR ||
@@ -68,10 +69,10 @@ export function isLiteral (token) {
68
69
  * Returns `true` if the input is a token of type ERROR (`#VALUE!`). In all
69
70
  * other cases `false` is returned.
70
71
  *
71
- * @param {any} token The token
72
- * @returns {boolean} True if the specified token is error, False otherwise.
72
+ * @param token The token
73
+ * @returns True if the specified token is error, False otherwise.
73
74
  */
74
- export function isError (token) {
75
+ export function isError (token?: Pick<Token, 'type'> | null): boolean {
75
76
  return !!token && token.type === ERROR;
76
77
  }
77
78
 
@@ -81,10 +82,10 @@ export function isError (token) {
81
82
  * Returns `true` if the input is a token of type WHITESPACE (` `) or
82
83
  * NEWLINE (`\n`). In all other cases `false` is returned.
83
84
  *
84
- * @param {any} token The token
85
- * @returns {boolean} True if the specified token is whitespace, False otherwise.
85
+ * @param token The token
86
+ * @returns True if the specified token is whitespace, False otherwise.
86
87
  */
87
- export function isWhitespace (token) {
88
+ export function isWhitespace (token?: Pick<Token, 'type'> | null): boolean {
88
89
  return !!token && (
89
90
  token.type === WHITESPACE ||
90
91
  token.type === NEWLINE
@@ -97,10 +98,10 @@ export function isWhitespace (token) {
97
98
  * Returns `true` if the input is a token of type FUNCTION.
98
99
  * In all other cases `false` is returned.
99
100
  *
100
- * @param {any} token The token
101
- * @returns {boolean} True if the specified token is function, False otherwise.
101
+ * @param token The token
102
+ * @returns True if the specified token is function, False otherwise.
102
103
  */
103
- export function isFunction (token) {
104
+ export function isFunction (token?: Pick<Token, 'type'> | null): boolean {
104
105
  return !!token && token.type === FUNCTION;
105
106
  }
106
107
 
@@ -108,10 +109,10 @@ export function isFunction (token) {
108
109
  * Returns `true` if the input is a token of type FX_PREFIX (leading `=` in
109
110
  * formula). In all other cases `false` is returned.
110
111
  *
111
- * @param {any} token The token
112
- * @returns {boolean} True if the specified token is effects prefix, False otherwise.
112
+ * @param token The token
113
+ * @returns True if the specified token is effects prefix, False otherwise.
113
114
  */
114
- export function isFxPrefix (token) {
115
+ export function isFxPrefix (token?: Pick<Token, 'type'> | null): boolean {
115
116
  return !!token && token.type === FX_PREFIX;
116
117
  }
117
118
 
@@ -121,9 +122,9 @@ export function isFxPrefix (token) {
121
122
  * Returns `true` if the input is a token of type OPERATOR (`+` or `:`). In all
122
123
  * other cases `false` is returned.
123
124
  *
124
- * @param {any} token The token
125
- * @returns {boolean} True if the specified token is operator, False otherwise.
125
+ * @param token The token
126
+ * @returns True if the specified token is operator, False otherwise.
126
127
  */
127
- export function isOperator (token) {
128
+ export function isOperator (token?: Pick<Token, 'type'> | null): boolean {
128
129
  return !!token && token.type === OPERATOR;
129
130
  }
@@ -1,7 +1,7 @@
1
1
  const PERIOD = 46;
2
2
  const COLON = 58;
3
3
 
4
- export function advRangeOp (str, pos) {
4
+ export function advRangeOp (str: string, pos: number): number {
5
5
  const c0 = str.charCodeAt(pos);
6
6
  if (c0 === PERIOD) {
7
7
  const c1 = str.charCodeAt(pos + 1);
@@ -1,5 +1,5 @@
1
1
  // regular: [A-Za-z0-9_\u00a1-\uffff]
2
- export function canEndRange (str, pos) {
2
+ export function canEndRange (str: string, pos: number): boolean {
3
3
  const c = str.charCodeAt(pos);
4
4
  return !(
5
5
  (c >= 65 && c <= 90) || // A-Z
@@ -11,7 +11,7 @@ export function canEndRange (str, pos) {
11
11
  }
12
12
 
13
13
  // partial: [A-Za-z0-9_($.]
14
- export function canEndPartialRange (str, pos) {
14
+ export function canEndPartialRange (str: string, pos: number): boolean {
15
15
  const c = str.charCodeAt(pos);
16
16
  return !(
17
17
  (c >= 65 && c <= 90) || // A-Z
@@ -1,6 +1,21 @@
1
- import { BOOLEAN } from '../constants.js';
1
+ import { BOOLEAN } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
2
3
 
3
- export function lexBoolean (str, pos) {
4
+ function preventMatch (c: number) {
5
+ return (
6
+ (c >= 65 && c <= 90) || // A-Z
7
+ (c >= 97 && c <= 122) || // a-z
8
+ (c >= 48 && c <= 57) || // 0-9
9
+ (c === 95) || // _
10
+ (c === 92) || // \
11
+ (c === 40) || // (
12
+ (c === 46) || // .
13
+ (c === 63) || // ?
14
+ (c > 0xA0) // \u00a1-\uffff
15
+ );
16
+ }
17
+
18
+ export function lexBoolean (str: string, pos: number): Token | undefined {
4
19
  // "true" (case insensitive)
5
20
  const c0 = str.charCodeAt(pos);
6
21
  if (c0 === 84 || c0 === 116) {
@@ -10,8 +25,10 @@ export function lexBoolean (str, pos) {
10
25
  if (c2 === 85 || c2 === 117) {
11
26
  const c3 = str.charCodeAt(pos + 3);
12
27
  if (c3 === 69 || c3 === 101) {
13
- // non char to follow?
14
- return { type: BOOLEAN, value: str.slice(pos, pos + 4) };
28
+ const c4 = str.charCodeAt(pos + 4);
29
+ if (!preventMatch(c4)) {
30
+ return { type: BOOLEAN, value: str.slice(pos, pos + 4) };
31
+ }
15
32
  }
16
33
  }
17
34
  }
@@ -26,8 +43,10 @@ export function lexBoolean (str, pos) {
26
43
  if (c3 === 83 || c3 === 115) {
27
44
  const c4 = str.charCodeAt(pos + 4);
28
45
  if (c4 === 69 || c4 === 101) {
29
- // non char to follow?
30
- return { type: BOOLEAN, value: str.slice(pos, pos + 5) };
46
+ const c5 = str.charCodeAt(pos + 5);
47
+ if (!preventMatch(c5)) {
48
+ return { type: BOOLEAN, value: str.slice(pos, pos + 5) };
49
+ }
31
50
  }
32
51
  }
33
52
  }
@@ -1,4 +1,5 @@
1
- import { CONTEXT, CONTEXT_QUOTE } from '../constants.js';
1
+ import { CONTEXT, CONTEXT_QUOTE } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
2
3
 
3
4
  const QUOT_SINGLE = 39; // '
4
5
  const BR_OPEN = 91; // [
@@ -7,10 +8,10 @@ const EXCL = 33; // !
7
8
 
8
9
  // xlsx xml uses a variant of the syntax that has external references in
9
10
  // bracets. Any of: [1]Sheet1!A1, '[1]Sheet one'!A1, [1]!named
10
- export function lexContext (str, pos, options) {
11
+ export function lexContextQuoted (str: string, pos: number, options: { xlsx: boolean }): Token | undefined {
11
12
  const c0 = str.charCodeAt(pos);
12
- let br1;
13
- let br2;
13
+ let br1: number;
14
+ let br2: number;
14
15
  // quoted context: '(?:''|[^'])*('|$)(?=!)
15
16
  if (c0 === QUOT_SINGLE) {
16
17
  const start = pos;
@@ -44,8 +45,15 @@ export function lexContext (str, pos, options) {
44
45
  pos++;
45
46
  }
46
47
  }
47
- // unquoted context
48
- else if (c0 !== EXCL) {
48
+ }
49
+
50
+ // xlsx xml uses a variant of the syntax that has external references in
51
+ // bracets. Any of: [1]Sheet1!A1, '[1]Sheet one'!A1, [1]!named
52
+ export function lexContextUnquoted (str: string, pos: number, options: { xlsx: boolean }): Token | undefined {
53
+ const c0 = str.charCodeAt(pos);
54
+ let br1: number;
55
+ let br2: number;
56
+ if (c0 !== QUOT_SINGLE && c0 !== EXCL) {
49
57
  const start = pos;
50
58
  while (pos < str.length) {
51
59
  const c = str.charCodeAt(pos);
@@ -1,10 +1,10 @@
1
- /* eslint-disable no-mixed-operators */
2
- import { ERROR } from '../constants.js';
1
+ import { ERROR } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
3
3
 
4
4
  const re_ERROR = /#(?:NAME\?|FIELD!|CALC!|VALUE!|REF!|DIV\/0!|NULL!|NUM!|N\/A|GETTING_DATA\b|SPILL!|UNKNOWN!|SYNTAX\?|ERROR!|CONNECT!|BLOCKED!|EXTERNAL!)/iy;
5
5
  const HASH = 35;
6
6
 
7
- export function lexError (str, pos) {
7
+ export function lexError (str: string, pos: number): Token | undefined {
8
8
  if (str.charCodeAt(pos) === HASH) {
9
9
  re_ERROR.lastIndex = pos;
10
10
  const m = re_ERROR.exec(str);
@@ -1,9 +1,10 @@
1
- import { FUNCTION } from '../constants.js';
1
+ import { FUNCTION } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
2
3
 
3
4
  const PAREN_OPEN = 40;
4
5
 
5
6
  // [A-Za-z_]+[A-Za-z\d_.]*(?=\()
6
- export function lexFunction (str, pos) {
7
+ export function lexFunction (str: string, pos: number): Token | undefined {
7
8
  const start = pos;
8
9
  // starts with: a-zA-Z_
9
10
  let c = str.charCodeAt(pos);
@@ -0,0 +1,112 @@
1
+ import { CONTEXT, FUNCTION, REF_NAMED, UNKNOWN } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
3
+ import { lexContextUnquoted } from './lexContext.ts';
4
+
5
+ const BR_OPEN = 91; // [
6
+ const PAREN_OPEN = 40;
7
+ const EXCL = 33; // !
8
+ const OFFS = 32;
9
+
10
+ // build a map of characters to allow-bitmasks
11
+ const ALLOWED = new Uint8Array(180 - OFFS);
12
+ const OK_NAME_0 = 0b000001;
13
+ const OK_FUNC_0 = 0b000010;
14
+ const OK_CNTX_0 = 0b000100;
15
+ const OK_NAME_N = 0b001000;
16
+ const OK_FUNC_N = 0b010000;
17
+ const OK_CNTX_N = 0b100000;
18
+ const OK_0 = OK_NAME_0 | OK_FUNC_0 | OK_CNTX_0;
19
+ const OK_N = OK_NAME_N | OK_FUNC_N | OK_CNTX_N;
20
+ const OK_HIGHCHAR = OK_NAME_0 | OK_NAME_N | OK_CNTX_0 | OK_CNTX_N;
21
+ for (let c = OFFS; c < 180; c++) {
22
+ const char = String.fromCharCode(c);
23
+ const n0 = /^[a-zA-Z_\\\u00a1-\uffff]$/.test(char);
24
+ const f0 = /^[a-zA-Z_]$/.test(char);
25
+ const nN = /^[a-zA-Z0-9_.\\?\u00a1-\uffff]$/.test(char);
26
+ const fN = /^[a-zA-Z0-9_.]$/.test(char);
27
+ const cX = /^[a-zA-Z0-9_.¡¤§¨ª\u00ad¯-\uffff]$/.test(char);
28
+ ALLOWED[c - OFFS] = (
29
+ (n0 ? OK_NAME_0 : 0) |
30
+ (nN ? OK_NAME_N : 0) |
31
+ (f0 ? OK_FUNC_0 : 0) |
32
+ (fN ? OK_FUNC_N : 0) |
33
+ (cX ? OK_CNTX_0 : 0) |
34
+ (cX ? OK_CNTX_N : 0)
35
+ );
36
+ }
37
+
38
+ function nameOrUnknown (str, s, start, pos, name) {
39
+ const len = pos - start;
40
+ if (name && len && len < 255) {
41
+ // names starting with \ must be at least 3 char long
42
+ if (s === 92 && len < 3) {
43
+ return;
44
+ }
45
+ // single characters R and C are forbidden as names
46
+ if (len === 1 && (s === 114 || s === 82 || s === 99 || s === 67)) {
47
+ return;
48
+ }
49
+ return { type: REF_NAMED, value: str.slice(start, pos) };
50
+ }
51
+ return { type: UNKNOWN, value: str.slice(start, pos) };
52
+ }
53
+
54
+ export function lexNameFuncCntx (
55
+ str: string,
56
+ pos: number,
57
+ opts: { xlsx: boolean }
58
+ ): Token | undefined {
59
+ const start = pos;
60
+
61
+ const s = str.charCodeAt(pos);
62
+ const a = s > 180 ? OK_HIGHCHAR : ALLOWED[s - OFFS];
63
+ // name: [a-zA-Z_\\\u00a1-\uffff]
64
+ // func: [a-zA-Z_]
65
+ // cntx: [a-zA-Z_0-9.¡¤§¨ª\u00ad¯-\uffff]
66
+ if (((a & OK_CNTX_0) && !(a & OK_NAME_0) && !(a & OK_FUNC_0)) || s === BR_OPEN) {
67
+ // its a context so delegate to that lexer
68
+ return lexContextUnquoted(str, pos, opts);
69
+ }
70
+ if (!(a & OK_0)) {
71
+ return;
72
+ }
73
+ let name = (a & OK_NAME_0) ? 1 : 0;
74
+ let func = (a & OK_FUNC_0) ? 1 : 0;
75
+ let cntx = (a & OK_CNTX_0) ? 1 : 0;
76
+ pos++;
77
+
78
+ let c: number;
79
+ do {
80
+ c = str.charCodeAt(pos);
81
+ const a = s > 180 ? OK_HIGHCHAR : ALLOWED[c - OFFS] ?? 0;
82
+ if (a & OK_N) {
83
+ // name: [a-zA-Z_0-9.\\?\u00a1-\uffff]
84
+ // func: [a-zA-Z_0-9.]
85
+ // cntx: [a-zA-Z_0-9.¡¤§¨ª\u00ad¯-\uffff]
86
+ if (name && !(a & OK_NAME_N)) {
87
+ name = 0;
88
+ }
89
+ if (func && !(a & OK_FUNC_N)) {
90
+ func = 0;
91
+ }
92
+ if (cntx && !(a & OK_CNTX_N)) {
93
+ cntx = 0;
94
+ }
95
+ }
96
+ else {
97
+ if (c === PAREN_OPEN && func) {
98
+ return { type: FUNCTION, value: str.slice(start, pos) };
99
+ }
100
+ else if (c === EXCL && cntx) {
101
+ return { type: CONTEXT, value: str.slice(start, pos) };
102
+ }
103
+ return nameOrUnknown(str, s, start, pos, name);
104
+ }
105
+ pos++;
106
+ }
107
+ while ((name || func || cntx) && pos < str.length);
108
+
109
+ if (start !== pos) {
110
+ return nameOrUnknown(str, s, start, pos, name);
111
+ }
112
+ }
@@ -1,5 +1,5 @@
1
- /* eslint-disable max-len */
2
- import { REF_NAMED } from '../constants.js';
1
+ import { REF_NAMED } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
3
3
 
4
4
  // The advertized named ranges rules are a bit off from what Excel seems to do.
5
5
  // In the "extended range" of chars, it looks like it allows most things above
@@ -8,7 +8,7 @@ import { REF_NAMED } from '../constants.js';
8
8
  //
9
9
  // I've simplified to allowing everything above U+00A1:
10
10
  // /^[a-zA-Z\\_\u00a1-\uffff][a-zA-Z0-9\\_.?\u00a1-\uffff]{0,254}/
11
- export function lexNamed (str, pos) {
11
+ export function lexNamed (str: string, pos: number): Token | undefined {
12
12
  const start = pos;
13
13
  // starts with: [a-zA-Z\\_\u00a1-\uffff]
14
14
  const s = str.charCodeAt(pos);
@@ -25,7 +25,7 @@ export function lexNamed (str, pos) {
25
25
  return;
26
26
  }
27
27
  // has any number of: [a-zA-Z0-9\\_.?\u00a1-\uffff]
28
- let c;
28
+ let c: number;
29
29
  do {
30
30
  c = str.charCodeAt(pos);
31
31
  if (
@@ -1,6 +1,7 @@
1
- import { NEWLINE } from '../constants.js';
1
+ import { NEWLINE } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
2
3
 
3
- export function lexNewLine (str, pos) {
4
+ export function lexNewLine (str: string, pos: number): Token | undefined {
4
5
  const start = pos;
5
6
  while (str.charCodeAt(pos) === 10) {
6
7
  pos++;
@@ -1,6 +1,7 @@
1
- import { NUMBER } from '../constants.js';
1
+ import { NUMBER } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
2
3
 
3
- function advDigits (str, pos) {
4
+ function advDigits (str: string, pos: number): number {
4
5
  const start = pos;
5
6
  do {
6
7
  const c = str.charCodeAt(pos);
@@ -14,7 +15,7 @@ function advDigits (str, pos) {
14
15
  }
15
16
 
16
17
  // \d+(\.\d+)?(?:[eE][+-]?\d+)?
17
- export function lexNumber (str, pos) {
18
+ export function lexNumber (str: string, pos: number): Token | undefined {
18
19
  const start = pos;
19
20
 
20
21
  // integer
@@ -1,6 +1,7 @@
1
- import { OPERATOR } from '../constants.js';
1
+ import { OPERATOR } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
2
3
 
3
- export function lexOperator (str, pos) {
4
+ export function lexOperator (str: string, pos: number): Token | undefined {
4
5
  const c0 = str.charCodeAt(pos);
5
6
  const c1 = str.charCodeAt(pos + 1);
6
7
  if (
@@ -14,9 +15,9 @@ export function lexOperator (str, pos) {
14
15
  // { } ! # % &
15
16
  c0 === 123 || c0 === 125 || c0 === 33 || c0 === 35 || c0 === 37 || c0 === 38 ||
16
17
  // ( ) * + , -
17
- c0 === 40 || c0 === 41 || c0 === 42 || c0 === 43 || c0 === 44 || c0 === 45 ||
18
+ (c0 >= 40 && c0 <= 45) ||
18
19
  // / : ; < = >
19
- c0 === 47 || c0 === 58 || c0 === 59 || c0 === 60 || c0 === 61 || c0 === 62 ||
20
+ c0 === 47 || (c0 >= 58 && c0 <= 62) ||
20
21
  // @ ^
21
22
  c0 === 64 || c0 === 94
22
23
  ) {