@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.
Files changed (141) hide show
  1. package/dist/index-BMr6cTgc.d.cts +1444 -0
  2. package/dist/index-BMr6cTgc.d.ts +1444 -0
  3. package/dist/index.cjs +3054 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +1 -0
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.js +2984 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/xlsx/index.cjs +3120 -0
  10. package/dist/xlsx/index.cjs.map +1 -0
  11. package/dist/xlsx/index.d.cts +55 -0
  12. package/dist/xlsx/index.d.ts +55 -0
  13. package/dist/xlsx/index.js +3049 -0
  14. package/dist/xlsx/index.js.map +1 -0
  15. package/docs/API.md +2959 -718
  16. package/docs/AST_format.md +2 -2
  17. package/eslint.config.mjs +40 -0
  18. package/lib/a1.spec.ts +32 -0
  19. package/lib/a1.ts +26 -0
  20. package/lib/addA1RangeBounds.ts +50 -0
  21. package/lib/addTokenMeta.spec.ts +166 -0
  22. package/lib/{addTokenMeta.js → addTokenMeta.ts} +53 -33
  23. package/lib/astTypes.ts +211 -0
  24. package/lib/cloneToken.ts +29 -0
  25. package/lib/{constants.js → constants.ts} +6 -3
  26. package/lib/fixRanges.spec.ts +220 -0
  27. package/lib/fixRanges.ts +260 -0
  28. package/lib/fromCol.spec.ts +15 -0
  29. package/lib/{fromCol.js → fromCol.ts} +1 -1
  30. package/lib/index.spec.ts +119 -0
  31. package/lib/index.ts +76 -0
  32. package/lib/isNodeType.ts +151 -0
  33. package/lib/isType.spec.ts +208 -0
  34. package/lib/{isType.js → isType.ts} +26 -25
  35. package/lib/lexers/{advRangeOp.js → advRangeOp.ts} +1 -1
  36. package/lib/lexers/{canEndRange.js → canEndRange.ts} +2 -2
  37. package/lib/lexers/{lexBoolean.js → lexBoolean.ts} +25 -6
  38. package/lib/lexers/{lexContext.js → lexContext.ts} +14 -6
  39. package/lib/lexers/{lexError.js → lexError.ts} +3 -3
  40. package/lib/lexers/{lexFunction.js → lexFunction.ts} +3 -2
  41. package/lib/lexers/lexNameFuncCntx.ts +112 -0
  42. package/lib/lexers/{lexNamed.js → lexNamed.ts} +4 -4
  43. package/lib/lexers/{lexNewLine.js → lexNewLine.ts} +3 -2
  44. package/lib/lexers/{lexNumber.js → lexNumber.ts} +4 -3
  45. package/lib/lexers/{lexOperator.js → lexOperator.ts} +5 -4
  46. package/lib/lexers/lexRange.ts +15 -0
  47. package/lib/lexers/{lexRangeA1.js → lexRangeA1.ts} +11 -7
  48. package/lib/lexers/{lexRangeR1C1.js → lexRangeR1C1.ts} +10 -6
  49. package/lib/lexers/{lexRangeTrim.js → lexRangeTrim.ts} +3 -2
  50. package/lib/lexers/{lexRefOp.js → lexRefOp.ts} +4 -3
  51. package/lib/lexers/{lexString.js → lexString.ts} +3 -3
  52. package/lib/lexers/{lexStructured.js → lexStructured.ts} +5 -5
  53. package/lib/lexers/{lexWhitespace.js → lexWhitespace.ts} +3 -2
  54. package/lib/lexers/sets.ts +51 -0
  55. package/lib/mergeRefTokens.spec.ts +141 -0
  56. package/lib/{mergeRefTokens.js → mergeRefTokens.ts} +14 -9
  57. package/lib/nodeTypes.ts +54 -0
  58. package/lib/parse.spec.ts +1410 -0
  59. package/lib/{parser.js → parse.ts} +81 -63
  60. package/lib/parseA1Range.spec.ts +233 -0
  61. package/lib/parseA1Range.ts +206 -0
  62. package/lib/parseA1Ref.spec.ts +337 -0
  63. package/lib/parseA1Ref.ts +115 -0
  64. package/lib/parseR1C1Range.ts +191 -0
  65. package/lib/parseR1C1Ref.spec.ts +323 -0
  66. package/lib/parseR1C1Ref.ts +127 -0
  67. package/lib/parseRef.spec.ts +90 -0
  68. package/lib/parseRef.ts +240 -0
  69. package/lib/{parseSRange.js → parseSRange.ts} +15 -10
  70. package/lib/parseStructRef.spec.ts +168 -0
  71. package/lib/parseStructRef.ts +76 -0
  72. package/lib/stringifyA1Range.spec.ts +72 -0
  73. package/lib/stringifyA1Range.ts +72 -0
  74. package/lib/stringifyA1Ref.spec.ts +64 -0
  75. package/lib/stringifyA1Ref.ts +59 -0
  76. package/lib/{stringifyPrefix.js → stringifyPrefix.ts} +17 -2
  77. package/lib/stringifyR1C1Range.spec.ts +92 -0
  78. package/lib/stringifyR1C1Range.ts +73 -0
  79. package/lib/stringifyR1C1Ref.spec.ts +63 -0
  80. package/lib/stringifyR1C1Ref.ts +67 -0
  81. package/lib/stringifyStructRef.spec.ts +124 -0
  82. package/lib/stringifyStructRef.ts +113 -0
  83. package/lib/stringifyTokens.ts +15 -0
  84. package/lib/toCol.spec.ts +11 -0
  85. package/lib/{toCol.js → toCol.ts} +4 -4
  86. package/lib/tokenTypes.ts +76 -0
  87. package/lib/tokenize-srefs.spec.ts +429 -0
  88. package/lib/tokenize.spec.ts +2103 -0
  89. package/lib/tokenize.ts +346 -0
  90. package/lib/translate.spec.ts +35 -0
  91. package/lib/translateToA1.spec.ts +247 -0
  92. package/lib/translateToA1.ts +231 -0
  93. package/lib/translateToR1C1.spec.ts +227 -0
  94. package/lib/translateToR1C1.ts +145 -0
  95. package/lib/types.ts +179 -0
  96. package/lib/xlsx/index.spec.ts +27 -0
  97. package/lib/xlsx/index.ts +32 -0
  98. package/package.json +45 -31
  99. package/tsconfig.json +28 -0
  100. package/typedoc-ignore-links.ts +17 -0
  101. package/typedoc.json +41 -0
  102. package/.eslintrc +0 -22
  103. package/benchmark/benchmark.js +0 -48
  104. package/benchmark/formulas.json +0 -15677
  105. package/dist/fx.d.ts +0 -823
  106. package/dist/fx.js +0 -2
  107. package/dist/package.json +0 -1
  108. package/lib/a1.js +0 -348
  109. package/lib/a1.spec.js +0 -458
  110. package/lib/addTokenMeta.spec.js +0 -153
  111. package/lib/astTypes.js +0 -96
  112. package/lib/extraTypes.js +0 -74
  113. package/lib/fixRanges.js +0 -104
  114. package/lib/fixRanges.spec.js +0 -171
  115. package/lib/fromCol.spec.js +0 -11
  116. package/lib/index.js +0 -134
  117. package/lib/index.spec.js +0 -67
  118. package/lib/isType.spec.js +0 -168
  119. package/lib/lexer-srefs.spec.js +0 -324
  120. package/lib/lexer.js +0 -264
  121. package/lib/lexer.spec.js +0 -1953
  122. package/lib/lexers/lexRange.js +0 -8
  123. package/lib/lexers/sets.js +0 -38
  124. package/lib/mergeRefTokens.spec.js +0 -121
  125. package/lib/package.json +0 -1
  126. package/lib/parseRef.js +0 -157
  127. package/lib/parseRef.spec.js +0 -71
  128. package/lib/parseStructRef.js +0 -48
  129. package/lib/parseStructRef.spec.js +0 -164
  130. package/lib/parser.spec.js +0 -1208
  131. package/lib/rc.js +0 -341
  132. package/lib/rc.spec.js +0 -403
  133. package/lib/stringifyStructRef.js +0 -80
  134. package/lib/stringifyStructRef.spec.js +0 -182
  135. package/lib/toCol.spec.js +0 -11
  136. package/lib/translate-toA1.spec.js +0 -214
  137. package/lib/translate-toRC.spec.js +0 -197
  138. package/lib/translate.js +0 -239
  139. package/lib/translate.spec.js +0 -21
  140. package/rollup.config.mjs +0 -22
  141. 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
-
@@ -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
- });
@@ -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
-