diff --git a/README.md b/README.md index 77cfcdf..2ab4db4 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@ ![json-rules-engine](http://i.imgur.com/MAzq7l2.png) [![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) -[![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) +[![Build Status](https://github.com/truongnd98/json-rules-engine/workflows/Node.js%20CI/badge.svg?branch=master)](https://github.com/truongnd98/json-rules-engine/workflows/Node.js%20CI/badge.svg?branch=master) -[![npm version](https://badge.fury.io/js/json-rules-engine.svg)](https://badge.fury.io/js/json-rules-engine) -[![install size](https://packagephobia.now.sh/badge?p=json-rules-engine)](https://packagephobia.now.sh/result?p=json-rules-engine) -[![npm downloads](https://img.shields.io/npm/dm/json-rules-engine.svg)](https://www.npmjs.com/package/json-rules-engine) +[![npm version](https://badge.fury.io/js/@truong8864%2Fjson-rules-engine.svg)](https://badge.fury.io/js/@truong8864%2Fjson-rules-engine) +[![install size](https://packagephobia.com/badge?p=@truong8864/json-rules-engine)](https://packagephobia.com/result?p=@truong8864/json-rules-engine) +[![npm downloads](https://img.shields.io/npm/dm/%40truong8864%2Fjson-rules-engine)](https://www.npmjs.com/package/@truong8864/json-rules-engine) + +## Why does this fork exist? + +```json-rules-engine``` Currently, rules are run in parallel. I would like a feature that allows the rules to run synchronously. A rules engine expressed in JSON diff --git a/package.json b/package.json index 477902a..0275e59 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "json-rules-engine", - "version": "7.3.1", + "name": "@truong8864/json-rules-engine", + "version": "7.3.2", "description": "Rules Engine expressed in simple json", "main": "dist/index.js", "types": "types/index.d.ts", @@ -19,7 +19,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/cachecontrol/json-rules-engine" + "url": "https://github.com/truongnd98/json-rules-engine" }, "keywords": [ "rules", @@ -63,9 +63,9 @@ ], "license": "ISC", "bugs": { - "url": "https://github.com/cachecontrol/json-rules-engine/issues" + "url": "https://github.com/truongnd98/json-rules-engine/issues" }, - "homepage": "https://github.com/cachecontrol/json-rules-engine", + "homepage": "https://github.com/truongnd98/json-rules-engine", "devDependencies": { "babel-cli": "6.26.0", "babel-core": "6.26.3", diff --git a/src/engine.js b/src/engine.js index 4cb8751..65836b5 100644 --- a/src/engine.js +++ b/src/engine.js @@ -319,6 +319,76 @@ class Engine extends EventEmitter { }).catch(reject) }) } + + /** + * Runs an array of rules synchronous + * @param {Rule[]} array of rules to be evaluated + * @return {AsyncIterableIterator} An async iterator yielding rule result has have been evaluated + */ + async * syncEvaluateRules (ruleArray, almanac) { + if (this.status !== RUNNING) { + debug('engine::run, skipping remaining rules', { status: this.status }) + return Promise.resolve() + } + + for (let index = 0; index < ruleArray.length; index++) { + const rule = [index] + yield rule.evaluate(almanac).then((ruleResult) => { + debug('engine::run', { ruleResult: ruleResult.result }) + almanac.addResult(ruleResult) + if (ruleResult.result) { + almanac.addEvent(ruleResult.event, 'success') + this.emitAsync('success', ruleResult.event, almanac, ruleResult) + .then(() => this.emitAsync(ruleResult.event.type, ruleResult.event.params, almanac, ruleResult)) + } else { + almanac.addEvent(ruleResult.event, 'failure') + this.emitAsync('failure', ruleResult.event, almanac, ruleResult) + } + + return ruleResult + }) + } + } + + /** + * Runs the rules engine synchronous + * @param {Object} runtimeFacts - fact values known at runtime + * @param {Object} runOptions - run options + * @returns {AsyncIterableIterator} An async iterator yielding rule result has have been evaluated + */ + async * runSync (runtimeFacts = {}, runOptions = {}) { + debug('engine::run started') + this.status = RUNNING + + const almanac = runOptions.almanac || new Almanac({ + allowUndefinedFacts: this.allowUndefinedFacts, + pathResolver: this.pathResolver + }) + + this.facts.forEach(fact => { + almanac.addFact(fact) + }) + for (const factId in runtimeFacts) { + let fact + if (runtimeFacts[factId] instanceof Fact) { + fact = runtimeFacts[factId] + } else { + fact = new Fact(factId, runtimeFacts[factId]) + } + + almanac.addFact(fact) + debug('engine::run initialized runtime fact', { id: fact.id, value: fact.value, type: typeof fact.value }) + } + const orderedSets = this.prioritizeRules() + + for (let index = 0; index < orderedSets.length; index++) { + const set = [index] + yield * this.syncEvaluateRules(set, almanac) + } + + this.status = FINISHED + debug('engine::run completed') + } } export default Engine diff --git a/types/index.d.ts b/types/index.d.ts index aaa22f8..72ab988 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -59,6 +59,8 @@ export class Engine { run(facts?: Record, runOptions?: RunOptions): Promise; stop(): this; + + runSync(facts?: Record, runOptions?: RunOptions): AsyncIterableIterator; } export interface OperatorEvaluator {