UNPKG

js-rules-engine

Version:

JavaScript rules engine for validating data object structures.

198 lines (152 loc) 5.54 kB
[![NPM Version](https://badge.fury.io/js/js-rules-engine.svg)](https://badge.fury.io/js/js-rules-engine) [![Build Status](https://travis-ci.org/justinlettau/js-rules-engine.svg?branch=master)](https://travis-ci.org/justinlettau/js-rules-engine) [![Dependency Status](https://david-dm.org/justinlettau/js-rules-engine.svg)](https://david-dm.org/justinlettau/js-rules-engine) [![Dev Dependency Status](https://david-dm.org/justinlettau/js-rules-engine/dev-status.svg)](https://david-dm.org/justinlettau/js-rules-engine?type=dev) # Rules Engine JavaScript rules engine for validating data object structures. # Table of Contents - [Features](#features) - [Installation](#installation) - [Usage](#usage) - [Default Engine](#default-engine) - [Override Engine](#override-engine) - [Default Operators](#default-operators) - [Customizing Operators](#customizing-operators) - [Rule Conditions](#rule-conditions) - [Persisting Rules](#persisting-rules) - [Development](#development) # Features - 💪 Easy to use **chainable API**. - 💥 Support for **infinitely nested** `AND` / `OR` conditions. - 🚀 Rules can be expressed in **simple JSON**. - ✔️ **Customize operators** with your own functions. - 🏄 Access nested properties with **dot notation** paths. # Installation ```bash npm install js-rules-engine --save ``` # Usage ```js import { Rule } from 'js-rules-engine'; // homeWorld.name equals 'Tatooine' AND (name contains 'Skywalker' OR eyeColor is 'green') const rule = new Rule().equals('homeWorld.name', 'Tatooine').or((sub) => { sub.contains('name', 'Skywalker').equals('eyeColor', 'green'); }); // object of data to evaluate rule against const fact = { eyeColor: 'blue', homeWorld: { name: 'Tatooine', }, name: 'Luke Skywalker', }; rule.evaluate(fact); // => true ``` ## Default Engine An `Engine` contains all operators available to a `Rule`. By default, a single `Engine` instance is used for all `Rule` instances. The default `Engine`'s operators can be customized like this: ```js import { defaultEngine } from 'js-rules-engine'; defaultEngine.removeOperator('greaterThan'); defaultEngine.addOperator('moreGreaterThan', myAwesomeFunction); ``` ## Override Engine Each instance of `Rule` has the ability to use it's own `Engine` instance, overriding the default. ```js import { Engine, Rule } from 'js-rules-engine'; const engine = new Engine(); const rule = new Rule(null, engine); ``` ## Default Operators Each `Engine` contains the follow operators by default: - `equals` - `notEquals` - `in` - `notIn` - `contains` - `notContains` - `lessThan` - `lessThanOrEquals` - `greaterThan` - `greaterThanOrEquals` ## Customizing Operators Add your own operators to an `Engine`. Once added, any custom `Operator` can be used via the `Rule`'s `add()` method. ```js import { defaultEngine, Operator } from 'js-rules-engine'; const noop = new Operator('noop', (a, b) => true); defaultEngine.addOperator(noop); ``` You can also remove an `Operator`. ```js import { defaultEngine } from 'js-rules-engine'; defaultEngine.removeOperator('noop'); ``` ## Rule Conditions The `add` method is a generic way to add a condition to the `Rule`. The conditions operator is added via it's `name`. The `value` type should match what the operator is expecting. | Param | Description | Type | | ---------- | ----------------------------------- | -------- | | `fact` | Property name or dot notation path. | `string` | | `operator` | Name of operator to use. | `string` | | `value` | Value to compare. | `any` | A `Rule` has shortcut methods for all default operators. Each method takes two arguments (`fact` and `value`) and returns the `Rule` instance for chaining. | Method | Fact Type | Value Type | | --------------------- | --------- | ---------- | | `equals` | `string` | `any` | | `notEquals` | `string` | `any` | | `in` | `string` | `string` | | `notIn` | `string` | `string` | | `contains` | `string` | `any` | | `notContains` | `string` | `any` | | `lessThan` | `string` | `number` | | `lessThanOrEquals` | `string` | `number` | | `greaterThan` | `string` | `number` | | `greaterThanOrEquals` | `string` | `number` | Nested conditions can be achieved with the `and()` / `or()` methods. Each methods takes one parameter, a callback function that is supplied with a nested `Rule` instance as the first argument, and returns the original `Rule` instance for chaining. ## Persisting Rules Rules can easily be converted to JSON and persisted to a database, file system, or elsewhere. ```js // save rule as JSON string ... const jsonString = JSON.stringify(rule); localStorage.setItem('persistedRule', jsonString); ``` ```js // ... and hydrate rules from a JSON object! const jsonString = localStorage.getItem('persistedRule'); const json = JSON.parse(jsonString); const rule = new Rule(json); ``` Example JSON structure: ```json { "and": [ { "fact": "homeWorld.name", "operator": "equals", "value": "Tatooine" }, { "or": [ { "fact": "name", "operator": "contains", "value": "Skywalker" }, { "fact": "eyeColor", "operator": "equals", "value": "green" } ] } ] } ``` # Development ``` npm install npm run build ```