Skip to content

Commit 5c70de9

Browse files
committed
Try out workflows
1 parent c413746 commit 5c70de9

File tree

8 files changed

+98
-22
lines changed

8 files changed

+98
-22
lines changed

.github/workflows/test.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Build
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v1
14+
15+
- uses: actions/cache@v2
16+
with:
17+
path: '**/node_modules'
18+
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
19+
20+
- name: Install packages
21+
run: yarn
22+
23+
- name: Run Typescript Checks
24+
run: yarn lint
25+
26+
- name: Run Tests
27+
run: yarn test:ci
28+
29+
- name: Build
30+
run: yarn build
31+
32+

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ A highly configurable rules engine based on [JSON Schema](https://json-schema.or
44

55
_NBD: It actually doesn't **have** to use JSON Schema, but it's suggested_
66

7+
## Why?
8+
9+
Three reasons:
10+
11+
1. Schema validation of a data structure can be used to implement boolean logic
12+
2. Tools for JSON schema are everywhere and support is wide
13+
3. Custom operators (like those in JSON rules engine) aren't sustainable. You can either make a PR for a new operator that may or may not get merged OR you have to take on the ownership in your own codebase of building and maintaining custom operators. With `json-schema-rules-engine`, you can implement new logic immediately whenever the spec is published (thanks to very actively maintained projects like [AJV](https://github.com/ajv-validator/ajv)).
14+
715
## Features
816

917
- Highly configurable - use any type of schema to express your logic (we strongly suggest JSON Schema)

package.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
{
22
"name": "json-schema-rules-engine",
3-
"version": "0.0.1",
3+
"version": "1.0.0",
44
"description": "Rules engine based on JSON Schema",
55
"main": "build/index.js",
66
"author": "Adam Jenkins",
77
"license": "MIT",
88
"browser": "build/bundle.min.js",
9-
"types": "index.d.ts",
9+
"types": "build/index.d.ts",
1010
"keywords": [
1111
"json schema",
1212
"rules engine"
1313
],
1414
"files": [
15-
"build",
16-
"index.d.ts"
15+
"build"
1716
],
1817
"scripts": {
19-
"dist": "yarn lint && yarn test && yarn build",
2018
"clean": "rimraf build",
2119
"build": "yarn clean && yarn babel && rollup -c",
2220
"babel": "babel src -d build --copy-files --no-copy-ignored",

src/engine.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,17 @@ export const createRulesEngine = (
2626
setRules: (next) => (rules = patch(next, rules)),
2727
run: async (context = {}) => {
2828
emit('start', { context, facts, rules, actions });
29-
const execute = createJob(validator, {
30-
...options,
31-
context,
32-
facts,
33-
rules,
34-
actions,
29+
const execute = createJob(
30+
validator,
31+
{
32+
...options,
33+
context,
34+
facts,
35+
rules,
36+
actions,
37+
},
3538
emit,
36-
});
39+
);
3740

3841
const results = await execute();
3942
emit('complete', { context, results });

src/evaluator.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,37 @@
11
export const createEvaluator =
22
(validator, opts, emit, rule) =>
3-
(factMapId) =>
3+
(mapId) =>
44
async ([factName, { params, path, is }]) => {
5-
const onError = (params) => emit('error', { ...params, rule, factMapId });
5+
emit('debug', { type: 'STARTING_FACT', rule, mapId, factName });
6+
const onError = (params) =>
7+
emit('error', { ...params, factName, rule, mapId });
68

79
const fact = opts.facts[factName] || opts.context[factName];
810
try {
911
const value = await (typeof fact === 'function' ? fact(params) : fact);
1012
const resolved = path ? opts.resolver(value, path) : value;
13+
emit('debug', {
14+
type: 'EXECUTED_FACT',
15+
rule,
16+
mapId,
17+
path,
18+
factName,
19+
value,
20+
resolved,
21+
});
1122
try {
1223
const result = await validator(resolved, is);
24+
emit('debug', {
25+
type: 'EVALUATED_FACT',
26+
rule,
27+
mapId,
28+
path,
29+
factName,
30+
value,
31+
resolved,
32+
is,
33+
result,
34+
});
1335
return { factName, ...result, value, resolved };
1436
} catch (error) {
1537
onError({ type: 'FactEvaluationError', path, is, resolved });

src/fact.map.processor.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { createEvaluator } from './evaluator';
33
export const createFactMapProcessor = (validator, opts, emit) => (rule) => {
44
const evaluator = createEvaluator(validator, opts, emit, rule);
55
return async (factMap, id) => {
6+
emit('debug', { type: 'STARTING_FACT_MAP', rule, mapId: id });
7+
68
// flags for if there was an error processing the fact map
79
// and if all evaluations in the fact map passed
810
let error = false;
@@ -18,6 +20,8 @@ export const createFactMapProcessor = (validator, opts, emit) => (rule) => {
1820
return acc;
1921
}, {});
2022

23+
emit('debug', { type: 'FINISHED_FACT_MAP', rule, mapId: id, results });
24+
2125
// return the results in the same form they were passed in
2226
return {
2327
[id]: {

src/index.d.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,28 +60,32 @@ export type JobConstruct = EngineOptions & {
6060
type StartingFactMapEvent = {
6161
type: 'STARTING_FACT_MAP';
6262
rule: string;
63-
index: number;
63+
mapId: string | number;
6464
};
6565

6666
type StartingFactEvent = {
6767
type: 'STARTING_FACT';
6868
rule: string;
69-
index: number;
69+
mapId: string | number;
70+
factName: string;
7071
};
7172

7273
type ExecutedFactEvent = {
7374
type: 'EXECUTED_FACT';
7475
rule: string;
75-
index: number;
76-
params: any;
76+
mapId: string | number;
77+
factName: string;
78+
params?: any;
79+
path?: string;
7780
value: any;
7881
resolved: any;
7982
};
8083

8184
type EvaluatedFactEvent = {
8285
type: 'EVALUATED_FACT';
8386
rule: string;
84-
index: number;
87+
mapId: string | number;
88+
factName: string;
8589
value: any;
8690
resolved: any;
8791
is: Record<string, any>;
@@ -91,6 +95,8 @@ type EvaluatedFactEvent = {
9195
type FactEvaluationError = {
9296
type: 'FactEvaluationError';
9397
rule: string;
98+
mapId: string | number;
99+
factName: string;
94100
error: Error;
95101
context: Context;
96102
factName: string;
@@ -103,7 +109,8 @@ type FactEvaluationError = {
103109
type FactExecutionError = {
104110
type: 'FactExecutionError';
105111
rule: string;
106-
index: number;
112+
mapId: string | number;
113+
factName: string;
107114
error: Error;
108115
context: Context;
109116
factName: string;

src/rule.runner.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ export const createRuleRunner = (validator, opts, emit) => {
1414
opts.resolver,
1515
);
1616

17+
const process = processor(rule);
18+
1719
const ruleResults = await Promise.all(
1820
Array.isArray(interpolated)
19-
? interpolated.map(processor(rule))
21+
? interpolated.map(process)
2022
: Object.entries(interpolated).map(([factMap, id]) =>
21-
processor(rule)(factMap, id),
23+
process(factMap, id),
2224
),
2325
);
2426

0 commit comments

Comments
 (0)