@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
package/lib/fixRanges.ts
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { isRange } from './isType.ts';
|
|
2
|
+
import { parseA1Ref, parseA1RefXlsx } from './parseA1Ref.ts';
|
|
3
|
+
import { stringifyA1Ref, stringifyA1RefXlsx } from './stringifyA1Ref.ts';
|
|
4
|
+
import { addA1RangeBounds } from './addA1RangeBounds.ts';
|
|
5
|
+
import { parseStructRef, parseStructRefXlsx } from './parseStructRef.ts';
|
|
6
|
+
import { stringifyStructRef, stringifyStructRefXlsx } from './stringifyStructRef.ts';
|
|
7
|
+
import { tokenize, type OptsTokenize, tokenizeXlsx } from './tokenize.ts';
|
|
8
|
+
import { REF_STRUCT } from './constants.ts';
|
|
9
|
+
import type { ReferenceA1, ReferenceA1Xlsx, Token } from './types.ts';
|
|
10
|
+
import { cloneToken } from './cloneToken.ts';
|
|
11
|
+
import { stringifyTokens } from './stringifyTokens.ts';
|
|
12
|
+
|
|
13
|
+
// There is no R1C1 counterpart to this. This is because without an anchor cell
|
|
14
|
+
// it is impossible to determine if a relative+absolute range (R[1]C[1]:R5C5)
|
|
15
|
+
// needs to be flipped or not. The solution is to convert to A1 first:
|
|
16
|
+
// translateToRC(fixRanges(translateToA1(...)))
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Options for {@link fixTokenRanges} and {@link fixFormulaRanges}.
|
|
20
|
+
*/
|
|
21
|
+
export type OptsFixRanges = {
|
|
22
|
+
/**
|
|
23
|
+
* Fill in any undefined bounds of range objects. Top to 0, bottom to 1048575, left to 0, and right to 16383.
|
|
24
|
+
* @defaultValue false
|
|
25
|
+
*/
|
|
26
|
+
addBounds?: boolean,
|
|
27
|
+
/**
|
|
28
|
+
* Enforces using the `[#This Row]` instead of the `@` shorthand when serializing structured ranges.
|
|
29
|
+
* @defaultValue false
|
|
30
|
+
*/
|
|
31
|
+
thisRow?: boolean,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Normalizes A1 style ranges and structured references in a list of tokens.
|
|
36
|
+
*
|
|
37
|
+
* It ensures that that the top and left coordinates of an A1 range are on the
|
|
38
|
+
* left-hand side of a colon operator:
|
|
39
|
+
*
|
|
40
|
+
* ```
|
|
41
|
+
* B2:A1 → A1:B2
|
|
42
|
+
* 1:A1 → A1:1
|
|
43
|
+
* A:A1 → A1:A
|
|
44
|
+
* B:A → A:B
|
|
45
|
+
* 2:1 → 1:2
|
|
46
|
+
* A1:A1 → A1
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* When `{ addBounds }` option is set to true, the missing bounds are also added.
|
|
50
|
+
* This can be done to ensure Excel compatible ranges. The fixes then additionally include:
|
|
51
|
+
*
|
|
52
|
+
* ```
|
|
53
|
+
* 1:A1 → A1:1 → 1:1
|
|
54
|
+
* A:A1 → A1:A → A:A
|
|
55
|
+
* A1:A → A:A
|
|
56
|
+
* A1:1 → A:1
|
|
57
|
+
* B2:B → B2:1048576
|
|
58
|
+
* B2:2 → B2:XFD2
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* Structured ranges are normalized to have consistent order and capitalization
|
|
62
|
+
* of sections as well as removing redundant ones.
|
|
63
|
+
*
|
|
64
|
+
* Returns a new array of tokens with values and position data updated.
|
|
65
|
+
*
|
|
66
|
+
* @see {@link OptsFixRanges}
|
|
67
|
+
* @param tokens A list of tokens to be adjusted.
|
|
68
|
+
* @param [options] Options.
|
|
69
|
+
* @returns A token list with ranges adjusted.
|
|
70
|
+
*/
|
|
71
|
+
export function fixTokenRanges (
|
|
72
|
+
tokens: Token[],
|
|
73
|
+
options: OptsFixRanges = {}
|
|
74
|
+
): Token[] {
|
|
75
|
+
if (!Array.isArray(tokens)) {
|
|
76
|
+
throw new Error('fixRanges expects an array of tokens');
|
|
77
|
+
}
|
|
78
|
+
const { addBounds, thisRow } = options;
|
|
79
|
+
let offsetSkew = 0;
|
|
80
|
+
const output: Token[] = [];
|
|
81
|
+
for (const t of tokens) {
|
|
82
|
+
const token = cloneToken(t);
|
|
83
|
+
let offsetDelta = 0;
|
|
84
|
+
if (token.type === REF_STRUCT) {
|
|
85
|
+
const sref = parseStructRef(token.value);
|
|
86
|
+
const newValue = stringifyStructRef(sref, { thisRow });
|
|
87
|
+
offsetDelta = newValue.length - token.value.length;
|
|
88
|
+
token.value = newValue;
|
|
89
|
+
}
|
|
90
|
+
else if (isRange(token)) {
|
|
91
|
+
const ref = parseA1Ref(token.value, { allowTernary: true }) as ReferenceA1;
|
|
92
|
+
const range = ref.range;
|
|
93
|
+
// fill missing dimensions?
|
|
94
|
+
if (addBounds) {
|
|
95
|
+
addA1RangeBounds(range);
|
|
96
|
+
}
|
|
97
|
+
const newValue = stringifyA1Ref(ref);
|
|
98
|
+
offsetDelta = newValue.length - token.value.length;
|
|
99
|
+
token.value = newValue;
|
|
100
|
+
}
|
|
101
|
+
// ensure that positioning is still correct
|
|
102
|
+
if (offsetSkew || offsetDelta) {
|
|
103
|
+
if (token.loc) {
|
|
104
|
+
token.loc[0] += offsetSkew;
|
|
105
|
+
}
|
|
106
|
+
offsetSkew += offsetDelta;
|
|
107
|
+
if (token.loc) {
|
|
108
|
+
token.loc[1] += offsetSkew;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
offsetSkew += offsetDelta;
|
|
113
|
+
}
|
|
114
|
+
output.push(token);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return output;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Normalizes A1 style ranges and structured references in a list of tokens.
|
|
122
|
+
*
|
|
123
|
+
* It ensures that that the top and left coordinates of an A1 range are on the
|
|
124
|
+
* left-hand side of a colon operator:
|
|
125
|
+
*
|
|
126
|
+
* ```
|
|
127
|
+
* B2:A1 → A1:B2
|
|
128
|
+
* 1:A1 → A1:1
|
|
129
|
+
* A:A1 → A1:A
|
|
130
|
+
* B:A → A:B
|
|
131
|
+
* 2:1 → 1:2
|
|
132
|
+
* A1:A1 → A1
|
|
133
|
+
* ```
|
|
134
|
+
*
|
|
135
|
+
* When `{ addBounds }` option is set to true, the missing bounds are also added.
|
|
136
|
+
* This can be done to ensure Excel compatible ranges. The fixes then additionally include:
|
|
137
|
+
*
|
|
138
|
+
* ```
|
|
139
|
+
* 1:A1 → A1:1 → 1:1
|
|
140
|
+
* A:A1 → A1:A → A:A
|
|
141
|
+
* A1:A → A:A
|
|
142
|
+
* A1:1 → A:1
|
|
143
|
+
* B2:B → B2:1048576
|
|
144
|
+
* B2:2 → B2:XFD2
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* Structured ranges are normalized to have consistent order and capitalization
|
|
148
|
+
* of sections as well as removing redundant ones.
|
|
149
|
+
*
|
|
150
|
+
* Returns a new array of tokens with values and position data updated.
|
|
151
|
+
*
|
|
152
|
+
* @see {@link OptsFixRanges}
|
|
153
|
+
* @param tokens A list of tokens to be adjusted.
|
|
154
|
+
* @param [options] Options.
|
|
155
|
+
* @returns A token list with ranges adjusted.
|
|
156
|
+
*/
|
|
157
|
+
export function fixTokenRangesXlsx (
|
|
158
|
+
tokens: Token[],
|
|
159
|
+
options: OptsFixRanges = {}
|
|
160
|
+
): Token[] {
|
|
161
|
+
if (!Array.isArray(tokens)) {
|
|
162
|
+
throw new Error('fixRanges expects an array of tokens');
|
|
163
|
+
}
|
|
164
|
+
const { addBounds, thisRow } = options;
|
|
165
|
+
let offsetSkew = 0;
|
|
166
|
+
const output: Token[] = [];
|
|
167
|
+
for (const t of tokens) {
|
|
168
|
+
const token = cloneToken(t);
|
|
169
|
+
let offsetDelta = 0;
|
|
170
|
+
if (token.type === REF_STRUCT) {
|
|
171
|
+
const sref = parseStructRefXlsx(token.value);
|
|
172
|
+
const newValue = stringifyStructRefXlsx(sref, { thisRow });
|
|
173
|
+
offsetDelta = newValue.length - token.value.length;
|
|
174
|
+
token.value = newValue;
|
|
175
|
+
}
|
|
176
|
+
else if (isRange(token)) {
|
|
177
|
+
const ref = parseA1RefXlsx(token.value, { allowTernary: true }) as ReferenceA1Xlsx;
|
|
178
|
+
const range = ref.range;
|
|
179
|
+
// fill missing dimensions?
|
|
180
|
+
if (addBounds) {
|
|
181
|
+
addA1RangeBounds(range);
|
|
182
|
+
}
|
|
183
|
+
const newValue = stringifyA1RefXlsx(ref);
|
|
184
|
+
offsetDelta = newValue.length - token.value.length;
|
|
185
|
+
token.value = newValue;
|
|
186
|
+
}
|
|
187
|
+
// ensure that positioning is still correct
|
|
188
|
+
if (offsetSkew || offsetDelta) {
|
|
189
|
+
if (token.loc) {
|
|
190
|
+
token.loc[0] += offsetSkew;
|
|
191
|
+
}
|
|
192
|
+
offsetSkew += offsetDelta;
|
|
193
|
+
if (token.loc) {
|
|
194
|
+
token.loc[1] += offsetSkew;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
offsetSkew += offsetDelta;
|
|
199
|
+
}
|
|
200
|
+
output.push(token);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return output;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Normalizes A1 style ranges and structured references in a formula.
|
|
208
|
+
*
|
|
209
|
+
* Internally it uses {@link fixTokenRanges} so see it's documentation for details.
|
|
210
|
+
*
|
|
211
|
+
* Returns the same formula with the ranges updated. If an array of tokens was
|
|
212
|
+
* supplied, then a new array is returned.
|
|
213
|
+
*
|
|
214
|
+
* @see {@link OptsFixRanges} & {@link OptsTokenize}
|
|
215
|
+
* @param formula A string (an Excel formula) or a token list that should be adjusted.
|
|
216
|
+
* @param [options] Options
|
|
217
|
+
* @returns A formula string with ranges adjusted
|
|
218
|
+
*/
|
|
219
|
+
export function fixFormulaRanges (
|
|
220
|
+
formula: string,
|
|
221
|
+
options: OptsFixRanges & OptsTokenize = {}
|
|
222
|
+
): string {
|
|
223
|
+
if (typeof formula !== 'string') {
|
|
224
|
+
throw new Error('fixFormulaRanges expects a string formula');
|
|
225
|
+
}
|
|
226
|
+
return stringifyTokens(
|
|
227
|
+
fixTokenRanges(
|
|
228
|
+
tokenize(formula, options),
|
|
229
|
+
options
|
|
230
|
+
)
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Normalizes A1 style ranges and structured references in a formula.
|
|
236
|
+
*
|
|
237
|
+
* Internally it uses {@link fixTokenRanges} so see it's documentation for details.
|
|
238
|
+
*
|
|
239
|
+
* Returns the same formula with the ranges updated. If an array of tokens was
|
|
240
|
+
* supplied, then a new array is returned.
|
|
241
|
+
*
|
|
242
|
+
* @see {@link OptsFixRanges} & {@link OptsTokenize}
|
|
243
|
+
* @param formula A string (an Excel formula) or a token list that should be adjusted.
|
|
244
|
+
* @param [options] Options
|
|
245
|
+
* @returns A formula string with ranges adjusted
|
|
246
|
+
*/
|
|
247
|
+
export function fixFormulaRangesXlsx (
|
|
248
|
+
formula: string,
|
|
249
|
+
options: OptsFixRanges & OptsTokenize = {}
|
|
250
|
+
): string {
|
|
251
|
+
if (typeof formula !== 'string') {
|
|
252
|
+
throw new Error('fixFormulaRanges expects a string formula');
|
|
253
|
+
}
|
|
254
|
+
return stringifyTokens(
|
|
255
|
+
fixTokenRangesXlsx(
|
|
256
|
+
tokenizeXlsx(formula, options),
|
|
257
|
+
options
|
|
258
|
+
)
|
|
259
|
+
);
|
|
260
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { describe, test, expect } from 'vitest';
|
|
2
|
+
import { fromCol } from './fromCol.ts';
|
|
3
|
+
|
|
4
|
+
describe('fromCol parses column id strings to numbers', () => {
|
|
5
|
+
test('single letter columns', () => {
|
|
6
|
+
expect(fromCol('a')).toBe(0);
|
|
7
|
+
expect(fromCol('A')).toBe(0);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test('multi-letter columns', () => {
|
|
11
|
+
expect(fromCol('AA')).toBe(26);
|
|
12
|
+
expect(fromCol('zz')).toBe(701);
|
|
13
|
+
expect(fromCol('ZZZ')).toBe(18277);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* @param {string} columnString The column string identifier
|
|
10
10
|
* @returns {number} Zero based column index number
|
|
11
11
|
*/
|
|
12
|
-
export function fromCol (columnString) {
|
|
12
|
+
export function fromCol (columnString: string): number {
|
|
13
13
|
const x = (columnString || '');
|
|
14
14
|
const l = x.length;
|
|
15
15
|
let n = 0;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
addA1RangeBounds,
|
|
4
|
+
fixTokenRanges,
|
|
5
|
+
fixFormulaRanges,
|
|
6
|
+
fromCol,
|
|
7
|
+
isError,
|
|
8
|
+
isFunction,
|
|
9
|
+
isFxPrefix,
|
|
10
|
+
isLiteral,
|
|
11
|
+
isOperator,
|
|
12
|
+
isRange,
|
|
13
|
+
isReference,
|
|
14
|
+
isWhitespace,
|
|
15
|
+
mergeRefTokens,
|
|
16
|
+
nodeTypes,
|
|
17
|
+
parse,
|
|
18
|
+
parseA1Ref,
|
|
19
|
+
parseR1C1Ref,
|
|
20
|
+
parseStructRef,
|
|
21
|
+
stringifyA1Ref,
|
|
22
|
+
stringifyR1C1Ref,
|
|
23
|
+
stringifyStructRef,
|
|
24
|
+
toCol,
|
|
25
|
+
tokenize,
|
|
26
|
+
tokenTypes,
|
|
27
|
+
translateFormulaToA1,
|
|
28
|
+
translateTokensToA1,
|
|
29
|
+
translateFormulaToR1C1,
|
|
30
|
+
translateTokensToR1C1
|
|
31
|
+
} from './index.ts';
|
|
32
|
+
|
|
33
|
+
// What happens when B2:A1 -> should work!
|
|
34
|
+
describe('fx main interface', () => {
|
|
35
|
+
it('addA1RangeBounds exists', () => {
|
|
36
|
+
expect(typeof addA1RangeBounds === 'function').toBeTruthy();
|
|
37
|
+
});
|
|
38
|
+
it('fixTokenRanges exists', () => {
|
|
39
|
+
expect(typeof fixTokenRanges === 'function').toBeTruthy();
|
|
40
|
+
});
|
|
41
|
+
it('fixFormulaRanges exists', () => {
|
|
42
|
+
expect(typeof fixFormulaRanges === 'function').toBeTruthy();
|
|
43
|
+
});
|
|
44
|
+
it('fromCol exists', () => {
|
|
45
|
+
expect(typeof fromCol === 'function').toBeTruthy();
|
|
46
|
+
});
|
|
47
|
+
it('isError exists', () => {
|
|
48
|
+
expect(typeof isError === 'function').toBeTruthy();
|
|
49
|
+
});
|
|
50
|
+
it('isFunction exists', () => {
|
|
51
|
+
expect(typeof isFunction === 'function').toBeTruthy();
|
|
52
|
+
});
|
|
53
|
+
it('isFxPrefix exists', () => {
|
|
54
|
+
expect(typeof isFxPrefix === 'function').toBeTruthy();
|
|
55
|
+
});
|
|
56
|
+
it('isLiteral exists', () => {
|
|
57
|
+
expect(typeof isLiteral === 'function').toBeTruthy();
|
|
58
|
+
});
|
|
59
|
+
it('isOperator exists', () => {
|
|
60
|
+
expect(typeof isOperator === 'function').toBeTruthy();
|
|
61
|
+
});
|
|
62
|
+
it('isRange exists', () => {
|
|
63
|
+
expect(typeof isRange === 'function').toBeTruthy();
|
|
64
|
+
});
|
|
65
|
+
it('isReference exists', () => {
|
|
66
|
+
expect(typeof isReference === 'function').toBeTruthy();
|
|
67
|
+
});
|
|
68
|
+
it('isWhitespace exists', () => {
|
|
69
|
+
expect(typeof isWhitespace === 'function').toBeTruthy();
|
|
70
|
+
});
|
|
71
|
+
it('mergeRefTokens exists', () => {
|
|
72
|
+
expect(typeof mergeRefTokens === 'function').toBeTruthy();
|
|
73
|
+
});
|
|
74
|
+
it('parse exists', () => {
|
|
75
|
+
expect(typeof parse === 'function').toBeTruthy();
|
|
76
|
+
});
|
|
77
|
+
it('parseA1Ref exists', () => {
|
|
78
|
+
expect(typeof parseA1Ref === 'function').toBeTruthy();
|
|
79
|
+
});
|
|
80
|
+
it('parseR1C1Ref exists', () => {
|
|
81
|
+
expect(typeof parseR1C1Ref === 'function').toBeTruthy();
|
|
82
|
+
});
|
|
83
|
+
it('parseStructRef exists', () => {
|
|
84
|
+
expect(typeof parseStructRef === 'function').toBeTruthy();
|
|
85
|
+
});
|
|
86
|
+
it('stringifyA1Ref exists', () => {
|
|
87
|
+
expect(typeof stringifyA1Ref === 'function').toBeTruthy();
|
|
88
|
+
});
|
|
89
|
+
it('stringifyR1C1Ref exists', () => {
|
|
90
|
+
expect(typeof stringifyR1C1Ref === 'function').toBeTruthy();
|
|
91
|
+
});
|
|
92
|
+
it('stringifyStructRef exists', () => {
|
|
93
|
+
expect(typeof stringifyStructRef === 'function').toBeTruthy();
|
|
94
|
+
});
|
|
95
|
+
it('toCol exists', () => {
|
|
96
|
+
expect(typeof toCol === 'function').toBeTruthy();
|
|
97
|
+
});
|
|
98
|
+
it('tokenize exists', () => {
|
|
99
|
+
expect(typeof tokenize === 'function').toBeTruthy();
|
|
100
|
+
});
|
|
101
|
+
it('translateFormulaToA1 exists', () => {
|
|
102
|
+
expect(typeof translateFormulaToA1 === 'function').toBeTruthy();
|
|
103
|
+
});
|
|
104
|
+
it('translateTokensToA1 exists', () => {
|
|
105
|
+
expect(typeof translateTokensToA1 === 'function').toBeTruthy();
|
|
106
|
+
});
|
|
107
|
+
it('translateFormulaToR1C1 exists', () => {
|
|
108
|
+
expect(typeof translateFormulaToR1C1 === 'function').toBeTruthy();
|
|
109
|
+
});
|
|
110
|
+
it('translateTokensToR1C1 exists', () => {
|
|
111
|
+
expect(typeof translateTokensToR1C1 === 'function').toBeTruthy();
|
|
112
|
+
});
|
|
113
|
+
it('nodeTypes exists', () => {
|
|
114
|
+
expect(typeof nodeTypes === 'object').toBeTruthy();
|
|
115
|
+
});
|
|
116
|
+
it('tokenTypes exists', () => {
|
|
117
|
+
expect(typeof tokenTypes === 'object').toBeTruthy();
|
|
118
|
+
});
|
|
119
|
+
});
|
package/lib/index.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A tokenizer, parser, and other utilities to work with Excel formula code.
|
|
3
|
+
*
|
|
4
|
+
* The base entry-point methods expect and return the variant of references that uses contexts.
|
|
5
|
+
* If you are using xlsx files or otherwise want to work with the xlsx-file variant of references
|
|
6
|
+
* you should use the {@link fx/xlsx} variant methods.
|
|
7
|
+
*
|
|
8
|
+
* See [Prefixes.md](./Prefixes.md) for documentation on how scopes work in Fx.
|
|
9
|
+
*
|
|
10
|
+
* @packageDocumentation
|
|
11
|
+
* @module fx
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export { tokenize, type OptsTokenize } from './tokenize.ts';
|
|
15
|
+
export { parse, type OptsParse } from './parse.ts';
|
|
16
|
+
export { translateFormulaToR1C1, translateTokensToR1C1, type OptsTranslateToR1C1 } from './translateToR1C1.ts';
|
|
17
|
+
export {
|
|
18
|
+
translateFormulaToA1, type OptsTranslateFormulaToA1,
|
|
19
|
+
translateTokensToA1, type OptsTranslateTokensToA1
|
|
20
|
+
} from './translateToA1.ts';
|
|
21
|
+
export { MAX_COLS, MAX_ROWS } from './constants.ts';
|
|
22
|
+
export { mergeRefTokens } from './mergeRefTokens.ts';
|
|
23
|
+
export { fixTokenRanges, fixFormulaRanges, type OptsFixRanges } from './fixRanges.ts';
|
|
24
|
+
export {
|
|
25
|
+
isError,
|
|
26
|
+
isFunction,
|
|
27
|
+
isFxPrefix,
|
|
28
|
+
isLiteral,
|
|
29
|
+
isOperator,
|
|
30
|
+
isRange,
|
|
31
|
+
isReference,
|
|
32
|
+
isWhitespace
|
|
33
|
+
} from './isType.ts';
|
|
34
|
+
export {
|
|
35
|
+
isArrayNode,
|
|
36
|
+
isBinaryNode,
|
|
37
|
+
isCallNode,
|
|
38
|
+
isErrorNode,
|
|
39
|
+
isExpressionNode,
|
|
40
|
+
isIdentifierNode,
|
|
41
|
+
isLambdaNode,
|
|
42
|
+
isLetDeclaratorNode,
|
|
43
|
+
isLetNode,
|
|
44
|
+
isLiteralNode,
|
|
45
|
+
isReferenceNode,
|
|
46
|
+
isUnaryNode
|
|
47
|
+
} from './isNodeType.ts';
|
|
48
|
+
export { addA1RangeBounds } from './addA1RangeBounds.ts';
|
|
49
|
+
export { toCol } from './toCol.ts';
|
|
50
|
+
export { fromCol } from './fromCol.ts';
|
|
51
|
+
export { parseA1Range } from './parseA1Range.ts';
|
|
52
|
+
export { parseA1Ref, type OptsParseA1Ref } from './parseA1Ref.ts';
|
|
53
|
+
export { parseR1C1Range } from './parseR1C1Range.ts';
|
|
54
|
+
export { parseR1C1Ref, type OptsParseR1C1Ref } from './parseR1C1Ref.ts';
|
|
55
|
+
export { parseStructRef } from './parseStructRef.ts';
|
|
56
|
+
export { stringifyA1Ref } from './stringifyA1Ref.ts';
|
|
57
|
+
export { stringifyR1C1Ref } from './stringifyR1C1Ref.ts';
|
|
58
|
+
export { stringifyStructRef, type OptsStringifyStructRef } from './stringifyStructRef.ts';
|
|
59
|
+
export { stringifyTokens } from './stringifyTokens.ts';
|
|
60
|
+
export type {
|
|
61
|
+
RangeA1,
|
|
62
|
+
RangeR1C1,
|
|
63
|
+
Token,
|
|
64
|
+
TokenEnhanced,
|
|
65
|
+
ReferenceA1,
|
|
66
|
+
ReferenceA1Xlsx,
|
|
67
|
+
ReferenceR1C1,
|
|
68
|
+
ReferenceR1C1Xlsx,
|
|
69
|
+
ReferenceStruct,
|
|
70
|
+
ReferenceStructXlsx,
|
|
71
|
+
ReferenceName,
|
|
72
|
+
ReferenceNameXlsx
|
|
73
|
+
} from './types.ts';
|
|
74
|
+
export type * from './astTypes.ts';
|
|
75
|
+
export { tokenTypes } from './tokenTypes.ts';
|
|
76
|
+
export { nodeTypes } from './nodeTypes.ts';
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Node,
|
|
3
|
+
Identifier,
|
|
4
|
+
ReferenceIdentifier,
|
|
5
|
+
Literal,
|
|
6
|
+
ErrorLiteral,
|
|
7
|
+
UnaryExpression,
|
|
8
|
+
BinaryExpression,
|
|
9
|
+
CallExpression,
|
|
10
|
+
ArrayExpression,
|
|
11
|
+
LambdaExpression,
|
|
12
|
+
LetExpression,
|
|
13
|
+
LetDeclarator,
|
|
14
|
+
AstExpression
|
|
15
|
+
} from './astTypes.ts';
|
|
16
|
+
import {
|
|
17
|
+
ARRAY,
|
|
18
|
+
BINARY,
|
|
19
|
+
CALL,
|
|
20
|
+
ERROR,
|
|
21
|
+
ERROR_LITERAL,
|
|
22
|
+
IDENTIFIER,
|
|
23
|
+
LAMBDA,
|
|
24
|
+
LET,
|
|
25
|
+
LET_DECL,
|
|
26
|
+
LITERAL,
|
|
27
|
+
REFERENCE,
|
|
28
|
+
UNARY
|
|
29
|
+
} from './constants.ts';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Determines whether the specified node is an Identifier.
|
|
33
|
+
* @param node An AST node.
|
|
34
|
+
* @returns True if the specified token is an Identifier, False otherwise.
|
|
35
|
+
*/
|
|
36
|
+
export function isIdentifierNode (node?: Node | null): node is Identifier {
|
|
37
|
+
return node?.type === IDENTIFIER;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Determines whether the specified node is a ReferenceIdentifier.
|
|
42
|
+
* @param node An AST node.
|
|
43
|
+
* @returns True if the specified token is a ReferenceIdentifier, False otherwise.
|
|
44
|
+
*/
|
|
45
|
+
export function isReferenceNode (node?: Node | null): node is ReferenceIdentifier {
|
|
46
|
+
return node?.type === REFERENCE;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Determines whether the specified node is a Literal.
|
|
51
|
+
* @param node An AST node.
|
|
52
|
+
* @returns True if the specified token is a Literal, False otherwise.
|
|
53
|
+
*/
|
|
54
|
+
export function isLiteralNode (node?: Node | null): node is Literal {
|
|
55
|
+
return node?.type === LITERAL;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Determines whether the specified node is an ErrorLiteral.
|
|
60
|
+
* @param node An AST node.
|
|
61
|
+
* @returns True if the specified token is an ErrorLiteral, False otherwise.
|
|
62
|
+
*/
|
|
63
|
+
export function isErrorNode (node?: Node | null): node is ErrorLiteral {
|
|
64
|
+
return node?.type === ERROR_LITERAL;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Determines whether the specified node is a UnaryExpression.
|
|
69
|
+
* @param node An AST node.
|
|
70
|
+
* @returns True if the specified token is a UnaryExpression, False otherwise.
|
|
71
|
+
*/
|
|
72
|
+
export function isUnaryNode (node?: Node | null): node is UnaryExpression {
|
|
73
|
+
return node?.type === UNARY;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Determines whether the specified node is a BinaryExpression.
|
|
78
|
+
* @param node An AST node.
|
|
79
|
+
* @returns True if the specified token is a BinaryExpression, False otherwise.
|
|
80
|
+
*/
|
|
81
|
+
export function isBinaryNode (node?: Node | null): node is BinaryExpression {
|
|
82
|
+
return node?.type === BINARY;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Determines whether the specified node is a CallExpression.
|
|
87
|
+
* @param node An AST node.
|
|
88
|
+
* @returns True if the specified token is a CallExpression, False otherwise.
|
|
89
|
+
*/
|
|
90
|
+
export function isCallNode (node?: Node | null): node is CallExpression {
|
|
91
|
+
return node?.type === CALL;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Determines whether the specified node is a ArrayExpression.
|
|
96
|
+
* @param node An AST node.
|
|
97
|
+
* @returns True if the specified token is a ArrayExpression, False otherwise.
|
|
98
|
+
*/
|
|
99
|
+
export function isArrayNode (node?: Node | null): node is ArrayExpression {
|
|
100
|
+
return node?.type === ARRAY;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Determines whether the specified node is a LambdaExpression.
|
|
105
|
+
* @param node An AST node.
|
|
106
|
+
* @returns True if the specified token is a LambdaExpression, False otherwise.
|
|
107
|
+
*/
|
|
108
|
+
export function isLambdaNode (node?: Node | null): node is LambdaExpression {
|
|
109
|
+
return node?.type === ARRAY;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Determines whether the specified node is a LetExpression.
|
|
114
|
+
* @param node An AST node.
|
|
115
|
+
* @returns True if the specified token is a LetExpression, False otherwise.
|
|
116
|
+
*/
|
|
117
|
+
export function isLetNode (node?: Node | null): node is LetExpression {
|
|
118
|
+
return node?.type === LET;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Determines whether the specified node is a LetDeclarator.
|
|
123
|
+
* @param node An AST node.
|
|
124
|
+
* @returns True if the specified token is a LetDeclarator, False otherwise.
|
|
125
|
+
*/
|
|
126
|
+
export function isLetDeclaratorNode (node?: Node | null): node is LetDeclarator {
|
|
127
|
+
return node?.type === LET_DECL;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Determines whether the specified node is a AstExpression.
|
|
132
|
+
* @param node An AST node.
|
|
133
|
+
* @returns True if the specified token is a AstExpression, False otherwise.
|
|
134
|
+
*/
|
|
135
|
+
export function isExpressionNode (node?: Node | null): node is AstExpression {
|
|
136
|
+
const type = node?.type;
|
|
137
|
+
if (type) {
|
|
138
|
+
return (
|
|
139
|
+
type === REFERENCE ||
|
|
140
|
+
type === LITERAL ||
|
|
141
|
+
type === ERROR ||
|
|
142
|
+
type === UNARY ||
|
|
143
|
+
type === BINARY ||
|
|
144
|
+
type === CALL ||
|
|
145
|
+
type === ARRAY ||
|
|
146
|
+
type === LAMBDA ||
|
|
147
|
+
type === LET
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
}
|