UNPKG

6.86 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _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
9var _debug = require('./debug');
10
11var _debug2 = _interopRequireDefault(_debug);
12
13var _lodash = require('lodash.isobjectlike');
14
15var _lodash2 = _interopRequireDefault(_lodash);
16
17function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18
19function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
20
21var Condition = function () {
22 function Condition(properties) {
23 _classCallCheck(this, Condition);
24
25 if (!properties) throw new Error('Condition: constructor options required');
26 var booleanOperator = Condition.booleanOperator(properties);
27 Object.assign(this, properties);
28 if (booleanOperator) {
29 var subConditions = properties[booleanOperator];
30 if (!Array.isArray(subConditions)) {
31 throw new Error('"' + booleanOperator + '" must be an array');
32 }
33 this.operator = booleanOperator;
34 // boolean conditions always have a priority; default 1
35 this.priority = parseInt(properties.priority, 10) || 1;
36 this[booleanOperator] = subConditions.map(function (c) {
37 return new Condition(c);
38 });
39 } else {
40 if (!Object.prototype.hasOwnProperty.call(properties, 'fact')) throw new Error('Condition: constructor "fact" property required');
41 if (!Object.prototype.hasOwnProperty.call(properties, 'operator')) throw new Error('Condition: constructor "operator" property required');
42 if (!Object.prototype.hasOwnProperty.call(properties, 'value')) throw new Error('Condition: constructor "value" property required');
43
44 // a non-boolean condition does not have a priority by default. this allows
45 // priority to be dictated by the fact definition
46 if (Object.prototype.hasOwnProperty.call(properties, 'priority')) {
47 properties.priority = parseInt(properties.priority, 10);
48 }
49 }
50 }
51
52 /**
53 * Converts the condition into a json-friendly structure
54 * @param {Boolean} stringify - whether to return as a json string
55 * @returns {string,object} json string or json-friendly object
56 */
57
58
59 _createClass(Condition, [{
60 key: 'toJSON',
61 value: function toJSON() {
62 var stringify = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
63
64 var props = {};
65 if (this.priority) {
66 props.priority = this.priority;
67 }
68 var oper = Condition.booleanOperator(this);
69 if (oper) {
70 props[oper] = this[oper].map(function (c) {
71 return c.toJSON(stringify);
72 });
73 } else {
74 props.operator = this.operator;
75 props.value = this.value;
76 props.fact = this.fact;
77 if (this.factResult !== undefined) {
78 props.factResult = this.factResult;
79 }
80 if (this.result !== undefined) {
81 props.result = this.result;
82 }
83 if (this.params) {
84 props.params = this.params;
85 }
86 if (this.path) {
87 props.path = this.path;
88 }
89 }
90 if (stringify) {
91 return JSON.stringify(props);
92 }
93 return props;
94 }
95
96 /**
97 * Interprets .value as either a primitive, or if a fact, retrieves the fact value
98 */
99
100 }, {
101 key: '_getValue',
102 value: function _getValue(almanac) {
103 var value = this.value;
104 if ((0, _lodash2.default)(value) && Object.prototype.hasOwnProperty.call(value, 'fact')) {
105 // value: { fact: 'xyz' }
106 return almanac.factValue(value.fact, value.params, value.path);
107 }
108 return Promise.resolve(value);
109 }
110
111 /**
112 * Takes the fact result and compares it to the condition 'value', using the operator
113 * LHS OPER RHS
114 * <fact + params + path> <operator> <value>
115 *
116 * @param {Almanac} almanac
117 * @param {Map} operatorMap - map of available operators, keyed by operator name
118 * @returns {Boolean} - evaluation result
119 */
120
121 }, {
122 key: 'evaluate',
123 value: function evaluate(almanac, operatorMap) {
124 var _this = this;
125
126 if (!almanac) return Promise.reject(new Error('almanac required'));
127 if (!operatorMap) return Promise.reject(new Error('operatorMap required'));
128 if (this.isBooleanOperator()) return Promise.reject(new Error('Cannot evaluate() a boolean condition'));
129
130 var op = operatorMap.get(this.operator);
131 if (!op) return Promise.reject(new Error('Unknown operator: ' + this.operator));
132
133 return this._getValue(almanac) // todo - parallelize
134 .then(function (rightHandSideValue) {
135 return almanac.factValue(_this.fact, _this.params, _this.path).then(function (leftHandSideValue) {
136 var result = op.evaluate(leftHandSideValue, rightHandSideValue);
137 (0, _debug2.default)('condition::evaluate <' + leftHandSideValue + ' ' + _this.operator + ' ' + rightHandSideValue + '?> (' + result + ')');
138 return { result: result, leftHandSideValue: leftHandSideValue, rightHandSideValue: rightHandSideValue, operator: _this.operator };
139 });
140 });
141 }
142
143 /**
144 * Returns the boolean operator for the condition
145 * If the condition is not a boolean condition, the result will be 'undefined'
146 * @return {string 'all' or 'any'}
147 */
148
149 }, {
150 key: 'booleanOperator',
151
152
153 /**
154 * Returns the condition's boolean operator
155 * Instance version of Condition.isBooleanOperator
156 * @returns {string,undefined} - 'any', 'all', or undefined (if not a boolean condition)
157 */
158 value: function booleanOperator() {
159 return Condition.booleanOperator(this);
160 }
161
162 /**
163 * Whether the operator is boolean ('all', 'any')
164 * @returns {Boolean}
165 */
166
167 }, {
168 key: 'isBooleanOperator',
169 value: function isBooleanOperator() {
170 return Condition.booleanOperator(this) !== undefined;
171 }
172 }], [{
173 key: 'booleanOperator',
174 value: function booleanOperator(condition) {
175 if (Object.prototype.hasOwnProperty.call(condition, 'any')) {
176 return 'any';
177 } else if (Object.prototype.hasOwnProperty.call(condition, 'all')) {
178 return 'all';
179 }
180 }
181 }]);
182
183 return Condition;
184}();
185
186exports.default = Condition;
\No newline at end of file