@borgar/fx 3.0.0 → 4.0.0-rc.1
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/.eslintrc +25 -12
- package/.jsdoc/config.json +17 -0
- package/.jsdoc/publish.js +195 -0
- package/README.md +8 -311
- package/dist/fx.js +1 -1
- package/docs/API.md +708 -0
- package/docs/AST format.md +144 -0
- package/docs/References.md +60 -0
- package/lib/a1.js +156 -30
- package/lib/a1.spec.js +9 -2
- package/lib/{addMeta.js → addTokenMeta.js} +50 -5
- package/lib/{addMeta.spec.js → addTokenMeta.spec.js} +16 -16
- package/lib/constants.js +14 -4
- package/lib/fixRanges.js +64 -10
- package/lib/fixRanges.spec.js +35 -6
- package/lib/index.js +95 -16
- package/lib/isType.js +119 -8
- package/lib/lexer-srefs.spec.js +311 -0
- package/lib/lexer.js +56 -16
- package/lib/lexer.spec.js +247 -214
- package/lib/lexerParts.js +40 -16
- package/lib/mergeRefTokens.js +38 -25
- package/lib/mergeRefTokens.spec.js +39 -39
- package/lib/parseRef.js +17 -12
- package/lib/parser.js +498 -0
- package/lib/parser.spec.js +777 -0
- package/lib/rc.js +95 -22
- package/lib/rc.spec.js +16 -5
- package/lib/sr.js +277 -0
- package/lib/sr.spec.js +179 -0
- package/lib/translate-toA1.spec.js +53 -2
- package/lib/translate-toRC.spec.js +35 -2
- package/lib/translate.js +137 -21
- package/package.json +3 -1
- package/References.md +0 -39
package/lib/fixRanges.js
CHANGED
|
@@ -1,12 +1,45 @@
|
|
|
1
1
|
import { isRange } from './isType.js';
|
|
2
|
-
import { parseA1Ref, stringifyA1Ref,
|
|
2
|
+
import { parseA1Ref, stringifyA1Ref, addA1RangeBounds } from './a1.js';
|
|
3
|
+
import { parseStructRef, stringifyStructRef } from './sr.js';
|
|
3
4
|
import { tokenize } from './lexer.js';
|
|
5
|
+
import { REF_STRUCT } from './constants.js';
|
|
4
6
|
|
|
5
7
|
// There is no R1C1 counerpart to this. This is because without an anchor cell
|
|
6
8
|
// it is impossible to determine if a relative+absolute range (R[1]C[1]:R5C5)
|
|
7
9
|
// needs to be flipped or not. The solution is to convert to A1 first:
|
|
8
10
|
// translateToRC(fixRanges(translateToA1(...)))
|
|
9
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Normalizes A1 style ranges in a formula or list of tokens so that the top and
|
|
14
|
+
* left coordinates of the range are on the left-hand side of a colon operator:
|
|
15
|
+
*
|
|
16
|
+
* `B2:A1` → `A1:B2`
|
|
17
|
+
* `1:A1` → `A1:1`
|
|
18
|
+
* `A:A1` → `A1:A`
|
|
19
|
+
* `B:A` → `A:B`
|
|
20
|
+
* `2:1` → `1:2`
|
|
21
|
+
* `A1:A1` → `A1`
|
|
22
|
+
*
|
|
23
|
+
* When `{ addBounds: true }` is passed as an option, the missing bounds are
|
|
24
|
+
* also added. This can be done to ensure Excel compatible ranges. The fixes
|
|
25
|
+
* then additionally include:
|
|
26
|
+
*
|
|
27
|
+
* `1:A1` → `A1:1` → `1:1`
|
|
28
|
+
* `A:A1` → `A1:A` → `A:A`
|
|
29
|
+
* `A1:A` → `A:A`
|
|
30
|
+
* `A1:1` → `A:1`
|
|
31
|
+
* `B2:B` → `B2:1048576`
|
|
32
|
+
* `B2:2` → `B2:XFD2`
|
|
33
|
+
*
|
|
34
|
+
* Returns the same formula with the ranges updated. If an array of tokens was
|
|
35
|
+
* supplied, then a new array is returned.
|
|
36
|
+
*
|
|
37
|
+
* @param {(string | Array<Object>)} formula A string (an Excel formula) or a token list that should be adjusted.
|
|
38
|
+
* @param {Object} [options={}] Options
|
|
39
|
+
* @param {boolean} [options.addBounds=false] Fill in any undefined bounds of range objects. Top to 0, bottom to 1048575, left to 0, and right to 16383.
|
|
40
|
+
* @param {boolean} [options.r1c1=false] Ranges are expected to be in the R1C1 style format rather than the more popular A1 style.
|
|
41
|
+
* @return {(string | Array<Object>)} A formula string or token list (depending on which was input)
|
|
42
|
+
*/
|
|
10
43
|
export function fixRanges (tokens, options = { addBounds: false }) {
|
|
11
44
|
if (typeof tokens === 'string') {
|
|
12
45
|
return fixRanges(tokenize(tokens, options), options)
|
|
@@ -20,20 +53,41 @@ export function fixRanges (tokens, options = { addBounds: false }) {
|
|
|
20
53
|
if (r1c1) {
|
|
21
54
|
throw new Error('fixRanges does not have an R1C1 mode');
|
|
22
55
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
56
|
+
let offsetSkew = 0;
|
|
57
|
+
return tokens.map(t => {
|
|
58
|
+
const token = { ...t };
|
|
59
|
+
if (t.loc) {
|
|
60
|
+
token.loc = [ ...t.loc ];
|
|
61
|
+
}
|
|
62
|
+
let offsetDelta = 0;
|
|
63
|
+
if (token.type === REF_STRUCT) {
|
|
64
|
+
const newValue = stringifyStructRef(parseStructRef(token.value));
|
|
65
|
+
offsetDelta = newValue.length - token.value.length;
|
|
66
|
+
token.value = newValue;
|
|
67
|
+
}
|
|
68
|
+
else if (isRange(token)) {
|
|
69
|
+
const ref = parseA1Ref(token.value, { allowTernary: true });
|
|
26
70
|
const range = ref.range;
|
|
27
71
|
// fill missing dimensions?
|
|
28
72
|
if (addBounds) {
|
|
29
|
-
|
|
73
|
+
addA1RangeBounds(range);
|
|
30
74
|
}
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
75
|
+
const newValue = stringifyA1Ref(ref);
|
|
76
|
+
offsetDelta = newValue.length - token.value.length;
|
|
77
|
+
token.value = newValue;
|
|
78
|
+
}
|
|
79
|
+
// ensure that positioning is still correct
|
|
80
|
+
if (offsetSkew || offsetDelta) {
|
|
81
|
+
if (token.loc) {
|
|
82
|
+
token.loc[0] += offsetSkew;
|
|
35
83
|
}
|
|
36
|
-
|
|
84
|
+
offsetSkew += offsetDelta;
|
|
85
|
+
if (token.loc) {
|
|
86
|
+
token.loc[1] += offsetSkew;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
offsetSkew += offsetDelta;
|
|
37
91
|
}
|
|
38
92
|
return token;
|
|
39
93
|
});
|
package/lib/fixRanges.spec.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { test, Test } from 'tape';
|
|
2
2
|
import { tokenize } from './lexer.js';
|
|
3
|
-
import {
|
|
3
|
+
import { addTokenMeta } from './addTokenMeta.js';
|
|
4
4
|
import { fixRanges } from './fixRanges.js';
|
|
5
|
-
import {
|
|
5
|
+
import { FUNCTION, FX_PREFIX, OPERATOR, REF_RANGE, REF_STRUCT, REF_TERNARY } from './constants.js';
|
|
6
6
|
|
|
7
7
|
Test.prototype.isFixed = function (expr, expected, options = {}) {
|
|
8
8
|
const result = fixRanges(expr, options);
|
|
@@ -13,13 +13,13 @@ test('fixRanges basics', t => {
|
|
|
13
13
|
const fx = '=SUM([wb]Sheet1!B2:A1)';
|
|
14
14
|
t.throws(() => fixRanges(123), 'throws on non arrays (number)');
|
|
15
15
|
t.throws(() => fixRanges(null), 'throws on non arrays (null)');
|
|
16
|
-
const tokens =
|
|
16
|
+
const tokens = addTokenMeta(tokenize(fx, { mergeRefs: true }));
|
|
17
17
|
tokens[3].foo = 'bar';
|
|
18
18
|
const fixedTokens = fixRanges(tokens, { debug: 0 });
|
|
19
19
|
t.ok(tokens !== fixedTokens, 'emits a new array instance');
|
|
20
20
|
t.ok(tokens[3] !== fixedTokens[3], 'does not mutate existing range tokens');
|
|
21
21
|
t.deepEqual(tokens[3], {
|
|
22
|
-
type:
|
|
22
|
+
type: REF_RANGE,
|
|
23
23
|
value: '[wb]Sheet1!B2:A1',
|
|
24
24
|
index: 3,
|
|
25
25
|
depth: 1,
|
|
@@ -27,14 +27,26 @@ test('fixRanges basics', t => {
|
|
|
27
27
|
foo: 'bar'
|
|
28
28
|
}, 'keeps meta (pre-fix range token)');
|
|
29
29
|
t.deepEqual(fixedTokens[3], {
|
|
30
|
-
type:
|
|
30
|
+
type: REF_RANGE,
|
|
31
31
|
value: '[wb]Sheet1!A1:B2',
|
|
32
32
|
index: 3,
|
|
33
33
|
depth: 1,
|
|
34
34
|
groupId: 'fxg1',
|
|
35
35
|
foo: 'bar'
|
|
36
36
|
}, 'keeps meta (post-fix range token)');
|
|
37
|
-
|
|
37
|
+
const tokensWithRanges = tokenize(
|
|
38
|
+
'=SUM(B2:A,table[[#This Row],[Foo]])',
|
|
39
|
+
{ withLocation: true, mergeRefs: true, allowTernary: true }
|
|
40
|
+
);
|
|
41
|
+
t.deepEqual(fixRanges(tokensWithRanges, { addBounds: true }), [
|
|
42
|
+
{ type: FX_PREFIX, value: '=', loc: [ 0, 1 ] },
|
|
43
|
+
{ type: FUNCTION, value: 'SUM', loc: [ 1, 4 ] },
|
|
44
|
+
{ type: OPERATOR, value: '(', loc: [ 4, 5 ] },
|
|
45
|
+
{ type: REF_TERNARY, value: 'A2:B1048576', loc: [ 5, 16 ] },
|
|
46
|
+
{ type: OPERATOR, value: ',', loc: [ 16, 17 ] },
|
|
47
|
+
{ type: REF_STRUCT, value: 'table[@Foo]', loc: [ 17, 28 ] },
|
|
48
|
+
{ type: OPERATOR, value: ')', loc: [ 28, 29 ] }
|
|
49
|
+
], 'updates token source location information');
|
|
38
50
|
t.end();
|
|
39
51
|
});
|
|
40
52
|
|
|
@@ -109,3 +121,20 @@ test('fixRanges A1 addBounds', t => {
|
|
|
109
121
|
t.isFixed('=2:B20', '=B2:XFD20', opt);
|
|
110
122
|
t.end();
|
|
111
123
|
});
|
|
124
|
+
|
|
125
|
+
test('fixRanges structured references', t => {
|
|
126
|
+
t.isFixed('=Table1[[#This Row],[Foo]]', '=Table1[@Foo]');
|
|
127
|
+
t.isFixed('=[[#This Row],[s:s]]', '=[@[s:s]]');
|
|
128
|
+
t.isFixed('=Table1[[#Totals],col name:Foo]', '=Table1[[#Totals],[col name]:[Foo]]');
|
|
129
|
+
t.isFixed('[[#data],[#headers]]', '[[#Headers],[#Data]]');
|
|
130
|
+
t.isFixed('[[#headers],[#data]]', '[[#Headers],[#Data]]');
|
|
131
|
+
t.isFixed('[[#totals],[#data]]', '[[#Data],[#Totals]]');
|
|
132
|
+
t.isFixed('[ [#totals], [#data] ]', '[[#Data],[#Totals]]');
|
|
133
|
+
t.isFixed('[[#data],[#totals]]', '[[#Data],[#Totals]]');
|
|
134
|
+
t.isFixed('[[#all],foo:bar]', '[[#All],[foo]:[bar]]');
|
|
135
|
+
t.isFixed('[[#all],[#all],[#all],[#all],[ColumnName]]', '[[#All],[ColumnName]]');
|
|
136
|
+
t.isFixed('[@[foo]:bar]', '[@[foo]:[bar]]');
|
|
137
|
+
t.isFixed('[@foo bar]', '[@[foo bar]]');
|
|
138
|
+
t.isFixed('[ @foo bar ]', '[@[foo bar]]');
|
|
139
|
+
t.end();
|
|
140
|
+
});
|
package/lib/index.js
CHANGED
|
@@ -1,14 +1,32 @@
|
|
|
1
1
|
export { tokenize } from './lexer.js';
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export { default as rc } from './rc.js';
|
|
2
|
+
export { parse } from './parser.js';
|
|
3
|
+
export { addTokenMeta } from './addTokenMeta.js';
|
|
4
|
+
export { translateToR1C1, translateToA1 } from './translate.js';
|
|
6
5
|
export { MAX_COLS, MAX_ROWS } from './constants.js';
|
|
7
6
|
export { isReference, isRange } from './isType.js';
|
|
8
|
-
export { mergeRefTokens
|
|
7
|
+
export { mergeRefTokens } from './mergeRefTokens.js';
|
|
9
8
|
export { fixRanges } from './fixRanges.js';
|
|
10
9
|
|
|
10
|
+
export {
|
|
11
|
+
fromCol,
|
|
12
|
+
toCol,
|
|
13
|
+
parseA1Ref,
|
|
14
|
+
stringifyA1Ref,
|
|
15
|
+
addA1RangeBounds
|
|
16
|
+
} from './a1.js';
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
parseR1C1Ref,
|
|
20
|
+
stringifyR1C1Ref
|
|
21
|
+
} from './rc.js';
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
parseStructRef,
|
|
25
|
+
stringifyStructRef
|
|
26
|
+
} from './sr.js';
|
|
27
|
+
|
|
11
28
|
import {
|
|
29
|
+
// token types
|
|
12
30
|
OPERATOR,
|
|
13
31
|
BOOLEAN,
|
|
14
32
|
ERROR,
|
|
@@ -19,15 +37,49 @@ import {
|
|
|
19
37
|
STRING,
|
|
20
38
|
CONTEXT,
|
|
21
39
|
CONTEXT_QUOTE,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
40
|
+
REF_RANGE,
|
|
41
|
+
REF_BEAM,
|
|
42
|
+
REF_TERNARY,
|
|
43
|
+
REF_NAMED,
|
|
44
|
+
REF_STRUCT,
|
|
26
45
|
FX_PREFIX,
|
|
27
|
-
UNKNOWN
|
|
46
|
+
UNKNOWN,
|
|
47
|
+
// AST types
|
|
48
|
+
UNARY,
|
|
49
|
+
BINARY,
|
|
50
|
+
REFERENCE,
|
|
51
|
+
LITERAL,
|
|
52
|
+
ERROR_LITERAL,
|
|
53
|
+
CALL,
|
|
54
|
+
ARRAY,
|
|
55
|
+
IDENTIFIER
|
|
28
56
|
} from './constants.js';
|
|
29
57
|
|
|
30
|
-
|
|
58
|
+
/**
|
|
59
|
+
* A dictionary of the types used to identify token variants.
|
|
60
|
+
*
|
|
61
|
+
* @readonly
|
|
62
|
+
* @constant {Object<string>} tokenTypes
|
|
63
|
+
* @property {string} OPERATOR - Newline (`\n`)
|
|
64
|
+
* @property {string} BOOLEAN - Boolean literal (`TRUE`)
|
|
65
|
+
* @property {string} ERROR - Error literal (`#VALUE!`)
|
|
66
|
+
* @property {string} NUMBER - Number literal (`123.4`, `-1.5e+2`)
|
|
67
|
+
* @property {string} FUNCTION - Function name (`SUM`)
|
|
68
|
+
* @property {string} NEWLINE - Newline character (`\n`)
|
|
69
|
+
* @property {string} WHITESPACE - Whitespace character sequence (` `)
|
|
70
|
+
* @property {string} STRING - String literal (`"Lorem ipsum"`)
|
|
71
|
+
* @property {string} CONTEXT - Reference context ([Workbook.xlsx]Sheet1)
|
|
72
|
+
* @property {string} CONTEXT_QUOTE - Quoted reference context (`'[My workbook.xlsx]Sheet1'`)
|
|
73
|
+
* @property {string} REF_RANGE - A range identifier (`A1`)
|
|
74
|
+
* @property {string} REF_BEAM - A range "beam" identifier (`A:A` or `1:1`)
|
|
75
|
+
* @property {string} REF_TERNARY - A ternary range identifier (`B2:B`)
|
|
76
|
+
* @property {string} REF_NAMED - A name / named range identifier (`income`)
|
|
77
|
+
* @property {string} REF_STRUCT - A structured reference identifier (`table[[Column1]:[Column2]]`)
|
|
78
|
+
* @property {string} FX_PREFIX - A leading equals sign at the start of a formula (`=`)
|
|
79
|
+
* @property {string} UNKNOWN - Any unidentifiable range of characters.
|
|
80
|
+
* @see tokenize
|
|
81
|
+
*/
|
|
82
|
+
export const tokenTypes = Object.freeze({
|
|
31
83
|
OPERATOR,
|
|
32
84
|
BOOLEAN,
|
|
33
85
|
ERROR,
|
|
@@ -38,10 +90,37 @@ export const tokenTypes = {
|
|
|
38
90
|
STRING,
|
|
39
91
|
CONTEXT,
|
|
40
92
|
CONTEXT_QUOTE,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
93
|
+
REF_RANGE,
|
|
94
|
+
REF_BEAM,
|
|
95
|
+
REF_TERNARY,
|
|
96
|
+
REF_NAMED,
|
|
97
|
+
REF_STRUCT,
|
|
45
98
|
FX_PREFIX,
|
|
46
99
|
UNKNOWN
|
|
47
|
-
};
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* A dictionary of the types used to identify AST node variants.
|
|
104
|
+
*
|
|
105
|
+
* @readonly
|
|
106
|
+
* @constant {Object<string>} nodeTypes
|
|
107
|
+
* @property {string} UNARY - A unary operation (`10%`)
|
|
108
|
+
* @property {string} BINARY - A binary operation (`10+10`)
|
|
109
|
+
* @property {string} REFERENCE - A range identifier (`A1`)
|
|
110
|
+
* @property {string} LITERAL - A literal (number, string, or boolean) (`123`, `"foo"`, `false`)
|
|
111
|
+
* @property {string} ERROR - An error literal (`#VALUE!`)
|
|
112
|
+
* @property {string} CALL - A function call expression (`SUM(1,2)`)
|
|
113
|
+
* @property {string} ARRAY - An array expression (`{1,2;3,4}`)
|
|
114
|
+
* @property {string} IDENTIFIER - A function name identifier (`SUM`)
|
|
115
|
+
* @see parse
|
|
116
|
+
*/
|
|
117
|
+
export const nodeTypes = Object.freeze({
|
|
118
|
+
UNARY,
|
|
119
|
+
BINARY,
|
|
120
|
+
REFERENCE,
|
|
121
|
+
LITERAL,
|
|
122
|
+
ERROR: ERROR_LITERAL,
|
|
123
|
+
CALL,
|
|
124
|
+
ARRAY,
|
|
125
|
+
IDENTIFIER
|
|
126
|
+
});
|
package/lib/isType.js
CHANGED
|
@@ -1,18 +1,129 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
REF_RANGE, REF_BEAM, REF_NAMED, REF_TERNARY, REF_STRUCT,
|
|
3
|
+
FX_PREFIX, WHITESPACE, NEWLINE,
|
|
4
|
+
FUNCTION, OPERATOR,
|
|
5
|
+
ERROR, STRING, NUMBER, BOOLEAN
|
|
6
|
+
} from './constants.js';
|
|
2
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Determines whether the specified token is a range.
|
|
10
|
+
*
|
|
11
|
+
* Returns `true` if the input is a token that has a type of either REF_RANGE
|
|
12
|
+
* (`A1` or `A1:B2`), REF_TERNARY (`A1:A`, `A1:1`, `1:A1`, or `A:A1`), or
|
|
13
|
+
* REF_BEAM (`A:A` or `1:1`). In all other cases `false` is returned.
|
|
14
|
+
*
|
|
15
|
+
* @param {Object} token A token
|
|
16
|
+
* @return {boolean} True if the specified token is range, False otherwise.
|
|
17
|
+
*/
|
|
3
18
|
export function isRange (token) {
|
|
4
19
|
return !!token && (
|
|
5
|
-
token.type ===
|
|
6
|
-
token.type ===
|
|
7
|
-
token.type ===
|
|
20
|
+
token.type === REF_RANGE ||
|
|
21
|
+
token.type === REF_BEAM ||
|
|
22
|
+
token.type === REF_TERNARY
|
|
8
23
|
);
|
|
9
24
|
}
|
|
10
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Determines whether the specified token is a reference.
|
|
28
|
+
*
|
|
29
|
+
* Returns `true` if the input is a token of type REF_RANGE (`A1` or `A1:B2`),
|
|
30
|
+
* REF_TERNARY (`A1:A`, `A1:1`, `1:A1`, or `A:A1`), REF_BEAM (`A:A` or `1:1`),
|
|
31
|
+
* or REF_NAMED (`myrange`). In all other cases `false` is returned.
|
|
32
|
+
*
|
|
33
|
+
* @param {Object} token The token
|
|
34
|
+
* @return {boolean} True if the specified token is reference, False otherwise.
|
|
35
|
+
*/
|
|
11
36
|
export function isReference (token) {
|
|
12
37
|
return !!token && (
|
|
13
|
-
token.type ===
|
|
14
|
-
token.type ===
|
|
15
|
-
token.type ===
|
|
16
|
-
token.type ===
|
|
38
|
+
token.type === REF_RANGE ||
|
|
39
|
+
token.type === REF_BEAM ||
|
|
40
|
+
token.type === REF_TERNARY ||
|
|
41
|
+
token.type === REF_STRUCT ||
|
|
42
|
+
token.type === REF_NAMED
|
|
17
43
|
);
|
|
18
44
|
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Determines whether the specified token is a literal.
|
|
48
|
+
*
|
|
49
|
+
* Returns `true` if the input is a token of type BOOLEAN (`TRUE` or `FALSE`),
|
|
50
|
+
* ERROR (`#VALUE!`), NUMBER (123.4), or STRING (`"lorem ipsum"`). In all other
|
|
51
|
+
* cases `false` is returned.
|
|
52
|
+
*
|
|
53
|
+
* @param {Object} token The token
|
|
54
|
+
* @return {boolean} True if the specified token is literal, False otherwise.
|
|
55
|
+
*/
|
|
56
|
+
export function isLiteral (token) {
|
|
57
|
+
return !!token && (
|
|
58
|
+
token.type === BOOLEAN ||
|
|
59
|
+
token.type === ERROR ||
|
|
60
|
+
token.type === NUMBER ||
|
|
61
|
+
token.type === STRING
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Determines whether the specified token is an error.
|
|
67
|
+
*
|
|
68
|
+
* Returns `true` if the input is a token of type ERROR (`#VALUE!`). In all
|
|
69
|
+
* other cases `false` is returned.
|
|
70
|
+
*
|
|
71
|
+
* @param {Object} token The token
|
|
72
|
+
* @return {boolean} True if the specified token is error, False otherwise.
|
|
73
|
+
*/
|
|
74
|
+
export function isError (token) {
|
|
75
|
+
return !!token && token.type === ERROR;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Determines whether the specified token is whitespace.
|
|
80
|
+
*
|
|
81
|
+
* Returns `true` if the input is a token of type WHITESPACE (` `) or
|
|
82
|
+
* NEWLINE (`\n`). In all other cases `false` is returned.
|
|
83
|
+
*
|
|
84
|
+
* @param {Object} token The token
|
|
85
|
+
* @return {boolean} True if the specified token is whitespace, False otherwise.
|
|
86
|
+
*/
|
|
87
|
+
export function isWhitespace (token) {
|
|
88
|
+
return !!token && (
|
|
89
|
+
token.type === WHITESPACE ||
|
|
90
|
+
token.type === NEWLINE
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Determines whether the specified token is a function.
|
|
96
|
+
*
|
|
97
|
+
* Returns `true` if the input is a token of type FUNCTION.
|
|
98
|
+
* In all other cases `false` is returned.
|
|
99
|
+
*
|
|
100
|
+
* @param {Object} token The token
|
|
101
|
+
* @return {boolean} True if the specified token is function, False otherwise.
|
|
102
|
+
*/
|
|
103
|
+
export function isFunction (token) {
|
|
104
|
+
return !!token && token.type === FUNCTION;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Returns `true` if the input is a token of type FX_PREFIX (leading `=` in
|
|
109
|
+
* formula). In all other cases `false` is returned.
|
|
110
|
+
*
|
|
111
|
+
* @param {Object} token The token
|
|
112
|
+
* @return {boolean} True if the specified token is effects prefix, False otherwise.
|
|
113
|
+
*/
|
|
114
|
+
export function isFxPrefix (token) {
|
|
115
|
+
return !!token && token.type === FX_PREFIX;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Determines whether the specified token is an operator.
|
|
120
|
+
*
|
|
121
|
+
* Returns `true` if the input is a token of type OPERATOR (`+` or `:`). In all
|
|
122
|
+
* other cases `false` is returned.
|
|
123
|
+
*
|
|
124
|
+
* @param {Object} token The token
|
|
125
|
+
* @return {boolean} True if the specified token is operator, False otherwise.
|
|
126
|
+
*/
|
|
127
|
+
export function isOperator (token) {
|
|
128
|
+
return !!token && token.type === OPERATOR;
|
|
129
|
+
}
|