Skip to content

Instantly share code, notes, and snippets.

@adamkl
Last active Aug 4, 2020
Embed
What would you like to do?
Helpers for json-rule-engine
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);
}
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