@borgar/fx 4.5.0 → 4.6.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/.eslintrc +3 -12
- package/dist/fx.d.ts +147 -34
- package/docs/API.md +248 -121
- package/lib/a1.js +14 -14
- package/lib/addTokenMeta.js +6 -6
- package/lib/extraTypes.js +73 -0
- package/lib/fixRanges.js +8 -8
- package/lib/isType.js +16 -16
- package/lib/lexer.js +2 -2
- package/lib/mergeRefTokens.js +2 -2
- package/lib/parser.js +8 -8
- package/lib/rc.js +10 -10
- package/lib/sr.js +22 -22
- package/lib/translate.js +10 -10
- package/package.json +5 -4
package/lib/a1.js
CHANGED
|
@@ -16,7 +16,7 @@ const charFrom = String.fromCharCode;
|
|
|
16
16
|
* return garbage.
|
|
17
17
|
*
|
|
18
18
|
* @param {string} columnString The column string identifier
|
|
19
|
-
* @
|
|
19
|
+
* @returns {number} Zero based column index number
|
|
20
20
|
*/
|
|
21
21
|
export function fromCol (columnString) {
|
|
22
22
|
const x = (columnString || '');
|
|
@@ -48,7 +48,7 @@ export function fromCol (columnString) {
|
|
|
48
48
|
* return garbage.
|
|
49
49
|
*
|
|
50
50
|
* @param {number} columnIndex Zero based column index number
|
|
51
|
-
* @
|
|
51
|
+
* @returns {string} The column string identifier
|
|
52
52
|
*/
|
|
53
53
|
export function toCol (columnIndex) {
|
|
54
54
|
return (
|
|
@@ -85,8 +85,8 @@ export function toAbsolute (range) {
|
|
|
85
85
|
*
|
|
86
86
|
* @private
|
|
87
87
|
* @see parseA1Ref
|
|
88
|
-
* @param {
|
|
89
|
-
* @
|
|
88
|
+
* @param {RangeA1} range A range object
|
|
89
|
+
* @returns {string} An A1-style string represenation of a range
|
|
90
90
|
*/
|
|
91
91
|
export function toA1 (range) {
|
|
92
92
|
let { top, left, bottom, right } = range;
|
|
@@ -163,9 +163,9 @@ function splitA1 (str) {
|
|
|
163
163
|
* @private
|
|
164
164
|
* @see parseA1Ref
|
|
165
165
|
* @param {string} rangeString A range string
|
|
166
|
-
* @
|
|
166
|
+
* @returns {(RangeA1|null)} An object representing a valid range or null if it is invalid.
|
|
167
167
|
*/
|
|
168
|
-
export function fromA1 (
|
|
168
|
+
export function fromA1 (rangeString) {
|
|
169
169
|
let top = null;
|
|
170
170
|
let left = null;
|
|
171
171
|
let bottom = null;
|
|
@@ -174,7 +174,7 @@ export function fromA1 (rangeStr) {
|
|
|
174
174
|
let $left = false;
|
|
175
175
|
let $bottom = false;
|
|
176
176
|
let $right = false;
|
|
177
|
-
const [ part1, part2, part3 ] =
|
|
177
|
+
const [ part1, part2, part3 ] = rangeString.split(':');
|
|
178
178
|
if (part3) {
|
|
179
179
|
return null;
|
|
180
180
|
}
|
|
@@ -250,11 +250,11 @@ export function fromA1 (rangeStr) {
|
|
|
250
250
|
* syntax does not specify:
|
|
251
251
|
*
|
|
252
252
|
* @param {string} refString An A1-style reference string
|
|
253
|
-
* @param {
|
|
253
|
+
* @param {object} [options={}] Options
|
|
254
254
|
* @param {boolean} [options.allowNamed=true] Enable parsing names as well as ranges.
|
|
255
255
|
* @param {boolean} [options.allowTernary=false] Enables the recognition of ternary ranges in the style of `A1:A` or `A1:1`. These are supported by Google Sheets but not Excel. See: References.md.
|
|
256
256
|
* @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)
|
|
257
|
-
* @
|
|
257
|
+
* @returns {(ReferenceA1|null)} An object representing a valid reference or null if it is invalid.
|
|
258
258
|
*/
|
|
259
259
|
export function parseA1Ref (refString, { allowNamed = true, allowTernary = false, xlsx = false } = {}) {
|
|
260
260
|
const d = parseRef(refString, { allowNamed, allowTernary, xlsx, r1c1: false });
|
|
@@ -296,10 +296,10 @@ export function parseA1Ref (refString, { allowNamed = true, allowTernary = false
|
|
|
296
296
|
* // => 'Sheet1!A$1:$B2'
|
|
297
297
|
* ```
|
|
298
298
|
*
|
|
299
|
-
* @param {
|
|
300
|
-
* @param {
|
|
299
|
+
* @param {ReferenceA1} refObject A reference object
|
|
300
|
+
* @param {object} [options={}] Options
|
|
301
301
|
* @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)
|
|
302
|
-
* @
|
|
302
|
+
* @returns {string} The reference in A1-style string format
|
|
303
303
|
*/
|
|
304
304
|
export function stringifyA1Ref (refObject, { xlsx = false } = {}) {
|
|
305
305
|
const prefix = xlsx
|
|
@@ -341,8 +341,8 @@ export function stringifyA1Ref (refObject, { xlsx = false } = {}) {
|
|
|
341
341
|
* // }
|
|
342
342
|
* ```
|
|
343
343
|
*
|
|
344
|
-
* @param {
|
|
345
|
-
* @
|
|
344
|
+
* @param {RangeA1} range The range part of a reference object.
|
|
345
|
+
* @returns {RangeA1} same range with missing bounds filled in.
|
|
346
346
|
*/
|
|
347
347
|
export function addA1RangeBounds (range) {
|
|
348
348
|
if (range.top == null) {
|
package/lib/addTokenMeta.js
CHANGED
|
@@ -121,13 +121,13 @@ function addContext (ref, sheetName, workbookName) {
|
|
|
121
121
|
*
|
|
122
122
|
* All will be tagged with `.error` (boolean `true`).
|
|
123
123
|
*
|
|
124
|
-
* @param {Array<
|
|
125
|
-
* @param {
|
|
124
|
+
* @param {Array<Token>} tokenlist An array of tokens (from `tokenize()`)
|
|
125
|
+
* @param {object} [context={}] A contest used to match `A1` to `Sheet1!A1`.
|
|
126
126
|
* @param {string} [context.sheetName=''] An implied sheet name ('Sheet1')
|
|
127
127
|
* @param {string} [context.workbookName=''] An implied workbook name ('report.xlsx')
|
|
128
|
-
* @
|
|
128
|
+
* @returns {Array<TokenEnhanced>} The input array with the enchanced tokens
|
|
129
129
|
*/
|
|
130
|
-
export function addTokenMeta (
|
|
130
|
+
export function addTokenMeta (tokenlist, { sheetName = '', workbookName = '' } = {}) {
|
|
131
131
|
const parenStack = [];
|
|
132
132
|
let arrayStart = null;
|
|
133
133
|
const uid = getIDer();
|
|
@@ -135,7 +135,7 @@ export function addTokenMeta (tokens, { sheetName = '', workbookName = '' } = {}
|
|
|
135
135
|
|
|
136
136
|
const getCurrDepth = () => parenStack.length + (arrayStart ? 1 : 0);
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
tokenlist.forEach((token, i) => {
|
|
139
139
|
token.index = i;
|
|
140
140
|
token.depth = getCurrDepth();
|
|
141
141
|
if (token.value === '(') {
|
|
@@ -202,5 +202,5 @@ export function addTokenMeta (tokens, { sheetName = '', workbookName = '' } = {}
|
|
|
202
202
|
token.error = true;
|
|
203
203
|
}
|
|
204
204
|
});
|
|
205
|
-
return
|
|
205
|
+
return tokenlist;
|
|
206
206
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @typedef {Record<string, any>} ReferenceA1
|
|
45
|
+
* A reference containing an A1 style range. See [Prefixes.md] for
|
|
46
|
+
* documentation on how scopes work in Fx.
|
|
47
|
+
* @property {Array<string>} [context] A collection of scopes for the reference
|
|
48
|
+
* @property {string} [workbookName] A context workbook scope
|
|
49
|
+
* @property {string} [sheetName] A context sheet scope
|
|
50
|
+
* @property {RangeA1} [range] The reference's range
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @typedef {Record<string, any>} ReferenceR1C1
|
|
55
|
+
* A reference containing a R1C1 style range. See [Prefixes.md] for
|
|
56
|
+
* documentation on how scopes work in Fx.
|
|
57
|
+
* @property {Array<string>} [context] A collection of scopes for the reference
|
|
58
|
+
* @property {string} [workbookName] A context workbook scope
|
|
59
|
+
* @property {string} [sheetName] A context sheet scope
|
|
60
|
+
* @property {RangeR1C1} [range] The reference's range
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @typedef {Record<string, any>} ReferenceStruct
|
|
65
|
+
* A reference containing a table slice definition. See [Prefixes.md] for
|
|
66
|
+
* documentation on how scopes work in Fx.
|
|
67
|
+
* @property {Array<string>} [context] A collection of scopes for the reference
|
|
68
|
+
* @property {string} [workbookName] A context workbook scope
|
|
69
|
+
* @property {string} [sheetName] A context sheet scope
|
|
70
|
+
* @property {Array<string>} [sections] The sections this reference targets
|
|
71
|
+
* @property {Array<string>} [columns] The sections this reference targets
|
|
72
|
+
* @property {string} [table] The table this reference targets
|
|
73
|
+
*/
|
package/lib/fixRanges.js
CHANGED
|
@@ -40,19 +40,19 @@ import { REF_STRUCT } from './constants.js';
|
|
|
40
40
|
* Returns the same formula with the ranges updated. If an array of tokens was
|
|
41
41
|
* supplied, then a new array is returned.
|
|
42
42
|
*
|
|
43
|
-
* @param {(string | Array<
|
|
44
|
-
* @param {
|
|
43
|
+
* @param {(string | Array<Token>)} formula A string (an Excel formula) or a token list that should be adjusted.
|
|
44
|
+
* @param {object} [options={}] Options
|
|
45
45
|
* @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.
|
|
46
46
|
* @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)
|
|
47
|
-
* @
|
|
47
|
+
* @returns {(string | Array<Token>)} A formula string or token list (depending on which was input)
|
|
48
48
|
*/
|
|
49
|
-
export function fixRanges (
|
|
50
|
-
if (typeof
|
|
51
|
-
return fixRanges(tokenize(
|
|
49
|
+
export function fixRanges (formula, options = { addBounds: false }) {
|
|
50
|
+
if (typeof formula === 'string') {
|
|
51
|
+
return fixRanges(tokenize(formula, options), options)
|
|
52
52
|
.map(d => d.value)
|
|
53
53
|
.join('');
|
|
54
54
|
}
|
|
55
|
-
if (!Array.isArray(
|
|
55
|
+
if (!Array.isArray(formula)) {
|
|
56
56
|
throw new Error('fixRanges expects an array of tokens');
|
|
57
57
|
}
|
|
58
58
|
const { addBounds, r1c1, xlsx } = options;
|
|
@@ -60,7 +60,7 @@ export function fixRanges (tokens, options = { addBounds: false }) {
|
|
|
60
60
|
throw new Error('fixRanges does not have an R1C1 mode');
|
|
61
61
|
}
|
|
62
62
|
let offsetSkew = 0;
|
|
63
|
-
return
|
|
63
|
+
return formula.map(t => {
|
|
64
64
|
const token = { ...t };
|
|
65
65
|
if (t.loc) {
|
|
66
66
|
token.loc = [ ...t.loc ];
|
package/lib/isType.js
CHANGED
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
* (`A1` or `A1:B2`), REF_TERNARY (`A1:A`, `A1:1`, `1:A1`, or `A:A1`), or
|
|
13
13
|
* REF_BEAM (`A:A` or `1:1`). In all other cases `false` is returned.
|
|
14
14
|
*
|
|
15
|
-
* @param {
|
|
16
|
-
* @
|
|
15
|
+
* @param {any} token A token
|
|
16
|
+
* @returns {boolean} True if the specified token is range, False otherwise.
|
|
17
17
|
*/
|
|
18
18
|
export function isRange (token) {
|
|
19
19
|
return !!token && (
|
|
@@ -30,8 +30,8 @@ export function isRange (token) {
|
|
|
30
30
|
* REF_TERNARY (`A1:A`, `A1:1`, `1:A1`, or `A:A1`), REF_BEAM (`A:A` or `1:1`),
|
|
31
31
|
* or REF_NAMED (`myrange`). In all other cases `false` is returned.
|
|
32
32
|
*
|
|
33
|
-
* @param {
|
|
34
|
-
* @
|
|
33
|
+
* @param {any} token The token
|
|
34
|
+
* @returns {boolean} True if the specified token is reference, False otherwise.
|
|
35
35
|
*/
|
|
36
36
|
export function isReference (token) {
|
|
37
37
|
return !!token && (
|
|
@@ -50,8 +50,8 @@ export function isReference (token) {
|
|
|
50
50
|
* ERROR (`#VALUE!`), NUMBER (123.4), or STRING (`"lorem ipsum"`). In all other
|
|
51
51
|
* cases `false` is returned.
|
|
52
52
|
*
|
|
53
|
-
* @param {
|
|
54
|
-
* @
|
|
53
|
+
* @param {any} token The token
|
|
54
|
+
* @returns {boolean} True if the specified token is literal, False otherwise.
|
|
55
55
|
*/
|
|
56
56
|
export function isLiteral (token) {
|
|
57
57
|
return !!token && (
|
|
@@ -68,8 +68,8 @@ export function isLiteral (token) {
|
|
|
68
68
|
* Returns `true` if the input is a token of type ERROR (`#VALUE!`). In all
|
|
69
69
|
* other cases `false` is returned.
|
|
70
70
|
*
|
|
71
|
-
* @param {
|
|
72
|
-
* @
|
|
71
|
+
* @param {any} token The token
|
|
72
|
+
* @returns {boolean} True if the specified token is error, False otherwise.
|
|
73
73
|
*/
|
|
74
74
|
export function isError (token) {
|
|
75
75
|
return !!token && token.type === ERROR;
|
|
@@ -81,8 +81,8 @@ export function isError (token) {
|
|
|
81
81
|
* Returns `true` if the input is a token of type WHITESPACE (` `) or
|
|
82
82
|
* NEWLINE (`\n`). In all other cases `false` is returned.
|
|
83
83
|
*
|
|
84
|
-
* @param {
|
|
85
|
-
* @
|
|
84
|
+
* @param {any} token The token
|
|
85
|
+
* @returns {boolean} True if the specified token is whitespace, False otherwise.
|
|
86
86
|
*/
|
|
87
87
|
export function isWhitespace (token) {
|
|
88
88
|
return !!token && (
|
|
@@ -97,8 +97,8 @@ export function isWhitespace (token) {
|
|
|
97
97
|
* Returns `true` if the input is a token of type FUNCTION.
|
|
98
98
|
* In all other cases `false` is returned.
|
|
99
99
|
*
|
|
100
|
-
* @param {
|
|
101
|
-
* @
|
|
100
|
+
* @param {any} token The token
|
|
101
|
+
* @returns {boolean} True if the specified token is function, False otherwise.
|
|
102
102
|
*/
|
|
103
103
|
export function isFunction (token) {
|
|
104
104
|
return !!token && token.type === FUNCTION;
|
|
@@ -108,8 +108,8 @@ export function isFunction (token) {
|
|
|
108
108
|
* Returns `true` if the input is a token of type FX_PREFIX (leading `=` in
|
|
109
109
|
* formula). In all other cases `false` is returned.
|
|
110
110
|
*
|
|
111
|
-
* @param {
|
|
112
|
-
* @
|
|
111
|
+
* @param {any} token The token
|
|
112
|
+
* @returns {boolean} True if the specified token is effects prefix, False otherwise.
|
|
113
113
|
*/
|
|
114
114
|
export function isFxPrefix (token) {
|
|
115
115
|
return !!token && token.type === FX_PREFIX;
|
|
@@ -121,8 +121,8 @@ export function isFxPrefix (token) {
|
|
|
121
121
|
* Returns `true` if the input is a token of type OPERATOR (`+` or `:`). In all
|
|
122
122
|
* other cases `false` is returned.
|
|
123
123
|
*
|
|
124
|
-
* @param {
|
|
125
|
-
* @
|
|
124
|
+
* @param {any} token The token
|
|
125
|
+
* @returns {boolean} True if the specified token is operator, False otherwise.
|
|
126
126
|
*/
|
|
127
127
|
export function isOperator (token) {
|
|
128
128
|
return !!token && token.type === OPERATOR;
|
package/lib/lexer.js
CHANGED
|
@@ -196,14 +196,14 @@ export function getTokens (fx, tokenHandlers, options = {}) {
|
|
|
196
196
|
*
|
|
197
197
|
* @see tokenTypes
|
|
198
198
|
* @param {string} formula An Excel formula string (an Excel expression) or an array of tokens.
|
|
199
|
-
* @param {
|
|
199
|
+
* @param {object} [options={}] Options
|
|
200
200
|
* @param {boolean} [options.allowTernary=false] Enables the recognition of ternary ranges in the style of `A1:A` or `A1:1`. These are supported by Google Sheets but not Excel. See: References.md.
|
|
201
201
|
* @param {boolean} [options.negativeNumbers=true] Merges unary minuses with their immediately following number tokens (`-`,`1`) => `-1` (alternatively these will be unary operations in the tree).
|
|
202
202
|
* @param {boolean} [options.r1c1=false] Ranges are expected to be in the R1C1 style format rather than the more popular A1 style.
|
|
203
203
|
* @param {boolean} [options.withLocation=true] Nodes will include source position offsets to the tokens: `{ loc: [ start, end ] }`
|
|
204
204
|
* @param {boolean} [options.mergeRefs=true] Should ranges be returned as whole references (`Sheet1!A1:B2`) or as separate tokens for each part: (`Sheet1`,`!`,`A1`,`:`,`B2`). This is the same as calling [`mergeRefTokens`](#mergeRefTokens)
|
|
205
205
|
* @param {boolean} [options.xlsx=false] Enables a `[1]Sheet1!A1` or `[1]!name` syntax form for external workbooks found only in XLSX files.
|
|
206
|
-
* @
|
|
206
|
+
* @returns {Array<Token>} An AST of nodes
|
|
207
207
|
*/
|
|
208
208
|
export function tokenize (formula, options = {}) {
|
|
209
209
|
return getTokens(formula, lexers, options);
|
package/lib/mergeRefTokens.js
CHANGED
|
@@ -63,8 +63,8 @@ const matcher = (tokens, currNode, anchorIndex, index = 0) => {
|
|
|
63
63
|
* as whole references (`Sheet1!A1:B2`) rather than separate tokens for each
|
|
64
64
|
* part: (`Sheet1`,`!`,`A1`,`:`,`B2`).
|
|
65
65
|
*
|
|
66
|
-
* @param {Array<
|
|
67
|
-
* @
|
|
66
|
+
* @param {Array<Token>} tokenlist An array of tokens (from `tokenize()`)
|
|
67
|
+
* @returns {Array<Token>} A new list of tokens with range parts merged.
|
|
68
68
|
*/
|
|
69
69
|
export function mergeRefTokens (tokenlist) {
|
|
70
70
|
const finalTokens = [];
|
package/lib/parser.js
CHANGED
|
@@ -478,8 +478,8 @@ prefix('{', function () {
|
|
|
478
478
|
* [AST_format.md](./AST_format.md)
|
|
479
479
|
*
|
|
480
480
|
* @see nodeTypes
|
|
481
|
-
* @param {(string | Array<
|
|
482
|
-
* @param {
|
|
481
|
+
* @param {(string | Array<Token>)} formula An Excel formula string (an Excel expression) or an array of tokens.
|
|
482
|
+
* @param {object} [options={}] Options
|
|
483
483
|
* @param {boolean} [options.allowNamed=true] Enable parsing names as well as ranges.
|
|
484
484
|
* @param {boolean} [options.allowTernary=false] Enables the recognition of ternary ranges in the style of `A1:A` or `A1:1`. These are supported by Google Sheets but not Excel. See: References.md.
|
|
485
485
|
* @param {boolean} [options.negativeNumbers=true] Merges unary minuses with their immediately following number tokens (`-`,`1`) => `-1` (alternatively these will be unary operations in the tree).
|
|
@@ -488,18 +488,18 @@ prefix('{', function () {
|
|
|
488
488
|
* @param {boolean} [options.r1c1=false] Ranges are expected to be in the R1C1 style format rather than the more popular A1 style.
|
|
489
489
|
* @param {boolean} [options.withLocation=false] Nodes will include source position offsets to the tokens: `{ loc: [ start, end ] }`
|
|
490
490
|
* @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)
|
|
491
|
-
* @
|
|
491
|
+
* @returns {object} An AST of nodes
|
|
492
492
|
*/
|
|
493
|
-
export function parse (
|
|
494
|
-
if (typeof
|
|
495
|
-
tokens = tokenize(
|
|
493
|
+
export function parse (formula, options) {
|
|
494
|
+
if (typeof formula === 'string') {
|
|
495
|
+
tokens = tokenize(formula, {
|
|
496
496
|
withLocation: false,
|
|
497
497
|
...options,
|
|
498
498
|
mergeRefs: true
|
|
499
499
|
});
|
|
500
500
|
}
|
|
501
|
-
else if (Array.isArray(
|
|
502
|
-
tokens =
|
|
501
|
+
else if (Array.isArray(formula)) {
|
|
502
|
+
tokens = formula;
|
|
503
503
|
}
|
|
504
504
|
else {
|
|
505
505
|
throw new Error('Parse requires a string or array of tokens.');
|
package/lib/rc.js
CHANGED
|
@@ -24,8 +24,8 @@ function toCoord (value, isAbs) {
|
|
|
24
24
|
*
|
|
25
25
|
* @private
|
|
26
26
|
* @see parseR1C1Ref
|
|
27
|
-
* @param {
|
|
28
|
-
* @
|
|
27
|
+
* @param {RangeR1C1} range A range object
|
|
28
|
+
* @returns {string} An R1C1-style string represenation of a range
|
|
29
29
|
*/
|
|
30
30
|
export function toR1C1 (range) {
|
|
31
31
|
let { r0, c0, r1, c1 } = range;
|
|
@@ -134,11 +134,11 @@ function parseR1C1Part (ref) {
|
|
|
134
134
|
* @private
|
|
135
135
|
* @see parseA1Ref
|
|
136
136
|
* @param {string} rangeString A range string
|
|
137
|
-
* @
|
|
137
|
+
* @returns {(RangeR1C1|null)} An object representing a valid reference or null if it is invalid.
|
|
138
138
|
*/
|
|
139
|
-
export function fromR1C1 (
|
|
139
|
+
export function fromR1C1 (rangeString) {
|
|
140
140
|
let final = null;
|
|
141
|
-
const [ part1, part2 ] =
|
|
141
|
+
const [ part1, part2 ] = rangeString.split(':', 2);
|
|
142
142
|
const range = parseR1C1Part(part1);
|
|
143
143
|
if (range) {
|
|
144
144
|
const [ r0, c0, $r0, $c0 ] = range;
|
|
@@ -267,11 +267,11 @@ export function fromR1C1 (ref) {
|
|
|
267
267
|
* ```
|
|
268
268
|
*
|
|
269
269
|
* @param {string} refString An R1C1-style reference string
|
|
270
|
-
* @param {
|
|
270
|
+
* @param {object} [options={}] Options
|
|
271
271
|
* @param {boolean} [options.allowNamed=true] Enable parsing names as well as ranges.
|
|
272
272
|
* @param {boolean} [options.allowTernary=false] Enables the recognition of ternary ranges in the style of `A1:A` or `A1:1`. These are supported by Google Sheets but not Excel. See: References.md.
|
|
273
273
|
* @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)
|
|
274
|
-
* @
|
|
274
|
+
* @returns {(ReferenceR1C1|null)} An object representing a valid reference or null if it is invalid.
|
|
275
275
|
*/
|
|
276
276
|
export function parseR1C1Ref (refString, { allowNamed = true, allowTernary = false, xlsx = false } = {}) {
|
|
277
277
|
const d = parseRef(refString, { allowNamed, allowTernary, xlsx, r1c1: true });
|
|
@@ -312,10 +312,10 @@ export function parseR1C1Ref (refString, { allowNamed = true, allowTernary = fal
|
|
|
312
312
|
* // => 'Sheet1!R[9]C9:R[9]C9'
|
|
313
313
|
* ```
|
|
314
314
|
*
|
|
315
|
-
* @param {
|
|
316
|
-
* @param {
|
|
315
|
+
* @param {ReferenceR1C1} refObject A reference object
|
|
316
|
+
* @param {object} [options={}] Options
|
|
317
317
|
* @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)
|
|
318
|
-
* @
|
|
318
|
+
* @returns {string} The reference in R1C1-style string format
|
|
319
319
|
*/
|
|
320
320
|
export function stringifyR1C1Ref (refObject, { xlsx = false } = {}) {
|
|
321
321
|
const prefix = xlsx
|
package/lib/sr.js
CHANGED
|
@@ -185,16 +185,16 @@ export function parseSRange (raw) {
|
|
|
185
185
|
*
|
|
186
186
|
* @tutorial References.md
|
|
187
187
|
* @param {string} ref A structured reference string
|
|
188
|
-
* @param {
|
|
188
|
+
* @param {object} [options={}] Options
|
|
189
189
|
* @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)
|
|
190
|
-
* @
|
|
190
|
+
* @returns {(ReferenceStruct|null)} An object representing a valid reference or null if it is invalid.
|
|
191
191
|
*/
|
|
192
|
-
export function parseStructRef (ref,
|
|
193
|
-
const r = parseRef(ref,
|
|
192
|
+
export function parseStructRef (ref, options = { xlsx: false }) {
|
|
193
|
+
const r = parseRef(ref, options);
|
|
194
194
|
if (r && r.struct) {
|
|
195
195
|
const structData = parseSRange(r.struct);
|
|
196
196
|
if (structData && structData.length === r.struct.length) {
|
|
197
|
-
return
|
|
197
|
+
return options.xlsx
|
|
198
198
|
? {
|
|
199
199
|
workbookName: r.workbookName,
|
|
200
200
|
sheetName: r.sheetName,
|
|
@@ -238,38 +238,38 @@ function toSentenceCase (str) {
|
|
|
238
238
|
* // => 'workbook.xlsx!tableName[[#Data],[Column1]:[Column2]]'
|
|
239
239
|
* ```
|
|
240
240
|
*
|
|
241
|
-
* @param {
|
|
242
|
-
* @param {
|
|
241
|
+
* @param {ReferenceStruct} refObject A structured reference object
|
|
242
|
+
* @param {object} [options={}] Options
|
|
243
243
|
* @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)
|
|
244
|
-
* @
|
|
244
|
+
* @returns {string} The structured reference in string format
|
|
245
245
|
*/
|
|
246
|
-
export function stringifyStructRef (
|
|
246
|
+
export function stringifyStructRef (refObject, { xlsx = false } = {}) {
|
|
247
247
|
let s = xlsx
|
|
248
|
-
? stringifyPrefixAlt(
|
|
249
|
-
: stringifyPrefix(
|
|
248
|
+
? stringifyPrefixAlt(refObject)
|
|
249
|
+
: stringifyPrefix(refObject);
|
|
250
250
|
|
|
251
|
-
if (
|
|
252
|
-
s +=
|
|
251
|
+
if (refObject.table) {
|
|
252
|
+
s += refObject.table;
|
|
253
253
|
}
|
|
254
|
-
const numColumns =
|
|
255
|
-
const numSections =
|
|
254
|
+
const numColumns = refObject.columns?.length ?? 0;
|
|
255
|
+
const numSections = refObject.sections?.length ?? 0;
|
|
256
256
|
// single section
|
|
257
257
|
if (numSections === 1 && !numColumns) {
|
|
258
|
-
s += `[#${toSentenceCase(
|
|
258
|
+
s += `[#${toSentenceCase(refObject.sections[0])}]`;
|
|
259
259
|
}
|
|
260
260
|
// single column
|
|
261
261
|
else if (!numSections && numColumns === 1) {
|
|
262
|
-
s += `[${quoteColname(
|
|
262
|
+
s += `[${quoteColname(refObject.columns[0])}]`;
|
|
263
263
|
}
|
|
264
264
|
else {
|
|
265
265
|
s += '[';
|
|
266
266
|
// single [#this row] sections get normalized to an @
|
|
267
|
-
const singleAt = numSections === 1 &&
|
|
267
|
+
const singleAt = numSections === 1 && refObject.sections[0].toLowerCase() === 'this row';
|
|
268
268
|
if (singleAt) {
|
|
269
269
|
s += '@';
|
|
270
270
|
}
|
|
271
271
|
else if (numSections) {
|
|
272
|
-
s +=
|
|
272
|
+
s += refObject.sections
|
|
273
273
|
.map(d => `[#${toSentenceCase(d)}]`)
|
|
274
274
|
.join(',');
|
|
275
275
|
if (numColumns) {
|
|
@@ -277,11 +277,11 @@ export function stringifyStructRef (ref, { xlsx = false } = {}) {
|
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
279
|
// a case of a single alphanumberic column with a [#this row] becomes [@col]
|
|
280
|
-
if (singleAt &&
|
|
281
|
-
s += quoteColname(
|
|
280
|
+
if (singleAt && refObject.columns.length === 1 && !needsBraces(refObject.columns[0])) {
|
|
281
|
+
s += quoteColname(refObject.columns[0]);
|
|
282
282
|
}
|
|
283
283
|
else if (numColumns) {
|
|
284
|
-
s +=
|
|
284
|
+
s += refObject.columns.slice(0, 2)
|
|
285
285
|
.map(d => (`[${quoteColname(d)}]`))
|
|
286
286
|
.join(':');
|
|
287
287
|
}
|
package/lib/translate.js
CHANGED
|
@@ -30,20 +30,20 @@ const settings = {
|
|
|
30
30
|
* // => "=SUM(RC[1],R2C5,Sheet!R3C5)");
|
|
31
31
|
* ```
|
|
32
32
|
*
|
|
33
|
-
* @param {(string | Array<
|
|
33
|
+
* @param {(string | Array<Token>)} formula A string (an Excel formula) or a token list that should be adjusted.
|
|
34
34
|
* @param {string} anchorCell A simple string reference to an A1 cell ID (`AF123` or`$C$5`).
|
|
35
|
-
* @param {
|
|
35
|
+
* @param {object} [options={}] The options
|
|
36
36
|
* @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)
|
|
37
37
|
* @param {boolean} [options.allowTernary=true] Enables the recognition of ternary ranges in the style of `A1:A` or `A1:1`. These are supported by Google Sheets but not Excel. See: References.md.
|
|
38
|
-
* @
|
|
38
|
+
* @returns {(string | Array<Token>)} A formula string or token list (depending on which was input)
|
|
39
39
|
*/
|
|
40
|
-
export function translateToR1C1 (
|
|
40
|
+
export function translateToR1C1 (formula, anchorCell, { xlsx = false, allowTernary = true } = {}) {
|
|
41
41
|
const { top, left } = fromA1(anchorCell);
|
|
42
|
-
const isString = typeof
|
|
42
|
+
const isString = typeof formula === 'string';
|
|
43
43
|
|
|
44
44
|
const tokens = isString
|
|
45
|
-
? tokenize(
|
|
46
|
-
:
|
|
45
|
+
? tokenize(formula, { ...settings, xlsx, allowTernary })
|
|
46
|
+
: formula;
|
|
47
47
|
|
|
48
48
|
let offsetSkew = 0;
|
|
49
49
|
const refOpts = { xlsx, allowTernary };
|
|
@@ -144,14 +144,14 @@ const defaultOptions = {
|
|
|
144
144
|
* `=Sheet3!#REF!:F3`. These are valid formulas in the Excel formula language
|
|
145
145
|
* and Excel will accept them, but they are not supported in Google Sheets.
|
|
146
146
|
*
|
|
147
|
-
* @param {(string | Array<
|
|
147
|
+
* @param {(string | Array<Token>)} formula A string (an Excel formula) or a token list that should be adjusted.
|
|
148
148
|
* @param {string} anchorCell A simple string reference to an A1 cell ID (`AF123` or`$C$5`).
|
|
149
|
-
* @param {
|
|
149
|
+
* @param {object} [options={}] The options
|
|
150
150
|
* @param {boolean} [options.wrapEdges=true] Wrap out-of-bounds ranges around sheet edges rather than turning them to #REF! errors
|
|
151
151
|
* @param {boolean} [options.mergeRefs=true] Should ranges be treated as whole references (`Sheet1!A1:B2`) or as separate tokens for each part: (`Sheet1`,`!`,`A1`,`:`,`B2`).
|
|
152
152
|
* @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)
|
|
153
153
|
* @param {boolean} [options.allowTernary=true] Enables the recognition of ternary ranges in the style of `A1:A` or `A1:1`. These are supported by Google Sheets but not Excel. See: References.md.
|
|
154
|
-
* @
|
|
154
|
+
* @returns {(string | Array<Token>)} A formula string or token list (depending on which was input)
|
|
155
155
|
*/
|
|
156
156
|
export function translateToA1 (formula, anchorCell, options = defaultOptions) {
|
|
157
157
|
const anchor = fromA1(anchorCell);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@borgar/fx",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.0",
|
|
4
4
|
"description": "Utilities for working with Excel formulas",
|
|
5
5
|
"main": "dist/fx.js",
|
|
6
6
|
"types": "dist/fx.d.ts",
|
|
@@ -45,15 +45,16 @@
|
|
|
45
45
|
"@babel/eslint-parser": "~7.22.15",
|
|
46
46
|
"@babel/preset-env": "~7.22.20",
|
|
47
47
|
"@borgar/eslint-config": "~3.1.0",
|
|
48
|
-
"@borgar/jsdoc-tsmd": "~0.
|
|
48
|
+
"@borgar/jsdoc-tsmd": "~0.2.0",
|
|
49
49
|
"@rollup/plugin-babel": "~6.0.3",
|
|
50
50
|
"babel-eslint": "~10.1.0",
|
|
51
51
|
"eslint": "~8.50.0",
|
|
52
|
+
"eslint-plugin-jsdoc": "~46.8.2",
|
|
52
53
|
"jsdoc": "~4.0.2",
|
|
53
54
|
"rollup": "~3.29.4",
|
|
54
55
|
"rollup-plugin-minification": "~0.2.0",
|
|
55
56
|
"tap-min": "~3.0.0",
|
|
56
|
-
"
|
|
57
|
-
"
|
|
57
|
+
"tape": "~5.7.0",
|
|
58
|
+
"typescript": "~5.2.2"
|
|
58
59
|
}
|
|
59
60
|
}
|