@@ -47,11 +47,14 @@ interface IExampleContext {
4747
4848type IExampleContextIgnore = Moment ;
4949
50+ type IExampleCustomEvaluatorFuncRunOptions = {dryRun: boolean };
51+
5052type IExampleFunctionTable = {
51- countRange: ([min , max ]: [min : number , max : number ], ctx : { times: number | undefined }) => boolean ;
53+ countRange: ([min , max ]: [min : number , max : number ], ctx : { times: number | undefined },
54+ runOpts : EvaluatorFuncRunOptions <IExampleCustomEvaluatorFuncRunOptions >) => Promise <boolean >;
5255}
5356
54- type IExampleExpression = Expression <IExampleContext , IExampleFunctionTable , IExampleContextIgnore >; // We pass Moment here to avoid TS exhaustion
57+ type IExampleExpression = Expression <IExampleContext , IExampleFunctionTable , IExampleContextIgnore , IExampleCustomEvaluatorFuncRunOptions >; // We pass Moment here to avoid TS exhaustion
5558
5659const context: IExampleContext = {
5760@@ -82,7 +85,8 @@ const validationContext: ValidationContext<IExampleContext, IExampleContextIgnor
8285};
8386
8487const functionsTable: IExampleFunctionTable = {
85- countRange : async ([min , max ]: [min : number , max : number ], ctx : { times: number | undefined }, runOptions : EvaluatorFuncRunOptions ): Promise <boolean > => {
88+ countRange: async ([min , max ]: [min : number , max : number ], ctx : { times: number | undefined },
89+ runOpts : EvaluatorFuncRunOptions < IExampleCustomEvaluatorFuncRunOptions > ): Promise <boolean > => {
8690 return ctx .times === undefined ? false : ctx .times >= min && ctx .times < max ;
8791 },
8892};
@@ -97,7 +101,7 @@ const expression: IExampleExpression = {
97101 lte: {
98102 op: ' +' ,
99103 lhs: {
100- ref: ' nested.value4'
104+ ref: ' nested.value4' ,
101105 },
102106 rhs: 2 ,
103107 },
@@ -114,24 +118,28 @@ const expression: IExampleExpression = {
114118 {
115119 times: {
116120 lte: {
117- ref: ' nested.value4'
118- }
121+ ref: ' nested.value4' ,
122+ },
119123 },
120124 },
121125 ],
122126 },
123127 ],
124128};
125129
126- // Example usage 1
127- const handler =
128- new ExpressionHandler <IExampleContext , IExampleFunctionTable , IExampleContextIgnore >(expression , functionsTable );
129- await handler .validate (validationContext ); // Should not throw
130- console .log (await handler .evaluate (context )); // true
131-
132- // Example usage 2
133- await validate <IExampleContext , IExampleFunctionTable , IExampleContextIgnore >(expression , validationContext , functionsTable ); // Should not throw
134- console .log (await evaluate <IExampleContext , IExampleFunctionTable , IExampleContextIgnore >(expression , context , functionsTable )); // true
130+ (async () => {
131+ // Example usage 1
132+ const handler =
133+ new ExpressionHandler < IExampleContext , IExampleFunctionTable, IExampleContextIgnore,
134+ IExampleCustomEvaluatorFuncRunOptions>(expression, functionsTable);
135+ await handler .validate (validationContext , {dryRun: false }); // Should not throw
136+ console .log (await handler .evaluate (context , {dryRun: true })); // true
137+
138+ // Example usage 2
139+ await validate < IExampleContext , IExampleFunctionTable , IExampleContextIgnore ,
140+ IExampleCustomEvaluatorFuncRunOptions > (expression , validationContext , functionsTable , {dryRun: true }); // Should not throw
141+ console .log (await evaluate <IExampleContext , IExampleFunctionTable , IExampleContextIgnore , IExampleCustomEvaluatorFuncRunOptions >(expression , context , functionsTable , {dryRun: true })); // true
142+ })()
135143```
136144
137145### Expression
@@ -140,7 +148,7 @@ There are 4 types of operators you can use (evaluated in that order of precedenc
140148- ` and ` - accepts a non-empty list of expressions
141149- ` or ` - accepts a non-empty list of expressions
142150- ` not ` - accepts another expressions
143- - ` <user defined funcs> ` - accepts any type of argument and evaluated by the user defined functions, and the given context (can be async) and run options (i.e. validation).
151+ - ` <user defined funcs> ` - accepts any type of argument and evaluated by the user defined functions, and the given context (can be async) and run options (i.e. validation + custom defined value ).
144152- ` <compare funcs> ` - operates on one of the context properties and compares it to a given value.
145153 - ` {property: {op: value}} `
146154 - available ops:
@@ -217,120 +225,133 @@ Example expressions, assuming we have the `user` and `maxCount` user defined fun
217225* Please see tests and examples dir for more usages and examples (under /src)*
218226
219227``` typescript
220- import {ValidationContext , validateRules , evaluateRules , RulesEngine , Rule , ResolvedConsequence , EngineRuleFuncRunOptions , EvaluatorFuncRunOptions } from ' json-expression-eval' ;
228+ import {ValidationContext , validateRules , evaluateRules , RulesEngine , Rule , ResolvedConsequence , EngineRuleFuncRunOptions } from ' json-expression-eval' ;
221229import {Moment } from ' moment' ;
222230import moment = require (' moment' );
223231
224232interface IExampleContext {
225- userId: string ;
226- times: number | undefined ;
227- date: Moment ;
228- nested: {
229- value: number | null ;
230- nested2: {
231- value2? : number ;
232- value3: boolean ;
233+ userId: string ;
234+ times: number | undefined ;
235+ date: Moment ;
236+ nested: {
237+ value: number | null ;
238+ nested2: {
239+ value2? : number ;
240+ value3: boolean ;
241+ };
233242 };
234- };
235243}
236244
237245type IExampleContextIgnore = Moment ;
246+
247+ type IExampleCustomEngineRuleFuncRunOptions = {dryRun: boolean };
248+
238249type IExamplePayload = number ;
239250
240251type IExampleFunctionTable = {
241- countRange: ([min , max ]: [min : number , max : number ], ctx : { times: number | undefined }, runOptions : EvaluatorFuncRunOptions ) => boolean ;
252+ countRange: ([min , max ]: [min : number , max : number ], ctx : { times: number | undefined },
253+ runOpts : EngineRuleFuncRunOptions <IExampleCustomEngineRuleFuncRunOptions >) => boolean ;
242254}
243255
244256type IExampleRuleFunctionTable = {
245- userRule: (user : string , ctx : IExampleContext , runOptions : EngineRuleFuncRunOptions ) => Promise <void | ResolvedConsequence <IExamplePayload >>;
257+ userRule: (user : string , ctx : IExampleContext ,
258+ runOpts : EngineRuleFuncRunOptions <IExampleCustomEngineRuleFuncRunOptions >) =>
259+ Promise <void | ResolvedConsequence <IExamplePayload >>;
246260}
247261
248262type IExampleRule = Rule <IExamplePayload , IExampleRuleFunctionTable , IExampleContext ,
249- IExampleFunctionTable , IExampleContextIgnore >;
263+ IExampleFunctionTable , IExampleContextIgnore , IExampleCustomEngineRuleFuncRunOptions >;
250264
251265const context: IExampleContext = {
252- 253- times: 3 ,
254- date: moment (),
255- nested: {
256- value: null ,
257- nested2: {
258- value3: true ,
266+ 267+ times: 3 ,
268+ date: moment (),
269+ nested: {
270+ value: null ,
271+ nested2: {
272+ value3: true ,
273+ },
259274 },
260- },
261275};
262276
263277// For validation we must provide a full example context
264278const validationContext: ValidationContext <IExampleContext , IExampleContextIgnore > = {
265- 266- times: 3 ,
267- date: moment (),
268- nested: {
269- value: 5 ,
270- nested2: {
271- value2: 6 ,
272- value3: true ,
279+ 280+ times: 3 ,
281+ date: moment (),
282+ nested: {
283+ value: 5 ,
284+ nested2: {
285+ value2: 6 ,
286+ value3: true ,
287+ },
273288 },
274- },
275289};
276290
277291const functionsTable: IExampleFunctionTable = {
278- countRange : ([min , max ]: [min : number , max : number ], ctx : { times: number | undefined }, runOptions : EvaluatorFuncRunOptions ): boolean => {
279- return ctx .times === undefined ? false : ctx .times >= min && ctx .times < max ;
280- },
292+ countRange: ([min , max ]: [min : number , max : number ], ctx : { times: number | undefined },
293+ runOptions : EngineRuleFuncRunOptions < IExampleCustomEngineRuleFuncRunOptions > ): boolean => {
294+ return ctx .times === undefined ? false : ctx .times >= min && ctx .times < max ;
295+ },
281296};
282297
283298const ruleFunctionsTable: IExampleRuleFunctionTable = {
284- userRule : async (user : string , ctx : IExampleContext , runOptions : EngineRuleFuncRunOptions ): Promise <void | ResolvedConsequence <number >> => {
285- if (ctx .userId === user ) {
286- return {
287- message: ` Username ${user } is not allowed ` ,
288- custom: 543 ,
289- }
290- }
291- },
299+ userRule : async (user : string , ctx : IExampleContext ,
300+ runOptions : EngineRuleFuncRunOptions <IExampleCustomEngineRuleFuncRunOptions >)
301+ : Promise <void | ResolvedConsequence <number >> => {
302+ if (ctx .userId === user ) {
303+ return {
304+ message: ` Username ${user } is not allowed ` ,
305+ custom: 543 ,
306+ }
307+ }
308+ },
292309};
293310
294311const rules: IExampleRule [] = [
295- {
296- condition: {
297- or: [
298- {
299- 312+ {
313+ condition: {
314+ or: [
315+ {
316+ 317+ },
318+ {
319+ and: [
320+ {
321+ countRange: [2 , 6 ],
322+ },
323+ {
324+ ' nested.nested2.value3' : true ,
325+ },
326+ ],
327+ },
328+ ],
300329 },
301- {
302- and: [
303- {
304- countRange: [2 , 6 ],
305- },
306- {
307- ' nested.nested2.value3' : true ,
308- },
309- ],
330+ consequence: {
331+ message: [' user' , {
332+ ref: ' userId' ,
333+ },
' should not equal [email protected] ' ],
334+ custom: 579 ,
310335 },
311- ],
312336 },
313- consequence: {
314- message: [' user' , {
315- ref: ' userId' ,
316- },
' should not equal [email protected] ' ],
317- custom: 579 ,
337+ {
338+ 318339 },
319- },
320- {
321- 322- },
323340];
324341
325- // Example usage 1
326- const engine = new RulesEngine < IExamplePayload , IExampleContext, IExampleRuleFunctionTable,
327- IExampleFunctionTable, IExampleContextIgnore>(functionsTable, ruleFunctionsTable);
328- await engine .validate (rules , validationContext ); // Should not throw
329- console .
log (
JSON .
stringify (
await engine .
evaluateAll (
rules ,
context )));
// [{"message":"user [email protected] should not equal [email protected] ","custom":579}]330-
331- // Example usage 2
332- await validateRules < IExamplePayload , IExampleContext , IExampleRuleFunctionTable ,
333- IExampleFunctionTable , IExampleContextIgnore > (rules , validationContext , functionsTable , ruleFunctionsTable ); // Should not throw
334- console .log (JSON .stringify (await evaluateRules < IExamplePayload , IExampleContext , IExampleRuleFunctionTable ,
335- IExampleFunctionTable ,
IExampleContextIgnore > (
rules ,
context ,
functionsTable ,
ruleFunctionsTable ,
false )));
// [{"message":"user [email protected] should not equal [email protected] ","custom":579}] 342+ (async () => {
343+ // Example usage 1
344+ const engine = new RulesEngine < IExamplePayload , IExampleContext, IExampleRuleFunctionTable,
345+ IExampleFunctionTable, IExampleContextIgnore, IExampleCustomEngineRuleFuncRunOptions>(
346+ functionsTable , ruleFunctionsTable );
347+ await engine .validate (rules , validationContext , {dryRun: false }); // Should not throw
348+ console .
log (
JSON .
stringify (
await engine .
evaluateAll (
rules ,
context , {dryRun:
false })));
// [{"message":"user [email protected] should not equal [email protected] ","custom":579}] 349+
350+ // Example usage 2
351+ await validateRules < IExamplePayload , IExampleContext , IExampleRuleFunctionTable ,
352+ IExampleFunctionTable , IExampleContextIgnore , IExampleCustomEngineRuleFuncRunOptions > (
353+ rules , validationContext , functionsTable , ruleFunctionsTable , {dryRun: false }); // Should not throw
354+ console .log (JSON .stringify (await evaluateRules < IExamplePayload , IExampleContext , IExampleRuleFunctionTable ,
355+ IExampleFunctionTable ,
IExampleContextIgnore ,
IExampleCustomEngineRuleFuncRunOptions > (
rules ,
context ,
functionsTable ,
ruleFunctionsTable ,
false , {dryRun:
false })));
// [{"message":"user [email protected] should not equal [email protected] ","custom":579}] 356+ })();
336357```
0 commit comments