1 | ![json-rules-engine](http://i.imgur.com/MAzq7l2.png)
|
2 | [![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard)
|
3 | [![Build Status](https://github.com/cachecontrol/json-rules-engine/workflows/Node.js%20CI/badge.svg?branch=master)](https://github.com/cachecontrol/json-rules-engine/workflows/Node.js%20CI/badge.svg?branch=master)
|
4 |
|
5 | [![npm version](https://badge.fury.io/js/json-rules-engine.svg)](https://badge.fury.io/js/json-rules-engine)
|
6 | [![install size](https://packagephobia.now.sh/badge?p=json-rules-engine)](https://packagephobia.now.sh/result?p=json-rules-engine)
|
7 | [![npm downloads](https://img.shields.io/npm/dm/json-rules-engine.svg)](https://www.npmjs.com/package/json-rules-engine)
|
8 |
|
9 | A rules engine expressed in JSON
|
10 |
|
11 | * [Synopsis](#synopsis)
|
12 | * [Features](#features)
|
13 | * [Installation](#installation)
|
14 | * [Docs](#docs)
|
15 | * [Examples](#examples)
|
16 | * [Basic Example](#basic-example)
|
17 | * [Advanced Example](#advanced-example)
|
18 | * [Debugging](#debugging)
|
19 | * [Node](#node)
|
20 | * [Browser](#browser)
|
21 | * [Related Projects](#related-projects)
|
22 | * [License](#license)
|
23 |
|
24 | ## Synopsis
|
25 |
|
26 | ```json-rules-engine``` is a powerful, lightweight rules engine. Rules are composed of simple json structures, making them human readable and easy to persist.
|
27 |
|
28 | ## Features
|
29 |
|
30 | * Rules expressed in simple, easy to read JSON
|
31 | * Full support for ```ALL``` and ```ANY``` boolean operators, including recursive nesting
|
32 | * Fast by default, faster with configuration; priority levels and cache settings for fine tuning performance
|
33 | * Secure; no use of eval()
|
34 | * Isomorphic; runs in node and browser
|
35 | * Lightweight & extendable; 17kb gzipped w/few dependencies
|
36 |
|
37 | ## Installation
|
38 |
|
39 | ```bash
|
40 | $ npm install json-rules-engine
|
41 | ```
|
42 |
|
43 | ## Docs
|
44 |
|
45 | - [engine](./docs/engine.md)
|
46 | - [rules](./docs/rules.md)
|
47 | - [almanac](./docs/almanac.md)
|
48 | - [facts](./docs/facts.md)
|
49 |
|
50 | ## Examples
|
51 |
|
52 | See the [Examples](./examples), which demonstrate the major features and capabilities.
|
53 |
|
54 | ## Basic Example
|
55 |
|
56 | This example demonstrates an engine for detecting whether a basketball player has fouled out (a player who commits five personal fouls over the course of a 40-minute game, or six in a 48-minute game, fouls out).
|
57 |
|
58 | ```js
|
59 | const { Engine } = require('json-rules-engine')
|
60 |
|
61 |
|
62 | /**
|
63 | * Setup a new engine
|
64 | */
|
65 | let engine = new Engine()
|
66 |
|
67 | // define a rule for detecting the player has exceeded foul limits. Foul out any player who:
|
68 | // (has committed 5 fouls AND game is 40 minutes) OR (has committed 6 fouls AND game is 48 minutes)
|
69 | engine.addRule({
|
70 | conditions: {
|
71 | any: [{
|
72 | all: [{
|
73 | fact: 'gameDuration',
|
74 | operator: 'equal',
|
75 | value: 40
|
76 | }, {
|
77 | fact: 'personalFoulCount',
|
78 | operator: 'greaterThanInclusive',
|
79 | value: 5
|
80 | }]
|
81 | }, {
|
82 | all: [{
|
83 | fact: 'gameDuration',
|
84 | operator: 'equal',
|
85 | value: 48
|
86 | }, {
|
87 | fact: 'personalFoulCount',
|
88 | operator: 'greaterThanInclusive',
|
89 | value: 6
|
90 | }]
|
91 | }]
|
92 | },
|
93 | event: { // define the event to fire when the conditions evaluate truthy
|
94 | type: 'fouledOut',
|
95 | params: {
|
96 | message: 'Player has fouled out!'
|
97 | }
|
98 | }
|
99 | })
|
100 |
|
101 | /**
|
102 | * Define facts the engine will use to evaluate the conditions above.
|
103 | * Facts may also be loaded asynchronously at runtime; see the advanced example below
|
104 | */
|
105 | let facts = {
|
106 | personalFoulCount: 6,
|
107 | gameDuration: 40
|
108 | }
|
109 |
|
110 | // Run the engine to evaluate
|
111 | engine
|
112 | .run(facts)
|
113 | .then(({ events }) => {
|
114 | events.map(event => console.log(event.params.message))
|
115 | })
|
116 |
|
117 | /*
|
118 | * Output:
|
119 | *
|
120 | * Player has fouled out!
|
121 | */
|
122 | ```
|
123 |
|
124 | This is available in the [examples](./examples/02-nested-boolean-logic.js)
|
125 |
|
126 | ## Advanced Example
|
127 |
|
128 | This example demonstates an engine for identifying employees who work for Microsoft and are taking Christmas day off.
|
129 |
|
130 | This demonstrates an engine which uses asynchronous fact data.
|
131 | Fact information is loaded via API call during runtime, and the results are cached and recycled for all 3 conditions.
|
132 | It also demonstates use of the condition _path_ feature to reference properties of objects returned by facts.
|
133 |
|
134 | ```js
|
135 | const { Engine } = require('json-rules-engine')
|
136 |
|
137 | // example client for making asynchronous requests to an api, database, etc
|
138 | import apiClient from './account-api-client'
|
139 |
|
140 | /**
|
141 | * Setup a new engine
|
142 | */
|
143 | let engine = new Engine()
|
144 |
|
145 | /**
|
146 | * Rule for identifying microsoft employees taking pto on christmas
|
147 | *
|
148 | * the account-information fact returns:
|
149 | * { company: 'XYZ', status: 'ABC', ptoDaysTaken: ['YYYY-MM-DD', 'YYYY-MM-DD'] }
|
150 | */
|
151 | let microsoftRule = {
|
152 | conditions: {
|
153 | all: [{
|
154 | fact: 'account-information',
|
155 | operator: 'equal',
|
156 | value: 'microsoft',
|
157 | path: '$.company' // access the 'company' property of "account-information"
|
158 | }, {
|
159 | fact: 'account-information',
|
160 | operator: 'in',
|
161 | value: ['active', 'paid-leave'], // 'status' can be active or paid-leave
|
162 | path: '$.status' // access the 'status' property of "account-information"
|
163 | }, {
|
164 | fact: 'account-information',
|
165 | operator: 'contains', // the 'ptoDaysTaken' property (an array) must contain '2016-12-25'
|
166 | value: '2016-12-25',
|
167 | path: '$.ptoDaysTaken' // access the 'ptoDaysTaken' property of "account-information"
|
168 | }]
|
169 | },
|
170 | event: {
|
171 | type: 'microsoft-christmas-pto',
|
172 | params: {
|
173 | message: 'current microsoft employee taking christmas day off'
|
174 | }
|
175 | }
|
176 | }
|
177 | engine.addRule(microsoftRule)
|
178 |
|
179 | /**
|
180 | * 'account-information' fact executes an api call and retrieves account data, feeding the results
|
181 | * into the engine. The major advantage of this technique is that although there are THREE conditions
|
182 | * requiring this data, only ONE api call is made. This results in much more efficient runtime performance
|
183 | * and fewer network requests.
|
184 | */
|
185 | engine.addFact('account-information', function (params, almanac) {
|
186 | console.log('loading account information...')
|
187 | return almanac.factValue('accountId')
|
188 | .then((accountId) => {
|
189 | return apiClient.getAccountInformation(accountId)
|
190 | })
|
191 | })
|
192 |
|
193 | // define fact(s) known at runtime
|
194 | let facts = { accountId: 'lincoln' }
|
195 | engine
|
196 | .run(facts)
|
197 | .then(({ events }) => {
|
198 | console.log(facts.accountId + ' is a ' + events.map(event => event.params.message))
|
199 | })
|
200 |
|
201 | /*
|
202 | * OUTPUT:
|
203 | *
|
204 | * loading account information... // <-- API call is made ONCE and results recycled for all 3 conditions
|
205 | * lincoln is a current microsoft employee taking christmas day off
|
206 | */
|
207 | ```
|
208 |
|
209 | This is available in the [examples](./examples/03-dynamic-facts.js)
|
210 |
|
211 | ## Debugging
|
212 |
|
213 | To see what the engine is doing under the hood, debug output can be turned on via:
|
214 |
|
215 | ### Node
|
216 |
|
217 | ```bash
|
218 | DEBUG=json-rules-engine
|
219 | ```
|
220 |
|
221 | ### Browser
|
222 | ```js
|
223 | // set debug flag in local storage & refresh page to see console output
|
224 | localStorage.debug = 'json-rules-engine'
|
225 | ```
|
226 |
|
227 | ## Related Projects
|
228 |
|
229 | https://github.com/vinzdeveloper/json-rule-editor - configuration ui for json-rules-engine:
|
230 |
|
231 | <img width="1680" alt="rule editor 2" src="https://user-images.githubusercontent.com/61467683/82750274-dd3b3b80-9da6-11ea-96eb-434a6a1a9bc1.png">
|
232 |
|
233 |
|
234 | ## License
|
235 | [ISC](./LICENSE)
|