@@ -47,11 +47,14 @@ interface IExampleContext {
47
47
48
48
type IExampleContextIgnore = Moment ;
49
49
50
+ type IExampleCustomEvaluatorFuncRunOptions = {dryRun: boolean };
51
+
50
52
type 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 >;
52
55
}
53
56
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
55
58
56
59
const context: IExampleContext = {
57
60
userId: ' a@b.com' ,
@@ -82,7 +85,8 @@ const validationContext: ValidationContext<IExampleContext, IExampleContextIgnor
82
85
};
83
86
84
87
const 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 > => {
86
90
return ctx .times === undefined ? false : ctx .times >= min && ctx .times < max ;
87
91
},
88
92
};
@@ -97,7 +101,7 @@ const expression: IExampleExpression = {
97
101
lte: {
98
102
op: ' +' ,
99
103
lhs: {
100
- ref: ' nested.value4'
104
+ ref: ' nested.value4' ,
101
105
},
102
106
rhs: 2 ,
103
107
},
@@ -114,24 +118,28 @@ const expression: IExampleExpression = {
114
118
{
115
119
times: {
116
120
lte: {
117
- ref: ' nested.value4'
118
- }
121
+ ref: ' nested.value4' ,
122
+ },
119
123
},
120
124
},
121
125
],
122
126
},
123
127
],
124
128
};
125
129
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
+ })()
135
143
```
136
144
137
145
### Expression
@@ -140,7 +148,7 @@ There are 4 types of operators you can use (evaluated in that order of precedenc
140
148
- ` and ` - accepts a non-empty list of expressions
141
149
- ` or ` - accepts a non-empty list of expressions
142
150
- ` 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 ).
144
152
- ` <compare funcs> ` - operates on one of the context properties and compares it to a given value.
145
153
- ` {property: {op: value}} `
146
154
- available ops:
@@ -217,120 +225,133 @@ Example expressions, assuming we have the `user` and `maxCount` user defined fun
217
225
* Please see tests and examples dir for more usages and examples (under /src)*
218
226
219
227
``` 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' ;
221
229
import {Moment } from ' moment' ;
222
230
import moment = require (' moment' );
223
231
224
232
interface 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
+ };
233
242
};
234
- };
235
243
}
236
244
237
245
type IExampleContextIgnore = Moment ;
246
+
247
+ type IExampleCustomEngineRuleFuncRunOptions = {dryRun: boolean };
248
+
238
249
type IExamplePayload = number ;
239
250
240
251
type 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 ;
242
254
}
243
255
244
256
type 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 >>;
246
260
}
247
261
248
262
type IExampleRule = Rule <IExamplePayload , IExampleRuleFunctionTable , IExampleContext ,
249
- IExampleFunctionTable , IExampleContextIgnore >;
263
+ IExampleFunctionTable , IExampleContextIgnore , IExampleCustomEngineRuleFuncRunOptions >;
250
264
251
265
const context: IExampleContext = {
252
- userId: ' a@b.com' ,
253
- times: 3 ,
254
- date: moment (),
255
- nested: {
256
- value: null ,
257
- nested2: {
258
- value3: true ,
266
+ userId: ' a@b.com' ,
267
+ times: 3 ,
268
+ date: moment (),
269
+ nested: {
270
+ value: null ,
271
+ nested2: {
272
+ value3: true ,
273
+ },
259
274
},
260
- },
261
275
};
262
276
263
277
// For validation we must provide a full example context
264
278
const validationContext: ValidationContext <IExampleContext , IExampleContextIgnore > = {
265
- userId: ' a@b.com' ,
266
- times: 3 ,
267
- date: moment (),
268
- nested: {
269
- value: 5 ,
270
- nested2: {
271
- value2: 6 ,
272
- value3: true ,
279
+ userId: ' a@b.com' ,
280
+ times: 3 ,
281
+ date: moment (),
282
+ nested: {
283
+ value: 5 ,
284
+ nested2: {
285
+ value2: 6 ,
286
+ value3: true ,
287
+ },
273
288
},
274
- },
275
289
};
276
290
277
291
const 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
+ },
281
296
};
282
297
283
298
const 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
+ },
292
309
};
293
310
294
311
const rules: IExampleRule [] = [
295
- {
296
- condition: {
297
- or: [
298
- {
299
- userId: ' a@b.com' ,
312
+ {
313
+ condition: {
314
+ or: [
315
+ {
316
+ userId: ' a@b.com' ,
317
+ },
318
+ {
319
+ and: [
320
+ {
321
+ countRange: [2 , 6 ],
322
+ },
323
+ {
324
+ ' nested.nested2.value3' : true ,
325
+ },
326
+ ],
327
+ },
328
+ ],
300
329
},
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 a@b.com' ],
334
+ custom: 579 ,
310
335
},
311
- ],
312
336
},
313
- consequence: {
314
- message: [' user' , {
315
- ref: ' userId' ,
316
- }, ' should not equal a@b.com' ],
317
- custom: 579 ,
337
+ {
338
+ userRule: ' b@c.com' ,
318
339
},
319
- },
320
- {
321
- userRule: ' b@c.com' ,
322
- },
323
340
];
324
341
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 a@b.com should not equal a@b.com","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 a@b.com should not equal a@b.com","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 a@b.com should not equal a@b.com","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 a@b.com should not equal a@b.com","custom":579}]
356
+ })();
336
357
```
0 commit comments