@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.
- package/dist/index-BMr6cTgc.d.cts +1444 -0
- package/dist/index-BMr6cTgc.d.ts +1444 -0
- package/dist/index.cjs +3054 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2984 -0
- package/dist/index.js.map +1 -0
- package/dist/xlsx/index.cjs +3120 -0
- package/dist/xlsx/index.cjs.map +1 -0
- package/dist/xlsx/index.d.cts +55 -0
- package/dist/xlsx/index.d.ts +55 -0
- package/dist/xlsx/index.js +3049 -0
- package/dist/xlsx/index.js.map +1 -0
- package/docs/API.md +2959 -718
- package/docs/AST_format.md +2 -2
- package/eslint.config.mjs +40 -0
- package/lib/a1.spec.ts +32 -0
- package/lib/a1.ts +26 -0
- package/lib/addA1RangeBounds.ts +50 -0
- package/lib/addTokenMeta.spec.ts +166 -0
- package/lib/{addTokenMeta.js → addTokenMeta.ts} +53 -33
- package/lib/astTypes.ts +211 -0
- package/lib/cloneToken.ts +29 -0
- package/lib/{constants.js → constants.ts} +6 -3
- package/lib/fixRanges.spec.ts +220 -0
- package/lib/fixRanges.ts +260 -0
- package/lib/fromCol.spec.ts +15 -0
- package/lib/{fromCol.js → fromCol.ts} +1 -1
- package/lib/index.spec.ts +119 -0
- package/lib/index.ts +76 -0
- package/lib/isNodeType.ts +151 -0
- package/lib/isType.spec.ts +208 -0
- package/lib/{isType.js → isType.ts} +26 -25
- package/lib/lexers/{advRangeOp.js → advRangeOp.ts} +1 -1
- package/lib/lexers/{canEndRange.js → canEndRange.ts} +2 -2
- package/lib/lexers/{lexBoolean.js → lexBoolean.ts} +25 -6
- package/lib/lexers/{lexContext.js → lexContext.ts} +14 -6
- package/lib/lexers/{lexError.js → lexError.ts} +3 -3
- package/lib/lexers/{lexFunction.js → lexFunction.ts} +3 -2
- package/lib/lexers/lexNameFuncCntx.ts +112 -0
- package/lib/lexers/{lexNamed.js → lexNamed.ts} +4 -4
- package/lib/lexers/{lexNewLine.js → lexNewLine.ts} +3 -2
- package/lib/lexers/{lexNumber.js → lexNumber.ts} +4 -3
- package/lib/lexers/{lexOperator.js → lexOperator.ts} +5 -4
- package/lib/lexers/lexRange.ts +15 -0
- package/lib/lexers/{lexRangeA1.js → lexRangeA1.ts} +11 -7
- package/lib/lexers/{lexRangeR1C1.js → lexRangeR1C1.ts} +10 -6
- package/lib/lexers/{lexRangeTrim.js → lexRangeTrim.ts} +3 -2
- package/lib/lexers/{lexRefOp.js → lexRefOp.ts} +4 -3
- package/lib/lexers/{lexString.js → lexString.ts} +3 -3
- package/lib/lexers/{lexStructured.js → lexStructured.ts} +5 -5
- package/lib/lexers/{lexWhitespace.js → lexWhitespace.ts} +3 -2
- package/lib/lexers/sets.ts +51 -0
- package/lib/mergeRefTokens.spec.ts +141 -0
- package/lib/{mergeRefTokens.js → mergeRefTokens.ts} +14 -9
- package/lib/nodeTypes.ts +54 -0
- package/lib/parse.spec.ts +1410 -0
- package/lib/{parser.js → parse.ts} +81 -63
- package/lib/parseA1Range.spec.ts +233 -0
- package/lib/parseA1Range.ts +206 -0
- package/lib/parseA1Ref.spec.ts +337 -0
- package/lib/parseA1Ref.ts +115 -0
- package/lib/parseR1C1Range.ts +191 -0
- package/lib/parseR1C1Ref.spec.ts +323 -0
- package/lib/parseR1C1Ref.ts +127 -0
- package/lib/parseRef.spec.ts +90 -0
- package/lib/parseRef.ts +240 -0
- package/lib/{parseSRange.js → parseSRange.ts} +15 -10
- package/lib/parseStructRef.spec.ts +168 -0
- package/lib/parseStructRef.ts +76 -0
- package/lib/stringifyA1Range.spec.ts +72 -0
- package/lib/stringifyA1Range.ts +72 -0
- package/lib/stringifyA1Ref.spec.ts +64 -0
- package/lib/stringifyA1Ref.ts +59 -0
- package/lib/{stringifyPrefix.js → stringifyPrefix.ts} +17 -2
- package/lib/stringifyR1C1Range.spec.ts +92 -0
- package/lib/stringifyR1C1Range.ts +73 -0
- package/lib/stringifyR1C1Ref.spec.ts +63 -0
- package/lib/stringifyR1C1Ref.ts +67 -0
- package/lib/stringifyStructRef.spec.ts +124 -0
- package/lib/stringifyStructRef.ts +113 -0
- package/lib/stringifyTokens.ts +15 -0
- package/lib/toCol.spec.ts +11 -0
- package/lib/{toCol.js → toCol.ts} +4 -4
- package/lib/tokenTypes.ts +76 -0
- package/lib/tokenize-srefs.spec.ts +429 -0
- package/lib/tokenize.spec.ts +2103 -0
- package/lib/tokenize.ts +346 -0
- package/lib/translate.spec.ts +35 -0
- package/lib/translateToA1.spec.ts +247 -0
- package/lib/translateToA1.ts +231 -0
- package/lib/translateToR1C1.spec.ts +227 -0
- package/lib/translateToR1C1.ts +145 -0
- package/lib/types.ts +179 -0
- package/lib/xlsx/index.spec.ts +27 -0
- package/lib/xlsx/index.ts +32 -0
- package/package.json +45 -31
- package/tsconfig.json +28 -0
- package/typedoc-ignore-links.ts +17 -0
- package/typedoc.json +41 -0
- package/.eslintrc +0 -22
- package/benchmark/benchmark.js +0 -48
- package/benchmark/formulas.json +0 -15677
- package/dist/fx.d.ts +0 -823
- package/dist/fx.js +0 -2
- package/dist/package.json +0 -1
- package/lib/a1.js +0 -348
- package/lib/a1.spec.js +0 -458
- package/lib/addTokenMeta.spec.js +0 -153
- package/lib/astTypes.js +0 -96
- package/lib/extraTypes.js +0 -74
- package/lib/fixRanges.js +0 -104
- package/lib/fixRanges.spec.js +0 -171
- package/lib/fromCol.spec.js +0 -11
- package/lib/index.js +0 -134
- package/lib/index.spec.js +0 -67
- package/lib/isType.spec.js +0 -168
- package/lib/lexer-srefs.spec.js +0 -324
- package/lib/lexer.js +0 -264
- package/lib/lexer.spec.js +0 -1953
- package/lib/lexers/lexRange.js +0 -8
- package/lib/lexers/sets.js +0 -38
- package/lib/mergeRefTokens.spec.js +0 -121
- package/lib/package.json +0 -1
- package/lib/parseRef.js +0 -157
- package/lib/parseRef.spec.js +0 -71
- package/lib/parseStructRef.js +0 -48
- package/lib/parseStructRef.spec.js +0 -164
- package/lib/parser.spec.js +0 -1208
- package/lib/rc.js +0 -341
- package/lib/rc.spec.js +0 -403
- package/lib/stringifyStructRef.js +0 -80
- package/lib/stringifyStructRef.spec.js +0 -182
- package/lib/toCol.spec.js +0 -11
- package/lib/translate-toA1.spec.js +0 -214
- package/lib/translate-toRC.spec.js +0 -197
- package/lib/translate.js +0 -239
- package/lib/translate.spec.js +0 -21
- package/rollup.config.mjs +0 -22
- 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.
|
|
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
|
|
16
|
-
* @returns
|
|
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
|
|
34
|
-
* @returns
|
|
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
|
|
54
|
-
* @returns
|
|
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
|
|
72
|
-
* @returns
|
|
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
|
|
85
|
-
* @returns
|
|
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
|
|
101
|
-
* @returns
|
|
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
|
|
112
|
-
* @returns
|
|
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
|
|
125
|
-
* @returns
|
|
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,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.
|
|
1
|
+
import { BOOLEAN } from '../constants.ts';
|
|
2
|
+
import type { Token } from '../types.ts';
|
|
2
3
|
|
|
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 {
|
|
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
|
-
|
|
14
|
-
|
|
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
|
-
|
|
30
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
48
|
-
|
|
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
|
-
|
|
2
|
-
import {
|
|
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.
|
|
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
|
-
|
|
2
|
-
import {
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
18
|
+
(c0 >= 40 && c0 <= 45) ||
|
|
18
19
|
// / : ; < = >
|
|
19
|
-
c0 === 47 || c0
|
|
20
|
+
c0 === 47 || (c0 >= 58 && c0 <= 62) ||
|
|
20
21
|
// @ ^
|
|
21
22
|
c0 === 64 || c0 === 94
|
|
22
23
|
) {
|