Helpers for json-rule-engine
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { processRules, RuleEngineError } from "./ruleEngineHelpers.ts"; | |
const rules = [ruleA, ruleB, ruleC]; | |
const facts = { | |
fact1: "Some data", | |
fact2: "Some other data", | |
fact3: 42 | |
}; | |
const { errors, events } = await processRules([rule1, rule2, rule3], facts); | |
if (errors.length > 0) { | |
throw new RuleEngineError(errors); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
Rule, | |
Engine, | |
RuleResult, | |
AllConditions, | |
Almanac, | |
AnyConditions, | |
Event, | |
NestedCondition, | |
ConditionProperties | |
} from 'json-rules-engine'; | |
export async function processRules<T>(rules: Rule[], facts: T) { | |
const errors = []; | |
const engine = new Engine(rules).on( | |
'failure', | |
async (event, almanac, ruleResult) => { | |
errors.push({ | |
type: event.type, | |
failedConditions: await getFailedConditions(almanac, ruleResult) | |
}); | |
} | |
); | |
const result = await engine.run(facts); | |
return { | |
...result, | |
errors | |
}; | |
} | |
async function getFailedConditions(almanac: Almanac, ruleResult: RuleResult) { | |
const allConditions = (ruleResult.conditions as AllConditions).all || []; | |
const anyConditions = (ruleResult.conditions as AnyConditions).any || []; | |
const conditions = [ | |
...allConditions, | |
...anyConditions | |
] as (ConditionProperties & { result: unknown; factResult: unknown })[]; | |
if (conditions.length === 0) { | |
return []; | |
} | |
return Promise.all( | |
conditions | |
.filter(c => !c.result) | |
.map(async c => { | |
const fact = c.fact; | |
const expected = c.value.fact | |
? await almanac.factValue(c.value.fact) | |
: c.value; | |
const actual = c.factResult; | |
return { | |
message: `condition for ${fact} failed: expected '${expected}', actual '${actual}'`, | |
fact, | |
expected, | |
actual | |
}; | |
}) | |
); | |
} | |
export class RuleEngineError extends Error { | |
constructor(errors) { | |
const message = errors | |
.map( | |
e => `${e.type}[${e.failedConditions.map(c => c.message).join(',')}]` | |
) | |
.join('; '); | |
super(message); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment