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
JavaScript
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;
}
}