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.0.4 to 1.1.0

dist/engine-default-operators.js

5

dist/almanac.js

@@ -29,3 +29,2 @@ 'use strict';

*/
var Almanac = function () {

@@ -127,3 +126,3 @@ function Almanac(factMap) {

value: function () {
var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(factId) {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(factId) {
var params = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];

@@ -162,3 +161,3 @@ var fact, cacheKey, cacheVal;

function factValue(_x2, _x3) {
return ref.apply(this, arguments);
return _ref.apply(this, arguments);
}

@@ -165,0 +164,0 @@

84

dist/condition.js

@@ -44,2 +44,9 @@ 'use strict';

/**
* Converts the condition into a json-friendly structure
* @param {Boolean} stringify - whether to return as a json string
* @returns {string,object} json string or json-friendly object
*/
_createClass(Condition, [{

@@ -72,53 +79,19 @@ key: 'toJSON',

}
/**
* Takes the fact result and compares it to the condition 'value', using the operator
* @param {mixed} comparisonValue - fact result
* @param {Map} operatorMap - map of available operators, keyed by operator name
* @returns {Boolean} - evaluation result
*/
}, {
key: 'validateComparisonValue',
value: function validateComparisonValue(comparisonValue) {
switch (this.operator) {
case 'contains':
case 'doesNotContain':
return Array.isArray(comparisonValue);
case 'lessThan':
case 'lessThanInclusive':
case 'greaterThan':
case 'greaterThanInclusive':
return Number.parseFloat(comparisonValue).toString() !== 'NaN';
default:
return true;
}
}
}, {
key: 'evaluate',
value: function evaluate(comparisonValue) {
if (!this.validateComparisonValue(comparisonValue)) {
return false;
}
switch (this.operator) {
case 'equal':
return comparisonValue === this.value;
case 'notEqual':
return comparisonValue !== this.value;
case 'in':
return this.value.includes(comparisonValue);
case 'notIn':
return !this.value.includes(comparisonValue);
case 'contains':
return comparisonValue.includes(this.value);
case 'doesNotContain':
return !comparisonValue.includes(this.value);
case 'lessThan':
return comparisonValue < this.value;
case 'lessThanInclusive':
return comparisonValue <= this.value;
case 'greaterThan':
return comparisonValue > this.value;
case 'greaterThanInclusive':
return comparisonValue >= this.value;
// for any/all, simply comparisonValue that the sub-condition array evaluated truthy
case 'any':
return comparisonValue === true;
case 'all':
return comparisonValue === true;
default:
throw new Error('Unknown operator: ' + this.operator);
}
value: function evaluate(comparisonValue, operatorMap) {
// for any/all, simply comparisonValue that the sub-condition array evaluated truthy
if (this.isBooleanOperator()) return comparisonValue === true;
var op = operatorMap.get(this.operator);
if (!op) throw new Error('Unknown operator: ' + this.operator);
return op.evaluate(comparisonValue, this.value);
}

@@ -134,5 +107,18 @@

key: 'booleanOperator',
/**
* Returns the condition's boolean operator
* Instance version of Condition.isBooleanOperator
* @returns {string,undefined} - 'any', 'all', or undefined (if not a boolean condition)
*/
value: function booleanOperator() {
return Condition.booleanOperator(this);
}
/**
* Whether the operator is boolean ('all', 'any')
* @returns {Boolean}
*/
}, {

@@ -139,0 +125,0 @@ key: 'isBooleanOperator',

@@ -22,2 +22,6 @@ 'use strict';

var _operator = require('./operator');
var _operator2 = _interopRequireDefault(_operator);
var _almanac = require('./almanac');

@@ -31,2 +35,6 @@

var _engineDefaultOperators = require('./engine-default-operators');
var _engineDefaultOperators2 = _interopRequireDefault(_engineDefaultOperators);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -55,3 +63,2 @@

*/
function Engine() {

@@ -65,7 +72,11 @@ var rules = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0];

_this.rules = [];
_this.operators = new Map();
_this.facts = new Map();
_this.status = READY;
rules.map(function (r) {
return _this.addRule(r);
});
_this.facts = new Map();
_this.status = READY;
_engineDefaultOperators2.default.map(function (o) {
return _this.addOperator(o);
});
return _this;

@@ -104,2 +115,21 @@ }

/**
* Add a custom operator definition
* @param {string} operatorOrName - operator identifier within the condition; i.e. instead of 'equals', 'greaterThan', etc
* @param {function(factValue, jsonValue)} callback - the method to execute when the operator is encountered.
*/
}, {
key: 'addOperator',
value: function addOperator(operatorOrName, cb) {
debug('engine::addOperator name:' + operatorOrName);
var operator = void 0;
if (operatorOrName instanceof _operator2.default) {
operator = operatorOrName;
} else {
operator = new _operator2.default(operatorOrName, cb);
}
this.operators.set(operator.name, operator);
}
/**
* Add a fact definition to the engine. Facts are called by rules as they are evaluated.

@@ -192,3 +222,3 @@ * @param {object|Fact} id - fact identifier or instance of Fact

value: function () {
var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(ruleArray, almanac) {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(ruleArray, almanac) {
var _this3 = this;

@@ -225,3 +255,3 @@

function evaluateRules(_x2, _x3) {
return ref.apply(this, arguments);
return _ref.apply(this, arguments);
}

@@ -242,3 +272,3 @@

value: function () {
var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee2() {
var _ref2 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2() {
var _this4 = this;

@@ -285,3 +315,3 @@

function run(_x4) {
return ref.apply(this, arguments);
return _ref2.apply(this, arguments);
}

@@ -288,0 +318,0 @@

@@ -28,3 +28,2 @@ 'use strict';

*/
function Fact(id, valueOrMethod, options) {

@@ -31,0 +30,0 @@ _classCallCheck(this, Fact);

@@ -6,3 +6,3 @@ 'use strict';

});
exports.Engine = exports.Rule = exports.Fact = undefined;
exports.Engine = exports.Operator = exports.Rule = exports.Fact = undefined;

@@ -25,2 +25,6 @@ exports.default = function (rules) {

var _operator = require('./operator');
var _operator2 = _interopRequireDefault(_operator);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -30,2 +34,3 @@

exports.Rule = _rule2.default;
exports.Operator = _operator2.default;
exports.Engine = _engine2.default;

@@ -36,3 +36,2 @@ 'use strict';

*/
function Rule(options) {

@@ -169,3 +168,3 @@ _classCallCheck(this, Rule);

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

@@ -183,5 +182,4 @@

*/
evaluateCondition = function () {
var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(condition) {
var _ref2 = _asyncToGenerator(regeneratorRuntime.mark(function _callee(condition) {
var comparisonValue, subConditions, conditionResult;

@@ -233,3 +231,3 @@ return regeneratorRuntime.wrap(function _callee$(_context) {

case 17:
conditionResult = condition.evaluate(comparisonValue);
conditionResult = condition.evaluate(comparisonValue, _this2.engine.operators);

@@ -250,3 +248,3 @@ if (!condition.isBooleanOperator()) {

return function evaluateCondition(_x3) {
return ref.apply(this, arguments);
return _ref2.apply(this, arguments);
};

@@ -264,3 +262,3 @@ }();

evaluateConditions = function () {
var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(conditions, method) {
var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(conditions, method) {
var conditionResults;

@@ -294,3 +292,3 @@ return regeneratorRuntime.wrap(function _callee2$(_context2) {

return function evaluateConditions(_x4, _x5) {
return ref.apply(this, arguments);
return _ref3.apply(this, arguments);
};

@@ -312,3 +310,3 @@ }();

prioritizeAndRun = function () {
var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee3(conditions, operator) {
var _ref4 = _asyncToGenerator(regeneratorRuntime.mark(function _callee3(conditions, operator) {
var method, orderedSets, cursor;

@@ -366,3 +364,3 @@ return regeneratorRuntime.wrap(function _callee3$(_context3) {

return function prioritizeAndRun(_x6, _x7) {
return ref.apply(this, arguments);
return _ref4.apply(this, arguments);
};

@@ -379,3 +377,3 @@ }();

any = function () {
var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee4(conditions) {
var _ref5 = _asyncToGenerator(regeneratorRuntime.mark(function _callee4(conditions) {
return regeneratorRuntime.wrap(function _callee4$(_context4) {

@@ -396,3 +394,3 @@ while (1) {

return function any(_x8) {
return ref.apply(this, arguments);
return _ref5.apply(this, arguments);
};

@@ -409,3 +407,3 @@ }();

all = function () {
var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee5(conditions) {
var _ref6 = _asyncToGenerator(regeneratorRuntime.mark(function _callee5(conditions) {
return regeneratorRuntime.wrap(function _callee5$(_context5) {

@@ -426,3 +424,3 @@ while (1) {

return function all(_x9) {
return ref.apply(this, arguments);
return _ref6.apply(this, arguments);
};

@@ -458,3 +456,3 @@ }();

function evaluate(_x2) {
return ref.apply(this, arguments);
return _ref.apply(this, arguments);
}

@@ -461,0 +459,0 @@

@@ -52,2 +52,30 @@ # Engine

### engine.addOperator(String operatorName, Function evaluateFunc(factValue, jsonValue))
Adds a custom operator to the engine. For situations that require going beyond the generic, built-in operators (`equal`, `greaterThan`, etc).
```js
/*
* operatorName - operator identifier mentioned in the rule condition
* evaluateFunc(factValue, jsonValue) - compares fact result to the condition 'value', returning boolean
* factValue - the value returned from the fact
* jsonValue - the "value" property stored in the condition itself
*/
engine.addOperator('startsWithLetter', (factValue, jsonValue) => {
if (!factValue.length) return false
return factValue[0].toLowerCase() === jsonValue.toLowerCase()
})
// and to use the operator...
rule.setConditions({
all: [
{
fact: 'username',
operator: 'startsWithLetter' // reference the operator name in the rule
value: 'a'
}
]
})
```
### engine.run([Object facts], [Object options]) -> Promise (Events)

@@ -54,0 +82,0 @@

@@ -26,4 +26,4 @@ 'use strict'

* Rule for identifying microsoft employees that have been terminated.
* - Demonstates re-using a same fact with different parameters
* - Demonstates calling a base fact, which serves to load data once and reuse later
* - Demonstrates re-using a same fact with different parameters
* - Demonstrates calling a base fact, which serves to load data once and reuse later
*/

@@ -54,4 +54,4 @@ var microsoftRule = {

* Rule for identifying accounts older than 5 years
* - Demonstates calling a base fact, also shared by the account-information-field fact
* - Demonstates performing computations on data retrieved by base fact
* - Demonstrates calling a base fact, also shared by the account-information-field fact
* - Demonstrates performing computations on data retrieved by base fact
*/

@@ -84,3 +84,3 @@ var tenureRule = {

* 'account-information' fact executes an api call and retrieves account data
* - Demonstates facts called only by other facts and never mentioned directly in a rule
* - Demonstrates facts called only by other facts and never mentioned directly in a rule
*/

@@ -87,0 +87,0 @@ engine.addFact('account-information', function (params, almanac) {

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

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

'use strict'
import Condition from '../src/condition'
import defaultOperators from '../src/engine-default-operators'
let operators = new Map()
defaultOperators.forEach(o => operators.set(o.name, o))
function condition () {

@@ -30,4 +34,4 @@ return {

setup({ operator: 'equal' })
expect(condition.evaluate(50)).to.equal(true)
expect(condition.evaluate(5)).to.equal(false)
expect(condition.evaluate(50, operators)).to.equal(true)
expect(condition.evaluate(5, operators)).to.equal(false)
})

@@ -37,4 +41,4 @@

setup({ operator: 'notEqual' })
expect(condition.evaluate(50)).to.equal(false)
expect(condition.evaluate(5)).to.equal(true)
expect(condition.evaluate(50, operators)).to.equal(false)
expect(condition.evaluate(5, operators)).to.equal(true)
})

@@ -47,4 +51,4 @@

})
expect(condition.evaluate(15)).to.equal(true)
expect(condition.evaluate(99)).to.equal(false)
expect(condition.evaluate(15, operators)).to.equal(true)
expect(condition.evaluate(99, operators)).to.equal(false)
})

@@ -57,4 +61,4 @@

})
expect(condition.evaluate([5, 10, 15])).to.equal(true)
expect(condition.evaluate([1, 2, 3])).to.equal(false)
expect(condition.evaluate([5, 10, 15], operators)).to.equal(true)
expect(condition.evaluate([1, 2, 3], operators)).to.equal(false)
})

@@ -67,4 +71,4 @@

})
expect(condition.evaluate([5, 10, 15])).to.equal(false)
expect(condition.evaluate([1, 2, 3])).to.equal(true)
expect(condition.evaluate([5, 10, 15], operators)).to.equal(false)
expect(condition.evaluate([1, 2, 3], operators)).to.equal(true)
})

@@ -77,4 +81,4 @@

})
expect(condition.evaluate(15)).to.equal(false)
expect(condition.evaluate(99)).to.equal(true)
expect(condition.evaluate(15, operators)).to.equal(false)
expect(condition.evaluate(99, operators)).to.equal(true)
})

@@ -84,5 +88,5 @@

setup({ operator: 'lessThan' })
expect(condition.evaluate(49)).to.equal(true)
expect(condition.evaluate(50)).to.equal(false)
expect(condition.evaluate(51)).to.equal(false)
expect(condition.evaluate(49, operators)).to.equal(true)
expect(condition.evaluate(50, operators)).to.equal(false)
expect(condition.evaluate(51, operators)).to.equal(false)
})

@@ -92,17 +96,17 @@

setup({ operator: 'lessThanInclusive' })
expect(condition.evaluate(49)).to.equal(true)
expect(condition.evaluate(50)).to.equal(true)
expect(condition.evaluate(51)).to.equal(false)
expect(condition.evaluate(49, operators)).to.equal(true)
expect(condition.evaluate(50, operators)).to.equal(true)
expect(condition.evaluate(51, operators)).to.equal(false)
})
it('evaluates "greaterThan"', () => {
setup({ operator: 'greaterThan' })
expect(condition.evaluate(51)).to.equal(true)
expect(condition.evaluate(49)).to.equal(false)
expect(condition.evaluate(50)).to.equal(false)
expect(condition.evaluate(51, operators)).to.equal(true)
expect(condition.evaluate(49, operators)).to.equal(false)
expect(condition.evaluate(50, operators)).to.equal(false)
})
it('evaluates "greaterThanInclusive"', () => {
setup({operator: 'greaterThanInclusive'})
expect(condition.evaluate(51)).to.equal(true)
expect(condition.evaluate(50)).to.equal(true)
expect(condition.evaluate(49)).to.equal(false)
expect(condition.evaluate(51, operators)).to.equal(true)
expect(condition.evaluate(50, operators)).to.equal(true)
expect(condition.evaluate(49, operators)).to.equal(false)
})

@@ -113,5 +117,5 @@

setup({operator: 'contains'})
expect(condition.evaluate(null)).to.equal(false)
expect(condition.evaluate(null, operators)).to.equal(false)
setup({operator: 'doesNotContain'})
expect(condition.evaluate(null)).to.equal(false)
expect(condition.evaluate(null, operators)).to.equal(false)
})

@@ -121,9 +125,9 @@

setup({operator: 'lessThan'})
expect(condition.evaluate(null)).to.equal(false)
expect(condition.evaluate(null, operators)).to.equal(false)
setup({operator: 'lessThanInclusive'})
expect(condition.evaluate(null)).to.equal(false)
expect(condition.evaluate(null, operators)).to.equal(false)
setup({operator: 'greaterThan'})
expect(condition.evaluate(null)).to.equal(false)
expect(condition.evaluate(null, operators)).to.equal(false)
setup({operator: 'greaterThanInclusive'})
expect(condition.evaluate(null)).to.equal(false)
expect(condition.evaluate(null, operators)).to.equal(false)
})

@@ -133,9 +137,9 @@

setup({operator: 'lessThan'})
expect(condition.evaluate('non-number')).to.equal(false)
expect(condition.evaluate('non-number', operators)).to.equal(false)
setup({operator: 'lessThan'})
expect(condition.evaluate(undefined)).to.equal(false)
expect(condition.evaluate(undefined, operators)).to.equal(false)
setup({operator: 'lessThan'})
expect(condition.evaluate([])).to.equal(false)
expect(condition.evaluate([], operators)).to.equal(false)
setup({operator: 'lessThan'})
expect(condition.evaluate({})).to.equal(false)
expect(condition.evaluate({}, operators)).to.equal(false)
})

@@ -142,0 +146,0 @@ })

@@ -7,2 +7,3 @@ 'use strict'

import { Rule } from '../src/index'
import { Operator } from '../src/index'

@@ -17,2 +18,3 @@ describe('Engine', () => {

expect(engine).to.have.property('addRule')
expect(engine).to.have.property('addOperator')
expect(engine).to.have.property('addFact')

@@ -24,4 +26,6 @@ expect(engine).to.have.property('run')

describe('constructor', () => {
it('begins in status "READY"', () => {
it('initializes with the default state', () => {
expect(engine.status).to.equal('READY')
expect(engine.rules.length).to.equal(0)
expect(engine.operators.size).to.equal(10)
})

@@ -76,2 +80,22 @@

describe('addOperator()', () => {
it('adds the operator', () => {
expect(engine.operators.size).to.equal(10)
engine.addOperator('startsWithLetter', (factValue, jsonValue) => {
return factValue[0] === jsonValue
})
expect(engine.operators.size).to.equal(11)
expect(engine.operators.get('startsWithLetter')).to.exist
expect(engine.operators.get('startsWithLetter')).to.be.an.instanceof(Operator)
})
it('accepts an operator instance', () => {
expect(engine.operators.size).to.equal(10)
let op = new Operator('my-operator', _ => true)
engine.addOperator(op)
expect(engine.operators.size).to.equal(11)
expect(engine.operators.get('my-operator')).to.equal(op)
})
})
describe('addFact()', () => {

@@ -78,0 +102,0 @@ const FACT_NAME = 'FACT_NAME'

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