@clipboard-health/rules-engine 1.1.1 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/src/index.js +7 -0
- package/src/index.js.map +1 -0
- package/src/lib/append-output.d.ts +6 -0
- package/src/lib/append-output.js +13 -0
- package/src/lib/append-output.js.map +1 -0
- package/src/lib/rule.d.ts +29 -0
- package/src/lib/rule.js +3 -0
- package/src/lib/rule.js.map +1 -0
- package/src/lib/runners/all.d.ts +7 -0
- package/src/lib/runners/all.js +17 -0
- package/src/lib/runners/all.js.map +1 -0
- package/src/lib/runners/first-match.d.ts +7 -0
- package/src/lib/runners/first-match.js +18 -0
- package/src/lib/runners/first-match.js.map +1 -0
- package/src/lib/runners/index.js +6 -0
- package/src/lib/runners/index.js.map +1 -0
- package/.eslintrc.json +0 -8
- package/examples/rules.ts +0 -71
- package/jest.config.ts +0 -19
- package/project.json +0 -33
- package/src/lib/append-output.ts +0 -16
- package/src/lib/rule.ts +0 -37
- package/src/lib/runners/all.spec.ts +0 -64
- package/src/lib/runners/all.ts +0 -18
- package/src/lib/runners/first-match.spec.ts +0 -59
- package/src/lib/runners/first-match.ts +0 -18
- package/tsconfig.json +0 -19
- package/tsconfig.lib.json +0 -9
- package/tsconfig.lint.json +0 -7
- package/tsconfig.spec.json +0 -7
- package/typedoc.json +0 -4
- /package/src/{index.ts → index.d.ts} +0 -0
- /package/src/lib/runners/{index.ts → index.d.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clipboard-health/rules-engine",
|
|
3
3
|
"description": "",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.5",
|
|
5
5
|
"bugs": "https://github.com/clipboardhealth/core-utils/issues",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"tslib": "2.6.3",
|
|
@@ -22,5 +22,6 @@
|
|
|
22
22
|
"embed": "embedme README.md"
|
|
23
23
|
},
|
|
24
24
|
"type": "commonjs",
|
|
25
|
-
"typings": "./src/index.d.ts"
|
|
25
|
+
"typings": "./src/index.d.ts",
|
|
26
|
+
"types": "./src/index.d.ts"
|
|
26
27
|
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./lib/append-output"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./lib/rule"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./lib/runners"), exports);
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/rules-engine/src/index.ts"],"names":[],"mappings":";;;AAAA,8DAAoC;AACpC,qDAA2B;AAC3B,wDAA8B"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ReadonlyDeep } from "type-fest";
|
|
2
|
+
import { type RuleContext } from "./rule";
|
|
3
|
+
/**
|
|
4
|
+
* Rule output is immutable, do not modify existing items, only append using this function.
|
|
5
|
+
*/
|
|
6
|
+
export declare function appendOutput<TInput, TOutput>(context: RuleContext<TInput, TOutput>, output: ReadonlyDeep<TOutput>): RuleContext<TInput, TOutput>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.appendOutput = appendOutput;
|
|
4
|
+
/**
|
|
5
|
+
* Rule output is immutable, do not modify existing items, only append using this function.
|
|
6
|
+
*/
|
|
7
|
+
function appendOutput(context, output) {
|
|
8
|
+
return {
|
|
9
|
+
input: context.input,
|
|
10
|
+
output: [...context.output, output],
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=append-output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"append-output.js","sourceRoot":"","sources":["../../../../../packages/rules-engine/src/lib/append-output.ts"],"names":[],"mappings":";;AAOA,oCAQC;AAXD;;GAEG;AACH,SAAgB,YAAY,CAC1B,OAAqC,EACrC,MAA6B;IAE7B,OAAO;QACL,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC;KACpC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type ReadonlyDeep } from "type-fest";
|
|
2
|
+
export interface RuleContext<TInput, TOutput> {
|
|
3
|
+
/**
|
|
4
|
+
* Input is immutable, rules must not modify it.
|
|
5
|
+
*/
|
|
6
|
+
input: ReadonlyDeep<TInput>;
|
|
7
|
+
/**
|
|
8
|
+
* Output is immutable, do not modify existing items, only append.
|
|
9
|
+
*
|
|
10
|
+
* @see {@link appendOutput}
|
|
11
|
+
*/
|
|
12
|
+
output: ReadonlyArray<ReadonlyDeep<TOutput>>;
|
|
13
|
+
}
|
|
14
|
+
export interface Rule<TInput, TOutput, TContext extends RuleContext<TInput, TOutput> = RuleContext<TInput, TOutput>> {
|
|
15
|
+
/**
|
|
16
|
+
* Returns whether the rule should run or not.
|
|
17
|
+
*
|
|
18
|
+
* Only the `input` and not the full `context` is passed to `runIf`. This prevents rules from
|
|
19
|
+
* relying on `output`, which may be appended to by previous rules by the time `run` is called.
|
|
20
|
+
*/
|
|
21
|
+
runIf: (input: ReadonlyDeep<TInput>) => boolean;
|
|
22
|
+
/**
|
|
23
|
+
* A pure function that runs rule logic and returns a new context by appending to the output
|
|
24
|
+
* array.
|
|
25
|
+
*
|
|
26
|
+
* @see {@link appendOutput}
|
|
27
|
+
*/
|
|
28
|
+
run: (context: TContext) => TContext;
|
|
29
|
+
}
|
package/src/lib/rule.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule.js","sourceRoot":"","sources":["../../../../../packages/rules-engine/src/lib/rule.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Rule, type RuleContext } from "../rule";
|
|
2
|
+
/**
|
|
3
|
+
* Run all rules that return true for `runIf`.
|
|
4
|
+
*
|
|
5
|
+
* @param rules The rules to run.
|
|
6
|
+
*/
|
|
7
|
+
export declare function all<TInput, TOutput, TContext extends RuleContext<TInput, TOutput>>(...rules: Array<Rule<TInput, TOutput, TContext>>): Rule<TInput, TOutput, TContext>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.all = all;
|
|
4
|
+
/**
|
|
5
|
+
* Run all rules that return true for `runIf`.
|
|
6
|
+
*
|
|
7
|
+
* @param rules The rules to run.
|
|
8
|
+
*/
|
|
9
|
+
function all(...rules) {
|
|
10
|
+
return {
|
|
11
|
+
runIf: (input) => rules.some((rule) => rule.runIf(input)),
|
|
12
|
+
run: (context) => rules
|
|
13
|
+
.filter((rule) => rule.runIf(context.input))
|
|
14
|
+
.reduce((previousContext, rule) => rule.run(previousContext), context),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=all.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"all.js","sourceRoot":"","sources":["../../../../../../packages/rules-engine/src/lib/runners/all.ts"],"names":[],"mappings":";;AAOA,kBAUC;AAfD;;;;GAIG;AACH,SAAgB,GAAG,CACjB,GAAG,KAA6C;IAEhD,OAAO;QACL,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACzD,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,CACf,KAAK;aACF,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;aAC3C,MAAM,CAAC,CAAC,eAAe,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3E,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Rule, type RuleContext } from "../rule";
|
|
2
|
+
/**
|
|
3
|
+
* Run the first rule that returns true for `runIf`.
|
|
4
|
+
*
|
|
5
|
+
* @param rules The rules to run.
|
|
6
|
+
*/
|
|
7
|
+
export declare function firstMatch<TInput, TOutput, TContext extends RuleContext<TInput, TOutput>>(...rules: Array<Rule<TInput, TOutput, TContext>>): Rule<TInput, TOutput, TContext>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.firstMatch = firstMatch;
|
|
4
|
+
/**
|
|
5
|
+
* Run the first rule that returns true for `runIf`.
|
|
6
|
+
*
|
|
7
|
+
* @param rules The rules to run.
|
|
8
|
+
*/
|
|
9
|
+
function firstMatch(...rules) {
|
|
10
|
+
return {
|
|
11
|
+
runIf: (input) => rules.some((rule) => rule.runIf(input)),
|
|
12
|
+
run: (context) => {
|
|
13
|
+
const rule = rules.find((rule) => rule.runIf(context.input));
|
|
14
|
+
return rule ? rule.run(context) : context;
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=first-match.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"first-match.js","sourceRoot":"","sources":["../../../../../../packages/rules-engine/src/lib/runners/first-match.ts"],"names":[],"mappings":";;AAOA,gCAUC;AAfD;;;;GAIG;AACH,SAAgB,UAAU,CACxB,GAAG,KAA6C;IAEhD,OAAO;QACL,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACzD,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE;YACf,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;YAC7D,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAC5C,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/rules-engine/src/lib/runners/index.ts"],"names":[],"mappings":";;;AAAA,gDAAsB;AACtB,wDAA8B"}
|
package/.eslintrc.json
DELETED
package/examples/rules.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
all,
|
|
3
|
-
appendOutput,
|
|
4
|
-
firstMatch,
|
|
5
|
-
type Rule,
|
|
6
|
-
type RuleContext,
|
|
7
|
-
} from "@clipboard-health/rules-engine";
|
|
8
|
-
|
|
9
|
-
interface Input {
|
|
10
|
-
number1: number;
|
|
11
|
-
number2: number;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface Output {
|
|
15
|
-
result: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const exampleContext: RuleContext<Input, Output> = {
|
|
19
|
-
input: {
|
|
20
|
-
number1: 2,
|
|
21
|
-
number2: 5,
|
|
22
|
-
},
|
|
23
|
-
output: [],
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const addNumbersIfPositiveRule: Rule<Input, Output> = {
|
|
27
|
-
runIf: (input) => input.number1 > 0 && input.number2 > 0,
|
|
28
|
-
run: (context) => {
|
|
29
|
-
const { number1, number2 } = context.input;
|
|
30
|
-
const sum = number1 + number2;
|
|
31
|
-
return appendOutput(context, { result: sum });
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const multiplyNumbersIfPositiveRule: Rule<Input, Output> = {
|
|
36
|
-
runIf: (input) => input.number1 > 0 && input.number2 > 0,
|
|
37
|
-
run: (context) => {
|
|
38
|
-
const { number1, number2 } = context.input;
|
|
39
|
-
const sum = number1 * number2;
|
|
40
|
-
return appendOutput(context, { result: sum });
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const divideNumbersIfNegative: Rule<Input, Output> = {
|
|
45
|
-
runIf: (input) => input.number1 < 0 && input.number2 < 0,
|
|
46
|
-
run: (context) => {
|
|
47
|
-
const { number1, number2 } = context.input;
|
|
48
|
-
const sum = number1 * number2;
|
|
49
|
-
return appendOutput(context, { result: sum });
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
// Using all() applies all the rules to the context
|
|
54
|
-
const allResult = all(
|
|
55
|
-
addNumbersIfPositiveRule,
|
|
56
|
-
divideNumbersIfNegative,
|
|
57
|
-
multiplyNumbersIfPositiveRule,
|
|
58
|
-
).run(exampleContext);
|
|
59
|
-
|
|
60
|
-
console.log(allResult.output);
|
|
61
|
-
// => [{ result: 7 }, { result: 10 }]
|
|
62
|
-
|
|
63
|
-
// Using firstMatch() applies the first the rules to the context
|
|
64
|
-
const firstMatchResult = firstMatch(
|
|
65
|
-
divideNumbersIfNegative,
|
|
66
|
-
addNumbersIfPositiveRule,
|
|
67
|
-
multiplyNumbersIfPositiveRule,
|
|
68
|
-
).run(exampleContext);
|
|
69
|
-
|
|
70
|
-
console.log(firstMatchResult.output);
|
|
71
|
-
// => [{ result: 7 }]
|
package/jest.config.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
coverageDirectory: "../../coverage/packages/rules-engine",
|
|
3
|
-
coveragePathIgnorePatterns: [],
|
|
4
|
-
coverageThreshold: {
|
|
5
|
-
global: {
|
|
6
|
-
branches: 100,
|
|
7
|
-
functions: 100,
|
|
8
|
-
lines: 100,
|
|
9
|
-
statements: 100,
|
|
10
|
-
},
|
|
11
|
-
},
|
|
12
|
-
displayName: "rules-engine",
|
|
13
|
-
moduleFileExtensions: ["ts", "js"],
|
|
14
|
-
preset: "../../jest.preset.js",
|
|
15
|
-
testEnvironment: "node",
|
|
16
|
-
transform: {
|
|
17
|
-
"^.+\\.[tj]s$": ["ts-jest", { tsconfig: "<rootDir>/tsconfig.spec.json" }],
|
|
18
|
-
},
|
|
19
|
-
};
|
package/project.json
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
3
|
-
"name": "rules-engine",
|
|
4
|
-
"projectType": "library",
|
|
5
|
-
"sourceRoot": "packages/rules-engine/src",
|
|
6
|
-
"tags": [],
|
|
7
|
-
"targets": {
|
|
8
|
-
"build": {
|
|
9
|
-
"executor": "@nx/js:tsc",
|
|
10
|
-
"options": {
|
|
11
|
-
"assets": ["packages/rules-engine/*.md"],
|
|
12
|
-
"main": "packages/rules-engine/src/index.js",
|
|
13
|
-
"outputPath": "dist/packages/rules-engine",
|
|
14
|
-
"tsConfig": "packages/rules-engine/tsconfig.lib.json"
|
|
15
|
-
},
|
|
16
|
-
"outputs": ["{options.outputPath}"]
|
|
17
|
-
},
|
|
18
|
-
"lint": {
|
|
19
|
-
"executor": "@nx/eslint:lint",
|
|
20
|
-
"options": {
|
|
21
|
-
"lintFilePatterns": ["packages/rules-engine/**/*.[jt]s"],
|
|
22
|
-
"maxWarnings": 0
|
|
23
|
-
},
|
|
24
|
-
"outputs": ["{options.outputFile}"]
|
|
25
|
-
},
|
|
26
|
-
"test": {
|
|
27
|
-
"executor": "@nx/jest:jest",
|
|
28
|
-
"options": {
|
|
29
|
-
"jestConfig": "packages/rules-engine/jest.config.ts"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
package/src/lib/append-output.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { type ReadonlyDeep } from "type-fest";
|
|
2
|
-
|
|
3
|
-
import { type RuleContext } from "./rule";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Rule output is immutable, do not modify existing items, only append using this function.
|
|
7
|
-
*/
|
|
8
|
-
export function appendOutput<TInput, TOutput>(
|
|
9
|
-
context: RuleContext<TInput, TOutput>,
|
|
10
|
-
output: ReadonlyDeep<TOutput>,
|
|
11
|
-
): RuleContext<TInput, TOutput> {
|
|
12
|
-
return {
|
|
13
|
-
input: context.input,
|
|
14
|
-
output: [...context.output, output],
|
|
15
|
-
};
|
|
16
|
-
}
|
package/src/lib/rule.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { type ReadonlyDeep } from "type-fest";
|
|
2
|
-
|
|
3
|
-
export interface RuleContext<TInput, TOutput> {
|
|
4
|
-
/**
|
|
5
|
-
* Input is immutable, rules must not modify it.
|
|
6
|
-
*/
|
|
7
|
-
input: ReadonlyDeep<TInput>;
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Output is immutable, do not modify existing items, only append.
|
|
11
|
-
*
|
|
12
|
-
* @see {@link appendOutput}
|
|
13
|
-
*/
|
|
14
|
-
output: ReadonlyArray<ReadonlyDeep<TOutput>>;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface Rule<
|
|
18
|
-
TInput,
|
|
19
|
-
TOutput,
|
|
20
|
-
TContext extends RuleContext<TInput, TOutput> = RuleContext<TInput, TOutput>,
|
|
21
|
-
> {
|
|
22
|
-
/**
|
|
23
|
-
* Returns whether the rule should run or not.
|
|
24
|
-
*
|
|
25
|
-
* Only the `input` and not the full `context` is passed to `runIf`. This prevents rules from
|
|
26
|
-
* relying on `output`, which may be appended to by previous rules by the time `run` is called.
|
|
27
|
-
*/
|
|
28
|
-
runIf: (input: ReadonlyDeep<TInput>) => boolean;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* A pure function that runs rule logic and returns a new context by appending to the output
|
|
32
|
-
* array.
|
|
33
|
-
*
|
|
34
|
-
* @see {@link appendOutput}
|
|
35
|
-
*/
|
|
36
|
-
run: (context: TContext) => TContext;
|
|
37
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { type Rule, type RuleContext } from "../..";
|
|
2
|
-
import { appendOutput } from "../append-output";
|
|
3
|
-
import { all } from "./all";
|
|
4
|
-
|
|
5
|
-
interface Input {
|
|
6
|
-
a: number;
|
|
7
|
-
b: number;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
type Output = number;
|
|
11
|
-
|
|
12
|
-
type TestContext = RuleContext<Input, Output>;
|
|
13
|
-
|
|
14
|
-
type TestRule = Rule<Input, Output>;
|
|
15
|
-
|
|
16
|
-
const context: TestContext = {
|
|
17
|
-
input: { a: 1, b: 2 },
|
|
18
|
-
output: [],
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const testRule1: TestRule = {
|
|
22
|
-
runIf: () => false,
|
|
23
|
-
run: (context) => appendOutput(context, 1),
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const testRule2: TestRule = {
|
|
27
|
-
runIf: () => true,
|
|
28
|
-
run: (context) => appendOutput(context, 2),
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const testRule3: TestRule = {
|
|
32
|
-
runIf: () => true,
|
|
33
|
-
run: (context) => appendOutput(context, 3),
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const testRule4: TestRule = {
|
|
37
|
-
runIf: () => false,
|
|
38
|
-
run: (context) => appendOutput(context, 4),
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
describe("all", () => {
|
|
42
|
-
describe("if", () => {
|
|
43
|
-
it("returns true if any rules are true", () => {
|
|
44
|
-
expect(all(testRule1, testRule2, testRule3).runIf(context.input)).toBe(true);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it("returns false if all rules are false", () => {
|
|
48
|
-
expect(all(testRule1, testRule4).runIf(context.input)).toBe(false);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe("run", () => {
|
|
53
|
-
it("runs all the matching rules", () => {
|
|
54
|
-
expect(all(testRule1, testRule2, testRule3, testRule4).run(context)).toEqual({
|
|
55
|
-
...context,
|
|
56
|
-
output: [2, 3],
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it("returns the received context if no rule can be run", () => {
|
|
61
|
-
expect(all(testRule1, testRule4).run(context)).toEqual(context);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
});
|
package/src/lib/runners/all.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { type Rule, type RuleContext } from "../rule";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Run all rules that return true for `runIf`.
|
|
5
|
-
*
|
|
6
|
-
* @param rules The rules to run.
|
|
7
|
-
*/
|
|
8
|
-
export function all<TInput, TOutput, TContext extends RuleContext<TInput, TOutput>>(
|
|
9
|
-
...rules: Array<Rule<TInput, TOutput, TContext>>
|
|
10
|
-
): Rule<TInput, TOutput, TContext> {
|
|
11
|
-
return {
|
|
12
|
-
runIf: (input) => rules.some((rule) => rule.runIf(input)),
|
|
13
|
-
run: (context) =>
|
|
14
|
-
rules
|
|
15
|
-
.filter((rule) => rule.runIf(context.input))
|
|
16
|
-
.reduce((previousContext, rule) => rule.run(previousContext), context),
|
|
17
|
-
};
|
|
18
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { type Rule, type RuleContext } from "../..";
|
|
2
|
-
import { appendOutput } from "../append-output";
|
|
3
|
-
import { firstMatch } from "./first-match";
|
|
4
|
-
|
|
5
|
-
interface Input {
|
|
6
|
-
a: number;
|
|
7
|
-
b: number;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
type Output = number;
|
|
11
|
-
|
|
12
|
-
type TestContext = RuleContext<Input, Output>;
|
|
13
|
-
|
|
14
|
-
type TestRule = Rule<Input, Output>;
|
|
15
|
-
|
|
16
|
-
const context: TestContext = {
|
|
17
|
-
input: { a: 1, b: 2 },
|
|
18
|
-
output: [],
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const testRule1: TestRule = {
|
|
22
|
-
runIf: () => false,
|
|
23
|
-
run: (context) => appendOutput(context, 1),
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const testRule2: TestRule = {
|
|
27
|
-
runIf: () => true,
|
|
28
|
-
run: (context) => appendOutput(context, 2),
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const testRule3: TestRule = {
|
|
32
|
-
runIf: () => false,
|
|
33
|
-
run: (context) => appendOutput(context, 3),
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
describe("firstMatch", () => {
|
|
37
|
-
describe("if", () => {
|
|
38
|
-
it("returns true if any rules are true", () => {
|
|
39
|
-
expect(firstMatch(testRule1, testRule2, testRule3).runIf(context.input)).toBe(true);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it("returns false if all rules are false", () => {
|
|
43
|
-
expect(firstMatch(testRule3).runIf(context.input)).toBe(false);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
describe("run", () => {
|
|
48
|
-
it("runs the first matching rule", () => {
|
|
49
|
-
expect(firstMatch(testRule1, testRule2, testRule3).run(context)).toEqual({
|
|
50
|
-
...context,
|
|
51
|
-
output: [2],
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("returns the received context if no rule can be run", () => {
|
|
56
|
-
expect(firstMatch(testRule1, testRule3).run(context)).toEqual(context);
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { type Rule, type RuleContext } from "../rule";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Run the first rule that returns true for `runIf`.
|
|
5
|
-
*
|
|
6
|
-
* @param rules The rules to run.
|
|
7
|
-
*/
|
|
8
|
-
export function firstMatch<TInput, TOutput, TContext extends RuleContext<TInput, TOutput>>(
|
|
9
|
-
...rules: Array<Rule<TInput, TOutput, TContext>>
|
|
10
|
-
): Rule<TInput, TOutput, TContext> {
|
|
11
|
-
return {
|
|
12
|
-
runIf: (input) => rules.some((rule) => rule.runIf(input)),
|
|
13
|
-
run: (context) => {
|
|
14
|
-
const rule = rules.find((rule) => rule.runIf(context.input));
|
|
15
|
-
return rule ? rule.run(context) : context;
|
|
16
|
-
},
|
|
17
|
-
};
|
|
18
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../tsconfig.base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"outDir": "../../dist/out-tsc"
|
|
5
|
-
},
|
|
6
|
-
"files": [],
|
|
7
|
-
"include": [],
|
|
8
|
-
"references": [
|
|
9
|
-
{
|
|
10
|
-
"path": "./tsconfig.lib.json"
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"path": "./tsconfig.lint.json"
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
"path": "./tsconfig.spec.json"
|
|
17
|
-
}
|
|
18
|
-
]
|
|
19
|
-
}
|
package/tsconfig.lib.json
DELETED
package/tsconfig.lint.json
DELETED
package/tsconfig.spec.json
DELETED
package/typedoc.json
DELETED
|
File without changes
|
|
File without changes
|