@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/astTypes.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/* eslint-disable jsdoc/require-property-description */
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @typedef {number[]} SourceLocation
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @typedef {Node} Identifier
|
|
9
|
-
* @property {"Identifier"} type
|
|
10
|
-
* @property {SourceLocation} [loc]
|
|
11
|
-
* @property {string} name
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @typedef {Node} ReferenceIdentifier
|
|
16
|
-
* @property {"ReferenceIdentifier"} type
|
|
17
|
-
* @property {SourceLocation} [loc]
|
|
18
|
-
* @property {string} value
|
|
19
|
-
* @property {"name" | "range" | "beam" | "table"} kind
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* @typedef {Node} Literal
|
|
24
|
-
* @property {"Literal"} type
|
|
25
|
-
* @property {SourceLocation} [loc]
|
|
26
|
-
* @property {string} raw
|
|
27
|
-
* @property {string | number | boolean} value
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @typedef {Node} ErrorLiteral
|
|
32
|
-
* @property {"ErrorLiteral"} type
|
|
33
|
-
* @property {SourceLocation} [loc]
|
|
34
|
-
* @property {string} raw
|
|
35
|
-
* @property {string} value
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* @typedef {Node} UnaryExpression
|
|
40
|
-
* @property {"UnaryExpression"} type
|
|
41
|
-
* @property {SourceLocation} [loc]
|
|
42
|
-
* @property {"+" | "-" | "%" | "#" | "@"} operator
|
|
43
|
-
* @property {AstExpression[]} arguments
|
|
44
|
-
*/
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* @typedef {Node} BinaryExpression
|
|
48
|
-
* @property {"BinaryExpression"} type
|
|
49
|
-
* @property {SourceLocation} [loc]
|
|
50
|
-
* @property {"=" | "<" | ">" | "<=" | ">=" | "<>" | "-" | "+" | "*" | "/" | "^" | ":" | " " | "," | "&"} operator
|
|
51
|
-
* @property {AstExpression[]} arguments
|
|
52
|
-
*/
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* @typedef {Node} CallExpression
|
|
56
|
-
* @property {"CallExpression"} type
|
|
57
|
-
* @property {SourceLocation} [loc]
|
|
58
|
-
* @property {Identifier} callee
|
|
59
|
-
* @property {AstExpression[]} arguments
|
|
60
|
-
*/
|
|
61
|
-
|
|
62
|
-
// FIXME: the awkward naming is because tooling fails, fix tooling :)
|
|
63
|
-
/**
|
|
64
|
-
* @typedef {Node} MatrixExpression
|
|
65
|
-
* @property {"ArrayExpression"} type
|
|
66
|
-
* @property {SourceLocation} [loc]
|
|
67
|
-
* @property {Array<Array<ReferenceIdentifier | Literal | ErrorLiteral | CallExpression>>} arguments
|
|
68
|
-
*/
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* @typedef {Node} LambdaExpression
|
|
72
|
-
* @property {"LambdaExpression"} type
|
|
73
|
-
* @property {SourceLocation} [loc]
|
|
74
|
-
* @property {Identifier[]} params
|
|
75
|
-
* @property {null | AstExpression} body
|
|
76
|
-
*/
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* @typedef {Node} LetExpression
|
|
80
|
-
* @property {"LetExpression"} type
|
|
81
|
-
* @property {SourceLocation} [loc]
|
|
82
|
-
* @property {LetDeclarator[]} declarations
|
|
83
|
-
* @property {null | AstExpression} body
|
|
84
|
-
*/
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* @typedef {Node} LetDeclarator
|
|
88
|
-
* @property {"LetDeclarator"} type
|
|
89
|
-
* @property {SourceLocation} [loc]
|
|
90
|
-
* @property {Identifier} id
|
|
91
|
-
* @property {null | AstExpression} init
|
|
92
|
-
*/
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* @typedef {ReferenceIdentifier | Literal | ErrorLiteral | UnaryExpression | BinaryExpression | CallExpression | MatrixExpression | LambdaExpression | LetExpression} AstExpression
|
|
96
|
-
*/
|
package/lib/extraTypes.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {object} Token A formula language token.
|
|
3
|
-
* @augments Record<string,any>
|
|
4
|
-
* @property {string} type The type of the token
|
|
5
|
-
* @property {string} value The value of the token
|
|
6
|
-
* @property {boolean} [unterminated] Signifies an unterminated string token
|
|
7
|
-
* @property {Array<number>} [loc] Source position offsets to the token
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @typedef {object} TokenEnhanced A token with extra meta data.
|
|
12
|
-
* @augments Token
|
|
13
|
-
* @property {number} index A zero based position in a token list
|
|
14
|
-
* @property {string} [groupId] The ID of a group which this token belongs (e.g. matching parens)
|
|
15
|
-
* @property {number} [depth] This token's level of nesting inside parentheses
|
|
16
|
-
* @property {boolean} [error] Token is of unknown type or a paren without a match
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* @typedef {Record<string, any>} RangeR1C1 A range in R1C1 style coordinates.
|
|
21
|
-
* @property {number | null} [r0] Top row of the range
|
|
22
|
-
* @property {number | null} [r1] Bottom row of the range
|
|
23
|
-
* @property {number | null} [c0] Left column of the range
|
|
24
|
-
* @property {number | null} [c1] Right column of the range
|
|
25
|
-
* @property {boolean | null} [$r0] Signifies that r0 is an absolute value
|
|
26
|
-
* @property {boolean | null} [$r1] Signifies that r1 is an absolute value
|
|
27
|
-
* @property {boolean | null} [$c0] Signifies that c0 is an absolute value
|
|
28
|
-
* @property {boolean | null} [$c1] Signifies that c1 is an absolute value
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @typedef {Record<string, any>} RangeA1 A range in A1 style coordinates.
|
|
33
|
-
* @property {number | null} [top] Top row of the range
|
|
34
|
-
* @property {number | null} [bottom] Bottom row of the range
|
|
35
|
-
* @property {number | null} [left] Left column of the range
|
|
36
|
-
* @property {number | null} [right] Right column of the range
|
|
37
|
-
* @property {boolean | null} [$top] Signifies that top is a "locked" value
|
|
38
|
-
* @property {boolean | null} [$bottom] Signifies that bottom is a "locked" value
|
|
39
|
-
* @property {boolean | null} [$left] Signifies that left is a "locked" value
|
|
40
|
-
* @property {boolean | null} [$right] Signifies that right is a "locked" value
|
|
41
|
-
* @property {"head" | "tail" | "both"} [trim] Should empty rows and columns at the top/left or bottom/right be discarded when range is read?
|
|
42
|
-
*/
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* @typedef {Record<string, any>} ReferenceA1
|
|
46
|
-
* A reference containing an A1 style range. See [Prefixes.md] for
|
|
47
|
-
* documentation on how scopes work in Fx.
|
|
48
|
-
* @property {Array<string>} [context] A collection of scopes for the reference
|
|
49
|
-
* @property {string} [workbookName] A context workbook scope
|
|
50
|
-
* @property {string} [sheetName] A context sheet scope
|
|
51
|
-
* @property {RangeA1} [range] The reference's range
|
|
52
|
-
*/
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* @typedef {Record<string, any>} ReferenceR1C1
|
|
56
|
-
* A reference containing a R1C1 style range. See [Prefixes.md] for
|
|
57
|
-
* documentation on how scopes work in Fx.
|
|
58
|
-
* @property {Array<string>} [context] A collection of scopes for the reference
|
|
59
|
-
* @property {string} [workbookName] A context workbook scope
|
|
60
|
-
* @property {string} [sheetName] A context sheet scope
|
|
61
|
-
* @property {RangeR1C1} [range] The reference's range
|
|
62
|
-
*/
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* @typedef {Record<string, any>} ReferenceStruct
|
|
66
|
-
* A reference containing a table slice definition. See [Prefixes.md] for
|
|
67
|
-
* documentation on how scopes work in Fx.
|
|
68
|
-
* @property {Array<string>} [context] A collection of scopes for the reference
|
|
69
|
-
* @property {string} [workbookName] A context workbook scope
|
|
70
|
-
* @property {string} [sheetName] A context sheet scope
|
|
71
|
-
* @property {Array<string>} [sections] The sections this reference targets
|
|
72
|
-
* @property {Array<string>} [columns] The sections this reference targets
|
|
73
|
-
* @property {string} [table] The table this reference targets
|
|
74
|
-
*/
|
package/lib/fixRanges.js
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { isRange } from './isType.js';
|
|
2
|
-
import { parseA1Ref, stringifyA1Ref, addA1RangeBounds } from './a1.js';
|
|
3
|
-
import { parseStructRef } from './parseStructRef.js';
|
|
4
|
-
import { stringifyStructRef } from './stringifyStructRef.js';
|
|
5
|
-
import { tokenize } from './lexer.js';
|
|
6
|
-
import { REF_STRUCT } from './constants.js';
|
|
7
|
-
|
|
8
|
-
// There is no R1C1 counterpart to this. This is because without an anchor cell
|
|
9
|
-
// it is impossible to determine if a relative+absolute range (R[1]C[1]:R5C5)
|
|
10
|
-
// needs to be flipped or not. The solution is to convert to A1 first:
|
|
11
|
-
// translateToRC(fixRanges(translateToA1(...)))
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Normalizes A1 style ranges and structured references in a formula or list of
|
|
15
|
-
* tokens.
|
|
16
|
-
*
|
|
17
|
-
* It ensures that that the top and left coordinates of an A1 range are on the
|
|
18
|
-
* left-hand side of a colon operator:
|
|
19
|
-
*
|
|
20
|
-
* `B2:A1` → `A1:B2`
|
|
21
|
-
* `1:A1` → `A1:1`
|
|
22
|
-
* `A:A1` → `A1:A`
|
|
23
|
-
* `B:A` → `A:B`
|
|
24
|
-
* `2:1` → `1:2`
|
|
25
|
-
* `A1:A1` → `A1`
|
|
26
|
-
*
|
|
27
|
-
* When `{ addBounds: true }` is passed as an option, the missing bounds are
|
|
28
|
-
* also added. This can be done to ensure Excel compatible ranges. The fixes
|
|
29
|
-
* then additionally include:
|
|
30
|
-
*
|
|
31
|
-
* `1:A1` → `A1:1` → `1:1`
|
|
32
|
-
* `A:A1` → `A1:A` → `A:A`
|
|
33
|
-
* `A1:A` → `A:A`
|
|
34
|
-
* `A1:1` → `A:1`
|
|
35
|
-
* `B2:B` → `B2:1048576`
|
|
36
|
-
* `B2:2` → `B2:XFD2`
|
|
37
|
-
*
|
|
38
|
-
* Structured ranges are normalized cleaned up to have consistent order and
|
|
39
|
-
* capitalization of sections as well as removing redundant ones.
|
|
40
|
-
*
|
|
41
|
-
* Returns the same formula with the ranges updated. If an array of tokens was
|
|
42
|
-
* supplied, then a new array is returned.
|
|
43
|
-
*
|
|
44
|
-
* @param {(string | Array<Token>)} formula A string (an Excel formula) or a token list that should be adjusted.
|
|
45
|
-
* @param {object} [options={}] Options
|
|
46
|
-
* @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.
|
|
47
|
-
* @param {boolean} [options.xlsx=false] Switches to the `[1]Sheet1!A1` or `[1]!name` prefix syntax form for external workbooks. See: [Prefixes.md](./Prefixes.md)
|
|
48
|
-
* @param {boolean} [options.thisRow=false] Enforces using the `[#This Row]` instead of the `@` shorthand when serializing structured ranges.
|
|
49
|
-
* @returns {(string | Array<Token>)} A formula string or token list (depending on which was input)
|
|
50
|
-
*/
|
|
51
|
-
export function fixRanges (formula, options = { addBounds: false }) {
|
|
52
|
-
if (typeof formula === 'string') {
|
|
53
|
-
return fixRanges(tokenize(formula, options), options)
|
|
54
|
-
.map(d => d.value)
|
|
55
|
-
.join('');
|
|
56
|
-
}
|
|
57
|
-
if (!Array.isArray(formula)) {
|
|
58
|
-
throw new Error('fixRanges expects an array of tokens');
|
|
59
|
-
}
|
|
60
|
-
const { addBounds, r1c1, xlsx, thisRow } = options;
|
|
61
|
-
if (r1c1) {
|
|
62
|
-
throw new Error('fixRanges does not have an R1C1 mode');
|
|
63
|
-
}
|
|
64
|
-
let offsetSkew = 0;
|
|
65
|
-
return formula.map(t => {
|
|
66
|
-
const token = { ...t };
|
|
67
|
-
if (t.loc) {
|
|
68
|
-
token.loc = [ ...t.loc ];
|
|
69
|
-
}
|
|
70
|
-
let offsetDelta = 0;
|
|
71
|
-
if (token.type === REF_STRUCT) {
|
|
72
|
-
const sref = parseStructRef(token.value, { xlsx });
|
|
73
|
-
const newValue = stringifyStructRef(sref, { xlsx, thisRow });
|
|
74
|
-
offsetDelta = newValue.length - token.value.length;
|
|
75
|
-
token.value = newValue;
|
|
76
|
-
}
|
|
77
|
-
else if (isRange(token)) {
|
|
78
|
-
const ref = parseA1Ref(token.value, { xlsx, allowTernary: true });
|
|
79
|
-
const range = ref.range;
|
|
80
|
-
// fill missing dimensions?
|
|
81
|
-
if (addBounds) {
|
|
82
|
-
addA1RangeBounds(range);
|
|
83
|
-
}
|
|
84
|
-
const newValue = stringifyA1Ref(ref, { xlsx });
|
|
85
|
-
offsetDelta = newValue.length - token.value.length;
|
|
86
|
-
token.value = newValue;
|
|
87
|
-
}
|
|
88
|
-
// ensure that positioning is still correct
|
|
89
|
-
if (offsetSkew || offsetDelta) {
|
|
90
|
-
if (token.loc) {
|
|
91
|
-
token.loc[0] += offsetSkew;
|
|
92
|
-
}
|
|
93
|
-
offsetSkew += offsetDelta;
|
|
94
|
-
if (token.loc) {
|
|
95
|
-
token.loc[1] += offsetSkew;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
offsetSkew += offsetDelta;
|
|
100
|
-
}
|
|
101
|
-
return token;
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
package/lib/fixRanges.spec.js
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import { test, Test } from 'tape';
|
|
2
|
-
import { tokenize } from './lexer.js';
|
|
3
|
-
import { addTokenMeta } from './addTokenMeta.js';
|
|
4
|
-
import { fixRanges } from './fixRanges.js';
|
|
5
|
-
import { FUNCTION, FX_PREFIX, OPERATOR, REF_RANGE, REF_STRUCT, REF_TERNARY } from './constants.js';
|
|
6
|
-
|
|
7
|
-
Test.prototype.isFixed = function (expr, expected, options = {}) {
|
|
8
|
-
const result = fixRanges(expr, options);
|
|
9
|
-
this.is(result, expected,
|
|
10
|
-
`\x1b[36m${expr} → ${expected} \x1b[37mopts=${JSON.stringify(options)}\x1b[0m`);
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
test('fixRanges basics', t => {
|
|
14
|
-
const fx = '=SUM([wb]Sheet1!B2:A1)';
|
|
15
|
-
t.throws(() => fixRanges(123), 'throws on non arrays (number)');
|
|
16
|
-
t.throws(() => fixRanges(null), 'throws on non arrays (null)');
|
|
17
|
-
const tokens = addTokenMeta(tokenize(fx, { mergeRefs: true }));
|
|
18
|
-
tokens[3].foo = 'bar';
|
|
19
|
-
const fixedTokens = fixRanges(tokens, { debug: 0 });
|
|
20
|
-
t.ok(tokens !== fixedTokens, 'emits a new array instance');
|
|
21
|
-
t.ok(tokens[3] !== fixedTokens[3], 'does not mutate existing range tokens');
|
|
22
|
-
t.deepEqual(tokens[3], {
|
|
23
|
-
type: REF_RANGE,
|
|
24
|
-
value: '[wb]Sheet1!B2:A1',
|
|
25
|
-
index: 3,
|
|
26
|
-
depth: 1,
|
|
27
|
-
groupId: 'fxg1',
|
|
28
|
-
foo: 'bar'
|
|
29
|
-
}, 'keeps meta (pre-fix range token)');
|
|
30
|
-
t.deepEqual(fixedTokens[3], {
|
|
31
|
-
type: REF_RANGE,
|
|
32
|
-
value: '[wb]Sheet1!A1:B2',
|
|
33
|
-
index: 3,
|
|
34
|
-
depth: 1,
|
|
35
|
-
groupId: 'fxg1',
|
|
36
|
-
foo: 'bar'
|
|
37
|
-
}, 'keeps meta (post-fix range token)');
|
|
38
|
-
const tokensWithRanges = tokenize(
|
|
39
|
-
'=SUM(B2:A,table[[#This Row],[Foo]])',
|
|
40
|
-
{ withLocation: true, mergeRefs: true, allowTernary: true }
|
|
41
|
-
);
|
|
42
|
-
t.deepEqual(fixRanges(tokensWithRanges, { addBounds: true }), [
|
|
43
|
-
{ type: FX_PREFIX, value: '=', loc: [ 0, 1 ] },
|
|
44
|
-
{ type: FUNCTION, value: 'SUM', loc: [ 1, 4 ] },
|
|
45
|
-
{ type: OPERATOR, value: '(', loc: [ 4, 5 ] },
|
|
46
|
-
{ type: REF_TERNARY, value: 'A2:B1048576', loc: [ 5, 16 ] },
|
|
47
|
-
{ type: OPERATOR, value: ',', loc: [ 16, 17 ] },
|
|
48
|
-
{ type: REF_STRUCT, value: 'table[@Foo]', loc: [ 17, 28 ] },
|
|
49
|
-
{ type: OPERATOR, value: ')', loc: [ 28, 29 ] }
|
|
50
|
-
], 'updates token source location information');
|
|
51
|
-
t.end();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('fixRanges A1', t => {
|
|
55
|
-
const opt = { allowTernary: true };
|
|
56
|
-
// doesn't mess with things that it doesn't have to
|
|
57
|
-
t.isFixed('=A1', '=A1', opt);
|
|
58
|
-
t.isFixed('=ZZ123', '=ZZ123', opt);
|
|
59
|
-
t.isFixed('=A1:B2', '=A1:B2', opt);
|
|
60
|
-
t.isFixed('=B3:OFFSET(A1,10,10)', '=B3:OFFSET(A1,10,10)', opt);
|
|
61
|
-
t.isFixed('=A:B', '=A:B', opt);
|
|
62
|
-
t.isFixed('=C:C', '=C:C', opt);
|
|
63
|
-
t.isFixed('=3:6', '=3:6', opt);
|
|
64
|
-
t.isFixed('=3:3', '=3:3', opt);
|
|
65
|
-
// redundancy
|
|
66
|
-
t.isFixed('=A1:$A$1', '=A1:$A$1', opt);
|
|
67
|
-
t.isFixed('=A1:A1', '=A1', opt);
|
|
68
|
-
// lowercase to uppercase
|
|
69
|
-
t.isFixed('=a1', '=A1', opt);
|
|
70
|
-
t.isFixed('=zz123', '=ZZ123', opt);
|
|
71
|
-
t.isFixed('=a1:b2', '=A1:B2', opt);
|
|
72
|
-
// flipped rects
|
|
73
|
-
t.isFixed('=B2:A1', '=A1:B2', opt);
|
|
74
|
-
t.isFixed('=$B$2:$A$1', '=$A$1:$B$2', opt);
|
|
75
|
-
// flipped beams
|
|
76
|
-
t.isFixed('=C:A', '=A:C', opt);
|
|
77
|
-
t.isFixed('=$D:B', '=B:$D', opt);
|
|
78
|
-
t.isFixed('=10:1', '=1:10', opt);
|
|
79
|
-
t.isFixed('=$5:3', '=3:$5', opt);
|
|
80
|
-
// flipped partials - bottom
|
|
81
|
-
t.isFixed('=A:A1', '=A1:A', opt);
|
|
82
|
-
t.isFixed('=A:A$1', '=A$1:A', opt);
|
|
83
|
-
// flipped partials - right
|
|
84
|
-
t.isFixed('=1:A1', '=A1:1', opt);
|
|
85
|
-
// $1:$A1 is rather counter intuitive case:
|
|
86
|
-
// This range is parsed as { left=null, top=$1, right=$A, bottom=1 } but,
|
|
87
|
-
// because left is null, right and left are flipped around, making this
|
|
88
|
-
// end up as { left=$A, top=$1, right=null, bottom=1 } which serializes
|
|
89
|
-
// as $A$1:1
|
|
90
|
-
t.isFixed('=$1:$A1', '=$A$1:1', opt);
|
|
91
|
-
t.end();
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test('fixRanges A1 addBounds', t => {
|
|
95
|
-
const opt = { allowTernary: true, addBounds: true };
|
|
96
|
-
t.isFixed('=B3:OFFSET(A1,10,10)', '=B3:OFFSET(A1,10,10)', opt);
|
|
97
|
-
t.isFixed('=A:A', '=A:A', opt);
|
|
98
|
-
t.isFixed('=A:A1', '=A:A', opt);
|
|
99
|
-
t.isFixed('=A:A$1', '=A:A', opt);
|
|
100
|
-
t.isFixed('=A:$A$1', '=A:$A', opt);
|
|
101
|
-
t.isFixed('=A.:A', '=A.:A', opt);
|
|
102
|
-
// partials - bottom
|
|
103
|
-
t.isFixed('=A1:A', '=A:A', opt);
|
|
104
|
-
t.isFixed('=A1:Z', '=A:Z', opt);
|
|
105
|
-
t.isFixed('=A:A1', '=A:A', opt);
|
|
106
|
-
t.isFixed('=$A1:A', '=$A:A', opt);
|
|
107
|
-
t.isFixed('=A$1:A', '=A:A', opt);
|
|
108
|
-
t.isFixed('=A1:$A', '=A:$A', opt);
|
|
109
|
-
t.isFixed('=A2:A', '=A2:A1048576', opt);
|
|
110
|
-
t.isFixed('=B2:B', '=B2:B1048576', opt);
|
|
111
|
-
t.isFixed('=A:A2', '=A2:A1048576', opt);
|
|
112
|
-
t.isFixed('=B:B2', '=B2:B1048576', opt);
|
|
113
|
-
t.isFixed('=B.:.B2', '=B2.:.B1048576', opt);
|
|
114
|
-
// flipped partials - bottom
|
|
115
|
-
t.isFixed('=A1:1', '=1:1', opt);
|
|
116
|
-
t.isFixed('=A1:4', '=1:4', opt);
|
|
117
|
-
t.isFixed('=1:A1', '=1:1', opt);
|
|
118
|
-
t.isFixed('=$A1:1', '=1:1', opt);
|
|
119
|
-
t.isFixed('=A$1:1', '=$1:1', opt);
|
|
120
|
-
t.isFixed('=A1:$1', '=1:$1', opt);
|
|
121
|
-
t.isFixed('=B1:1', '=B1:XFD1', opt);
|
|
122
|
-
t.isFixed('=1:B1', '=B1:XFD1', opt);
|
|
123
|
-
t.isFixed('=B2:20', '=B2:XFD20', opt);
|
|
124
|
-
t.isFixed('=2:B20', '=B2:XFD20', opt);
|
|
125
|
-
t.isFixed('=2:.B20', '=B2:.XFD20', opt);
|
|
126
|
-
t.end();
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
test('fixRanges structured references', t => {
|
|
130
|
-
t.isFixed('=Table1[[#This Row],[Foo]]', '=Table1[@Foo]');
|
|
131
|
-
t.isFixed('=[[#This Row],[s:s]]', '=[@[s:s]]');
|
|
132
|
-
t.isFixed('=Table1[[#Totals],col name:Foo]', '=Table1[[#Totals],[col name]:[Foo]]');
|
|
133
|
-
t.isFixed('[[#data],[#headers]]', '[[#Headers],[#Data]]');
|
|
134
|
-
t.isFixed('[[#headers],[#data]]', '[[#Headers],[#Data]]');
|
|
135
|
-
t.isFixed('[[#totals],[#data]]', '[[#Data],[#Totals]]');
|
|
136
|
-
t.isFixed('[ [#totals], [#data] ]', '[[#Data],[#Totals]]');
|
|
137
|
-
t.isFixed('[[#data],[#totals]]', '[[#Data],[#Totals]]');
|
|
138
|
-
t.isFixed('[[#all],foo:bar]', '[[#All],[foo]:[bar]]');
|
|
139
|
-
t.isFixed('[[#all],[#all],[#all],[#all],[ColumnName]]', '[[#All],[ColumnName]]');
|
|
140
|
-
t.isFixed('[@[foo]:bar]', '[@[foo]:[bar]]');
|
|
141
|
-
t.isFixed('[@foo bar]', '[@[foo bar]]');
|
|
142
|
-
// Care must be taken with spaces in column headers.
|
|
143
|
-
// Excel considers refs only valid if they match the column name
|
|
144
|
-
// but the parser does not know the names, so it must preserve
|
|
145
|
-
// leading/trailing whitespace.
|
|
146
|
-
t.isFixed('[ @[foo bar] ]', '[@[foo bar]]');
|
|
147
|
-
t.isFixed('[ @[ foo bar ] ]', '[@[ foo bar ]]');
|
|
148
|
-
t.isFixed('[ @foo bar ]', '[@[foo bar ]]');
|
|
149
|
-
t.isFixed('[@ foo bar]', '[@[ foo bar]]');
|
|
150
|
-
t.isFixed('[ @ foo bar ]', '[@[ foo bar ]]');
|
|
151
|
-
t.end();
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
test('fixRanges works with xlsx mode', t => {
|
|
155
|
-
// should not mess with invalid ranges in normal mode
|
|
156
|
-
t.isFixed("='[Workbook]'!Table[Column]", "='[Workbook]'!Table[Column]");
|
|
157
|
-
t.isFixed('=[Workbook]!Table[Column]', '=[Workbook]!Table[Column]');
|
|
158
|
-
t.isFixed("='[Foo]'!A1", "='[Foo]'!A1");
|
|
159
|
-
t.isFixed('=[Foo]!A1', '=[Foo]!A1');
|
|
160
|
-
// should fix things in xlsx mode
|
|
161
|
-
const opts = { xlsx: true };
|
|
162
|
-
t.isFixed("='[Workbook]'!Table[Column]", '=[Workbook]!Table[Column]', opts);
|
|
163
|
-
t.isFixed('=[Workbook]!Table[Column]', '=[Workbook]!Table[Column]', opts);
|
|
164
|
-
t.isFixed('=[Lorem Ipsum]!Table[Column]', "='[Lorem Ipsum]'!Table[Column]", opts);
|
|
165
|
-
t.isFixed("='[Foo]'!A1", '=[Foo]!A1', opts);
|
|
166
|
-
t.isFixed('=[Foo]Bar!A1', '=[Foo]Bar!A1', opts);
|
|
167
|
-
t.isFixed('=[Foo Bar]Baz!A1', "='[Foo Bar]Baz'!A1", opts);
|
|
168
|
-
t.isFixed('=[Foo]!A1', '=[Foo]!A1', opts);
|
|
169
|
-
t.isFixed('=[Lorem Ipsum]!A1', "='[Lorem Ipsum]'!A1", opts);
|
|
170
|
-
t.end();
|
|
171
|
-
});
|
package/lib/fromCol.spec.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { test } from 'tape';
|
|
2
|
-
import { fromCol } from './fromCol.js';
|
|
3
|
-
|
|
4
|
-
test('fromCol parses column id strings to numbers', t => {
|
|
5
|
-
t.is(fromCol('a'), 0);
|
|
6
|
-
t.is(fromCol('A'), 0);
|
|
7
|
-
t.is(fromCol('AA'), 26);
|
|
8
|
-
t.is(fromCol('zz'), 701);
|
|
9
|
-
t.is(fromCol('ZZZ'), 18277);
|
|
10
|
-
t.end();
|
|
11
|
-
});
|
package/lib/index.js
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
export { tokenize } from './lexer.js';
|
|
2
|
-
export { parse } from './parser.js';
|
|
3
|
-
export { addTokenMeta } from './addTokenMeta.js';
|
|
4
|
-
export { translateToR1C1, translateToA1 } from './translate.js';
|
|
5
|
-
export { MAX_COLS, MAX_ROWS } from './constants.js';
|
|
6
|
-
export { mergeRefTokens } from './mergeRefTokens.js';
|
|
7
|
-
export { fixRanges } from './fixRanges.js';
|
|
8
|
-
export {
|
|
9
|
-
isError,
|
|
10
|
-
isFunction,
|
|
11
|
-
isFxPrefix,
|
|
12
|
-
isLiteral,
|
|
13
|
-
isOperator,
|
|
14
|
-
isRange,
|
|
15
|
-
isReference,
|
|
16
|
-
isWhitespace
|
|
17
|
-
} from './isType.js';
|
|
18
|
-
|
|
19
|
-
export { fromCol } from './fromCol.js';
|
|
20
|
-
export { toCol } from './toCol.js';
|
|
21
|
-
|
|
22
|
-
export {
|
|
23
|
-
parseA1Ref,
|
|
24
|
-
stringifyA1Ref,
|
|
25
|
-
addA1RangeBounds
|
|
26
|
-
} from './a1.js';
|
|
27
|
-
|
|
28
|
-
export {
|
|
29
|
-
parseR1C1Ref,
|
|
30
|
-
stringifyR1C1Ref
|
|
31
|
-
} from './rc.js';
|
|
32
|
-
|
|
33
|
-
export { stringifyStructRef } from './stringifyStructRef.js';
|
|
34
|
-
export { parseStructRef } from './parseStructRef.js';
|
|
35
|
-
|
|
36
|
-
import {
|
|
37
|
-
// token types
|
|
38
|
-
OPERATOR,
|
|
39
|
-
BOOLEAN,
|
|
40
|
-
ERROR,
|
|
41
|
-
NUMBER,
|
|
42
|
-
FUNCTION,
|
|
43
|
-
NEWLINE,
|
|
44
|
-
WHITESPACE,
|
|
45
|
-
STRING,
|
|
46
|
-
CONTEXT,
|
|
47
|
-
CONTEXT_QUOTE,
|
|
48
|
-
REF_RANGE,
|
|
49
|
-
REF_BEAM,
|
|
50
|
-
REF_TERNARY,
|
|
51
|
-
REF_NAMED,
|
|
52
|
-
REF_STRUCT,
|
|
53
|
-
FX_PREFIX,
|
|
54
|
-
UNKNOWN,
|
|
55
|
-
// AST types
|
|
56
|
-
UNARY,
|
|
57
|
-
BINARY,
|
|
58
|
-
REFERENCE,
|
|
59
|
-
LITERAL,
|
|
60
|
-
ERROR_LITERAL,
|
|
61
|
-
CALL,
|
|
62
|
-
ARRAY,
|
|
63
|
-
IDENTIFIER
|
|
64
|
-
} from './constants.js';
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* A dictionary of the types used to identify token variants.
|
|
68
|
-
*
|
|
69
|
-
* @readonly
|
|
70
|
-
* @constant {Object<string>} tokenTypes
|
|
71
|
-
* @property {string} OPERATOR - Newline (`\n`)
|
|
72
|
-
* @property {string} BOOLEAN - Boolean literal (`TRUE`)
|
|
73
|
-
* @property {string} ERROR - Error literal (`#VALUE!`)
|
|
74
|
-
* @property {string} NUMBER - Number literal (`123.4`, `-1.5e+2`)
|
|
75
|
-
* @property {string} FUNCTION - Function name (`SUM`)
|
|
76
|
-
* @property {string} NEWLINE - Newline character (`\n`)
|
|
77
|
-
* @property {string} WHITESPACE - Whitespace character sequence (` `)
|
|
78
|
-
* @property {string} STRING - String literal (`"Lorem ipsum"`)
|
|
79
|
-
* @property {string} CONTEXT - Reference context ([Workbook.xlsx]Sheet1)
|
|
80
|
-
* @property {string} CONTEXT_QUOTE - Quoted reference context (`'[My workbook.xlsx]Sheet1'`)
|
|
81
|
-
* @property {string} REF_RANGE - A range identifier (`A1`)
|
|
82
|
-
* @property {string} REF_BEAM - A range "beam" identifier (`A:A` or `1:1`)
|
|
83
|
-
* @property {string} REF_TERNARY - A ternary range identifier (`B2:B`)
|
|
84
|
-
* @property {string} REF_NAMED - A name / named range identifier (`income`)
|
|
85
|
-
* @property {string} REF_STRUCT - A structured reference identifier (`table[[Column1]:[Column2]]`)
|
|
86
|
-
* @property {string} FX_PREFIX - A leading equals sign at the start of a formula (`=`)
|
|
87
|
-
* @property {string} UNKNOWN - Any unidentifiable range of characters.
|
|
88
|
-
* @see tokenize
|
|
89
|
-
*/
|
|
90
|
-
export const tokenTypes = Object.freeze({
|
|
91
|
-
OPERATOR,
|
|
92
|
-
BOOLEAN,
|
|
93
|
-
ERROR,
|
|
94
|
-
NUMBER,
|
|
95
|
-
FUNCTION,
|
|
96
|
-
NEWLINE,
|
|
97
|
-
WHITESPACE,
|
|
98
|
-
STRING,
|
|
99
|
-
CONTEXT,
|
|
100
|
-
CONTEXT_QUOTE,
|
|
101
|
-
REF_RANGE,
|
|
102
|
-
REF_BEAM,
|
|
103
|
-
REF_TERNARY,
|
|
104
|
-
REF_NAMED,
|
|
105
|
-
REF_STRUCT,
|
|
106
|
-
FX_PREFIX,
|
|
107
|
-
UNKNOWN
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* A dictionary of the types used to identify AST node variants.
|
|
112
|
-
*
|
|
113
|
-
* @readonly
|
|
114
|
-
* @constant {Object<string>} nodeTypes
|
|
115
|
-
* @property {string} UNARY - A unary operation (`10%`)
|
|
116
|
-
* @property {string} BINARY - A binary operation (`10+10`)
|
|
117
|
-
* @property {string} REFERENCE - A range identifier (`A1`)
|
|
118
|
-
* @property {string} LITERAL - A literal (number, string, or boolean) (`123`, `"foo"`, `false`)
|
|
119
|
-
* @property {string} ERROR - An error literal (`#VALUE!`)
|
|
120
|
-
* @property {string} CALL - A function call expression (`SUM(1,2)`)
|
|
121
|
-
* @property {string} ARRAY - An array expression (`{1,2;3,4}`)
|
|
122
|
-
* @property {string} IDENTIFIER - A function name identifier (`SUM`)
|
|
123
|
-
* @see parse
|
|
124
|
-
*/
|
|
125
|
-
export const nodeTypes = Object.freeze({
|
|
126
|
-
UNARY,
|
|
127
|
-
BINARY,
|
|
128
|
-
REFERENCE,
|
|
129
|
-
LITERAL,
|
|
130
|
-
ERROR: ERROR_LITERAL,
|
|
131
|
-
CALL,
|
|
132
|
-
ARRAY,
|
|
133
|
-
IDENTIFIER
|
|
134
|
-
});
|
package/lib/index.spec.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { test } from 'tape';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
addA1RangeBounds,
|
|
5
|
-
addTokenMeta,
|
|
6
|
-
fixRanges,
|
|
7
|
-
fromCol,
|
|
8
|
-
isError,
|
|
9
|
-
isFunction,
|
|
10
|
-
isFxPrefix,
|
|
11
|
-
isLiteral,
|
|
12
|
-
isOperator,
|
|
13
|
-
isRange,
|
|
14
|
-
isReference,
|
|
15
|
-
isWhitespace,
|
|
16
|
-
mergeRefTokens,
|
|
17
|
-
nodeTypes,
|
|
18
|
-
parse,
|
|
19
|
-
parseA1Ref,
|
|
20
|
-
parseR1C1Ref,
|
|
21
|
-
parseStructRef,
|
|
22
|
-
stringifyA1Ref,
|
|
23
|
-
stringifyR1C1Ref,
|
|
24
|
-
stringifyStructRef,
|
|
25
|
-
toCol,
|
|
26
|
-
tokenize,
|
|
27
|
-
tokenTypes,
|
|
28
|
-
translateToA1,
|
|
29
|
-
translateToR1C1
|
|
30
|
-
} from './index.js';
|
|
31
|
-
|
|
32
|
-
// What happens when B2:A1 -> should work!
|
|
33
|
-
test('fx main interface', t => {
|
|
34
|
-
t.ok(typeof addA1RangeBounds === 'function', 'addA1RangeBounds exists');
|
|
35
|
-
t.ok(typeof addTokenMeta === 'function', 'addTokenMeta exists');
|
|
36
|
-
t.ok(typeof fixRanges === 'function', 'fixRanges exists');
|
|
37
|
-
|
|
38
|
-
t.ok(typeof fromCol === 'function', 'fromCol exists');
|
|
39
|
-
|
|
40
|
-
t.ok(typeof isError === 'function', 'isError exists');
|
|
41
|
-
t.ok(typeof isFunction === 'function', 'isFunction exists');
|
|
42
|
-
t.ok(typeof isFxPrefix === 'function', 'isFxPrefix exists');
|
|
43
|
-
t.ok(typeof isLiteral === 'function', 'isLiteral exists');
|
|
44
|
-
t.ok(typeof isOperator === 'function', 'isOperator exists');
|
|
45
|
-
t.ok(typeof isRange === 'function', 'isRange exists');
|
|
46
|
-
t.ok(typeof isReference === 'function', 'isReference exists');
|
|
47
|
-
t.ok(typeof isWhitespace === 'function', 'isWhitespace exists');
|
|
48
|
-
|
|
49
|
-
t.ok(typeof mergeRefTokens === 'function', 'mergeRefTokens exists');
|
|
50
|
-
t.ok(typeof parse === 'function', 'parse exists');
|
|
51
|
-
t.ok(typeof parseA1Ref === 'function', 'parseA1Ref exists');
|
|
52
|
-
t.ok(typeof parseR1C1Ref === 'function', 'parseR1C1Ref exists');
|
|
53
|
-
t.ok(typeof parseStructRef === 'function', 'parseStructRef exists');
|
|
54
|
-
t.ok(typeof stringifyA1Ref === 'function', 'stringifyA1Ref exists');
|
|
55
|
-
t.ok(typeof stringifyR1C1Ref === 'function', 'stringifyR1C1Ref exists');
|
|
56
|
-
t.ok(typeof stringifyStructRef === 'function', 'stringifyStructRef exists');
|
|
57
|
-
t.ok(typeof toCol === 'function', 'toCol exists');
|
|
58
|
-
t.ok(typeof tokenize === 'function', 'tokenize exists');
|
|
59
|
-
t.ok(typeof translateToA1 === 'function', 'translateToA1 exists');
|
|
60
|
-
t.ok(typeof translateToR1C1 === 'function', 'translateToR1C1 exists');
|
|
61
|
-
|
|
62
|
-
t.ok(typeof nodeTypes === 'object', 'nodeTypes exists');
|
|
63
|
-
t.ok(typeof tokenTypes === 'object', 'tokenTypes exists');
|
|
64
|
-
|
|
65
|
-
t.end();
|
|
66
|
-
});
|
|
67
|
-
|