UNPKG

the-rule-engine

Version:

⚙️ A small fluent DSL for conditional logic (validation, gating, etc)

91 lines (86 loc) 2.41 kB
// src/index.js export function createRuleEngine() { const rules = []; let thenFn = null; let elseFn = null; const evaluateLogic = (context) => { let result = null; for (const rule of rules) { const value = rule.fn(context); switch (rule.type) { case 'when': result = value; break; case 'and': result = result && value; break; case 'or': result = result || value; break; case 'not': result = !value; break; } } return result; }; const wrapCondition = (fnOrEngine) => { if (typeof fnOrEngine === 'function') return fnOrEngine; if (fnOrEngine?.evaluateLogicOnly) { return (ctx) => fnOrEngine.evaluateLogicOnly(ctx); } throw new Error('Condition must be a function or a RuleEngine instance'); }; const api = { when(fnOrEngine) { rules.push({ type: 'when', fn: wrapCondition(fnOrEngine) }); return api; }, and(fnOrEngine) { rules.push({ type: 'and', fn: wrapCondition(fnOrEngine) }); return api; }, or(fnOrEngine) { rules.push({ type: 'or', fn: wrapCondition(fnOrEngine) }); return api; }, not(fnOrEngine) { rules.push({ type: 'not', fn: wrapCondition(fnOrEngine) }); return api; }, group(cb) { const sub = createRuleEngine(); cb(sub); rules.push({ type: rules.length === 0 ? 'when' : 'and', fn: (ctx) => sub.evaluateLogicOnly(ctx) }); return api; }, orGroup(cb) { const sub = createRuleEngine(); cb(sub); rules.push({ type: 'or', fn: (ctx) => sub.evaluateLogicOnly(ctx) }); return api; }, andGroup(cb) { const sub = createRuleEngine(); cb(sub); rules.push({ type: 'and', fn: (ctx) => sub.evaluateLogicOnly(ctx) }); return api; }, notGroup(cb) { const sub = createRuleEngine(); cb(sub); rules.push({ type: rules.length === 0 ? 'when' : 'and', fn: (ctx) => !sub.evaluateLogicOnly(ctx) }); return api; }, then(fn) { thenFn = fn; return api; }, otherwise(fn) { elseFn = fn; return api; }, evaluate(ctx) { const matched = evaluateLogic(ctx); if (matched && thenFn) return thenFn(ctx); if (!matched && elseFn) return elseFn(ctx); return null; }, evaluateLogicOnly(ctx) { return evaluateLogic(ctx); } }; return api; }