json-rules-engine
Advanced tools
Comparing version 2.0.0 to 2.0.1
@@ -0,1 +1,4 @@ | ||
2.0.1 / 2017-07-05 | ||
* Bugfix rule result serialization | ||
2.0.0 / 2017-04-21 | ||
@@ -2,0 +5,0 @@ * Publishing 2.0.0 |
@@ -19,2 +19,3 @@ /** | ||
var iteratorSymbol = $Symbol.iterator || "@@iterator"; | ||
var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator"; | ||
var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; | ||
@@ -193,4 +194,4 @@ | ||
if (typeof process === "object" && process.domain) { | ||
invoke = process.domain.bind(invoke); | ||
if (typeof global.process === "object" && global.process.domain) { | ||
invoke = global.process.domain.bind(invoke); | ||
} | ||
@@ -234,2 +235,5 @@ | ||
defineIteratorMethods(AsyncIterator.prototype); | ||
AsyncIterator.prototype[asyncIteratorSymbol] = function () { | ||
return this; | ||
}; | ||
runtime.AsyncIterator = AsyncIterator; | ||
@@ -418,2 +422,11 @@ | ||
// A Generator should always return itself as the iterator object when the | ||
// @@iterator function is called on it. Some browsers' implementations of the | ||
// iterator prototype chain incorrectly implement this, causing the Generator | ||
// object to not be returned from this call. This ensures that doesn't happen. | ||
// See https://github.com/facebook/regenerator/issues/274 for more details. | ||
Gp[iteratorSymbol] = function() { | ||
return this; | ||
}; | ||
Gp.toString = function() { | ||
@@ -420,0 +433,0 @@ return "[object Generator]"; |
@@ -13,7 +13,7 @@ 'use strict'; | ||
var _events = require('events'); | ||
var _ruleResult = require('./rule-result'); | ||
var _lodash = require('lodash.clonedeep'); | ||
var _ruleResult2 = _interopRequireDefault(_ruleResult); | ||
var _lodash2 = _interopRequireDefault(_lodash); | ||
var _events = require('events'); | ||
@@ -199,7 +199,3 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
case 0: | ||
ruleResult = { | ||
conditions: (0, _lodash2.default)(this.conditions), | ||
event: (0, _lodash2.default)(this.event), | ||
priority: (0, _lodash2.default)(this.priority) | ||
}; | ||
ruleResult = new _ruleResult2.default(this.conditions, this.event, this.priority); | ||
@@ -476,3 +472,4 @@ /** | ||
processResult = function processResult(result) { | ||
ruleResult.result = result; | ||
ruleResult.setResult(result); | ||
if (result) _this3.emit('success', ruleResult.event, almanac, ruleResult);else _this3.emit('failure', ruleResult.event, almanac, ruleResult); | ||
@@ -479,0 +476,0 @@ return ruleResult; |
@@ -6,9 +6,9 @@ | ||
[Methods](#Methods) | ||
[Methods](#methods) | ||
[Conditions](#Conditions) | ||
[Conditions](#conditions) | ||
[Events](#Events) | ||
[Events](#events) | ||
[Operators](#Operators) | ||
[Operators](#operators) | ||
@@ -346,2 +346,2 @@ [Rule Results](#rule-results) | ||
A demonstration can be found in the [rule-results](../examples/09-rule-results.js) example. | ||
A demonstration can be found in the [rule-results](../examples/09-rule-results.js) example. |
@@ -6,7 +6,7 @@ # Walkthrough | ||
```js | ||
let Engine = require('json-rules-engine') | ||
let engine = new Engine() | ||
let RuleEngine = require('json-rules-engine'); | ||
let engine = new RuleEngine.Engine(); | ||
``` | ||
More on engines can be found [here](./docs/engine.md) | ||
More on engines can be found [here](./engine.md) | ||
@@ -24,3 +24,3 @@ ## Step 2: Add Rules | ||
} | ||
} | ||
}; | ||
let conditions = { | ||
@@ -37,23 +37,25 @@ all: [ | ||
}, | ||
any: [ | ||
{ | ||
fact: 'state', | ||
params: { | ||
country: 'us' | ||
}, | ||
operator: 'equal', | ||
value: 'colorado' | ||
}, { | ||
fact: 'state', | ||
params: { | ||
country: 'us' | ||
}, | ||
operator: 'equal', | ||
value: 'utah' | ||
} | ||
] | ||
{ | ||
any: [ | ||
{ | ||
fact: 'state', | ||
params: { | ||
country: 'us' | ||
}, | ||
operator: 'equal', | ||
value: 'CO' | ||
}, { | ||
fact: 'state', | ||
params: { | ||
country: 'us' | ||
}, | ||
operator: 'equal', | ||
value: 'UT' | ||
} | ||
] | ||
} | ||
] | ||
} | ||
let rule = new Rule({ conditions, event}) | ||
engine.addRule(rule) | ||
}; | ||
let rule = new RuleEngine.Rule({ conditions, event}); | ||
engine.addRule(rule); | ||
``` | ||
@@ -63,3 +65,3 @@ | ||
More on rules can be found [here](./docs/rules.md) | ||
More on rules can be found [here](./rules.md) | ||
@@ -73,3 +75,2 @@ ### Step 3: Define Facts | ||
```js | ||
/* | ||
@@ -82,5 +83,8 @@ * Define the 'state' fact | ||
// via almanac.factValue() | ||
return stateLookupByZip(params.country, almanac.factValue('zip-code')) | ||
} | ||
engine.addFact('state', stateFact) | ||
return almanac.factValue('zip-code') | ||
.then(zip => { | ||
return stateLookupByZip(params.country, zip); | ||
}); | ||
}; | ||
engine.addFact('state', stateFact); | ||
@@ -94,8 +98,20 @@ /* | ||
return almanac.factValue('userId').then((userId) => { | ||
return db.getUser(userId) | ||
return getUser(userId); | ||
}).then((user) => { | ||
return user.age | ||
return user.age; | ||
}) | ||
} | ||
engine.addFact('age', ageFact) | ||
}; | ||
engine.addFact('age', ageFact); | ||
/* | ||
* Define the 'zip-code' fact | ||
*/ | ||
let zipCodeFact = function(params, almanac) { | ||
return almanac.factValue('userId').then((userId) => { | ||
return getUser(userId); | ||
}).then((user) => { | ||
return user.zipCode; | ||
}) | ||
}; | ||
engine.addFact('zip-code', zipCodeFact); | ||
``` | ||
@@ -105,5 +121,5 @@ | ||
**Important:** facts should be *pure functions*; their computed values will vary based on the ```params``` argument. By establishing facts as pure functions, it allows the rules engine to cache results throughout each ```run()```; facts called multiple times with the same ```params``` will trigger the computation once and cache the results for future calls. If fact caching not desired, this behavior can be turned off via the options; see the [docs](./docs/facts.md). | ||
**Important:** facts should be *pure functions*; their computed values will vary based on the ```params``` argument. By establishing facts as pure functions, it allows the rules engine to cache results throughout each ```run()```; facts called multiple times with the same ```params``` will trigger the computation once and cache the results for future calls. If fact caching not desired, this behavior can be turned off via the options; see the [docs](./facts.md). | ||
More on facts can be found [here](./docs/facts.md). More on almanacs can be found [here](./docs/almanac.md) | ||
More on facts can be found [here](./facts.md). More on almanacs can be found [here](./almanac.md) | ||
@@ -122,3 +138,3 @@ | ||
// } | ||
}) | ||
}); | ||
@@ -129,2 +145,3 @@ // - OR - | ||
engine.on('success', function (event, engine) { | ||
console.log('Success event:\n', event); | ||
// event: { | ||
@@ -137,3 +154,3 @@ // type: "young-adult-rocky-mnts", | ||
// } | ||
}) | ||
}); | ||
``` | ||
@@ -147,11 +164,47 @@ | ||
// evaluate the rules | ||
engine.run() | ||
//engine.run(); | ||
// Optionally, facts known at runtime may be passed to run() | ||
engine.run({ userId: 1 }) // any time a rule condition requires 'userId', '1' will be returned | ||
engine.run({ userId: 1 }); // any time a rule condition requires 'userId', '1' will be returned | ||
// run() returns a promise | ||
engine.run().then((events) => { | ||
engine.run({ userId: 4 }).then((events) => { | ||
console.log('all rules executed; the following events were triggered: ', events) | ||
}) | ||
}); | ||
``` | ||
Helper methods (for this example) | ||
```js | ||
function stateLookupByZip(country, zip) { | ||
var state; | ||
switch (zip.toString()) { | ||
case '80014': | ||
state = 'CO'; | ||
break; | ||
case '84101': | ||
state = 'UT'; | ||
break; | ||
case '90210': | ||
state = 'CA'; | ||
break; | ||
default: | ||
state = 'NY'; | ||
} | ||
return state; | ||
} | ||
var users = { | ||
1: {age: 22, zipCode: 80014}, | ||
2: {age: 16, zipCode: 80014}, | ||
3: {age: 35, zipCode: 84101}, | ||
4: {age: 23, zipCode: 90210}, | ||
}; | ||
function getUser(id) { | ||
return new Promise((resolve, reject) => { | ||
setTimeout(() => { | ||
resolve(users[id]); | ||
}, 500); | ||
}); | ||
} | ||
``` |
{ | ||
"name": "json-rules-engine", | ||
"version": "2.0.0", | ||
"version": "2.0.1", | ||
"description": "Rules Engine expressed in simple json", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -19,3 +19,4 @@ ![json-rules-engine](http://i.imgur.com/MAzq7l2.png) | ||
* Secure; no use of eval() | ||
* Lightweight & extendable; less than 500 lines of javascript w/few dependencies | ||
* Isomorphic; runs in node and browser | ||
* Lightweight & extendable; 24kb gzipped w/few dependencies | ||
@@ -208,2 +209,4 @@ ## Installation | ||
#### Node | ||
```bash | ||
@@ -213,3 +216,9 @@ DEBUG=json-rules-engine | ||
#### Browser | ||
```js | ||
// set debug flag in local storage & refresh page to see console output | ||
localStorage.debug = 'json-rules-engine' | ||
``` | ||
## License | ||
[ISC](./LICENSE) |
@@ -279,2 +279,15 @@ 'use strict' | ||
}) | ||
context('rule events: json serializing', () => { | ||
beforeEach(() => simpleSetup()) | ||
it('serializes properties', async () => { | ||
let successSpy = sinon.spy() | ||
let rule = engine.rules[0] | ||
rule.on('success', successSpy) | ||
await engine.run() | ||
let ruleResult = successSpy.getCall(0).args[2] | ||
let expected = '{"conditions":{"priority":1,"any":[{"operator":"greaterThanInclusive","value":21,"fact":"age"},{"operator":"equal","value":true,"fact":"qualified"}]},"event":{"type":"setDrinkingFlag","params":{"canOrderDrinks":true}},"priority":100,"result":true}' | ||
expect(JSON.stringify(ruleResult)).to.equal(expected) | ||
}) | ||
}) | ||
}) |
237301
65
5442
221