@jss-rule-engine/core
Version:
Rule engine for Sitecore JSS
158 lines (120 loc) • 5.58 kB
text/typescript
import { parseXml } from '@rgrove/parse-xml';
import { ParsedRuleXmlData, RuleActionData, RuleConditionData, RuleData, RuleEngineContext } from './types/ruleEngine';
function parseUnionCondition(conditionXmlNode: any, ruleEngineContext: RuleEngineContext) {
var parsedCondition = {
conditions: new Array<any>(),
className: conditionXmlNode.name
} as RuleConditionData;
var childNodes = conditionXmlNode.children.filter((x: any) => x.type == "element" && x.name == "condition");
childNodes.forEach((ruleXmlNode: any) => {
var parsedRule = parseCondition(ruleXmlNode, ruleEngineContext);
if (parsedRule) {
parsedCondition.conditions?.push(parsedRule);
} else {
throw new Error('Condition wasnt parsed' + ruleXmlNode);
}
});
return parsedCondition;
}
function parseRegularCondition(conditionXmlNode: any, _ruleEngineContext: RuleEngineContext) {
var parsedCondition = {
className: "condition",
attributes: new Map<string, any>()
} as RuleConditionData;
var attributeKeys = Object.keys(conditionXmlNode.attributes);
attributeKeys.forEach((attr:string) => {
switch(attr)
{
case 'id':
parsedCondition.id = conditionXmlNode.attributes[attr];
case 'except':
parsedCondition.except = conditionXmlNode.attributes[attr] == 'true';
default:
parsedCondition.attributes.set(attr, conditionXmlNode.attributes[attr]);
}
});
return parsedCondition;
}
function parseAction(actionXmlNode: any, _ruleEngineContext: RuleEngineContext) {
var parsedAction = {
className: "action",
attributes: new Map<string, any>()
} as RuleActionData;
var attributeKeys = Object.keys(actionXmlNode?.attributes);
attributeKeys.forEach(attr => {
if (attr == 'id') {
parsedAction.id = actionXmlNode.attributes[attr];
} else {
parsedAction.attributes.set(attr, actionXmlNode.attributes[attr]);
}
});
return parsedAction;
}
function parseCondition(conditionXmlNode: any, ruleEngineContext: RuleEngineContext) {
if (conditionXmlNode.name == "or" || conditionXmlNode.name == "and") {
return parseUnionCondition(conditionXmlNode, ruleEngineContext);
}
return parseRegularCondition(conditionXmlNode, ruleEngineContext);
}
export default function (ruleXml: string, ruleEngineContext: RuleEngineContext) : ParsedRuleXmlData | null {
if (!ruleXml || ruleXml.length == 0) {
return null;
}
ruleXml = ruleXml.replaceAll('\t', '').replaceAll('\n', '').replaceAll('\r', '');
let xmlDoc: any = parseXml(ruleXml);
var rulesetNode = xmlDoc.children.find((x: any) => x.type == "element" && x.name == "ruleset");
if (!rulesetNode ||
!rulesetNode.children ||
rulesetNode.type != "element" ||
rulesetNode.name != "ruleset") {
throw new Error("Ruleset node is missing.");
}
var parsedRule = {
rules: []
} as ParsedRuleXmlData;
var rulesNodes = rulesetNode.children.filter((x: any) =>
x.type == "element" && x.name == "rule");
if (!rulesNodes) {
console.log('Rule nodes are missing.');
return null;
}
rulesNodes.forEach((ruleXmlNode: any) => {
var rule = {
conditions: [],
actions: [],
attributes: new Map<string, any>()
} as RuleData;
var attributeKeys = Object.keys(ruleXmlNode.attributes);
attributeKeys.forEach((attr: string) => {
rule.attributes?.set(attr, ruleXmlNode.attributes[attr])
});
var conditionsRootNode = ruleXmlNode.children.find((x: any) => x.type == "element" && x.name == "conditions");
if (conditionsRootNode && conditionsRootNode.children) {
//ruleEngineContext.ruleEngine?.debugMessage(conditionsRootNode);
conditionsRootNode.children.filter((x: any) => x.type == "element").forEach((conditionXmlNode: any) => {
var parsedCondition = parseCondition(conditionXmlNode, ruleEngineContext);
if (parsedCondition) {
ruleEngineContext.ruleEngine?.debugMessage('Parsed condition element:');
rule.conditions?.push(parsedCondition);
} else {
throw new Error('Condition wasnt parsed ' + conditionXmlNode);
}
});
}
var actionsRootNode = ruleXmlNode.children.find((x: any) => x.type == "element" && x.name == "actions");
if (actionsRootNode && actionsRootNode.children) {
ruleEngineContext.ruleEngine?.debugMessage(actionsRootNode);
actionsRootNode.children.filter((x: any) => x.type == "element").forEach((actionXmlNode: any) => {
var parsedAction = parseAction(actionXmlNode, ruleEngineContext);
if (parsedAction) {
ruleEngineContext.ruleEngine?.debugMessage('Parsed action element:');
rule.actions?.push(parsedAction);
} else {
throw new Error('Condition wasnt parsed ' + actionXmlNode);
}
});
}
parsedRule.rules?.push(rule);
});
return parsedRule;
}