@borgar/fx 4.12.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 (139) 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.ts +18 -0
  36. package/lib/lexers/canEndRange.ts +25 -0
  37. package/lib/lexers/lexBoolean.ts +55 -0
  38. package/lib/lexers/lexContext.ts +104 -0
  39. package/lib/lexers/lexError.ts +15 -0
  40. package/lib/lexers/lexFunction.ts +37 -0
  41. package/lib/lexers/lexNameFuncCntx.ts +112 -0
  42. package/lib/lexers/lexNamed.ts +60 -0
  43. package/lib/lexers/lexNewLine.ts +12 -0
  44. package/lib/lexers/lexNumber.ts +48 -0
  45. package/lib/lexers/lexOperator.ts +26 -0
  46. package/lib/lexers/lexRange.ts +15 -0
  47. package/lib/lexers/lexRangeA1.ts +134 -0
  48. package/lib/lexers/lexRangeR1C1.ts +146 -0
  49. package/lib/lexers/lexRangeTrim.ts +26 -0
  50. package/lib/lexers/lexRefOp.ts +19 -0
  51. package/lib/lexers/lexString.ts +22 -0
  52. package/lib/lexers/lexStructured.ts +25 -0
  53. package/lib/lexers/lexWhitespace.ts +31 -0
  54. package/lib/lexers/sets.ts +51 -0
  55. package/lib/mergeRefTokens.spec.ts +141 -0
  56. package/lib/{mergeRefTokens.js → mergeRefTokens.ts} +47 -32
  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.ts +240 -0
  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 +46 -30
  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/dist/fx.d.ts +0 -823
  104. package/dist/fx.js +0 -2
  105. package/dist/package.json +0 -1
  106. package/lib/a1.js +0 -348
  107. package/lib/a1.spec.js +0 -458
  108. package/lib/addTokenMeta.spec.js +0 -153
  109. package/lib/astTypes.js +0 -96
  110. package/lib/extraTypes.js +0 -74
  111. package/lib/fixRanges.js +0 -104
  112. package/lib/fixRanges.spec.js +0 -170
  113. package/lib/fromCol.spec.js +0 -11
  114. package/lib/index.js +0 -134
  115. package/lib/index.spec.js +0 -67
  116. package/lib/isType.spec.js +0 -168
  117. package/lib/lexer-srefs.spec.js +0 -324
  118. package/lib/lexer.js +0 -283
  119. package/lib/lexer.spec.js +0 -1953
  120. package/lib/lexerParts.js +0 -228
  121. package/lib/mergeRefTokens.spec.js +0 -121
  122. package/lib/package.json +0 -1
  123. package/lib/parseRef.js +0 -157
  124. package/lib/parseRef.spec.js +0 -71
  125. package/lib/parseSRange.js +0 -167
  126. package/lib/parseStructRef.js +0 -48
  127. package/lib/parseStructRef.spec.js +0 -164
  128. package/lib/parser.spec.js +0 -1208
  129. package/lib/rc.js +0 -341
  130. package/lib/rc.spec.js +0 -403
  131. package/lib/stringifyStructRef.js +0 -80
  132. package/lib/stringifyStructRef.spec.js +0 -182
  133. package/lib/toCol.spec.js +0 -11
  134. package/lib/translate-toA1.spec.js +0 -214
  135. package/lib/translate-toRC.spec.js +0 -197
  136. package/lib/translate.js +0 -239
  137. package/lib/translate.spec.js +0 -21
  138. package/rollup.config.mjs +0 -22
  139. 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
  }
