fix(evaluators): fix preprocessing and add test cases (#1519)

* fix(evaluators): fix preprocessing and add test cases

* fix(plugin-workflow): fix calculation test case
This commit is contained in:
Junyi 2023-03-01 23:55:53 +08:00 committed by GitHub
parent f8256548e5
commit ac039ad0e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 4 deletions

View File

@ -0,0 +1,42 @@
import evaluators from '..';
const mathEval = evaluators.get('math.js');
const formulaEval = evaluators.get('formula.js');
describe('evaluate', () => {
it('reference null or undefined', () => {
const result = formulaEval('{{a.b}}', { a: null });
expect(result).toBeNull();
});
it('function result string with quote', () => {
const result = formulaEval('{{a}}', { a() { return "I'm done." } });
expect(result).toBe("I'm done.");
});
it('function result number', () => {
const result = formulaEval('{{a}}', { a() { return 1 } });
expect(result).toBe(1);
});
it('number path to array item 0 (math.js)', () => {
expect(() => mathEval('{{a.0}}', { a: [1, 2, 3] })).toThrow();
});
it('number path to array item 1 (math.js)', () => {
const result = mathEval('{{a}}[1]', { a: [1, 2, 3] });
expect(result).toBe(1);
});
it('number path to array item 1 (math.js)', () => {
const result = mathEval('{{a.1}}', { a: [1, 2, 3] });
expect(result).toBe(1);
});
it('number path to object member 0 (math.js)', () => {
const result = mathEval('{{a.1}}', { a: { 1: 1 } });
expect(result).toBe(1);
});
});

View File

@ -9,7 +9,7 @@ export type Evaluator = (expression: string, scope?: Scope) => any;
function appendArrayColumn(scope, key) {
const paths = key.split('.');
let data = scope;
for (let p = 0; p < paths.length; p++) {
for (let p = 0; p < paths.length && data != null; p++) {
const path = paths[p];
const isIndex = path.match(/^\d+$/);
if (Array.isArray(data) && !isIndex && !data[path]) {
@ -19,13 +19,43 @@ function appendArrayColumn(scope, key) {
}
}
function replaceNumberIndex(path: string, scope: Scope): string {
const segments = path.split('.');
const paths = [];
for (let i = 0; i < segments.length; i++) {
const p = segments[i];
if (p.match(/^\d+$/)) {
paths.push(Array.isArray(get(scope, segments.slice(0, i))) ? `[${p}]` : `["${p}"]`);
} else {
if (i) {
paths.push('.', p);
} else {
paths.push(p);
}
}
}
return paths.join('');
}
export function evaluate(this: Evaluator, expression: string, scope: Scope = {}) {
const context = cloneDeep(scope);
const exp = expression.trim().replace(/{{\s*([^{}]+)\s*}}/g, (_, v) => {
appendArrayColumn(context, v);
const item = get(context, v);
const key = v.replace(/\.(\d+)/g, '["$1"]');
return ` ${typeof item === 'function' ? item() : key} `;
if (item == null) {
return 'null';
}
if (typeof item === 'function') {
const result = item();
return typeof result === 'string' ? `'${result.replace(/'/g, "\\'")}'` : result;
}
return replaceNumberIndex(v, context);
});
return this(exp, context);
}

View File

@ -148,7 +148,7 @@ describe('workflow > instructions > calculation', () => {
const [execution] = await workflow.getExecutions();
const [job] = await execution.getJobs();
expect(job.result).toBe('a $context.data.title ');
expect(job.result).toBe('a$context.data.title');
});
it('text', async () => {