UNPKG

kantime-rule-engine

Version:

A library for custom validation in the form based on the user defined json schema.

254 lines (217 loc) 7.16 kB
import { isNullOrUndefined } from "util"; let _ = require("lodash"); let _jQ = require("jsonq"); let DataStructureMethods = require("./ruleEngineHelperMethods"); let _operators = require("./ruleEngineOperators"); let _functions = require("./ruleEngineFunctions"); let InputData = {}; let RuleOutput; export const RuleTraversal = (rulesList, RuleSetdefinition) => { let Queue = new DataStructureMethods.Queue(); _.each(rulesList, (RuleName) => { // let temp_RulesStack = new DataStructureMethods.Stack(); let tempRulesStack = LevelOrderTraversing(RuleName, RuleSetdefinition); while (!tempRulesStack.isEmpty()) { Queue.enqueue(tempRulesStack.pop()); } }); return Queue; } export const RuleParser =(RulesQueue, RuleSetdefinition, UserInPut) => { try { let RuleResult; InputData = UserInPut; RuleOutput = new Object(); _.each(RulesQueue, (RuleName) => { RuleResult = new Object(); let RuleDefinition = _jQ.pathValue(RuleSetdefinition, [RuleName]); try { let Operator = GetRuleOperator(RuleDefinition); let OperandValuesArray = GetRuleOperandsAsValues(RuleDefinition); RuleResult['val'] = RuleEvaluator(Operator, OperandValuesArray); RuleResult['hasError'] = false; RuleResult['errorMessage'] = ''; RuleOutput[RuleName] = RuleResult; } catch (error) { RuleResult['val'] = false; RuleResult['hasError'] = true; RuleResult['errorMessage'] = "[RuleName: " + RuleName + "] " + error; RuleOutput[RuleName] = RuleResult; } }); } catch (error) { throw "RuleParser -> " + error; } return RuleOutput; } //Level Order Traversing function LevelOrderTraversing(RuleName, RuleSetdefinition) { let RulesStack = new DataStructureMethods.Stack(); try { let tempRuleName = ""; let LevelOrderQueue = new DataStructureMethods.Queue(); LevelOrderQueue.enqueue(RuleName); while (LevelOrderQueue.getQueue().length > 0) { tempRuleName = LevelOrderQueue.dequeue(); let RuleDefinition = _jQ.pathValue(RuleSetdefinition, [tempRuleName]); RulesStack.push(tempRuleName); if (isNullOrUndefined(RuleDefinition)) { console.log("NullReferenceException: " + tempRuleName + " definition could not be found"); //throw "NullReferenceException: " + tempRuleName + " definition could not be found"; } else if (RuleDefinition.hasOwnProperty("Eval")) { _.each(RuleDefinition.Eval, ele => { let evalData = ele.split("."); if (evalData.indexOf("out") >= 0) { let index = evalData.indexOf("out") + 1; LevelOrderQueue.enqueue(evalData[index]); } }); } } } catch (error) { throw "LevelOrderTraversing -> " + error; } return RulesStack; } //Get Operator from Eval function GetRuleOperator(RuleDefinition) { try { if (RuleDefinition.hasOwnProperty("Eval")) { return RuleDefinition.Eval[0]; } else { throw "NullReferenceException: Object Eval is not defined"; } } catch (error) { throw "GetRuleOperator -> " + error; } } //Get the list of all Operand value function GetRuleOperandsAsValues(RuleDefinition) { try { let OperandValueArray = []; if (RuleDefinition.hasOwnProperty("Eval")) { _.each(RuleDefinition.Eval, (Operand, index) => { if (index != 0) { let Value = Operand; if (Operand.length != 0) Value = GetOperandValue(Operand); OperandValueArray.push(Value); } }); } return OperandValueArray; } catch (error) { throw "GetRuleOperandsAsValues -> " + error; } } //Get each operand value function GetOperandValue(Operand) { let OperandName = ""; let Value; let i = 0; try { if (Operand.indexOf("out.") >= 0) { i = Operand.indexOf('out.'); OperandName = Operand.substr(i, Operand.length); Value = GetValueFromOutStack(OperandName); Operand = Operand.substr(0, i - 1); } else { let isFunction = false; let isOperand = false; let KeyName; _.each(Operand.split("."), (Key) => { if (getIsFunction(Key)) isFunction = true; else if (!isOperand && getIsOperand(Key)) { if(Operand.indexOf('.') >= 0) KeyName = Key + '.'; else KeyName = Key; isOperand = true; } }); if (!isFunction && !isOperand) return Operand; i = Operand.indexOf(KeyName) OperandName = Operand.substr(i, Operand.length); Value = GetValueFromUserInput(OperandName); Operand = Operand.substr(0, i - 1); } if (Operand.length > 0) { let Data = Operand.split("."); for (let j = Data.length - 1; j >= 0; j--) { let Engine_function = _functions[Data[j]]; Value = Engine_function.apply(Value); } } } catch (error) { throw "GetOperandValue -> " + error; } return Value; } function getIsOperand (Key) { try { if (Key != undefined && Key != null && InputData.hasOwnProperty(Key)) { return true } return false; } catch (error) { return false; } } function getIsFunction (Key) { try { if (Key != undefined && Key != null && _functions.hasOwnProperty(Key)) { return true } return false; } catch (error) { return false; } } //Get the Operand value from out stack function GetValueFromOutStack(OperandName) { var Operandvalue = ""; try { let dockeylength = ("out.").length; let UserParams = OperandName.slice(dockeylength); if (UserParams != undefined && UserParams != "") { Operandvalue = RuleOutput[UserParams].val; if (Operandvalue == undefined) { throw "IndexOutOfRangeException: " + OperandName + " does not Exisits" } } } catch (error) { throw "GetOperandValuefromOutStack -> " + error; } return Operandvalue; } //Get the Operand value from user Input function GetValueFromUserInput(OperandName) { var Operandvalue = ""; try { if (OperandName != undefined && OperandName != "") { let jQinput = OperandName.split("."); let Data = []; for (let i = 0; i < jQinput.length; i++) { Data.push(jQinput[i]); if (_jQ.pathValue(InputData, Data) == undefined) return ""; } Operandvalue = _jQ.pathValue(InputData, jQinput); } } catch (error) { throw "GetValueFromUserInput -> " + error; } return Operandvalue; } //Evaluate the rule and return result function RuleEvaluator(Operator, OperandValuesArray) { try { let Engine_Operator = _operators[Operator]; return Engine_Operator.apply(OperandValuesArray); } catch (error) { throw "RuleEvaluator -> [Operator: " + Operator + ", Operands: " + OperandValuesArray + "] " + error; } }