feat:增加formulaEvalHandler&conditionComputeHandler用于跳过amis解析

This commit is contained in:
lvxiaojiao 2023-04-12 21:55:19 +08:00
parent 86f7b8962d
commit e840ac244c
8 changed files with 140 additions and 11 deletions

View File

@ -1,8 +1,10 @@
import moment from 'moment';
import {
resolveVariable,
resolveVariableAndFilter
resolveVariableAndFilter,
resolveVariableAndFilterForAsync
} from '../src/utils/tpl-builtin';
import {setFormulaEvalHandler} from '../src/utils';
const filters = [
{
@ -640,3 +642,19 @@ test(`compat:test2`, () => {
expect(resolveVariable('中文', data)).toEqual(123);
expect(resolveVariable('obj.x', data)).toEqual(123);
});
test('compat:formulaEvalHandler', async () => {
setFormulaEvalHandler(
(
path?: string,
data: object = {},
defaultFilter: string = '| html',
fallbackValue = (value: any) => value,
skipFormulaEvalHandler: boolean = false
) => {
return Promise.resolve(1 * 2 * 2);
}
);
expect(await resolveVariableAndFilterForAsync('${AAA(1,2)}')).toBe(4);
});

View File

@ -1,5 +1,10 @@
import moment from 'moment';
import {resolveCondition, guid, registerConditionComputer} from '../src/utils/';
import {
resolveCondition,
guid,
registerConditionComputer,
setConditionComputeHandler
} from '../src/utils/';
const data = {
name: 'amis',
@ -504,3 +509,39 @@ test(`condition register`, async () => {
expect(await resolveCondition(conditions, data)).toBe(true);
});
test(`condition conditionComputeHander`, async () => {
// 无法解析时,自定义解析逻辑
setConditionComputeHandler(
(conditions: any, data: any, defaultResult: boolean) => {
return Promise.resolve(true);
}
);
const conditions = {
id: guid(),
conjunction: 'and',
children: [
{
id: guid(),
left: {
type: 'date',
field: 'date'
},
op: 'equal',
right: '2023-03-19'
},
{
id: guid(),
left: {
type: 'field',
field: 'num'
},
op: 'equal',
right: '${AAA(5)}'
}
]
};
expect(await resolveCondition(conditions, data)).toBe(true);
});

View File

@ -11,6 +11,11 @@ const conditionResolverMap: {
[op: string]: (left: any, right: any, fieldType?: string) => boolean;
} = {};
const DEFAULT_RESULT = true;
let conditionComputeHandler: (
conditions: any,
data: any,
defaultResult: boolean
) => boolean | Promise<boolean>;
export async function resolveCondition(
conditions: any,
@ -26,11 +31,23 @@ export async function resolveCondition(
return defaultResult;
}
return await computeConditions(
conditions.children,
conditions.conjunction,
data
);
try {
return await computeConditions(
conditions.children,
conditions.conjunction,
data
);
} catch (e) {
// 如果函数未定义则交给handler
if (e.name === 'FormulaEvalError') {
return await conditionComputeHandler?.(
conditions.children,
conditions.conjunction,
data
);
}
return defaultResult;
}
}
async function computeConditions(
@ -73,7 +90,10 @@ async function computeCondition(
const leftValue = get(data, rule.left.field);
const rightValue: any = await resolveVariableAndFilterForAsync(
rule.right,
data
data,
undefined,
undefined,
true
);
const func =
@ -293,6 +313,16 @@ export function getConditionComputers() {
return conditionResolverMap;
}
export function setConditionComputeHandler(
fn: (
conditions: any,
data: any,
defaultResult: boolean
) => boolean | Promise<boolean>
) {
conditionComputeHandler = fn;
}
registerConditionComputer('greater', greaterFunc);
registerConditionComputer('greater', greaterForDateFunc, 'date');
registerConditionComputer('greater', greaterForDateFunc, 'time');

View File

@ -1,10 +1,27 @@
import {AsyncEvaluator, parse} from 'amis-formula';
let formulaEvalHandler: (
path: string,
data?: object,
...args: any[]
) => any | undefined;
/**
* functions中找不到处理的函数时执行
* @param fn
*/
export function setFormulaEvalHandler(
fn: (path: string, data?: object, ...args: any[]) => any
): void {
formulaEvalHandler = fn;
}
export const resolveVariableAndFilterForAsync = async (
path?: string,
data: object = {},
defaultFilter: string = '| html',
fallbackValue = (value: any) => value
fallbackValue = (value: any) => value,
skipFormulaEvalHandler: boolean = false
) => {
if (!path || typeof path !== 'string') {
return undefined;
@ -25,6 +42,15 @@ export const resolveVariableAndFilterForAsync = async (
: ret;
} catch (e) {
console.warn(e);
debugger;
if (e.name === 'FormulaEvalError') {
if (!skipFormulaEvalHandler) {
// 无法解析时执行handler自定义解析逻辑
return formulaEvalHandler?.(path, data, defaultFilter, fallbackValue);
}
// 跳过自定义解析逻辑,则直接抛异常
throw e;
}
return undefined;
}
};

View File

@ -16,6 +16,7 @@ import {stripNumber} from './stripNumber';
import {tokenize} from './tokenize';
import {resolveVariable} from './resolveVariable';
import {resolveVariableAndFilter} from './resolveVariableAndFilter';
import {resolveVariableAndFilterForAsync} from './resolveVariableAndFilterForAsync';
import {dataMapping, resolveMapping, resolveMappingObject} from './dataMapping';
import './filter'; // 扩充 formula 里面的 filter
@ -35,6 +36,7 @@ export {
tokenize,
resolveVariable,
resolveVariableAndFilter,
resolveVariableAndFilterForAsync,
resolveMapping,
resolveMappingObject,
dataMapping

View File

@ -0,0 +1,10 @@
/**
*
*/
export class FormulaEvalError extends Error {
constructor(message: string) {
super(message);
this.name = 'FormulaEvalError';
}
}

View File

@ -14,6 +14,7 @@ import isEqual from 'lodash/isEqual';
import isPlainObject from 'lodash/isPlainObject';
import get from 'lodash/get';
import {EvaluatorOptions, FilterContext, FilterMap, FunctionMap} from './types';
import {FormulaEvalError} from './error';
export class Evaluator {
readonly filters: FilterMap;
@ -452,7 +453,7 @@ export class Evaluator {
this.filters[ast.identifier]);
if (!fn) {
throw new Error(`${ast.identifier}函数没有定义`);
throw new FormulaEvalError(`${ast.identifier}函数没有定义`);
}
let args: Array<any> = ast.args;

View File

@ -3,6 +3,7 @@
*/
import {FilterContext} from './types';
import {createObject, Evaluator, stripNumber} from './evalutor';
import {FormulaEvalError} from './error';
export async function runSequence<T, U>(
arr: Array<T>,
@ -299,7 +300,7 @@ export class AsyncEvaluator extends (Evaluator as any) {
this.filters[ast.identifier]);
if (!fn) {
throw new Error(`${ast.identifier}函数没有定义`);
throw new FormulaEvalError(`${ast.identifier}函数没有定义`);
}
let args: Array<any> = ast.args;