mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-30 02:48:55 +08:00
feat:增加formulaEvalHandler&conditionComputeHandler用于跳过amis解析
This commit is contained in:
parent
86f7b8962d
commit
e840ac244c
@ -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);
|
||||
});
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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');
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
|
10
packages/amis-formula/src/error.ts
Normal file
10
packages/amis-formula/src/error.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* 表达式解析错误
|
||||
*/
|
||||
|
||||
export class FormulaEvalError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'FormulaEvalError';
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user