UNPKG

4.74 kBJavaScriptView Raw
1(function() {
2 'use strict';
3 exports.version = '3.0.0';
4
5 var isEqual = require('lodash.isequal');
6 var filterd = require('lodash.filter');
7 var clonedeep = require('lodash.clonedeep');
8 var matches = require('lodash.matches');
9
10 function RuleEngine(rules, options) {
11 this.init();
12 if (typeof(rules) != "undefined") {
13 this.register(rules);
14 }
15 if (options) {
16 this.ignoreFactChanges = options.ignoreFactChanges;
17 }
18 return this;
19 }
20 RuleEngine.prototype.init = function(rules) {
21 this.rules = [];
22 this.activeRules = [];
23 };
24 RuleEngine.prototype.register = function(rules) {
25 if (Array.isArray(rules)) {
26 this.rules = this.rules.concat(rules);
27 } else if (rules !== null && typeof(rules) == "object") {
28 this.rules.push(rules);
29 }
30 this.sync();
31 };
32 RuleEngine.prototype.sync = function() {
33 this.activeRules = this.rules.filter(function(a) {
34 if (typeof(a.on) === "undefined") {
35 a.on = true;
36 }
37 if (a.on === true) {
38 return a;
39 }
40 });
41 this.activeRules.sort(function(a, b) {
42 if (a.priority && b.priority) {
43 return b.priority - a.priority;
44 } else {
45 return 0;
46 }
47 });
48 };
49 RuleEngine.prototype.execute = function(fact, callback) {
50 //these new attributes have to be in both last session and current session to support
51 // the compare function
52 var thisHolder = this;
53 var complete = false;
54 fact.result = true;
55 var session = clonedeep(fact);
56 var lastSession = clonedeep(fact);
57 var _rules = this.activeRules;
58 var matchPath = [];
59 var ignoreFactChanges = this.ignoreFactChanges;
60 (function FnRuleLoop(x) {
61 var API = {
62 "rule": function() { return _rules[x]; },
63 "when": function(outcome) {
64 if (outcome) {
65 var _consequence = _rules[x].consequence;
66 _consequence.ruleRef = _rules[x].id || _rules[x].name || 'index_'+x;
67 process.nextTick(function() {
68 matchPath.push(_consequence.ruleRef);
69 _consequence.call(session, API, session);
70 });
71 } else {
72 process.nextTick(function() {
73 API.next();
74 });
75 }
76 },
77 "restart": function() {
78 return FnRuleLoop(0);
79 },
80 "stop": function() {
81 complete = true;
82 return FnRuleLoop(0);
83 },
84 "next": function() {
85 if (!ignoreFactChanges && !isEqual(lastSession, session)) {
86 lastSession = clonedeep(session);
87 process.nextTick(function() {
88 API.restart();
89 });
90 } else {
91 process.nextTick(function() {
92 return FnRuleLoop(x + 1);
93 });
94 }
95 }
96 };
97 _rules = thisHolder.activeRules;
98 if (x < _rules.length && complete === false) {
99 var _rule = _rules[x].condition;
100 _rule.call(session, API, session);
101 } else {
102 process.nextTick(function() {
103 session.matchPath = matchPath;
104 return callback(session);
105 });
106 }
107 })(0);
108 };
109 RuleEngine.prototype.findRules = function(filter) {
110 if (typeof(filter) === "undefined") {
111 return this.rules;
112 } else {
113 var find = matches(filter);
114 return filterd(this.rules, find);
115 }
116 }
117 RuleEngine.prototype.turn = function(state, filter) {
118 var state = (state === "on" || state === "ON") ? true : false;
119 var rules = this.findRules(filter);
120 for (var i = 0, j = rules.length; i < j; i++) {
121 rules[i].on = state;
122 }
123 this.sync();
124 }
125 RuleEngine.prototype.prioritize = function(priority, filter) {
126 priority = parseInt(priority, 10);
127 var rules = this.findRules(filter);
128 for (var i = 0, j = rules.length; i < j; i++) {
129 rules[i].priority = priority;
130 }
131 this.sync();
132 }
133 module.exports = RuleEngine;
134}(module.exports));