UNPKG

@jss-rule-engine/core

Version:

Rule engine for Sitecore JSS

219 lines (179 loc) 8.7 kB
import rulesFactory from './rules/initializeRules' import commandFactory from './commands/initializeCommands' import operatorFactory from './operators/initializeOperators' import ruleParser from './ruleParser' import ruleEngineRunner from './ruleEngineRunner' import { RuleEngineRequestContext, RuleEngineContext, RuleEngineSitecoreContext, ParsedRuleXmlData, OperatorFunctionDefinition, ConditionFunctionDefinition, ActionFunctionDefinition } from './types/ruleEngine' import { RuleEngineSessionContext } from './types/ruleEngineSessionContext' export interface IJssRuleEngine { commandDefinitions: Map<string, ActionFunctionDefinition>; ruleDefinitions: Map<string, ConditionFunctionDefinition>; operatorDefinitions: Map<string, OperatorFunctionDefinition>; debug: boolean; sitecoreContext?: RuleEngineSitecoreContext; requestContext?: RuleEngineRequestContext; mockDate?: Date; setOptions(options?: RuleEngineContext): void; initialize(options?: any): void; registerAction(id: string, command: ActionFunctionDefinition): void; registerCondition(id: string, rule: ConditionFunctionDefinition): void; registerOperator(id: string, operator: OperatorFunctionDefinition): void; parseRuleXml(ruleXml: string, ruleEngineContext: RuleEngineContext): ParsedRuleXmlData | null; setSitecoreContext(sitecoreContext: RuleEngineSitecoreContext): void; setRequestContext(requestContext?: RuleEngineRequestContext): void; setMockDate(dateObj: Date): void; getRuleEngineContext(): RuleEngineContext; runRule(parsedRule: ParsedRuleXmlData | null, ruleEngineContext: RuleEngineContext): Promise<any>; runRuleActions(parsedRule: ParsedRuleXmlData | null, ruleActions: any, ruleEngineContext: RuleEngineContext): Promise<void>; prefetchItems(ruleEngineContext: RuleEngineContext): void; parseAndRunRule(ruleXml: any, context?: RuleEngineContext): Promise<any>; debugMessage(...args: any[]): void; } export class JssRuleEngine implements IJssRuleEngine { commandDefinitions: Map<string, ActionFunctionDefinition> ruleDefinitions: Map<string, ConditionFunctionDefinition> operatorDefinitions: Map<string, OperatorFunctionDefinition> debug: boolean = false sitecoreContext?: RuleEngineSitecoreContext requestContext?: RuleEngineRequestContext mockDate?: Date constructor(options?:RuleEngineContext) { this.commandDefinitions = new Map<string, any>(); this.ruleDefinitions = new Map<string, any>(); this.operatorDefinitions = new Map<string, any>(); this.setOptions(options); this.initialize(options); } setOptions(options?:RuleEngineContext) { if(options) { this.debug = options.debug ? options.debug : false; this.sitecoreContext = options.sitecoreContext; this.requestContext = options.requestContext; this.mockDate = options.mockDate; } if(typeof(window) !== "undefined" && window && !this.requestContext) { if(!this.requestContext) { this.requestContext = { url: window.location.href }; } } this.setRequestContext(this.requestContext) } initialize(_options:any) { rulesFactory(this); commandFactory(this); operatorFactory(this); } registerAction(id:string, command:ActionFunctionDefinition) { this.commandDefinitions.set(id, command); } registerCondition(id:string, rule:ConditionFunctionDefinition) { this.ruleDefinitions.set(id, rule); } registerOperator(id:string, operator:OperatorFunctionDefinition) { this.operatorDefinitions.set(id, operator); } parseRuleXml(ruleXml:string, ruleEngineContext:RuleEngineContext) : ParsedRuleXmlData | null { var parsedRule = ruleParser(ruleXml, ruleEngineContext); return parsedRule; } setSitecoreContext(sitecoreContext:RuleEngineSitecoreContext) { this.sitecoreContext = sitecoreContext; } setRequestContext(requestContext?:RuleEngineRequestContext) { this.requestContext = requestContext; if(this.requestContext && this.requestContext.url) { console.log('Setting up request context', this.requestContext?.url) var queryString = this.requestContext.url.indexOf('?')>=0 ? this.requestContext.url.split('?')[1] : ''; console.log('Query string ', queryString) this.requestContext.queryString = queryString; const urlParams = new URLSearchParams(queryString); console.log('Url params', urlParams?.size) this.requestContext.urlParams = urlParams; this.requestContext.cookies = requestContext?.cookies; } } setMockDate(dateObj:Date) { this.mockDate = dateObj; } getRuleEngineContext() : RuleEngineContext{ var dateObj = { now: this.mockDate ? this.mockDate : new Date() }; return { //location: typeof(window) !== "undefined" && window ? window.location : null, //cookies: typeof(document) !== "undefined" && document ? document.cookie : null, sitecoreContext: this.sitecoreContext, requestContext: this.requestContext, dateTime: dateObj, sessionContext: new RuleEngineSessionContext(), //env: process.env, ruleEngine: this as JssRuleEngine, clientCommands: [] }; } async runRule(parsedRule:ParsedRuleXmlData | null, ruleEngineContext:RuleEngineContext){ var result = await ruleEngineRunner(parsedRule, ruleEngineContext); return result; } async runRuleActions(parsedRule:ParsedRuleXmlData | null, ruleActions:any, ruleEngineContext:RuleEngineContext) { console.log('#### runRuleActions ### ', parsedRule?.rules?.length, ruleActions.length); if(!parsedRule?.rules || parsedRule.rules.length != ruleActions.length) { console.warn("Parsed rules and provided rule actions array lengths doesn't match"); console.log('$$$$$', parsedRule, ruleActions); console.log('#######') return; } if(parsedRule.rules.length == 0) { console.log('Empty rules array'); } var rules = parsedRule.rules; for (let i = 0; i < rules.length; i++) { const rule = rules[i]; if(ruleActions[i] && rule.actions) { console.log('Running rule actions for rule ', i); await Promise.all(rule.actions.map(async(ruleAction)=> { console.log('Running rule action', ruleAction.id) var actionFunction = ruleEngineContext.ruleEngine?.commandDefinitions.get(ruleAction.id); if (typeof(actionFunction) === "undefined" || !ruleAction) { throw new Error('Rule definitions missing for id ' + ruleAction.id); } console.log('Running action function'); await actionFunction(ruleAction, ruleEngineContext); })); } } console.log('#### runRuleActions end'); } prefetchItems(_ruleEngineContext: RuleEngineContext){ //ruleEngineContext.prefetchKeys = uniq(ruleEngineContext.prefetchKeys); //TODO: Retrieve items for the rule here } async parseAndRunRule(ruleXml:any, context?:RuleEngineContext){ let ruleEngineContext = context ? context : this.getRuleEngineContext(); this.debugMessage('Context vars: ', ruleEngineContext.sessionContext?.keys()); let parsedRule = this.parseRuleXml(ruleXml, ruleEngineContext); this.prefetchItems(ruleEngineContext); var ruleResult = await this.runRule(parsedRule, ruleEngineContext); return ruleResult; } debugMessage(..._args: any[]) { if(this.debug && typeof(console) !== 'undefined') { console.log(..._args); } } }