import * as plugins from './smartrule.plugins.js'; import { Rule, TCheckFunc, TActionFunc, TTreeActionResult } from './smartrule.classes.rule.js'; export class SmartRule { public rules: Array> = []; /** * makes a decision based on the given obect and the given rules * @param objectArg */ public async makeDecision(objectArg: T) { // lets sort the rules this.rules = this.rules.sort((a, b) => { if (a.priority > b.priority) { return 1; } else { return 0; } }); // gets the next batch with the same priority const getNextParallelBatch = (priorityStart: number) => { return this.rules.filter((rule) => { return rule.priority === priorityStart; }); }; // lets run the checks const runNextBatch = async (startPriority: number, runRulesAmount: number): Promise => { const nextBatch = getNextParallelBatch(startPriority); runRulesAmount = runRulesAmount + nextBatch.length; const outcomes: TTreeActionResult[] = []; for (const rule of nextBatch) { const checkResult = await rule.checkFunction(objectArg); checkResult ? null : console.log( 'WARNING!!! Please make sure your rule always returns a statement of how to continue!' ); if (checkResult.startsWith('apply')) { await rule.actionFunction(objectArg); // here the action function is run } outcomes.push(checkResult); } if (outcomes.length > 0) { const finalOutcomeOfBatch: TTreeActionResult = outcomes.reduce( (previous, current, index, array) => { if (current.includes('continue') || previous.includes('continue')) { return 'continue'; } else { return 'stop'; } } ); if (finalOutcomeOfBatch === 'stop') { return; } } if (runRulesAmount < this.rules.length) { await runNextBatch(startPriority + 1, runRulesAmount); } else { return; } }; await runNextBatch(0, 0); } public createRule( priorityArg: number, checkFunctionArg: TCheckFunc, actionFunctionArg: TActionFunc ) { const rule = new Rule(this, priorityArg, checkFunctionArg, actionFunctionArg); this.rules.push(rule); } }