@@ -0,0 +1,18 @@
1
+ const PERIOD = 46;
2
+ const COLON = 58;
3
+
4
+ export function advRangeOp (str: string, pos: number): number {
5
+ const c0 = str.charCodeAt(pos);
6
+ if (c0 === PERIOD) {
7
+ const c1 = str.charCodeAt(pos + 1);
8
+ if (c1 === COLON) {
9
+ return str.charCodeAt(pos + 2) === PERIOD ? 3 : 2;
10
+ }
11
+ }
12
+ else if (c0 === COLON) {
13
+ const c1 = str.charCodeAt(pos + 1);
14
+ return c1 === PERIOD ? 2 : 1;
15
+ }
16
+ return 0;
17
+ }
18
+
@@ -0,0 +1,25 @@
1
+ // regular: [A-Za-z0-9_\u00a1-\uffff]
2
+ export function canEndRange (str: string, pos: number): boolean {
3
+ const c = str.charCodeAt(pos);
4
+ return !(
5
+ (c >= 65 && c <= 90) || // A-Z
6
+ (c >= 97 && c <= 122) || // a-z
7
+ (c >= 48 && c <= 57) || // 0-9
8
+ (c === 95) || // _
9
+ (c > 0xA0) // \u00a1-\uffff
10
+ );
11
+ }
12
+
13
+ // partial: [A-Za-z0-9_($.]
14
+ export function canEndPartialRange (str: string, pos: number): boolean {
15
+ const c = str.charCodeAt(pos);
16
+ return !(
17
+ (c >= 65 && c <= 90) || // A-Z
18
+ (c >= 97 && c <= 122) || // a-z
19
+ (c >= 48 && c <= 57) || // 0-9
20
+ (c === 95) || // _
21
+ (c === 40) || // (
22
+ (c === 36) || // $
23
+ (c === 46) // .
24
+ );
25
+ }
@@ -0,0 +1,55 @@
1
+ import { BOOLEAN } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
3
+
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 {
19
+ // "true" (case insensitive)
20
+ const c0 = str.charCodeAt(pos);
21
+ if (c0 === 84 || c0 === 116) {
22
+ const c1 = str.charCodeAt(pos + 1);
23
+ if (c1 === 82 || c1 === 114) {
24
+ const c2 = str.charCodeAt(pos + 2);
25
+ if (c2 === 85 || c2 === 117) {
26
+ const c3 = str.charCodeAt(pos + 3);
27
+ if (c3 === 69 || c3 === 101) {
28
+ const c4 = str.charCodeAt(pos + 4);
29
+ if (!preventMatch(c4)) {
30
+ return { type: BOOLEAN, value: str.slice(pos, pos + 4) };
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ // "false" (case insensitive)
37
+ if (c0 === 70 || c0 === 102) {
38
+ const c1 = str.charCodeAt(pos + 1);
39
+ if (c1 === 65 || c1 === 97) {
40
+ const c2 = str.charCodeAt(pos + 2);
41
+ if (c2 === 76 || c2 === 108) {
42
+ const c3 = str.charCodeAt(pos + 3);
43
+ if (c3 === 83 || c3 === 115) {
44
+ const c4 = str.charCodeAt(pos + 4);
45
+ if (c4 === 69 || c4 === 101) {
46
+ const c5 = str.charCodeAt(pos + 5);
47
+ if (!preventMatch(c5)) {
48
+ return { type: BOOLEAN, value: str.slice(pos, pos + 5) };
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,104 @@
1
+ import { CONTEXT, CONTEXT_QUOTE } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
3
+
4
+ const QUOT_SINGLE = 39; // '
5
+ const BR_OPEN = 91; // [
6
+ const BR_CLOSE = 93; // ]
7
+ const EXCL = 33; // !
8
+
9
+ // xlsx xml uses a variant of the syntax that has external references in
10
+ // bracets. Any of: [1]Sheet1!A1, '[1]Sheet one'!A1, [1]!named
11
+ export function lexContextQuoted (str: string, pos: number, options: { xlsx: boolean }): Token | undefined {
12
+ const c0 = str.charCodeAt(pos);
13
+ let br1: number;
14
+ let br2: number;
15
+ // quoted context: '(?:''|[^'])*('|$)(?=!)
16
+ if (c0 === QUOT_SINGLE) {
17
+ const start = pos;
18
+ pos++;
19
+ while (pos < str.length) {
20
+ const c = str.charCodeAt(pos);
21
+ if (c === BR_OPEN) {
22
+ if (br1) { return; } // only 1 allowed
23
+ br1 = pos;
24
+ }
25
+ else if (c === BR_CLOSE) {
26
+ if (br2) { return; } // only 1 allowed
27
+ br2 = pos;
28
+ }
29
+ else if (c === QUOT_SINGLE) {
30
+ pos++;
31
+ if (str.charCodeAt(pos) !== QUOT_SINGLE) {
32
+ let valid = br1 == null && br2 == null;
33
+ if (options.xlsx && (br1 === start + 1) && (br2 === pos - 2)) {
34
+ valid = true;
35
+ }
36
+ if ((br1 >= start + 1) && (br2 < pos - 2) && (br2 > br1 + 1)) {
37
+ valid = true;
38
+ }
39
+ if (valid && str.charCodeAt(pos) === EXCL) {
40
+ return { type: CONTEXT_QUOTE, value: str.slice(start, pos) };
41
+ }
42
+ return;
43
+ }
44
+ }
45
+ pos++;
46
+ }
47
+ }
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) {
57
+ const start = pos;
58
+ while (pos < str.length) {
59
+ const c = str.charCodeAt(pos);
60
+ if (c === BR_OPEN) {
61
+ if (br1) { return; } // only 1 allowed
62
+ br1 = pos;
63
+ }
64
+ else if (c === BR_CLOSE) {
65
+ if (br2) { return; } // only 1 allowed
66
+ br2 = pos;
67
+ }
68
+ else if (c === EXCL) {
69
+ let valid = br1 == null && br2 == null;
70
+ if (options.xlsx && (br1 === start) && (br2 === pos - 1)) {
71
+ valid = true;
72
+ }
73
+ if ((br1 >= start) && (br2 < pos - 1) && (br2 > br1 + 1)) {
74
+ valid = true;
75
+ }
76
+ if (valid) {
77
+ return { type: CONTEXT, value: str.slice(start, pos) };
78
+ }
79
+ }
80
+ else if (
81
+ (br1 == null || br2 != null) &&
82
+ // [0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff]
83
+ !(
84
+ (c >= 65 && c <= 90) || // A-Z
85
+ (c >= 97 && c <= 122) || // a-z
86
+ (c >= 48 && c <= 57) || // 0-9
87
+ (c === 46) || // .
88
+ (c === 95) || // _
89
+ (c === 161) || // ¡
90
+ (c === 164) || // ¤
91
+ (c === 167) || // §
92
+ (c === 168) || // ¨
93
+ (c === 170) || // ª
94
+ (c === 173) || // \u00ad
95
+ (c >= 175) // ¯-\uffff
96
+ )
97
+ ) {
98
+ return;
99
+ }
100
+ // 0-9A-Za-z._¡¤§¨ª\u00ad¯-\uffff
101
+ pos++;
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,15 @@
1
+ import { ERROR } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
3
+
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
+ const HASH = 35;
6
+
7
+ export function lexError (str: string, pos: number): Token | undefined {
8
+ if (str.charCodeAt(pos) === HASH) {
9
+ re_ERROR.lastIndex = pos;
10
+ const m = re_ERROR.exec(str);
11
+ if (m) {
12
+ return { type: ERROR, value: m[0] };
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,37 @@
1
+ import { FUNCTION } from '../constants.ts';
2
+ import type { Token } from '../types.ts';
3
+
4
+ const PAREN_OPEN = 40;
5
+
6
+ // [A-Za-z_]+[A-Za-z\d_.]*(?=\()
7
+ export function lexFunction (str: string, pos: number): Token | undefined {
8
+ const start = pos;
9
+ // starts with: a-zA-Z_
10
+ let c = str.charCodeAt(pos);
11
+ if (
12
+ (c < 65 || c > 90) && // A-Z
13
+ (c < 97 || c > 122) && // a-z
14
+ (c !== 95) // _
15
+ ) {
16
+ return;
17
+ }
18
+ pos++;
19
+ // has any number of: a-zA-Z0-9_.
20
+ do {
21
+ c = str.charCodeAt(pos);
22
+ if (
23
+ (c < 65 || c > 90) && // A-Z
24
+ (c < 97 || c > 122) && // a-z
25
+ (c < 48 || c > 57) && // 0-9
26
+ (c !== 95) && // _
27
+ (c !== 46) // .
28
+ ) {
29
+ break;
30
+ }
31
+ pos++;
32
+ } while (pos < str.length);
33
+ // followed by a (
34
+ if (str.charCodeAt(pos) === PAREN_OPEN) {
35
+ return { type: FUNCTION, value: str.slice(start, pos) };
36
+ }
37
+ }