@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.
- package/dist/fx.d.ts +647 -0
- package/dist/fx.js +1 -1
- package/docs/API.md +361 -280
- package/lib/addTokenMeta.js +8 -15
- package/lib/addTokenMeta.spec.js +24 -2
- package/lib/parser.js +1 -1
- package/package.json +14 -10
- package/tsd.json +12 -0
- package/.jsdoc/config.json +0 -17
- package/.jsdoc/publish.js +0 -217
package/lib/addTokenMeta.js
CHANGED
|
@@ -63,8 +63,8 @@ function isEquivalent (refA, refB) {
|
|
|
63
63
|
}
|
|
64
64
|
// must have same context
|
|
65
65
|
if (
|
|
66
|
-
!sameStr(refA.
|
|
67
|
-
!sameStr(refA.
|
|
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.
|
|
76
|
-
ref.
|
|
75
|
+
if (!ref.sheetName) {
|
|
76
|
+
ref.sheetName = sheetName;
|
|
77
77
|
}
|
|
78
|
-
|
|
79
|
-
|
|
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);
|
package/lib/addTokenMeta.spec.js
CHANGED
|
@@ -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
|
|
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
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@borgar/fx",
|
|
3
|
-
"version": "4.
|
|
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:
|
|
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.
|
|
43
|
-
"@babel/eslint-parser": "~7.
|
|
44
|
-
"@babel/preset-env": "~7.
|
|
45
|
-
"@borgar/eslint-config": "~3.
|
|
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.
|
|
51
|
+
"eslint": "~8.49.0",
|
|
49
52
|
"jsdoc": "~4.0.2",
|
|
50
|
-
"rollup": "~3.
|
|
53
|
+
"rollup": "~3.29.1",
|
|
51
54
|
"rollup-plugin-minification": "~0.2.0",
|
|
52
|
-
"tap-min": "~
|
|
53
|
-
"
|
|
55
|
+
"tap-min": "~3.0.0",
|
|
56
|
+
"typescript": "~5.2.2",
|
|
57
|
+
"tape": "~5.6.6"
|
|
54
58
|
}
|
|
55
59
|
}
|
package/tsd.json
ADDED
package/.jsdoc/config.json
DELETED
|
@@ -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
|
-
};
|