@borgar/fx 4.5.0 → 4.7.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/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
- * @return {number} Zero based column index number
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
- * @return {string} The column string identifier
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 {Object} range A range object
89
- * @return {string} An A1-style string represenation of a range
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
- * @return {(Object|null)} An object representing a valid reference or null if it is invalid.
166
+ * @returns {(RangeA1|null)} An object representing a valid range or null if it is invalid.
167
167
  */
168
- export function fromA1 (rangeStr) {
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 ] = rangeStr.split(':');
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 {Object} [options={}] Options
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
- * @return {(Object|null)} An object representing a valid reference or null if it is invalid.
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 {Object} refObject A reference object
300
- * @param {Object} [options={}] Options
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
- * @return {Object} The reference in A1-style string format
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 {Object} range The range part of a reference object.
345
- * @return {Object} same range with missing bounds filled in.
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) {
@@ -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<Object>} tokenlist An array of tokens (from `tokenize()`)
125
- * @param {Object} [context={}] A contest used to match `A1` to `Sheet1!A1`.
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
- * @return {Array<Object>} The input array with the enchanced tokens
128
+ * @returns {Array<TokenEnhanced>} The input array with the enchanced tokens
129
129
  */
130
- export function addTokenMeta (tokens, { sheetName = '', workbookName = '' } = {}) {
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
- tokens.forEach((token, i) => {
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 tokens;
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<Object>)} formula A string (an Excel formula) or a token list that should be adjusted.
44
- * @param {Object} [options={}] Options
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
- * @return {(string | Array<Object>)} A formula string or token list (depending on which was input)
47
+ * @returns {(string | Array<Token>)} A formula string or token list (depending on which was input)
48
48
  */
49
- export function fixRanges (tokens, options = { addBounds: false }) {
50
- if (typeof tokens === 'string') {
51
- return fixRanges(tokenize(tokens, options), options)
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(tokens)) {
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 tokens.map(t => {
63
+ return formula.map(t => {
64
64
  const token = { ...t };
65
65
  if (t.loc) {
66
66
  token.loc = [ ...t.loc ];
@@ -135,7 +135,15 @@ test('fixRanges structured references', t => {
135
135
  t.isFixed('[[#all],[#all],[#all],[#all],[ColumnName]]', '[[#All],[ColumnName]]');
136
136
  t.isFixed('[@[foo]:bar]', '[@[foo]:[bar]]');
137
137
  t.isFixed('[@foo bar]', '[@[foo bar]]');
138
- t.isFixed('[ @foo bar ]', '[@[foo bar]]');
138
+ // Care must be taken with spaces in column headers.
139
+ // Excel considers refs only valid if they match the column name
140
+ // but the parser does not know the names, so it must preserve
141
+ // leading/trailing whitespace.
142
+ t.isFixed('[ @[foo bar] ]', '[@[foo bar]]');
143
+ t.isFixed('[ @[ foo bar ] ]', '[@[ foo bar ]]');
144
+ t.isFixed('[ @foo bar ]', '[@[foo bar ]]');
145
+ t.isFixed('[@ foo bar]', '[@[ foo bar]]');
146
+ t.isFixed('[ @ foo bar ]', '[@[ foo bar ]]');
139
147
  t.end();
140
148
  });
141
149
 
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 {Object} token A token
16
- * @return {boolean} True if the specified token is range, False otherwise.
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 {Object} token The token
34
- * @return {boolean} True if the specified token is reference, False otherwise.
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 {Object} token The token
54
- * @return {boolean} True if the specified token is literal, False otherwise.
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 {Object} token The token
72
- * @return {boolean} True if the specified token is error, False otherwise.
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 {Object} token The token
85
- * @return {boolean} True if the specified token is whitespace, False otherwise.
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 {Object} token The token
101
- * @return {boolean} True if the specified token is function, False otherwise.
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 {Object} token The token
112
- * @return {boolean} True if the specified token is effects prefix, False otherwise.
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 {Object} token The token
125
- * @return {boolean} True if the specified token is operator, False otherwise.
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 {Object} [options={}] Options
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
- * @return {Array<Object>} An AST of nodes
206
+ * @returns {Array<Token>} An AST of nodes
207
207
  */
208
208
  export function tokenize (formula, options = {}) {
209
209
  return getTokens(formula, lexers, options);
@@ -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<Object>} tokenlist An array of tokens (from `tokenize()`)
67
- * @return {Array} A new list of tokens with range parts merged.
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<Object>)} formula An Excel formula string (an Excel expression) or an array of tokens.
482
- * @param {Object} [options={}] Options
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
- * @return {Object} An AST of nodes
491
+ * @returns {object} An AST of nodes
492
492
  */
493
- export function parse (source, options) {
494
- if (typeof source === 'string') {
495
- tokens = tokenize(source, {
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(source)) {
502
- tokens = source;
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 {Object} range A range object
28
- * @return {string} An R1C1-style string represenation of a range
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
- * @return {(Object|null)} An object representing a valid reference or null if it is invalid.
137
+ * @returns {(RangeR1C1|null)} An object representing a valid reference or null if it is invalid.
138
138
  */
139
- export function fromR1C1 (ref) {
139
+ export function fromR1C1 (rangeString) {
140
140
  let final = null;
141
- const [ part1, part2 ] = ref.split(':', 2);
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 {Object} [options={}] Options
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
- * @return {(Object|null)} An object representing a valid reference or null if it is invalid.
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 {Object} refObject A reference object
316
- * @param {Object} [options={}] Options
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
- * @return {Object} The reference in R1C1-style string format
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
@@ -71,7 +71,7 @@ export function parseSRange (raw) {
71
71
  // [column]
72
72
  else if ((m1 = matchColumn(s, false))) {
73
73
  pos += m1[0].length;
74
- columns.push(m1[1].trim());
74
+ columns.push(m1[1]);
75
75
  }
76
76
  // use the "normal" method
77
77
  // [[#keyword]]
@@ -126,7 +126,7 @@ export function parseSRange (raw) {
126
126
  const leftCol = expect_more ? matchColumn(raw.slice(pos)) : null;
127
127
  if (leftCol) {
128
128
  pos += leftCol[0].length;
129
- columns.push(leftCol[1].trim());
129
+ columns.push(leftCol[1]);
130
130
  s = raw.slice(pos);
131
131
  if (s[0] === ':') {
132
132
  s = s.slice(1);
@@ -134,7 +134,7 @@ export function parseSRange (raw) {
134
134
  const rightCol = matchColumn(s);
135
135
  if (rightCol) {
136
136
  pos += rightCol[0].length;
137
- columns.push(rightCol[1].trim());
137
+ columns.push(rightCol[1]);
138
138
  }
139
139
  else {
140
140
  return null;
@@ -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 {Object} [options={}] Options
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
- * @return {(Object|null)} An object representing a valid reference or null if it is invalid.
190
+ * @returns {(ReferenceStruct|null)} An object representing a valid reference or null if it is invalid.
191
191
  */
192
- export function parseStructRef (ref, opts = { xlsx: false }) {
193
- const r = parseRef(ref, opts);
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 opts.xlsx
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 {Object} refObject A structured reference object
242
- * @param {Object} [options={}] Options
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
- * @return {Object} The structured reference in string format
244
+ * @returns {string} The structured reference in string format
245
245
  */
246
- export function stringifyStructRef (ref, { xlsx = false } = {}) {
246
+ export function stringifyStructRef (refObject, { xlsx = false } = {}) {
247
247
  let s = xlsx
248
- ? stringifyPrefixAlt(ref)
249
- : stringifyPrefix(ref);
248
+ ? stringifyPrefixAlt(refObject)
249
+ : stringifyPrefix(refObject);
250
250
 
251
- if (ref.table) {
252
- s += ref.table;
251
+ if (refObject.table) {
252
+ s += refObject.table;
253
253
  }
254
- const numColumns = ref.columns?.length ?? 0;
255
- const numSections = ref.sections?.length ?? 0;
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(ref.sections[0])}]`;
258
+ s += `[#${toSentenceCase(refObject.sections[0])}]`;
259
259
  }
260
260
  // single column
261
261
  else if (!numSections && numColumns === 1) {
262
- s += `[${quoteColname(ref.columns[0])}]`;
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 && ref.sections[0].toLowerCase() === 'this row';
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 += ref.sections
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 && ref.columns.length === 1 && !needsBraces(ref.columns[0])) {
281
- s += quoteColname(ref.columns[0]);
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 += ref.columns.slice(0, 2)
284
+ s += refObject.columns.slice(0, 2)
285
285
  .map(d => (`[${quoteColname(d)}]`))
286
286
  .join(':');
287
287
  }
package/lib/sr.spec.js CHANGED
@@ -45,16 +45,24 @@ test('parse structured references', t => {
45
45
  columns: [ 'my column' ]
46
46
  });
47
47
 
48
- t.isSREqual('[ [my column]:otherColumn ]', {
48
+ t.isSREqual('[[my column]:otherColumn]', {
49
49
  columns: [ 'my column', 'otherColumn' ]
50
50
  });
51
51
 
52
- t.isSREqual('[ @[my column]:otherColumn ]', {
53
- columns: [ 'my column', 'otherColumn' ],
52
+ t.isSREqual('[ [my column]:otherColumn ]', {
53
+ columns: [ 'my column', 'otherColumn ' ]
54
+ });
55
+
56
+ t.isSREqual('[ [my column]: otherColumn ]', {
57
+ columns: [ 'my column', ' otherColumn ' ]
58
+ });
59
+
60
+ t.isSREqual('[ @[ my column ]: otherColumn ]', {
61
+ columns: [ ' my column ', ' otherColumn ' ],
54
62
  sections: [ 'this row' ]
55
63
  });
56
64
 
57
- t.isSREqual('[ [#Data], [my column]:otherColumn ]', {
65
+ t.isSREqual('[[#Data], [my column]:otherColumn]', {
58
66
  columns: [ 'my column', 'otherColumn' ],
59
67
  sections: [ 'data' ]
60
68
  });
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<Object>)} formula A string (an Excel formula) or a token list that should be adjusted.
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 {Object} [options={}] The options
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
- * @return {(string | Array<Object>)} A formula string or token list (depending on which was input)
38
+ * @returns {(string | Array<Token>)} A formula string or token list (depending on which was input)
39
39
  */
40
- export function translateToR1C1 (fx, anchorCell, { xlsx = false, allowTernary = true } = {}) {
40
+ export function translateToR1C1 (formula, anchorCell, { xlsx = false, allowTernary = true } = {}) {
41
41
  const { top, left } = fromA1(anchorCell);
42
- const isString = typeof fx === 'string';
42
+ const isString = typeof formula === 'string';
43
43
 
44
44
  const tokens = isString
45
- ? tokenize(fx, { ...settings, xlsx, allowTernary })
46
- : fx;
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<Object>)} formula A string (an Excel formula) or a token list that should be adjusted.
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 {Object} [options={}] The options
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
- * @return {(string | Array<Object>)} A formula string or token list (depending on which was input)
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);