@shepherdnerds/json-rules-engine 7.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+
7
+ var _operator = require('./operator');
8
+
9
+ var _operator2 = _interopRequireDefault(_operator);
10
+
11
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
+
13
+ var Operators = [];
14
+ Operators.push(new _operator2.default('equal', function (a, b) {
15
+ return a === b;
16
+ }));
17
+ Operators.push(new _operator2.default('notEqual', function (a, b) {
18
+ return a !== b;
19
+ }));
20
+ Operators.push(new _operator2.default('in', function (a, b) {
21
+ return b.indexOf(a) > -1;
22
+ }));
23
+ Operators.push(new _operator2.default('notIn', function (a, b) {
24
+ return b.indexOf(a) === -1;
25
+ }));
26
+
27
+ Operators.push(new _operator2.default('contains', function (a, b) {
28
+ return a.indexOf(b) > -1;
29
+ }, Array.isArray));
30
+ Operators.push(new _operator2.default('doesNotContain', function (a, b) {
31
+ return a.indexOf(b) === -1;
32
+ }, Array.isArray));
33
+
34
+ function numberValidator(factValue) {
35
+ return Number.parseFloat(factValue).toString() !== 'NaN';
36
+ }
37
+ Operators.push(new _operator2.default('lessThan', function (a, b) {
38
+ return a < b;
39
+ }, numberValidator));
40
+ Operators.push(new _operator2.default('lessThanInclusive', function (a, b) {
41
+ return a <= b;
42
+ }, numberValidator));
43
+ Operators.push(new _operator2.default('greaterThan', function (a, b) {
44
+ return a > b;
45
+ }, numberValidator));
46
+ Operators.push(new _operator2.default('greaterThanInclusive', function (a, b) {
47
+ return a >= b;
48
+ }, numberValidator));
49
+
50
+ exports.default = Operators;
package/dist/engine.js ADDED
@@ -0,0 +1,451 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.FINISHED = exports.RUNNING = exports.READY = undefined;
7
+
8
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
9
+
10
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
11
+
12
+ var _fact = require('./fact');
13
+
14
+ var _fact2 = _interopRequireDefault(_fact);
15
+
16
+ var _rule = require('./rule');
17
+
18
+ var _rule2 = _interopRequireDefault(_rule);
19
+
20
+ var _almanac = require('./almanac');
21
+
22
+ var _almanac2 = _interopRequireDefault(_almanac);
23
+
24
+ var _eventemitter = require('eventemitter2');
25
+
26
+ var _eventemitter2 = _interopRequireDefault(_eventemitter);
27
+
28
+ var _engineDefaultOperators = require('./engine-default-operators');
29
+
30
+ var _engineDefaultOperators2 = _interopRequireDefault(_engineDefaultOperators);
31
+
32
+ var _engineDefaultOperatorDecorators = require('./engine-default-operator-decorators');
33
+
34
+ var _engineDefaultOperatorDecorators2 = _interopRequireDefault(_engineDefaultOperatorDecorators);
35
+
36
+ var _debug = require('./debug');
37
+
38
+ var _debug2 = _interopRequireDefault(_debug);
39
+
40
+ var _condition = require('./condition');
41
+
42
+ var _condition2 = _interopRequireDefault(_condition);
43
+
44
+ var _operatorMap = require('./operator-map');
45
+
46
+ var _operatorMap2 = _interopRequireDefault(_operatorMap);
47
+
48
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
49
+
50
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
51
+
52
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
53
+
54
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
55
+
56
+ var READY = exports.READY = 'READY';
57
+ var RUNNING = exports.RUNNING = 'RUNNING';
58
+ var FINISHED = exports.FINISHED = 'FINISHED';
59
+
60
+ var Engine = function (_EventEmitter) {
61
+ _inherits(Engine, _EventEmitter);
62
+
63
+ /**
64
+ * Returns a new Engine instance
65
+ * @param {Rule[]} rules - array of rules to initialize with
66
+ */
67
+ function Engine() {
68
+ var rules = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
69
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
70
+
71
+ _classCallCheck(this, Engine);
72
+
73
+ var _this = _possibleConstructorReturn(this, (Engine.__proto__ || Object.getPrototypeOf(Engine)).call(this));
74
+
75
+ _this.rules = [];
76
+ _this.allowUndefinedFacts = options.allowUndefinedFacts || false;
77
+ _this.allowUndefinedConditions = options.allowUndefinedConditions || false;
78
+ _this.replaceFactsInEventParams = options.replaceFactsInEventParams || false;
79
+ _this.pathResolver = options.pathResolver;
80
+ _this.operators = new _operatorMap2.default();
81
+ _this.facts = new Map();
82
+ _this.conditions = new Map();
83
+ _this.status = READY;
84
+ rules.map(function (r) {
85
+ return _this.addRule(r);
86
+ });
87
+ _engineDefaultOperators2.default.map(function (o) {
88
+ return _this.addOperator(o);
89
+ });
90
+ _engineDefaultOperatorDecorators2.default.map(function (d) {
91
+ return _this.addOperatorDecorator(d);
92
+ });
93
+ return _this;
94
+ }
95
+
96
+ /**
97
+ * Add a rule definition to the engine
98
+ * @param {object|Rule} properties - rule definition. can be JSON representation, or instance of Rule
99
+ * @param {integer} properties.priority (>1) - higher runs sooner.
100
+ * @param {Object} properties.event - event to fire when rule evaluates as successful
101
+ * @param {string} properties.event.type - name of event to emit
102
+ * @param {string} properties.event.params - parameters to pass to the event listener
103
+ * @param {Object} properties.conditions - conditions to evaluate when processing this rule
104
+ */
105
+
106
+
107
+ _createClass(Engine, [{
108
+ key: 'addRule',
109
+ value: function addRule(properties) {
110
+ if (!properties) throw new Error('Engine: addRule() requires options');
111
+
112
+ var rule = void 0;
113
+ if (properties instanceof _rule2.default) {
114
+ rule = properties;
115
+ } else {
116
+ if (!Object.prototype.hasOwnProperty.call(properties, 'event')) throw new Error('Engine: addRule() argument requires "event" property');
117
+ if (!Object.prototype.hasOwnProperty.call(properties, 'conditions')) throw new Error('Engine: addRule() argument requires "conditions" property');
118
+ rule = new _rule2.default(properties);
119
+ }
120
+ rule.setEngine(this);
121
+ this.rules.push(rule);
122
+ this.prioritizedRules = null;
123
+ return this;
124
+ }
125
+
126
+ /**
127
+ * update a rule in the engine
128
+ * @param {object|Rule} rule - rule definition. Must be a instance of Rule
129
+ */
130
+
131
+ }, {
132
+ key: 'updateRule',
133
+ value: function updateRule(rule) {
134
+ var ruleIndex = this.rules.findIndex(function (ruleInEngine) {
135
+ return ruleInEngine.name === rule.name;
136
+ });
137
+ if (ruleIndex > -1) {
138
+ this.rules.splice(ruleIndex, 1);
139
+ this.addRule(rule);
140
+ this.prioritizedRules = null;
141
+ } else {
142
+ throw new Error('Engine: updateRule() rule not found');
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Remove a rule from the engine
148
+ * @param {object|Rule|string} rule - rule definition. Must be a instance of Rule
149
+ */
150
+
151
+ }, {
152
+ key: 'removeRule',
153
+ value: function removeRule(rule) {
154
+ var ruleRemoved = false;
155
+ if (!(rule instanceof _rule2.default)) {
156
+ var filteredRules = this.rules.filter(function (ruleInEngine) {
157
+ return ruleInEngine.name !== rule;
158
+ });
159
+ ruleRemoved = filteredRules.length !== this.rules.length;
160
+ this.rules = filteredRules;
161
+ } else {
162
+ var index = this.rules.indexOf(rule);
163
+ if (index > -1) {
164
+ ruleRemoved = Boolean(this.rules.splice(index, 1).length);
165
+ }
166
+ }
167
+ if (ruleRemoved) {
168
+ this.prioritizedRules = null;
169
+ }
170
+ return ruleRemoved;
171
+ }
172
+
173
+ /**
174
+ * sets a condition that can be referenced by the given name.
175
+ * If a condition with the given name has already been set this will replace it.
176
+ * @param {string} name - the name of the condition to be referenced by rules.
177
+ * @param {object} conditions - the conditions to use when the condition is referenced.
178
+ */
179
+
180
+ }, {
181
+ key: 'setCondition',
182
+ value: function setCondition(name, conditions) {
183
+ if (!name) throw new Error('Engine: setCondition() requires name');
184
+ if (!conditions) throw new Error('Engine: setCondition() requires conditions');
185
+ if (!Object.prototype.hasOwnProperty.call(conditions, 'all') && !Object.prototype.hasOwnProperty.call(conditions, 'any') && !Object.prototype.hasOwnProperty.call(conditions, 'not') && !Object.prototype.hasOwnProperty.call(conditions, 'condition')) {
186
+ throw new Error('"conditions" root must contain a single instance of "all", "any", "not", or "condition"');
187
+ }
188
+ this.conditions.set(name, new _condition2.default(conditions));
189
+ return this;
190
+ }
191
+
192
+ /**
193
+ * Removes a condition that has previously been added to this engine
194
+ * @param {string} name - the name of the condition to remove.
195
+ * @returns true if the condition existed, otherwise false
196
+ */
197
+
198
+ }, {
199
+ key: 'removeCondition',
200
+ value: function removeCondition(name) {
201
+ return this.conditions.delete(name);
202
+ }
203
+
204
+ /**
205
+ * Add a custom operator definition
206
+ * @param {string} operatorOrName - operator identifier within the condition; i.e. instead of 'equals', 'greaterThan', etc
207
+ * @param {function(factValue, jsonValue)} callback - the method to execute when the operator is encountered.
208
+ */
209
+
210
+ }, {
211
+ key: 'addOperator',
212
+ value: function addOperator(operatorOrName, cb) {
213
+ this.operators.addOperator(operatorOrName, cb);
214
+ }
215
+
216
+ /**
217
+ * Remove a custom operator definition
218
+ * @param {string} operatorOrName - operator identifier within the condition; i.e. instead of 'equals', 'greaterThan', etc
219
+ */
220
+
221
+ }, {
222
+ key: 'removeOperator',
223
+ value: function removeOperator(operatorOrName) {
224
+ return this.operators.removeOperator(operatorOrName);
225
+ }
226
+
227
+ /**
228
+ * Add a custom operator decorator
229
+ * @param {string} decoratorOrName - decorator identifier within the condition; i.e. instead of 'someFact', 'everyValue', etc
230
+ * @param {function(factValue, jsonValue, next)} callback - the method to execute when the decorator is encountered.
231
+ */
232
+
233
+ }, {
234
+ key: 'addOperatorDecorator',
235
+ value: function addOperatorDecorator(decoratorOrName, cb) {
236
+ this.operators.addOperatorDecorator(decoratorOrName, cb);
237
+ }
238
+
239
+ /**
240
+ * Remove a custom operator decorator
241
+ * @param {string} decoratorOrName - decorator identifier within the condition; i.e. instead of 'someFact', 'everyValue', etc
242
+ */
243
+
244
+ }, {
245
+ key: 'removeOperatorDecorator',
246
+ value: function removeOperatorDecorator(decoratorOrName) {
247
+ return this.operators.removeOperatorDecorator(decoratorOrName);
248
+ }
249
+
250
+ /**
251
+ * Add a fact definition to the engine. Facts are called by rules as they are evaluated.
252
+ * @param {object|Fact} id - fact identifier or instance of Fact
253
+ * @param {function} definitionFunc - function to be called when computing the fact value for a given rule
254
+ * @param {Object} options - options to initialize the fact with. used when "id" is not a Fact instance
255
+ */
256
+
257
+ }, {
258
+ key: 'addFact',
259
+ value: function addFact(id, valueOrMethod, options) {
260
+ var factId = id;
261
+ var fact = void 0;
262
+ if (id instanceof _fact2.default) {
263
+ factId = id.id;
264
+ fact = id;
265
+ } else {
266
+ fact = new _fact2.default(id, valueOrMethod, options);
267
+ }
268
+ (0, _debug2.default)('engine::addFact', { id: factId });
269
+ this.facts.set(factId, fact);
270
+ return this;
271
+ }
272
+
273
+ /**
274
+ * Remove a fact definition to the engine. Facts are called by rules as they are evaluated.
275
+ * @param {object|Fact} id - fact identifier or instance of Fact
276
+ */
277
+
278
+ }, {
279
+ key: 'removeFact',
280
+ value: function removeFact(factOrId) {
281
+ var factId = void 0;
282
+ if (!(factOrId instanceof _fact2.default)) {
283
+ factId = factOrId;
284
+ } else {
285
+ factId = factOrId.id;
286
+ }
287
+
288
+ return this.facts.delete(factId);
289
+ }
290
+
291
+ /**
292
+ * Iterates over the engine rules, organizing them by highest -> lowest priority
293
+ * @return {Rule[][]} two dimensional array of Rules.
294
+ * Each outer array element represents a single priority(integer). Inner array is
295
+ * all rules with that priority.
296
+ */
297
+
298
+ }, {
299
+ key: 'prioritizeRules',
300
+ value: function prioritizeRules() {
301
+ if (!this.prioritizedRules) {
302
+ var ruleSets = this.rules.reduce(function (sets, rule) {
303
+ var priority = rule.priority;
304
+ if (!sets[priority]) sets[priority] = [];
305
+ sets[priority].push(rule);
306
+ return sets;
307
+ }, {});
308
+ this.prioritizedRules = Object.keys(ruleSets).sort(function (a, b) {
309
+ return Number(a) > Number(b) ? -1 : 1; // order highest priority -> lowest
310
+ }).map(function (priority) {
311
+ return ruleSets[priority];
312
+ });
313
+ }
314
+ return this.prioritizedRules;
315
+ }
316
+
317
+ /**
318
+ * Stops the rules engine from running the next priority set of Rules. All remaining rules will be resolved as undefined,
319
+ * and no further events emitted. Since rules of the same priority are evaluated in parallel(not series), other rules of
320
+ * the same priority may still emit events, even though the engine is in a "finished" state.
321
+ * @return {Engine}
322
+ */
323
+
324
+ }, {
325
+ key: 'stop',
326
+ value: function stop() {
327
+ this.status = FINISHED;
328
+ return this;
329
+ }
330
+
331
+ /**
332
+ * Returns a fact by fact-id
333
+ * @param {string} factId - fact identifier
334
+ * @return {Fact} fact instance, or undefined if no such fact exists
335
+ */
336
+
337
+ }, {
338
+ key: 'getFact',
339
+ value: function getFact(factId) {
340
+ return this.facts.get(factId);
341
+ }
342
+
343
+ /**
344
+ * Runs an array of rules
345
+ * @param {Rule[]} array of rules to be evaluated
346
+ * @return {Promise} resolves when all rules in the array have been evaluated
347
+ */
348
+
349
+ }, {
350
+ key: 'evaluateRules',
351
+ value: function evaluateRules(ruleArray, almanac) {
352
+ var _this2 = this;
353
+
354
+ return Promise.all(ruleArray.map(function (rule) {
355
+ if (_this2.status !== RUNNING) {
356
+ (0, _debug2.default)('engine::run, skipping remaining rules', { status: _this2.status });
357
+ return Promise.resolve();
358
+ }
359
+ return rule.evaluate(almanac).then(function (ruleResult) {
360
+ (0, _debug2.default)('engine::run', { ruleResult: ruleResult.result });
361
+ almanac.addResult(ruleResult);
362
+ if (ruleResult.result) {
363
+ almanac.addEvent(ruleResult.event, 'success');
364
+ return _this2.emitAsync('success', ruleResult.event, almanac, ruleResult).then(function () {
365
+ return _this2.emitAsync(ruleResult.event.type, ruleResult.event.params, almanac, ruleResult);
366
+ });
367
+ } else {
368
+ almanac.addEvent(ruleResult.event, 'failure');
369
+ return _this2.emitAsync('failure', ruleResult.event, almanac, ruleResult);
370
+ }
371
+ });
372
+ }));
373
+ }
374
+
375
+ /**
376
+ * Runs the rules engine
377
+ * @param {Object} runtimeFacts - fact values known at runtime
378
+ * @param {Object} runOptions - run options
379
+ * @return {Promise} resolves when the engine has completed running
380
+ */
381
+
382
+ }, {
383
+ key: 'run',
384
+ value: function run() {
385
+ var _this3 = this;
386
+
387
+ var runtimeFacts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
388
+ var runOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
389
+
390
+ (0, _debug2.default)('engine::run started');
391
+ this.status = RUNNING;
392
+
393
+ var almanac = runOptions.almanac || new _almanac2.default({
394
+ allowUndefinedFacts: this.allowUndefinedFacts,
395
+ pathResolver: this.pathResolver
396
+ });
397
+
398
+ this.facts.forEach(function (fact) {
399
+ almanac.addFact(fact);
400
+ });
401
+ for (var factId in runtimeFacts) {
402
+ var fact = void 0;
403
+ if (runtimeFacts[factId] instanceof _fact2.default) {
404
+ fact = runtimeFacts[factId];
405
+ } else {
406
+ fact = new _fact2.default(factId, runtimeFacts[factId]);
407
+ }
408
+
409
+ almanac.addFact(fact);
410
+ (0, _debug2.default)('engine::run initialized runtime fact', { id: fact.id, value: fact.value, type: _typeof(fact.value) });
411
+ }
412
+ var orderedSets = this.prioritizeRules();
413
+ var cursor = Promise.resolve();
414
+ // for each rule set, evaluate in parallel,
415
+ // before proceeding to the next priority set.
416
+ return new Promise(function (resolve, reject) {
417
+ orderedSets.map(function (set) {
418
+ cursor = cursor.then(function () {
419
+ return _this3.evaluateRules(set, almanac);
420
+ }).catch(reject);
421
+ return cursor;
422
+ });
423
+ cursor.then(function () {
424
+ _this3.status = FINISHED;
425
+ (0, _debug2.default)('engine::run completed');
426
+ var ruleResults = almanac.getResults();
427
+
428
+ var _ruleResults$reduce = ruleResults.reduce(function (hash, ruleResult) {
429
+ var group = ruleResult.result ? 'results' : 'failureResults';
430
+ hash[group].push(ruleResult);
431
+ return hash;
432
+ }, { results: [], failureResults: [] }),
433
+ results = _ruleResults$reduce.results,
434
+ failureResults = _ruleResults$reduce.failureResults;
435
+
436
+ resolve({
437
+ almanac: almanac,
438
+ results: results,
439
+ failureResults: failureResults,
440
+ events: almanac.getEvents('success'),
441
+ failureEvents: almanac.getEvents('failure')
442
+ });
443
+ }).catch(reject);
444
+ });
445
+ }
446
+ }]);
447
+
448
+ return Engine;
449
+ }(_eventemitter2.default);
450
+
451
+ exports.default = Engine;
package/dist/errors.js ADDED
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+
7
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
8
+
9
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
10
+
11
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
12
+
13
+ var UndefinedFactError = exports.UndefinedFactError = function (_Error) {
14
+ _inherits(UndefinedFactError, _Error);
15
+
16
+ function UndefinedFactError() {
17
+ var _ref;
18
+
19
+ _classCallCheck(this, UndefinedFactError);
20
+
21
+ for (var _len = arguments.length, props = Array(_len), _key = 0; _key < _len; _key++) {
22
+ props[_key] = arguments[_key];
23
+ }
24
+
25
+ var _this = _possibleConstructorReturn(this, (_ref = UndefinedFactError.__proto__ || Object.getPrototypeOf(UndefinedFactError)).call.apply(_ref, [this].concat(props)));
26
+
27
+ _this.code = 'UNDEFINED_FACT';
28
+ return _this;
29
+ }
30
+
31
+ return UndefinedFactError;
32
+ }(Error);
package/dist/fact.js ADDED
@@ -0,0 +1,129 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+
7
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
8
+
9
+ var _hashIt = require('hash-it');
10
+
11
+ var _hashIt2 = _interopRequireDefault(_hashIt);
12
+
13
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
+
15
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
16
+
17
+ var Fact = function () {
18
+ /**
19
+ * Returns a new fact instance
20
+ * @param {string} id - fact unique identifer
21
+ * @param {object} options
22
+ * @param {boolean} options.cache - whether to cache the fact's value for future rules
23
+ * @param {primitive|function} valueOrMethod - constant primitive, or method to call when computing the fact's value
24
+ * @return {Fact}
25
+ */
26
+ function Fact(id, valueOrMethod, options) {
27
+ _classCallCheck(this, Fact);
28
+
29
+ this.id = id;
30
+ var defaultOptions = { cache: true };
31
+ if (typeof options === 'undefined') {
32
+ options = defaultOptions;
33
+ }
34
+ if (typeof valueOrMethod !== 'function') {
35
+ this.value = valueOrMethod;
36
+ this.type = this.constructor.CONSTANT;
37
+ } else {
38
+ this.calculationMethod = valueOrMethod;
39
+ this.type = this.constructor.DYNAMIC;
40
+ }
41
+
42
+ if (!this.id) throw new Error('factId required');
43
+
44
+ this.priority = parseInt(options.priority || 1, 10);
45
+ this.options = Object.assign({}, defaultOptions, options);
46
+ this.cacheKeyMethod = this.defaultCacheKeys;
47
+ return this;
48
+ }
49
+
50
+ _createClass(Fact, [{
51
+ key: 'isConstant',
52
+ value: function isConstant() {
53
+ return this.type === this.constructor.CONSTANT;
54
+ }
55
+ }, {
56
+ key: 'isDynamic',
57
+ value: function isDynamic() {
58
+ return this.type === this.constructor.DYNAMIC;
59
+ }
60
+
61
+ /**
62
+ * Return the fact value, based on provided parameters
63
+ * @param {object} params
64
+ * @param {Almanac} almanac
65
+ * @return {any} calculation method results
66
+ */
67
+
68
+ }, {
69
+ key: 'calculate',
70
+ value: function calculate(params, almanac) {
71
+ // if constant fact w/set value, return immediately
72
+ if (Object.prototype.hasOwnProperty.call(this, 'value')) {
73
+ return this.value;
74
+ }
75
+ return this.calculationMethod(params, almanac);
76
+ }
77
+
78
+ /**
79
+ * Return a cache key (MD5 string) based on parameters
80
+ * @param {object} obj - properties to generate a hash key from
81
+ * @return {string} MD5 string based on the hash'd object
82
+ */
83
+
84
+ }, {
85
+ key: 'defaultCacheKeys',
86
+
87
+
88
+ /**
89
+ * Default properties to use when caching a fact
90
+ * Assumes every fact is a pure function, whose computed value will only
91
+ * change when input params are modified
92
+ * @param {string} id - fact unique identifer
93
+ * @param {object} params - parameters passed to fact calcution method
94
+ * @return {object} id + params
95
+ */
96
+ value: function defaultCacheKeys(id, params) {
97
+ return { params: params, id: id };
98
+ }
99
+
100
+ /**
101
+ * Generates the fact's cache key(MD5 string)
102
+ * Returns nothing if the fact's caching has been disabled
103
+ * @param {object} params - parameters that would be passed to the computation method
104
+ * @return {string} cache key
105
+ */
106
+
107
+ }, {
108
+ key: 'getCacheKey',
109
+ value: function getCacheKey(params) {
110
+ if (this.options.cache === true) {
111
+ var cacheProperties = this.cacheKeyMethod(this.id, params);
112
+ var _hash = Fact.hashFromObject(cacheProperties);
113
+ return _hash;
114
+ }
115
+ }
116
+ }], [{
117
+ key: 'hashFromObject',
118
+ value: function hashFromObject(obj) {
119
+ return (0, _hashIt2.default)(obj);
120
+ }
121
+ }]);
122
+
123
+ return Fact;
124
+ }();
125
+
126
+ Fact.CONSTANT = 'CONSTANT';
127
+ Fact.DYNAMIC = 'DYNAMIC';
128
+
129
+ exports.default = Fact;
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+
3
+ module.exports = require('./json-rules-engine');