@borgar/fx 4.3.0 → 4.4.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.
@@ -63,8 +63,8 @@ function isEquivalent (refA, refB) {
63
63
  }
64
64
  // must have same context
65
65
  if (
66
- !sameStr(refA.context[0], refB.context[0]) ||
67
- !sameStr(refA.context[1], refB.context[1])
66
+ !sameStr(refA.workbookName, refB.workbookName) ||
67
+ !sameStr(refA.sheetName, refB.sheetName)
68
68
  ) {
69
69
  return false;
70
70
  }
@@ -72,18 +72,11 @@ function isEquivalent (refA, refB) {
72
72
  }
73
73
 
74
74
  function addContext (ref, sheetName, workbookName) {
75
- if (!ref.context.length) {
76
- ref.context = [ workbookName, sheetName ];
75
+ if (!ref.sheetName) {
76
+ ref.sheetName = sheetName;
77
77
  }
78
- else if (ref.context.length === 1) {
79
- const scope = ref.context[0];
80
- if (scope === sheetName || scope === workbookName) {
81
- ref.context = [ workbookName, sheetName ];
82
- }
83
- else {
84
- // a single scope on a non-named range is going to be a sheet name
85
- ref.context = [ workbookName, scope ];
86
- }
78
+ if (!ref.workbookName) {
79
+ ref.workbookName = workbookName;
87
80
  }
88
81
  return ref;
89
82
  }
@@ -189,8 +182,8 @@ export function addTokenMeta (tokens, { sheetName = '', workbookName = '' } = {}
189
182
  token.type === REF_STRUCT
190
183
  ) {
191
184
  const ref = (token.type === REF_STRUCT)
192
- ? parseStructRef(token.value, { allowTernary: true })
193
- : parseA1Ref(token.value, { allowTernary: true });
185
+ ? parseStructRef(token.value, { allowTernary: true, xlsx: true })
186
+ : parseA1Ref(token.value, { allowTernary: true, xlsx: true });
194
187
  if (ref && (ref.range || ref.columns)) {
195
188
  ref.source = token.value;
196
189
  addContext(ref, sheetName, workbookName);
@@ -3,8 +3,8 @@ import { FX_PREFIX, OPERATOR, NUMBER, REF_RANGE, REF_BEAM, FUNCTION, WHITESPACE,
3
3
  import { addTokenMeta } from './addTokenMeta.js';
4
4
  import { tokenize } from './lexer.js';
5
5
 
6
- Test.prototype.isMetaTokens = function isTokens (expr, expect, opts) {
7
- const actual = addTokenMeta(tokenize(expr), opts);
6
+ Test.prototype.isMetaTokens = function isTokens (expr, expect, context, opts) {
7
+ const actual = addTokenMeta(tokenize(expr, opts), context);
8
8
  if (actual.length === expect.length) {
9
9
  actual.forEach((d, i) => {
10
10
  const keys = Object.keys(d).concat(Object.keys(expect[i]));
@@ -115,5 +115,27 @@ test('add extra meta to operators', t => {
115
115
  { index: 5, depth: 0, type: REF_STRUCT, value: 'table[[#All]]', groupId: 'fxg1' }
116
116
  ], { sheetName: 'Sheet1', workbookName: 'foo' });
117
117
 
118
+ t.isMetaTokens('=[foo]!A1+[foo]Sheet1!A1+Sheet1!A1+A1', [
119
+ { index: 0, depth: 0, type: FX_PREFIX, value: '=' },
120
+ { index: 1, depth: 0, type: REF_RANGE, value: '[foo]!A1', groupId: 'fxg1' },
121
+ { index: 2, depth: 0, type: OPERATOR, value: '+' },
122
+ { index: 3, depth: 0, type: REF_RANGE, value: '[foo]Sheet1!A1', groupId: 'fxg1' },
123
+ { index: 4, depth: 0, type: OPERATOR, value: '+' },
124
+ { index: 5, depth: 0, type: REF_RANGE, value: 'Sheet1!A1', groupId: 'fxg1' },
125
+ { index: 6, depth: 0, type: OPERATOR, value: '+' },
126
+ { index: 7, depth: 0, type: REF_RANGE, value: 'A1', groupId: 'fxg1' }
127
+ ], { sheetName: 'Sheet1', workbookName: 'foo' }, { xlsx: true });
128
+
129
+ t.isMetaTokens('=[foo]!table[#data]+[foo]Sheet1!table[#data]+Sheet1!table[#data]+table[#data]', [
130
+ { index: 0, depth: 0, type: FX_PREFIX, value: '=' },
131
+ { index: 1, depth: 0, type: REF_STRUCT, value: '[foo]!table[#data]', groupId: 'fxg1' },
132
+ { index: 2, depth: 0, type: OPERATOR, value: '+' },
133
+ { index: 3, depth: 0, type: REF_STRUCT, value: '[foo]Sheet1!table[#data]', groupId: 'fxg1' },
134
+ { index: 4, depth: 0, type: OPERATOR, value: '+' },
135
+ { index: 5, depth: 0, type: REF_STRUCT, value: 'Sheet1!table[#data]', groupId: 'fxg1' },
136
+ { index: 6, depth: 0, type: OPERATOR, value: '+' },
137
+ { index: 7, depth: 0, type: REF_STRUCT, value: 'table[#data]', groupId: 'fxg1' }
138
+ ], { sheetName: 'Sheet1', workbookName: 'foo' }, { xlsx: true });
139
+
118
140
  t.end();
119
141
  });
package/lib/parser.js CHANGED
@@ -493,7 +493,7 @@ prefix('{', function () {
493
493
  export function parse (source, options) {
494
494
  if (typeof source === 'string') {
495
495
  tokens = tokenize(source, {
496
- withLocation: true,
496
+ withLocation: false,
497
497
  ...options,
498
498
  mergeRefs: true
499
499
  });
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@borgar/fx",
3
- "version": "4.3.0",
3
+ "version": "4.4.0",
4
4
  "description": "Utilities for working with Excel formulas",
5
5
  "main": "dist/fx.js",
6
+ "types": "dist/fx.d.ts",
6
7
  "module": "lib/index.js",
7
8
  "exports": {
8
9
  ".": {
@@ -15,7 +16,8 @@
15
16
  "version": "npm run build",
16
17
  "lint": "eslint lib/*.js",
17
18
  "test": "tape lib/*.spec.js | tap-min",
18
- "build:docs": "echo '# _Fx_ API\n'>docs/API.md; jsdoc -c .jsdoc/config.json -d console lib>>docs/API.md",
19
+ "build:types": "jsdoc -c tsd.json lib>dist/fx.d.ts",
20
+ "build:docs": "echo '# _Fx_ API\n'>docs/API.md; jsdoc -t node_modules/@borgar/jsdoc-tsmd -d console lib>>docs/API.md",
19
21
  "build": "NODE_ENV=production rollup -c"
20
22
  },
21
23
  "repository": {
@@ -39,17 +41,19 @@
39
41
  "author": "Borgar Þorsteinsson <borgar@borgar.net> (http://borgar.net/)",
40
42
  "license": "MIT",
41
43
  "devDependencies": {
42
- "@babel/core": "~7.21.0",
43
- "@babel/eslint-parser": "~7.19.1",
44
- "@babel/preset-env": "~7.20.2",
45
- "@borgar/eslint-config": "~3.0.0",
44
+ "@babel/core": "~7.22.17",
45
+ "@babel/eslint-parser": "~7.22.15",
46
+ "@babel/preset-env": "~7.22.15",
47
+ "@borgar/eslint-config": "~3.1.0",
48
+ "@borgar/jsdoc-tsmd": "~0.1.0",
46
49
  "@rollup/plugin-babel": "~6.0.3",
47
50
  "babel-eslint": "~10.1.0",
48
- "eslint": "~8.34.0",
51
+ "eslint": "~8.49.0",
49
52
  "jsdoc": "~4.0.2",
50
- "rollup": "~3.17.2",
53
+ "rollup": "~3.29.1",
51
54
  "rollup-plugin-minification": "~0.2.0",
52
- "tap-min": "~2.0.0",
53
- "tape": "~5.6.3"
55
+ "tap-min": "~3.0.0",
56
+ "typescript": "~5.2.2",
57
+ "tape": "~5.6.6"
54
58
  }
55
59
  }
package/tsd.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "source": {
3
+ "includePattern": ".+\\.js(doc|x)?$",
4
+ "excludePattern": "((^|\\/|\\\\)_|spec\\.js$)"
5
+ },
6
+ "opts": {
7
+ "template": "node_modules/@borgar/jsdoc-tsmd",
8
+ "destination": "console",
9
+ "output": "typescript",
10
+ "validate": true
11
+ }
12
+ }
@@ -1,17 +0,0 @@
1
- {
2
- "source": {
3
- "includePattern": ".+\\.js(doc|x)?$",
4
- "excludePattern": "((^|\\/|\\\\)_|spec\\.js$)"
5
- },
6
- "opts": {
7
- "template": "./.jsdoc",
8
- "encoding": "utf8",
9
- "destination": "./docs/"
10
- },
11
- "templates": {
12
- "default": {
13
- "includeDate": false,
14
- "outputSourceFiles": false
15
- }
16
- }
17
- }
package/.jsdoc/publish.js DELETED
@@ -1,217 +0,0 @@
1
- /* eslint-disable no-undefined, no-console */
2
-
3
- function formatType (d, inTable = false) {
4
- return d.names?.map(n => `\`${n}\``).join(inTable ? ' \\| ' : ' | ') || '';
5
- }
6
-
7
- function formatArguments (args, showDefaults = true) {
8
- let inOpt = false;
9
- let r = args.reduce((a, d, i) => {
10
- if (d.name.includes('.')) {
11
- return a;
12
- }
13
- if (inOpt && !d.optional) {
14
- a += ']_';
15
- inOpt = false;
16
- }
17
- if (i) {
18
- a += ', ';
19
- }
20
- if (!inOpt && d.optional) {
21
- a += '_[';
22
- inOpt = true;
23
- }
24
- a += d.name;
25
- if (showDefaults && d.defaultvalue) {
26
- a += ' = `' + d.defaultvalue + '`';
27
- }
28
- return a;
29
- }, '');
30
- if (inOpt) {
31
- r += ']_';
32
- }
33
- return r;
34
- }
35
-
36
- function repValue (v) {
37
- if (v === undefined) {
38
- return '';
39
- }
40
- if (v === "''") {
41
- // FIXME: should transform all '' strings to "" style
42
- v = '""';
43
- }
44
- return '`' + v + '`';
45
- }
46
-
47
- function repArgName (name, optional = false) {
48
- const names = name.split('.');
49
- const nPath = names.length > 1 ? '.' + names.slice(1).join('.') : '';
50
- return (optional ? '_[' : '') + names[0] + (optional ? ']_' : '') + nPath;
51
- }
52
-
53
- function listToTable (args) {
54
- const useDefaults = args.some(d => !!d.defaultvalue);
55
- const table = useDefaults
56
- ? [
57
- '| Name | Type | Default | Description |',
58
- '| ---- | ---- | ------- | ----------- |' ]
59
- : [
60
- '| Name | Type | Description |',
61
- '| ---- | ---- | ----------- |' ];
62
- args.forEach(d => {
63
- const row = [ repArgName(d.name, d.optional) ];
64
- row.push(formatType(d.type, true));
65
- useDefaults && row.push(repValue(d.defaultvalue));
66
- row.push(transformLinks(d.description));
67
- table.push('| ' + row.join(' | ') + ' |');
68
- });
69
-
70
- return table.join('\n');
71
- }
72
-
73
- function adjustLineBreaks (md) {
74
- return md.trim().replace(
75
- /(?:```([^\0]*?)```|(\S)\n(?!\n))/g,
76
- (a, b, c) => {
77
- return (c ? (c + ' ') : a);
78
- }
79
- );
80
- }
81
-
82
- function formatSee (see) {
83
- if (see) {
84
- if (/^[a-z][a-z0-9]*$/i.test(see)) {
85
- see = `{@link ${see}}`;
86
- }
87
- return `\n**See also:** ${transformLinks(see)}.\n`;
88
- }
89
- return '';
90
- }
91
-
92
- const re_links = /(?:\[([^\]]+)\])?\{@link(?:code|plain)? ([^} ]+)([^}]+)?\}/g;
93
- function transformLinks (md) {
94
- return md.replace(re_links, (a, preLabel, href, postLabel) => {
95
- const hash = /^[a-z][a-z0-9]*$/i.test(href) ? '#' : '';
96
- return `[${preLabel || postLabel || href}](${hash}${href})`;
97
- });
98
- }
99
-
100
- function formatHeading (text, level = 2) {
101
- return '#'.repeat(level || 1) + ' ' + text;
102
- }
103
-
104
- function formatIndexLink (name, text) {
105
- return `[${text.replace(/([[\]])/g, '\\$1')}](#${name})`;
106
- }
107
-
108
- const formatIndex = {
109
- function: d => {
110
- return '- ' + formatIndexLink(d.name,
111
- `${d.name}( ${formatArguments(d.params, false)} )`
112
- );
113
- },
114
- constant: d => {
115
- return '- ' + formatIndexLink(d.name,
116
- `${d.name}`
117
- );
118
- }
119
- }
120
-
121
- const format = {
122
- function: d => {
123
- return [
124
- formatHeading(`<a name="${d.name}" href="#${d.name}">#</a> ${d.name}( ${formatArguments(d.params)} ) ⇒ ${formatType(d.returns[0].type)}`, 3),
125
- adjustLineBreaks(transformLinks(d.description)),
126
- formatSee(d.see),
127
- formatHeading('Parameters', 4),
128
- listToTable(d.params),
129
- formatHeading('Returns', 4),
130
- formatType(d.returns[0].type) + ' – ' + d.returns[0].description
131
- ];
132
- },
133
- constant: d => {
134
- return [
135
- formatHeading(`<a name="${d.name}" href="#${d.name}">#</a> ${d.name} ⇒ ${formatType(d.type)}`, 3),
136
- adjustLineBreaks(transformLinks(d.description)),
137
- formatSee(d.see),
138
- formatHeading('Properties', 4),
139
- listToTable(d.properties)
140
- ];
141
- }
142
- };
143
-
144
- const categoryHeadings = {
145
- package: null,
146
- function: 'Functions',
147
- constant: 'Constants'
148
- };
149
-
150
- exports.publish = (data, { destination }) => {
151
- data({ undocumented: true }).remove();
152
- const docs = data().get();
153
-
154
- const test = '';
155
- if (test) {
156
- const s = docs.find(d => d.name === test);
157
- const o = format[s.kind](s);
158
- console.log(o.join('\n\n'));
159
- return;
160
- }
161
-
162
- const categories = {};
163
- docs.forEach(d => {
164
- if (!categories[d.kind]) {
165
- categories[d.kind] = [];
166
- }
167
- categories[d.kind].push(d);
168
- });
169
-
170
- let output = [];
171
- const index = [];
172
-
173
- Object.keys(categories)
174
- .sort()
175
- .forEach(kind => {
176
- const heading = categoryHeadings[kind];
177
- if (heading == null) { return; }
178
- // emit category heading
179
- if (index.length) { index.push(''); }
180
- index.push('**' + heading + '**', '');
181
- output.push(formatHeading(heading, 2));
182
- // emit all members belonging to that category
183
- docs
184
- .filter(d => d.kind === kind)
185
- .filter(d => d.access !== 'private')
186
- .sort((a, b) => {
187
- if (a.name < b.name) { return -1; }
188
- if (a.name > b.name) { return 1; }
189
- return NaN;
190
- })
191
- .forEach((d, i) => {
192
- if (i) {
193
- output.push('---');
194
- }
195
- if (!format[d.kind]) {
196
- console.error('Unsupported member type ' + d.kind);
197
- process.exit(1);
198
- }
199
- index.push(formatIndex[d.kind](d));
200
- output.push(...format[d.kind](d));
201
- });
202
- });
203
-
204
- if (destination === 'console') {
205
- const outText = (
206
- index.map(d => d.trim()).join('\n') +
207
- '\n\n' +
208
- output.map(d => d.trim()).filter(Boolean).join('\n\n') +
209
- '\n'
210
- );
211
- console.log(outText);
212
- }
213
- else {
214
- console.error('This template only supports output to the console. Use the option "-d console" when you run JSDoc.');
215
- process.exit(1);
216
- }
217
- };