json-expression-eval
Advanced tools
Comparing version
import { RuleFunctionsTable, Rule, FunctionsTable, Context, ResolvedConsequence, ValidationContext } from '../types'; | ||
export declare const evaluateRules: <ConsequencePayload, C extends Context, RF extends RuleFunctionsTable<C, ConsequencePayload>, F extends FunctionsTable<C>, Ignore = never>(rules: Rule<ConsequencePayload, RF, C, F, Ignore>[], context: C, functionsTable: F, ruleFunctionsTable: RF, haltOnFirstMatch: boolean) => void | ResolvedConsequence<ConsequencePayload>[]; | ||
export declare const validateRules: <ConsequencePayload, C extends Context, RF extends RuleFunctionsTable<C, ConsequencePayload>, F extends FunctionsTable<C>, Ignore = never>(rules: Rule<ConsequencePayload, RF, C, F, Ignore>[], validationContext: import("../types").NonNullable<C, Ignore>, functionsTable: F, ruleFunctionsTable: RF) => void; | ||
export declare const evaluateRules: <ConsequencePayload, C extends Context, RF extends RuleFunctionsTable<C, ConsequencePayload>, F extends FunctionsTable<C>, Ignore = never>(rules: Rule<ConsequencePayload, RF, C, F, Ignore>[], context: C, functionsTable: F, ruleFunctionsTable: RF, haltOnFirstMatch: boolean) => Promise<void | ResolvedConsequence<ConsequencePayload>[]>; | ||
export declare const validateRules: <ConsequencePayload, C extends Context, RF extends RuleFunctionsTable<C, ConsequencePayload>, F extends FunctionsTable<C>, Ignore = never>(rules: Rule<ConsequencePayload, RF, C, F, Ignore>[], validationContext: import("../types").NonNullable<C, Ignore>, functionsTable: F, ruleFunctionsTable: RF) => Promise<void>; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -9,33 +18,35 @@ exports.validateRules = exports.evaluateRules = void 0; | ||
function run(rules, context, functionsTable, ruleFunctionsTable, haltOnFirstMatch, validation) { | ||
const errors = []; | ||
for (const rule of rules) { | ||
const keys = (0, helpers_1.objectKeys)(rule); | ||
const key = keys[0]; | ||
if (keys.length === 1 && key && (0, typeGuards_1.isRuleFunction)(rule, ruleFunctionsTable, key)) { | ||
const consequence = ruleFunctionsTable[key](rule[key], context); | ||
if (consequence) { | ||
errors.push(consequence); | ||
if (haltOnFirstMatch && !validation) { | ||
return errors; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const errors = []; | ||
for (const rule of rules) { | ||
const keys = (0, helpers_1.objectKeys)(rule); | ||
const key = keys[0]; | ||
if (keys.length === 1 && key && (0, typeGuards_1.isRuleFunction)(rule, ruleFunctionsTable, key)) { | ||
const consequence = yield ruleFunctionsTable[key](rule[key], context); | ||
if (consequence) { | ||
errors.push(consequence); | ||
if (haltOnFirstMatch && !validation) { | ||
return errors; | ||
} | ||
} | ||
} | ||
} | ||
else { | ||
if (!rule.condition) { | ||
throw new Error(`Missing condition for rule`); | ||
} | ||
if (!rule.consequence) { | ||
throw new Error(`Missing consequence for rule`); | ||
} | ||
if (validation) { | ||
(0, evaluator_1.validate)(rule.condition, context, functionsTable); | ||
(0, engineConsequenceEvaluator_1.evaluateEngineConsequence)(context, rule.consequence); | ||
} | ||
else { | ||
const ruleApplies = (0, evaluator_1.evaluate)(rule.condition, context, functionsTable); | ||
if (ruleApplies) { | ||
const consequence = (0, engineConsequenceEvaluator_1.evaluateEngineConsequence)(context, rule.consequence); | ||
errors.push(consequence); | ||
if (haltOnFirstMatch) { | ||
return errors; | ||
if (!rule.condition) { | ||
throw new Error(`Missing condition for rule`); | ||
} | ||
if (!rule.consequence) { | ||
throw new Error(`Missing consequence for rule`); | ||
} | ||
if (validation) { | ||
yield (0, evaluator_1.validate)(rule.condition, context, functionsTable); | ||
yield (0, engineConsequenceEvaluator_1.evaluateEngineConsequence)(context, rule.consequence); | ||
} | ||
else { | ||
const ruleApplies = yield (0, evaluator_1.evaluate)(rule.condition, context, functionsTable); | ||
if (ruleApplies) { | ||
const consequence = yield (0, engineConsequenceEvaluator_1.evaluateEngineConsequence)(context, rule.consequence); | ||
errors.push(consequence); | ||
if (haltOnFirstMatch) { | ||
return errors; | ||
} | ||
} | ||
@@ -45,13 +56,13 @@ } | ||
} | ||
} | ||
return errors.length ? errors : undefined; | ||
return errors.length ? errors : undefined; | ||
}); | ||
} | ||
const evaluateRules = (rules, context, functionsTable, ruleFunctionsTable, haltOnFirstMatch) => { | ||
const evaluateRules = (rules, context, functionsTable, ruleFunctionsTable, haltOnFirstMatch) => __awaiter(void 0, void 0, void 0, function* () { | ||
return run(rules, context, functionsTable, ruleFunctionsTable, haltOnFirstMatch, false); | ||
}; | ||
}); | ||
exports.evaluateRules = evaluateRules; | ||
const validateRules = (rules, validationContext, functionsTable, ruleFunctionsTable) => { | ||
run(rules, validationContext, functionsTable, ruleFunctionsTable, false, true); | ||
}; | ||
const validateRules = (rules, validationContext, functionsTable, ruleFunctionsTable) => __awaiter(void 0, void 0, void 0, function* () { | ||
yield run(rules, validationContext, functionsTable, ruleFunctionsTable, false, true); | ||
}); | ||
exports.validateRules = validateRules; | ||
//# sourceMappingURL=engine.js.map |
import { ResolvedConsequence, Context, RuleConsequence } from '../types'; | ||
export declare const evaluateEngineConsequence: <ConsequencePayload, C extends Context, Ignore = never>(context: C, consequence: RuleConsequence<ConsequencePayload, C, Ignore>) => ResolvedConsequence<ConsequencePayload>; | ||
export declare const evaluateEngineConsequence: <ConsequencePayload, C extends Context, Ignore = never>(context: C, consequence: RuleConsequence<ConsequencePayload, C, Ignore>) => Promise<ResolvedConsequence<ConsequencePayload>>; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.evaluateEngineConsequence = void 0; | ||
const helpers_1 = require("./helpers"); | ||
const evaluateEngineConsequence = (context, consequence) => { | ||
const evaluateEngineConsequence = (context, consequence) => __awaiter(void 0, void 0, void 0, function* () { | ||
let messageParts; | ||
@@ -26,4 +35,4 @@ if (typeof consequence.message === 'string') { | ||
}; | ||
}; | ||
}); | ||
exports.evaluateEngineConsequence = evaluateEngineConsequence; | ||
//# sourceMappingURL=engineConsequenceEvaluator.js.map |
import { Context, Expression, FunctionsTable, ValidationContext } from '../types'; | ||
export declare const evaluate: <C extends Context, F extends FunctionsTable<C>, Ignore = never>(expression: import("ts-toolbelt/out/Object/Either").Either<import("../types").FullExpression<C, F, Ignore>, "not" | "or" | "and" | import("ts-toolbelt/out/String/Join").Join<import("../types").Paths<C, [], any[] | Ignore, string>, "."> | keyof F, 1>, context: C, functionsTable: F) => boolean; | ||
export declare const validate: <C extends Context, F extends FunctionsTable<C>, Ignore = never>(expression: import("ts-toolbelt/out/Object/Either").Either<import("../types").FullExpression<C, F, Ignore>, "not" | "or" | "and" | import("ts-toolbelt/out/String/Join").Join<import("../types").Paths<C, [], any[] | Ignore, string>, "."> | keyof F, 1>, validationContext: import("../types").NonNullable<C, Ignore>, functionsTable: F) => void; | ||
export declare const evaluate: <C extends Context, F extends FunctionsTable<C>, Ignore = never>(expression: import("ts-toolbelt/out/Object/Either").Either<import("../types").FullExpression<C, F, Ignore>, "not" | "or" | "and" | import("ts-toolbelt/out/String/Join").Join<import("../types").Paths<C, [], any[] | Ignore, string>, "."> | keyof F, 1>, context: C, functionsTable: F) => Promise<boolean>; | ||
export declare const validate: <C extends Context, F extends FunctionsTable<C>, Ignore = never>(expression: import("ts-toolbelt/out/Object/Either").Either<import("../types").FullExpression<C, F, Ignore>, "not" | "or" | "and" | import("ts-toolbelt/out/String/Join").Join<import("../types").Paths<C, [], any[] | Ignore, string>, "."> | keyof F, 1>, validationContext: import("../types").NonNullable<C, Ignore>, functionsTable: F) => Promise<void>; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -20,137 +29,145 @@ exports.validate = exports.evaluate = void 0; | ||
function evaluateCompareOp(expressionValue, expressionKey, contextValue, context, validation) { | ||
if (!(0, typeGuards_1._isObject)(expressionValue)) { | ||
return contextValue === expressionValue; | ||
} | ||
const compareKeys = (0, helpers_1.objectKeys)(expressionValue); | ||
if (compareKeys.length !== 1) { | ||
throw new Error('Invalid expression - too may keys'); | ||
} | ||
if ((0, typeGuards_1.isEqualCompareOp)(expressionValue)) { | ||
return contextValue === extractValueOrRef(context, validation, expressionValue.eq); | ||
} | ||
else if ((0, typeGuards_1.isNotEqualCompareOp)(expressionValue)) { | ||
return contextValue !== extractValueOrRef(context, validation, expressionValue.neq); | ||
} | ||
else if ((0, typeGuards_1.isInqCompareOp)(expressionValue)) { | ||
return expressionValue.inq.map((value) => extractValueOrRef(context, validation, value)) | ||
.indexOf(contextValue) >= 0; | ||
} | ||
else if ((0, typeGuards_1.isNinCompareOp)(expressionValue)) { | ||
return expressionValue.nin.map((value) => extractValueOrRef(context, validation, value)) | ||
.indexOf(contextValue) < 0; | ||
} | ||
else if ((0, typeGuards_1.isRegexCompareOp)(expressionValue)) { | ||
(0, helpers_1.contextStringAssertion)(expressionKey, contextValue); | ||
const regexpValue = extractValueOrRef(context, validation, expressionValue.regexp); | ||
(0, helpers_1.expressionStringAssertion)(expressionKey, regexpValue); | ||
return Boolean(contextValue.match(new RegExp(regexpValue))); | ||
} | ||
else if ((0, typeGuards_1.isRegexiCompareOp)(expressionValue)) { | ||
(0, helpers_1.contextStringAssertion)(expressionKey, contextValue); | ||
const regexpiValue = extractValueOrRef(context, validation, expressionValue.regexpi); | ||
(0, helpers_1.expressionStringAssertion)(expressionKey, regexpiValue); | ||
return Boolean(contextValue.match(new RegExp(regexpiValue, `i`))); | ||
} | ||
else if ((0, typeGuards_1.isGtCompareOp)(expressionValue)) { | ||
(0, helpers_1.contextNumberAssertion)(expressionKey, contextValue); | ||
const gtValue = extractValueOrRef(context, validation, expressionValue.gt); | ||
(0, helpers_1.expressionNumberAssertion)(expressionKey, gtValue); | ||
return contextValue > gtValue; | ||
} | ||
else if ((0, typeGuards_1.isGteCompareOp)(expressionValue)) { | ||
(0, helpers_1.contextNumberAssertion)(expressionKey, contextValue); | ||
const gteValue = extractValueOrRef(context, validation, expressionValue.gte); | ||
(0, helpers_1.expressionNumberAssertion)(expressionKey, gteValue); | ||
return contextValue >= gteValue; | ||
} | ||
else if ((0, typeGuards_1.isLteCompareOp)(expressionValue)) { | ||
(0, helpers_1.contextNumberAssertion)(expressionKey, contextValue); | ||
const lteValue = extractValueOrRef(context, validation, expressionValue.lte); | ||
(0, helpers_1.expressionNumberAssertion)(expressionKey, lteValue); | ||
return contextValue <= lteValue; | ||
} | ||
else if ((0, typeGuards_1.isLtCompareOp)(expressionValue)) { | ||
(0, helpers_1.contextNumberAssertion)(expressionKey, contextValue); | ||
const ltValue = extractValueOrRef(context, validation, expressionValue.lt); | ||
(0, helpers_1.expressionNumberAssertion)(expressionKey, ltValue); | ||
return contextValue < ltValue; | ||
} | ||
else if ((0, typeGuards_1.isBetweenCompareOp)(expressionValue)) { | ||
(0, helpers_1.contextNumberAssertion)(expressionKey, contextValue); | ||
if (expressionValue.between.length !== 2) { | ||
throw new Error(`Invalid expression - ${expressionKey}.length must be 2`); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!(0, typeGuards_1._isObject)(expressionValue)) { | ||
return contextValue === expressionValue; | ||
} | ||
const [lowRaw, highRaw] = expressionValue.between; | ||
const low = extractValueOrRef(context, validation, lowRaw); | ||
const high = extractValueOrRef(context, validation, highRaw); | ||
(0, helpers_1.expressionNumberAssertion)(`${expressionKey}[0]`, low); | ||
(0, helpers_1.expressionNumberAssertion)(`${expressionKey}[1]`, high); | ||
if (low > high) { | ||
throw new Error(`Invalid expression - ${expressionKey} first value is higher than second value`); | ||
const compareKeys = (0, helpers_1.objectKeys)(expressionValue); | ||
if (compareKeys.length !== 1) { | ||
throw new Error('Invalid expression - too may keys'); | ||
} | ||
return contextValue >= low && contextValue <= high; | ||
} | ||
else { | ||
return (0, helpers_1.assertUnreachable)(expressionValue, `Invalid expression - unknown op ${compareKeys[0]}`); | ||
} | ||
if ((0, typeGuards_1.isEqualCompareOp)(expressionValue)) { | ||
return contextValue === extractValueOrRef(context, validation, expressionValue.eq); | ||
} | ||
else if ((0, typeGuards_1.isNotEqualCompareOp)(expressionValue)) { | ||
return contextValue !== extractValueOrRef(context, validation, expressionValue.neq); | ||
} | ||
else if ((0, typeGuards_1.isInqCompareOp)(expressionValue)) { | ||
return expressionValue.inq.map((value) => extractValueOrRef(context, validation, value)) | ||
.indexOf(contextValue) >= 0; | ||
} | ||
else if ((0, typeGuards_1.isNinCompareOp)(expressionValue)) { | ||
return expressionValue.nin.map((value) => extractValueOrRef(context, validation, value)) | ||
.indexOf(contextValue) < 0; | ||
} | ||
else if ((0, typeGuards_1.isRegexCompareOp)(expressionValue)) { | ||
(0, helpers_1.contextStringAssertion)(expressionKey, contextValue); | ||
const regexpValue = extractValueOrRef(context, validation, expressionValue.regexp); | ||
(0, helpers_1.expressionStringAssertion)(expressionKey, regexpValue); | ||
return Boolean(contextValue.match(new RegExp(regexpValue))); | ||
} | ||
else if ((0, typeGuards_1.isRegexiCompareOp)(expressionValue)) { | ||
(0, helpers_1.contextStringAssertion)(expressionKey, contextValue); | ||
const regexpiValue = extractValueOrRef(context, validation, expressionValue.regexpi); | ||
(0, helpers_1.expressionStringAssertion)(expressionKey, regexpiValue); | ||
return Boolean(contextValue.match(new RegExp(regexpiValue, `i`))); | ||
} | ||
else if ((0, typeGuards_1.isGtCompareOp)(expressionValue)) { | ||
(0, helpers_1.contextNumberAssertion)(expressionKey, contextValue); | ||
const gtValue = extractValueOrRef(context, validation, expressionValue.gt); | ||
(0, helpers_1.expressionNumberAssertion)(expressionKey, gtValue); | ||
return contextValue > gtValue; | ||
} | ||
else if ((0, typeGuards_1.isGteCompareOp)(expressionValue)) { | ||
(0, helpers_1.contextNumberAssertion)(expressionKey, contextValue); | ||
const gteValue = extractValueOrRef(context, validation, expressionValue.gte); | ||
(0, helpers_1.expressionNumberAssertion)(expressionKey, gteValue); | ||
return contextValue >= gteValue; | ||
} | ||
else if ((0, typeGuards_1.isLteCompareOp)(expressionValue)) { | ||
(0, helpers_1.contextNumberAssertion)(expressionKey, contextValue); | ||
const lteValue = extractValueOrRef(context, validation, expressionValue.lte); | ||
(0, helpers_1.expressionNumberAssertion)(expressionKey, lteValue); | ||
return contextValue <= lteValue; | ||
} | ||
else if ((0, typeGuards_1.isLtCompareOp)(expressionValue)) { | ||
(0, helpers_1.contextNumberAssertion)(expressionKey, contextValue); | ||
const ltValue = extractValueOrRef(context, validation, expressionValue.lt); | ||
(0, helpers_1.expressionNumberAssertion)(expressionKey, ltValue); | ||
return contextValue < ltValue; | ||
} | ||
else if ((0, typeGuards_1.isBetweenCompareOp)(expressionValue)) { | ||
(0, helpers_1.contextNumberAssertion)(expressionKey, contextValue); | ||
if (expressionValue.between.length !== 2) { | ||
throw new Error(`Invalid expression - ${expressionKey}.length must be 2`); | ||
} | ||
const [lowRaw, highRaw] = expressionValue.between; | ||
const low = extractValueOrRef(context, validation, lowRaw); | ||
const high = extractValueOrRef(context, validation, highRaw); | ||
(0, helpers_1.expressionNumberAssertion)(`${expressionKey}[0]`, low); | ||
(0, helpers_1.expressionNumberAssertion)(`${expressionKey}[1]`, high); | ||
if (low > high) { | ||
throw new Error(`Invalid expression - ${expressionKey} first value is higher than second value`); | ||
} | ||
return contextValue >= low && contextValue <= high; | ||
} | ||
else { | ||
return (0, helpers_1.assertUnreachable)(expressionValue, `Invalid expression - unknown op ${compareKeys[0]}`); | ||
} | ||
}); | ||
} | ||
function handleAndOp(andExpression, context, functionsTable, validation) { | ||
if (andExpression.length === 0) { | ||
throw new Error('Invalid expression - and operator must have at least one expression'); | ||
} | ||
for (const currExpression of andExpression) { | ||
const result = run(currExpression, context, functionsTable, validation); | ||
if (!validation && !result) { | ||
return false; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (andExpression.length === 0) { | ||
throw new Error('Invalid expression - and operator must have at least one expression'); | ||
} | ||
} | ||
return true; | ||
for (const currExpression of andExpression) { | ||
const result = yield run(currExpression, context, functionsTable, validation); | ||
if (!validation && !result) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
}); | ||
} | ||
function handleOrOp(orExpression, context, functionsTable, validation) { | ||
if (orExpression.length === 0) { | ||
throw new Error('Invalid expression - or operator must have at least one expression'); | ||
} | ||
for (const currExpression of orExpression) { | ||
const result = run(currExpression, context, functionsTable, validation); | ||
if (!validation && result) { | ||
return true; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (orExpression.length === 0) { | ||
throw new Error('Invalid expression - or operator must have at least one expression'); | ||
} | ||
} | ||
return false; | ||
for (const currExpression of orExpression) { | ||
const result = yield run(currExpression, context, functionsTable, validation); | ||
if (!validation && result) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}); | ||
} | ||
function run(expression, context, functionsTable, validation) { | ||
const expressionKeys = (0, helpers_1.objectKeys)(expression); | ||
if (expressionKeys.length !== 1) { | ||
throw new Error('Invalid expression - too may keys'); | ||
} | ||
const expressionKey = expressionKeys[0]; | ||
if ((0, typeGuards_1.isAndCompareOp)(expression)) { | ||
return handleAndOp(expression.and, context, functionsTable, validation); | ||
} | ||
else if ((0, typeGuards_1.isOrCompareOp)(expression)) { | ||
return handleOrOp(expression.or, context, functionsTable, validation); | ||
} | ||
else if ((0, typeGuards_1.isNotCompareOp)(expression)) { | ||
return !run(expression.not, context, functionsTable, validation); | ||
} | ||
else if ((0, typeGuards_1.isFunctionCompareOp)(expression, functionsTable, expressionKey)) { | ||
return validation ? true : functionsTable[expressionKey](expression[expressionKey], context); | ||
} | ||
else { | ||
const { value: contextValue, exists } = (0, helpers_1.getFromPath)(context, expressionKey); | ||
if (validation && !exists) { | ||
throw new Error(`Invalid expression - unknown context key ${expressionKey}`); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const expressionKeys = (0, helpers_1.objectKeys)(expression); | ||
if (expressionKeys.length !== 1) { | ||
throw new Error('Invalid expression - too may keys'); | ||
} | ||
return evaluateCompareOp(expression[expressionKey], expressionKey, contextValue, context, validation); | ||
} | ||
const expressionKey = expressionKeys[0]; | ||
if ((0, typeGuards_1.isAndCompareOp)(expression)) { | ||
return handleAndOp(expression.and, context, functionsTable, validation); | ||
} | ||
else if ((0, typeGuards_1.isOrCompareOp)(expression)) { | ||
return handleOrOp(expression.or, context, functionsTable, validation); | ||
} | ||
else if ((0, typeGuards_1.isNotCompareOp)(expression)) { | ||
return !(yield run(expression.not, context, functionsTable, validation)); | ||
} | ||
else if ((0, typeGuards_1.isFunctionCompareOp)(expression, functionsTable, expressionKey)) { | ||
return validation ? true : yield functionsTable[expressionKey](expression[expressionKey], context); | ||
} | ||
else { | ||
const { value: contextValue, exists } = (0, helpers_1.getFromPath)(context, expressionKey); | ||
if (validation && !exists) { | ||
throw new Error(`Invalid expression - unknown context key ${expressionKey}`); | ||
} | ||
return evaluateCompareOp(expression[expressionKey], expressionKey, contextValue, context, validation); | ||
} | ||
}); | ||
} | ||
const evaluate = (expression, context, functionsTable) => { | ||
const evaluate = (expression, context, functionsTable) => __awaiter(void 0, void 0, void 0, function* () { | ||
return run(expression, context, functionsTable, false); | ||
}; | ||
}); | ||
exports.evaluate = evaluate; | ||
// Throws in case of validation error. Does not run functions or compare fields | ||
const validate = (expression, validationContext, functionsTable) => { | ||
run(expression, validationContext, functionsTable, true); | ||
}; | ||
const validate = (expression, validationContext, functionsTable) => __awaiter(void 0, void 0, void 0, function* () { | ||
yield run(expression, validationContext, functionsTable, true); | ||
}); | ||
exports.validate = validate; | ||
//# sourceMappingURL=evaluator.js.map |
@@ -6,4 +6,4 @@ import { Context, Expression, FunctionsTable, ValidationContext } from '../types'; | ||
constructor(expression: Expression<C, F, Ignore>, functionsTable: F); | ||
evaluate(context: C): boolean; | ||
validate(validationContext: ValidationContext<C, Ignore>): void; | ||
evaluate(context: C): Promise<boolean>; | ||
validate(validationContext: ValidationContext<C, Ignore>): Promise<void>; | ||
} |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -11,6 +20,10 @@ exports.ExpressionHandler = void 0; | ||
evaluate(context) { | ||
return (0, evaluator_1.evaluate)(this.expression, context, this.functionsTable); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return (0, evaluator_1.evaluate)(this.expression, context, this.functionsTable); | ||
}); | ||
} | ||
validate(validationContext) { | ||
(0, evaluator_1.validate)(this.expression, validationContext, this.functionsTable); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
yield (0, evaluator_1.validate)(this.expression, validationContext, this.functionsTable); | ||
}); | ||
} | ||
@@ -17,0 +30,0 @@ } |
@@ -6,5 +6,5 @@ import { Context, FunctionsTable, ValidationContext, RuleFunctionsTable, Rule, ResolvedConsequence } from '../types'; | ||
constructor(functionsTable: F, ruleFunctionsTable: RF); | ||
evaluate(rules: Rule<ConsequencePayload, RF, C, F, Ignore>[], context: C): void | ResolvedConsequence<ConsequencePayload>; | ||
evaluateAll(rules: Rule<ConsequencePayload, RF, C, F, Ignore>[], context: C): void | ResolvedConsequence<ConsequencePayload>[]; | ||
validate(rules: Rule<ConsequencePayload, RF, C, F, Ignore>[], validationContext: ValidationContext<C, Ignore>): void; | ||
evaluate(rules: Rule<ConsequencePayload, RF, C, F, Ignore>[], context: C): Promise<void | ResolvedConsequence<ConsequencePayload>>; | ||
evaluateAll(rules: Rule<ConsequencePayload, RF, C, F, Ignore>[], context: C): Promise<void | ResolvedConsequence<ConsequencePayload>[]>; | ||
validate(rules: Rule<ConsequencePayload, RF, C, F, Ignore>[], validationContext: ValidationContext<C, Ignore>): Promise<void>; | ||
} |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -12,9 +21,15 @@ exports.RulesEngine = void 0; | ||
var _a; | ||
return (_a = (0, engine_1.evaluateRules)(rules, context, this.functionsTable, this.ruleFunctionsTable, true)) === null || _a === void 0 ? void 0 : _a[0]; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return (_a = (yield (0, engine_1.evaluateRules)(rules, context, this.functionsTable, this.ruleFunctionsTable, true))) === null || _a === void 0 ? void 0 : _a[0]; | ||
}); | ||
} | ||
evaluateAll(rules, context) { | ||
return (0, engine_1.evaluateRules)(rules, context, this.functionsTable, this.ruleFunctionsTable, false); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return (0, engine_1.evaluateRules)(rules, context, this.functionsTable, this.ruleFunctionsTable, false); | ||
}); | ||
} | ||
validate(rules, validationContext) { | ||
(0, engine_1.validateRules)(rules, validationContext, this.functionsTable, this.ruleFunctionsTable); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
yield (0, engine_1.validateRules)(rules, validationContext, this.functionsTable, this.ruleFunctionsTable); | ||
}); | ||
} | ||
@@ -21,0 +36,0 @@ } |
@@ -18,5 +18,5 @@ import { Context, FunctionsTable, Expression, StringPaths, RequireOnlyOne } from './evaluator'; | ||
} | ||
export declare type RuleFunc<C, ConsequencePayload> = (param: any, context: C) => (void | ResolvedConsequence<ConsequencePayload>); | ||
export declare type RuleFunc<C, ConsequencePayload> = (param: any, context: C) => void | ResolvedConsequence<ConsequencePayload> | Promise<(void | ResolvedConsequence<ConsequencePayload>)>; | ||
export declare type RuleFunctionsTable<C, ConsequencePayload> = Record<string, RuleFunc<C, ConsequencePayload>>; | ||
export declare type RuleFunctionParam<ConsequencePayload, C extends Context, RF extends RuleFunctionsTable<C, ConsequencePayload>, K extends keyof RF> = Parameters<RF[K]>[0]; | ||
export declare type RuleFunctionParam<ConsequencePayload, C extends Context, RF extends RuleFunctionsTable<C, ConsequencePayload>, K extends keyof RF> = Awaited<Parameters<RF[K]>[0]>; | ||
export declare type RuleFunctionsParams<ConsequencePayload, C extends Context, RF extends RuleFunctionsTable<C, ConsequencePayload>> = { | ||
@@ -23,0 +23,0 @@ [K in keyof RF]: RuleFunctionParam<ConsequencePayload, C, RF, K>; |
import { Object, String, Union } from 'ts-toolbelt'; | ||
import { Paths } from './paths'; | ||
import { NonNullable } from './required'; | ||
export declare type FuncCompareOp<C extends Context, F extends FunctionsTable<C>, K extends keyof F> = Parameters<F[K]>[0]; | ||
export declare type FuncCompareOp<C extends Context, F extends FunctionsTable<C>, K extends keyof F> = Awaited<Parameters<F[K]>[0]>; | ||
export declare type StringPaths<O extends object, Ignore> = String.Join<Paths<O, [], Ignore | any[], string>, '.'>; | ||
@@ -70,5 +70,5 @@ export declare type Primitive = string | number | boolean; | ||
export declare type Expression<C extends Context, F extends FunctionsTable<C>, Ignore = never> = RequireOnlyOne<FullExpression<C, F, Ignore>>; | ||
export declare type Func<T> = (param: any, context: T) => boolean; | ||
export declare type Func<T> = (param: any, context: T) => boolean | Promise<boolean>; | ||
export declare type FunctionsTable<T> = Record<string, Func<T>>; | ||
export declare type Context = Record<string, any>; | ||
export declare type ValidationContext<C extends Context, Ignore = never> = NonNullable<C, Ignore>; |
{ | ||
"name": "json-expression-eval", | ||
"version": "4.3.0", | ||
"version": "5.0.0", | ||
"description": "json serializable rule engine / boolean expression evaluator", | ||
@@ -52,2 +52,3 @@ "main": "dist/index.js", | ||
"@types/chai": "^4.2.16", | ||
"@types/chai-as-promised": "^7.1.5", | ||
"@types/mocha": "^8.2.2", | ||
@@ -57,2 +58,3 @@ "@types/node": "^14.14.37", | ||
"chai": "^4.3.4", | ||
"chai-as-promised": "^7.1.1", | ||
"mocha": "^6.2.3", | ||
@@ -59,0 +61,0 @@ "moment": "^2.29.1", |
@@ -85,3 +85,3 @@ [](https://www.npmjs.com/package/json-expression-eval) | ||
const functionsTable: IExampleFunctionTable = { | ||
countRange: ([min, max]: [min: number, max: number], ctx: { times: number | undefined }): boolean => { | ||
countRange: async ([min, max]: [min: number, max: number], ctx: { times: number | undefined }): Promise<boolean> => { | ||
return ctx.times === undefined ? false : ctx.times >= min && ctx.times < max; | ||
@@ -119,8 +119,8 @@ }, | ||
new ExpressionHandler<IExampleContext, IExampleFunctionTable, IExampleContextIgnore>(expression, functionsTable); | ||
handler.validate(validationContext); // Should not throw | ||
console.log(handler.evaluate(context)); // true | ||
await handler.validate(validationContext); // Should not throw | ||
console.log(await handler.evaluate(context)); // true | ||
// Example usage 2 | ||
validate<IExampleContext, IExampleFunctionTable, IExampleContextIgnore>(expression, validationContext, functionsTable); // Should not throw | ||
console.log(evaluate<IExampleContext, IExampleFunctionTable, IExampleContextIgnore>(expression, context, functionsTable)); // true | ||
await validate<IExampleContext, IExampleFunctionTable, IExampleContextIgnore>(expression, validationContext, functionsTable); // Should not throw | ||
console.log(await evaluate<IExampleContext, IExampleFunctionTable, IExampleContextIgnore>(expression, context, functionsTable)); // true | ||
``` | ||
@@ -134,3 +134,3 @@ | ||
- `not` - accepts another expressions | ||
- `<user defined funcs>` - accepts any type of argument and evaluated by the user defined functions and the given context. | ||
- `<user defined funcs>` - accepts any type of argument and evaluated by the user defined functions and the given context. Can be async. | ||
- `<compare funcs>` - operates on one of the context properties and compares it to a given value. | ||
@@ -214,3 +214,3 @@ - `{property: {op: value}}` | ||
type IExampleRuleFunctionTable = { | ||
userRule: (user: string, ctx: IExampleContext) => void | ResolvedConsequence<IExamplePayload>; | ||
userRule: (user: string, ctx: IExampleContext) => Promise<void | ResolvedConsequence<IExamplePayload>>; | ||
} | ||
@@ -254,3 +254,3 @@ | ||
const ruleFunctionsTable: IExampleRuleFunctionTable = { | ||
userRule: (user: string, ctx: IExampleContext): void | ResolvedConsequence<number> => { | ||
userRule: async (user: string, ctx: IExampleContext): Promise<void | ResolvedConsequence<number>> => { | ||
if (ctx.userId === user) { | ||
@@ -299,10 +299,10 @@ return { | ||
IExampleFunctionTable, IExampleContextIgnore>(functionsTable, ruleFunctionsTable); | ||
engine.validate(rules, validationContext); // Should not throw | ||
console.log(JSON.stringify(engine.evaluateAll(rules, context))); // [{"message":"user a@b.com should not equal a@b.com","custom":579}] | ||
await engine.validate(rules, validationContext); // Should not throw | ||
console.log(JSON.stringify(await engine.evaluateAll(rules, context))); // [{"message":"user a@b.com should not equal a@b.com","custom":579}] | ||
// Example usage 2 | ||
validateRules<IExamplePayload, IExampleContext, IExampleRuleFunctionTable, | ||
await validateRules<IExamplePayload, IExampleContext, IExampleRuleFunctionTable, | ||
IExampleFunctionTable, IExampleContextIgnore>(rules, validationContext, functionsTable, ruleFunctionsTable); // Should not throw | ||
console.log(JSON.stringify(evaluateRules<IExamplePayload, IExampleContext, IExampleRuleFunctionTable, | ||
console.log(JSON.stringify(await evaluateRules<IExamplePayload, IExampleContext, IExampleRuleFunctionTable, | ||
IExampleFunctionTable, IExampleContextIgnore>(rules, context, functionsTable, ruleFunctionsTable, false))); // [{"message":"user a@b.com should not equal a@b.com","custom":579}] | ||
``` |
Sorry, the diff of this file is not supported yet
191555
3.43%717
9.97%16
14.29%