New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

json-rules-engine

Package Overview
Dependencies
Maintainers
1
Versions
82
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

json-rules-engine - npm Package Compare versions

Comparing version 1.2.1 to 1.3.0

.vscode/launch.json

21

CHANGELOG.md

@@ -0,1 +1,22 @@

1.3.0 / 2016-10-24
==================
* Rule event emissions
* Rule chaining
1.2.1 / 2016-10-22
==================
* Use Array.indexOf instead of Array.includes for older node version compatibility
1.2.0 / 2016-09-13
==================
* Fact path support
1.1.0 / 2016-09-11
==================
* Custom operator support
1.0.4 / 2016-06-18

@@ -2,0 +23,0 @@ ==================

62

dist/rule.js

@@ -17,2 +17,4 @@ 'use strict';

var _events = require('events');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -24,5 +26,11 @@

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; }
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; }
var debug = require('debug')('json-rules-engine');
var Rule = function () {
var Rule = function (_EventEmitter) {
_inherits(Rule, _EventEmitter);
/**

@@ -41,2 +49,4 @@ * returns a new Rule instance

var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(Rule).call(this));
if (typeof options === 'string') {

@@ -46,10 +56,17 @@ options = JSON.parse(options);

if (options && options.conditions) {
this.setConditions(options.conditions);
_this.setConditions(options.conditions);
}
if (options && options.onSuccess) {
_this.on('success', options.onSuccess);
}
if (options && options.onFailure) {
_this.on('failure', options.onFailure);
}
var priority = options && options.priority || 1;
this.setPriority(priority);
_this.setPriority(priority);
var event = options && options.event || { type: 'unknown' };
this.setEvent(event);
_this.setEvent(event);
return _this;
}

@@ -141,3 +158,3 @@

value: function prioritizeConditions(conditions) {
var _this = this;
var _this2 = this;

@@ -149,3 +166,3 @@ var factSets = conditions.reduce(function (sets, condition) {

if (!priority) {
var fact = _this.engine.getFact(condition.fact);
var fact = _this2.engine.getFact(condition.fact);
priority = fact && fact.priority || 1;

@@ -174,3 +191,3 @@ }

var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee6(almanac) {
var _this2 = this;
var _this3 = this;

@@ -189,3 +206,3 @@ var evaluateCondition, evaluateConditions, prioritizeAndRun, any, all;

var _ref2 = _asyncToGenerator(regeneratorRuntime.mark(function _callee(condition) {
var comparisonValue, subConditions;
var comparisonValue, subConditions, passes;
return regeneratorRuntime.wrap(function _callee$(_context) {

@@ -236,5 +253,16 @@ while (1) {

case 17:
return _context.abrupt('return', condition.evaluate(comparisonValue, _this2.engine.operators));
_context.next = 19;
return condition.evaluate(comparisonValue, _this3.engine.operators);
case 18:
case 19:
passes = _context.sent;
if (passes) {
_this3.emit('success', _this3.event, almanac);
} else {
_this3.emit('failure', _this3.event, almanac);
}
return _context.abrupt('return', passes);
case 22:
case 'end':

@@ -244,3 +272,3 @@ return _context.stop();

}
}, _callee, _this2);
}, _callee, _this3);
}));

@@ -287,3 +315,3 @@

}
}, _callee2, _this2);
}, _callee2, _this3);
}));

@@ -328,3 +356,3 @@

}
orderedSets = _this2.prioritizeConditions(conditions);
orderedSets = _this3.prioritizeConditions(conditions);
cursor = Promise.resolve();

@@ -359,3 +387,3 @@

}
}, _callee3, _this2);
}, _callee3, _this3);
}));

@@ -388,3 +416,3 @@

}
}, _callee4, _this2);
}, _callee4, _this3);
}));

@@ -417,3 +445,3 @@

}
}, _callee5, _this2);
}, _callee5, _this3);
}));

@@ -461,4 +489,4 @@

return Rule;
}();
}(_events.EventEmitter);
exports.default = Rule;

@@ -25,2 +25,10 @@ # Almanac

### almanac.addRuntimeFact(String factId, Mixed value)
Sets a constant fact mid-run. Often used in conjunction with rule and engine event emissions.
```js
almanac.addRuntimeFact('account-id', 1)
```
## Common Use Cases

@@ -105,2 +113,37 @@

})
```
```
### Rule Chaining
The `almanac.addRuntimeFact()` method may be used in conjunction with event emissions to
set fact values during runtime, effectively enabling _rule-chaining_. Note that ordering
of rule execution is enabled via the `priority` option, and is crucial component to propertly
configuring rule chaining.
```js
engine.addRule({
conditions,
event,
onSuccess: function (event, almanac) {
almanac.addRuntimeFact('rule-1-passed', true) // track that the rule passed
},
onFailure: function (event, almanac) {
almanac.addRuntimeFact('rule-1-passed', false) // track that the rule failed
},
priority: 10 // a higher priority ensures this rule will be run prior to subsequent rules
})
// in a later rule:
engine.addRule({
conditions: {
all: [{
fact: 'rule-1-passed',
operator: 'equal',
value: true
}
},
priority: 1 // lower priority ensures this is run AFTER its predecessor
}
```
See the [full example](../examples/07-rule-chaining.js)

@@ -46,3 +46,5 @@ # Engine

event: {},
priority: 1
priority: 1, // optional, default: 1
onSuccess: function (event, almanac) {}, // optional
onFailure: function (event, almanac) {}, // optional
})

@@ -49,0 +51,0 @@

@@ -79,2 +79,25 @@ # Rules

### Events
Listen for 'success' and 'failure' events emitted when rule is evaluated.
#### ```rule.on('success', Function(Object event, Almanac almanac))```
```js
// whenever rule is evaluated and the conditions pass, 'success' will trigger
rule.on('success', function(event, almanac) {
console.log(event) // { type: 'my-event', params: { id: 1 }
})
```
#### ```rule.on('failure', Function(Object event, Almanac almanac))```
Companion to 'success', except fires when the rule fails.
```js
engine.on('failure', function(event, almanac) {
console.log(event) // { type: 'my-event', params: { id: 1 }
})
```
## Conditions

@@ -81,0 +104,0 @@

@@ -7,6 +7,6 @@ 'use strict'

* Usage:
* node ./examples/hello-world.js
* node ./examples/01-hello-world.js
*
* For detailed output:
* DEBUG=json-rules-engine node ./examples/hello-world.js
* DEBUG=json-rules-engine node ./examples/01-hello-world.js
*/

@@ -13,0 +13,0 @@

@@ -7,6 +7,6 @@ 'use strict'

* Usage:
* node ./examples/nested-boolean-logic.js
* node ./examples/02-nested-boolean-logic.js
*
* For detailed output:
* DEBUG=json-rules-engine node ./examples/nested-boolean-logic.js
* DEBUG=json-rules-engine node ./examples/02-nested-boolean-logic.js
*/

@@ -13,0 +13,0 @@

@@ -8,6 +8,6 @@ 'use strict'

* Usage:
* node ./examples/dynamic-facts.js
* node ./examples/03-dynamic-facts.js
*
* For detailed output:
* DEBUG=json-rules-engine node ./examples/dynamic-facts.js
* DEBUG=json-rules-engine node ./examples/03-dynamic-facts.js
*/

@@ -14,0 +14,0 @@

@@ -9,6 +9,6 @@ 'use strict'

* Usage:
* node ./examples/fact-dependency.js
* node ./examples/04-fact-dependency.js
*
* For detailed output:
* DEBUG=json-rules-engine node ./examples/fact-dependency.js
* DEBUG=json-rules-engine node ./examples/04-fact-dependency.js
*/

@@ -15,0 +15,0 @@

@@ -7,6 +7,6 @@ 'use strict'

* Usage:
* node ./examples/optimize-runtime-with-fact-priority.js
* node ./examples/05-optimize-runtime-with-fact-priority.js
*
* For detailed output:
* DEBUG=json-rules-engine node ./examples/optimize-runtime-with-fact-priority.js
* DEBUG=json-rules-engine node ./examples/05-optimize-runtime-with-fact-priority.js
*/

@@ -13,0 +13,0 @@

@@ -13,6 +13,6 @@ 'use strict'

* Usage:
* node ./examples/custom-operators.js
* node ./examples/06-custom-operators.js
*
* For detailed output:
* DEBUG=json-rules-engine node ./examples/custom-operators.js
* DEBUG=json-rules-engine node ./examples/06-custom-operators.js
*/

@@ -19,0 +19,0 @@

{
"name": "json-rules-engine",
"version": "1.2.1",
"version": "1.3.0",
"description": "Rules Engine expressed in simple json",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

@@ -96,3 +96,3 @@ ![json-rules-engine](http://i.imgur.com/MAzq7l2.png)

Run this example [here](./examples/nested-boolean-logic.js)
This is available in the [examples](./examples/02-nested-boolean-logic.js)

@@ -183,3 +183,3 @@ ## Advanced Example

Run this example [here](./examples/nested-boolean-logic.js)
This is available in the [examples](./examples/03-dynamic-facts)

@@ -186,0 +186,0 @@ ## Docs

'use strict'
import engineFactory from '../src/index'
import Almanac from '../src/almanac'
import sinon from 'sinon'

@@ -23,3 +25,4 @@ describe('Engine: event', () => {

engine = engineFactory()
let determineDrinkingAgeRule = factories.rule({ conditions, event, priority: 100 })
let ruleOptions = { conditions, event, priority: 100 }
let determineDrinkingAgeRule = factories.rule(ruleOptions)
engine.addRule(determineDrinkingAgeRule)

@@ -29,59 +32,93 @@ engine.addFact('age', 21)

it('passes the event type and params', (done) => {
engine.on('success', function (a, engine) {
try {
expect(a).to.eql(event)
expect(engine).to.eql(engine)
} catch (e) { return done(e) }
done()
describe('engine events', () => {
it('passes the event type and params', (done) => {
engine.on('success', function (a, engine) {
try {
expect(a).to.eql(event)
expect(engine).to.eql(engine)
} catch (e) { return done(e) }
done()
})
engine.run()
})
engine.run()
})
it('emits using the event "type"', (done) => {
engine.on('setDrinkingFlag', function (params, engine) {
try {
expect(params).to.eql(event.params)
expect(engine).to.eql(engine)
} catch (e) { return done(e) }
done()
it('emits using the event "type"', (done) => {
engine.on('setDrinkingFlag', function (params, e) {
try {
expect(params).to.eql(event.params)
expect(engine).to.eql(e)
} catch (e) { return done(e) }
done()
})
engine.run()
})
engine.run()
})
it('allows facts to be added by the event handler, affecting subsequent rules', () => {
let drinkOrderParams = { wine: 'merlot', quantity: 2 }
let drinkOrderEvent = {
type: 'offerDrink',
params: drinkOrderParams
}
let drinkOrderConditions = {
any: [{
fact: 'canOrderDrinks',
operator: 'equal',
value: true
}]
}
let drinkOrderRule = factories.rule({
conditions: drinkOrderConditions,
event: drinkOrderEvent,
priority: 1
it('allows facts to be added by the event handler, affecting subsequent rules', () => {
let drinkOrderParams = { wine: 'merlot', quantity: 2 }
let drinkOrderEvent = {
type: 'offerDrink',
params: drinkOrderParams
}
let drinkOrderConditions = {
any: [{
fact: 'canOrderDrinks',
operator: 'equal',
value: true
}]
}
let drinkOrderRule = factories.rule({
conditions: drinkOrderConditions,
event: drinkOrderEvent,
priority: 1
})
engine.addRule(drinkOrderRule)
return new Promise((resolve, reject) => {
engine.on('success', function (event, almanac) {
switch (event.type) {
case 'setDrinkingFlag':
almanac.addRuntimeFact('canOrderDrinks', event.params.canOrderDrinks)
break
case 'offerDrink':
expect(event.params).to.eql(drinkOrderParams)
break
default:
reject(new Error('default case not expected'))
}
})
engine.run().then(resolve).catch(reject)
})
})
engine.addRule(drinkOrderRule)
return new Promise((resolve, reject) => {
engine.on('success', function (event, almanac) {
switch (event.type) {
case 'setDrinkingFlag':
almanac.addRuntimeFact('canOrderDrinks', event.params.canOrderDrinks)
break
case 'offerDrink':
expect(event.params).to.eql(drinkOrderParams)
break
default:
reject(new Error('default case not expected'))
}
})
describe('rule events', () => {
it('on-success, it passes the event type and params', (done) => {
let failureSpy = sinon.spy()
let rule = engine.rules[0]
rule.on('success', function (e, a) {
try {
expect(e).to.eql(event)
expect(a).to.be.an.instanceof(Almanac)
expect(failureSpy.callCount).to.equal(0)
} catch (err) { return done(err) }
done()
})
engine.run().then(resolve).catch(reject)
rule.on('failure', failureSpy)
engine.run()
})
it('on-failure, it passes the event type and params', (done) => {
let successSpy = sinon.spy()
let rule = engine.rules[0]
rule.on('failure', function (e, a) {
try {
expect(e).to.eql(event)
expect(a).to.be.an.instanceof(Almanac)
expect(successSpy.callCount).to.equal(0)
} catch (err) { return done(err) }
done()
})
rule.on('success', successSpy)
engine.addFact('age', 10)
engine.run()
})
})
})

@@ -55,2 +55,32 @@ 'use strict'

describe('event emissions', () => {
it('can emit', () => {
let rule = new Rule()
let successSpy = sinon.spy()
rule.on('test', successSpy)
rule.emit('test')
expect(successSpy.callCount).to.equal(1)
})
it('can be initialized with an onSuccess option', (done) => {
let event = { type: 'test' }
let onSuccess = function (e) {
expect(e).to.equal(event)
done()
}
let rule = new Rule({ onSuccess })
rule.emit('success', event)
})
it('can be initialized with an onFailure option', (done) => {
let event = { type: 'test' }
let onFailure = function (e) {
expect(e).to.equal(event)
done()
}
let rule = new Rule({ onFailure })
rule.emit('failure', event)
})
})
describe('setConditions()', () => {

@@ -57,0 +87,0 @@ describe('validations', () => {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc