@nocobase/evaluators 0.11.1-alpha.4 → 0.12.0-alpha.1
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/package.json +3 -3
- package/src/client/engines/formulajs.ts +0 -9
- package/src/client/engines/mathjs.ts +0 -9
- package/src/client/index.tsx +0 -25
- package/src/index.ts +0 -2
- package/src/server/__tests__/index.test.ts +0 -62
- package/src/server/index.ts +0 -14
- package/src/utils/formulajs.ts +0 -16
- package/src/utils/index.ts +0 -65
- package/src/utils/mathjs.ts +0 -12
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/evaluators",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0-alpha.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@formulajs/formulajs": "4.2.0",
|
|
10
|
-
"@nocobase/utils": "0.
|
|
10
|
+
"@nocobase/utils": "0.12.0-alpha.1",
|
|
11
11
|
"mathjs": "^10.6.0"
|
|
12
12
|
},
|
|
13
13
|
"repository": {
|
|
@@ -15,5 +15,5 @@
|
|
|
15
15
|
"url": "git+https://github.com/nocobase/nocobase.git",
|
|
16
16
|
"directory": "packages/evaluators"
|
|
17
17
|
},
|
|
18
|
-
"gitHead": "
|
|
18
|
+
"gitHead": "543dcc0216b7b1451b552b0f685bc3e0682f9d59"
|
|
19
19
|
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { evaluate } from '../../utils';
|
|
2
|
-
import formulajs from '../../utils/formulajs';
|
|
3
|
-
|
|
4
|
-
export default {
|
|
5
|
-
label: 'Formula.js',
|
|
6
|
-
tooltip: '{{t("Formula.js supports most Microsoft Excel formula functions.")}}',
|
|
7
|
-
link: 'https://formulajs.info/functions/',
|
|
8
|
-
evaluate: evaluate.bind(formulajs),
|
|
9
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { evaluate } from '../../utils';
|
|
2
|
-
import mathjs from '../../utils/mathjs';
|
|
3
|
-
|
|
4
|
-
export default {
|
|
5
|
-
label: 'Math.js',
|
|
6
|
-
tooltip: `{{t('Math.js comes with a large set of built-in functions and constants, and offers an integrated solution to work with different data types')}}`,
|
|
7
|
-
link: 'https://mathjs.org/',
|
|
8
|
-
evaluate: evaluate.bind(mathjs),
|
|
9
|
-
};
|
package/src/client/index.tsx
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Registry } from '@nocobase/utils/client';
|
|
2
|
-
|
|
3
|
-
import mathjs from './engines/mathjs';
|
|
4
|
-
import formulajs from './engines/formulajs';
|
|
5
|
-
|
|
6
|
-
export interface Evaluator {
|
|
7
|
-
label: string;
|
|
8
|
-
tooltip?: string;
|
|
9
|
-
link?: string;
|
|
10
|
-
evaluate(exp: string, scope?: { [key: string]: any }): any;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const evaluators = new Registry<Evaluator>();
|
|
14
|
-
|
|
15
|
-
evaluators.register('math.js', mathjs);
|
|
16
|
-
evaluators.register('formula.js', formulajs);
|
|
17
|
-
|
|
18
|
-
export function getOptions() {
|
|
19
|
-
return Array.from((evaluators as Registry<Evaluator>).getEntities()).reduce(
|
|
20
|
-
(result: any[], [value, options]) => result.concat({ value, ...options }),
|
|
21
|
-
[],
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export default evaluators;
|
package/src/index.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import evaluators from '..';
|
|
2
|
-
|
|
3
|
-
const mathEval = evaluators.get('math.js');
|
|
4
|
-
const formulaEval = evaluators.get('formula.js');
|
|
5
|
-
|
|
6
|
-
describe('evaluate', () => {
|
|
7
|
-
it('reference null or undefined', () => {
|
|
8
|
-
const result = formulaEval('{{a.b}}', { a: null });
|
|
9
|
-
expect(result).toBeNull();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it('function result string with quote', () => {
|
|
13
|
-
const result = formulaEval('{{a}}', {
|
|
14
|
-
a() {
|
|
15
|
-
return "I'm done.";
|
|
16
|
-
},
|
|
17
|
-
});
|
|
18
|
-
expect(result).toBe("I'm done.");
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('function result number', () => {
|
|
22
|
-
const result = formulaEval('{{a}}', {
|
|
23
|
-
a() {
|
|
24
|
-
return 1;
|
|
25
|
-
},
|
|
26
|
-
});
|
|
27
|
-
expect(result).toBe(1);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('function result Date', () => {
|
|
31
|
-
const result = formulaEval('{{a}}', {
|
|
32
|
-
a() {
|
|
33
|
-
return new Date();
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
expect(result).toMatch(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?Z/);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('number path to array item 0 (math.js)', () => {
|
|
40
|
-
expect(() => mathEval('{{a.0}}', { a: [1, 2, 3] })).toThrow();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('number path to array item 1 (math.js)', () => {
|
|
44
|
-
const result = mathEval('{{a}}[1]', { a: [1, 2, 3] });
|
|
45
|
-
expect(result).toBe(1);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('number path to array item 1 (math.js)', () => {
|
|
49
|
-
const result = mathEval('{{a.1}}', { a: [1, 2, 3] });
|
|
50
|
-
expect(result).toBe(1);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('number path to object member 0 (math.js)', () => {
|
|
54
|
-
const result = mathEval('{{a.1}}', { a: { 1: 1 } });
|
|
55
|
-
expect(result).toBe(1);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('number lead string path to object member (formula.js)', () => {
|
|
59
|
-
const result = formulaEval('{{a.1a}}', { a: { '1a': 1 } });
|
|
60
|
-
expect(result).toBe(1);
|
|
61
|
-
});
|
|
62
|
-
});
|
package/src/server/index.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Registry } from '@nocobase/utils';
|
|
2
|
-
|
|
3
|
-
import { evaluate, Evaluator } from '../utils';
|
|
4
|
-
import mathjs from '../utils/mathjs';
|
|
5
|
-
import formulajs from '../utils/formulajs';
|
|
6
|
-
|
|
7
|
-
export { Evaluator, evaluate, appendArrayColumn } from '../utils';
|
|
8
|
-
|
|
9
|
-
export const evaluators = new Registry<Evaluator>();
|
|
10
|
-
|
|
11
|
-
evaluators.register('math.js', evaluate.bind(mathjs));
|
|
12
|
-
evaluators.register('formula.js', evaluate.bind(formulajs));
|
|
13
|
-
|
|
14
|
-
export default evaluators;
|
package/src/utils/formulajs.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import * as functions from '@formulajs/formulajs';
|
|
2
|
-
|
|
3
|
-
const fnNames = Object.keys(functions).filter((key) => key !== 'default');
|
|
4
|
-
const fns = fnNames.map((key) => functions[key]);
|
|
5
|
-
|
|
6
|
-
export default function (expression: string, scope = {}) {
|
|
7
|
-
const fn = new Function(...fnNames, ...Object.keys(scope), `return ${expression}`);
|
|
8
|
-
const result = fn(...fns, ...Object.values(scope));
|
|
9
|
-
if (typeof result === 'number') {
|
|
10
|
-
if (Number.isNaN(result) || !Number.isFinite(result)) {
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
13
|
-
return functions.ROUND(result, 9);
|
|
14
|
-
}
|
|
15
|
-
return result;
|
|
16
|
-
}
|
package/src/utils/index.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { get, cloneDeep } from 'lodash';
|
|
2
|
-
|
|
3
|
-
export type Scope = { [key: string]: any };
|
|
4
|
-
|
|
5
|
-
export type Evaluator = (expression: string, scope?: Scope) => any;
|
|
6
|
-
|
|
7
|
-
export function appendArrayColumn(scope, key) {
|
|
8
|
-
const paths = key.split('.');
|
|
9
|
-
let data = scope;
|
|
10
|
-
for (let p = 0; p < paths.length && data != null; p++) {
|
|
11
|
-
const path = paths[p];
|
|
12
|
-
const isIndex = path.match(/^\d+$/);
|
|
13
|
-
if (Array.isArray(data) && !isIndex && !data[path]) {
|
|
14
|
-
data[path] = data.map((item) => item[path]);
|
|
15
|
-
}
|
|
16
|
-
data = data?.[path];
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function replaceNumberIndex(path: string, scope: Scope): string {
|
|
21
|
-
const segments = path.split('.');
|
|
22
|
-
const paths: string[] = [];
|
|
23
|
-
|
|
24
|
-
for (let i = 0; i < segments.length; i++) {
|
|
25
|
-
const p = segments[i];
|
|
26
|
-
if (p[0] && '0123456789'.indexOf(p[0]) > -1) {
|
|
27
|
-
paths.push(Array.isArray(get(scope, segments.slice(0, i))) ? `[${p}]` : `["${p}"]`);
|
|
28
|
-
} else {
|
|
29
|
-
if (i) {
|
|
30
|
-
paths.push('.', p);
|
|
31
|
-
} else {
|
|
32
|
-
paths.push(p);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return paths.join('');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function evaluate(this: Evaluator, expression: string, scope: Scope = {}) {
|
|
41
|
-
const context = cloneDeep(scope);
|
|
42
|
-
const exp = expression.trim().replace(/{{\s*([^{}]+)\s*}}/g, (_, v) => {
|
|
43
|
-
appendArrayColumn(context, v);
|
|
44
|
-
|
|
45
|
-
const item = get(context, v);
|
|
46
|
-
|
|
47
|
-
let result;
|
|
48
|
-
|
|
49
|
-
if (item == null) {
|
|
50
|
-
result = 'null';
|
|
51
|
-
} else if (typeof item === 'function') {
|
|
52
|
-
result = item();
|
|
53
|
-
result = typeof result === 'string' ? `'${result.replace(/'/g, "\\'")}'` : result;
|
|
54
|
-
} else {
|
|
55
|
-
result = replaceNumberIndex(v, context);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (result instanceof Date) {
|
|
59
|
-
result = `'${result.toISOString()}'`;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return ` ${result} `;
|
|
63
|
-
});
|
|
64
|
-
return this(exp, context);
|
|
65
|
-
}
|
package/src/utils/mathjs.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import * as math from 'mathjs';
|
|
2
|
-
|
|
3
|
-
export default function (expression: string, scope = {}) {
|
|
4
|
-
const result = math.evaluate(expression, scope);
|
|
5
|
-
if (typeof result === 'number') {
|
|
6
|
-
if (Number.isNaN(result) || !Number.isFinite(result)) {
|
|
7
|
-
return null;
|
|
8
|
-
}
|
|
9
|
-
return math.round(result, 9);
|
|
10
|
-
}
|
|
11
|
-
return result;
|
|
12
|
-
}
|