@clipboard-health/rules-engine 1.0.3 → 1.1.2

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/.eslintrc.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": ["../../.eslintrc.json"],
3
+ "ignorePatterns": ["!**/*"],
4
+ "parserOptions": {
5
+ "project": "tsconfig.lint.json",
6
+ "tsconfigRootDir": "packages/rules-engine"
7
+ }
8
+ }
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @clipboard-health/rules-engine
2
2
 
3
- Exposes a functional rules-engine with 2 engines:
3
+ Exposes a functional rules engine with two rule runners:
4
4
 
5
5
  - `firstMatch`: Runs the first rule that matches the criteria
6
6
  - `all`: Runs all the rules that matches the criteria
@@ -81,7 +81,8 @@ const allResult = all(
81
81
  multiplyNumbersIfPositiveRule,
82
82
  ).run(exampleContext);
83
83
 
84
- console.log(allResult.output); // AllResult.output = [{ result: 7 }, { result: 10 }]
84
+ console.log(allResult.output);
85
+ // => [{ result: 7 }, { result: 10 }]
85
86
 
86
87
  // Using firstMatch() applies the first the rules to the context
87
88
  const firstMatchResult = firstMatch(
@@ -90,7 +91,8 @@ const firstMatchResult = firstMatch(
90
91
  multiplyNumbersIfPositiveRule,
91
92
  ).run(exampleContext);
92
93
 
93
- console.log(firstMatchResult.output); // [{ result: 7 }]
94
+ console.log(firstMatchResult.output);
95
+ // => [{ result: 7 }]
94
96
  ```
95
97
 
96
98
  ## Local development commands
@@ -0,0 +1,71 @@
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 ADDED
@@ -0,0 +1,19 @@
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/package.json CHANGED
@@ -1,15 +1,26 @@
1
1
  {
2
2
  "name": "@clipboard-health/rules-engine",
3
- "version": "1.0.3",
3
+ "description": "",
4
+ "version": "1.1.2",
5
+ "bugs": "https://github.com/clipboardhealth/core-utils/issues",
4
6
  "dependencies": {
7
+ "tslib": "2.6.3",
5
8
  "type-fest": "4.23.0"
6
9
  },
10
+ "keywords": [],
11
+ "license": "MIT",
7
12
  "main": "./src/index.js",
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/clipboardhealth/core-utils.git",
19
+ "directory": "packages/rules-engine"
20
+ },
8
21
  "scripts": {
9
- "build": "nx build rules-engine",
10
- "embed": "embedme README.md",
11
- "lint": "nx lint rules-engine",
12
- "test": "nx test rules-engine"
22
+ "embed": "embedme README.md"
13
23
  },
14
- "type": "commonjs"
15
- }
24
+ "type": "commonjs",
25
+ "typings": "./src/index.d.ts"
26
+ }
package/project.json ADDED
@@ -0,0 +1,33 @@
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/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./lib/append-output";
2
+ export * from "./lib/rule";
3
+ export * from "./lib/runners";
@@ -0,0 +1,16 @@
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
+ }
@@ -0,0 +1,37 @@
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
+ }
@@ -0,0 +1,64 @@
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
+ });
@@ -0,0 +1,18 @@
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
+ }
@@ -0,0 +1,59 @@
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
+ });
@@ -0,0 +1,18 @@
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
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./all";
2
+ export * from "./first-match";
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
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
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "declaration": true,
5
+ "types": ["node"]
6
+ },
7
+ "include": ["src/**/*.ts"],
8
+ "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
9
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "types": ["jest", "node"]
5
+ },
6
+ "include": ["."]
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "types": ["jest", "node"]
5
+ },
6
+ "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"]
7
+ }
package/typedoc.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": ["../../typedoc.base.json"],
3
+ "entryPoints": ["src/index.ts"]
4
+ }
package/CHANGELOG.md DELETED
@@ -1,68 +0,0 @@
1
- # Changelog
2
-
3
- This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
-
5
- ## [1.0.3](https://github.com/ClipboardHealth/cbh-core/compare/rules-engine-1.0.2...rules-engine-1.0.3) (2024-07-25)
6
-
7
- ## [1.0.2](https://github.com/ClipboardHealth/cbh-core/compare/rules-engine-1.0.1...rules-engine-1.0.2) (2024-07-18)
8
-
9
- ## [1.0.1](https://github.com/ClipboardHealth/cbh-core/compare/rules-engine-1.0.0...rules-engine-1.0.1) (2024-07-18)
10
-
11
-
12
- ### Bug Fixes
13
-
14
- * add build postTarget ([#692](https://github.com/ClipboardHealth/cbh-core/issues/692)) ([3b42efb](https://github.com/ClipboardHealth/cbh-core/commit/3b42efb603572c7a273c8eedd554773c6a364acf))
15
-
16
- ## [1.0.0](https://github.com/ClipboardHealth/cbh-core/compare/rules-engine-0.1.6...rules-engine-1.0.0) (2024-07-18)
17
-
18
-
19
- ### ⚠ BREAKING CHANGES
20
-
21
- * upgrade Nx to v18 (#690)
22
-
23
- ### Code Refactoring
24
-
25
- * upgrade Nx to v18 ([#690](https://github.com/ClipboardHealth/cbh-core/issues/690)) ([e6dd982](https://github.com/ClipboardHealth/cbh-core/commit/e6dd982db39022a72dfbf888f707768bae834ccb))
26
-
27
- ## [0.1.6](https://github.com/ClipboardHealth/cbh-core/compare/rules-engine-0.1.5...rules-engine-0.1.6) (2024-07-12)
28
-
29
-
30
- ### Bug Fixes
31
-
32
- * **deps:** update dependency type-fest to v4 ([#676](https://github.com/ClipboardHealth/cbh-core/issues/676)) ([3c5d3ec](https://github.com/ClipboardHealth/cbh-core/commit/3c5d3ec5c15f7ed01b842fc813e5290fc3ca6021))
33
-
34
- ## [0.1.5](https://github.com/ClipboardHealth/cbh-core/compare/rules-engine-0.1.4...rules-engine-0.1.5) (2024-07-12)
35
-
36
-
37
- ### Bug Fixes
38
-
39
- * testing Nx upgrade, attempt 2 ([4066dab](https://github.com/ClipboardHealth/cbh-core/commit/4066dab6f40e5b9b06d7d93d1973c09135c52817))
40
-
41
- ## [0.1.4](https://github.com/ClipboardHealth/cbh-core/compare/rules-engine-0.1.3...rules-engine-0.1.4) (2024-07-12)
42
-
43
-
44
- ### Bug Fixes
45
-
46
- * testing Nx upgrade ([f823f5d](https://github.com/ClipboardHealth/cbh-core/commit/f823f5d3e9624d33f55683df8346f99d51bef9e7))
47
-
48
- ## [0.1.3](https://github.com/ClipboardHealth/cbh-core/compare/rules-engine-0.1.2...rules-engine-0.1.3) (2024-07-12)
49
-
50
- ## [0.1.3](https://github.com/ClipboardHealth/cbh-core/compare/rules-engine-0.1.2...rules-engine-0.1.3) (2024-07-11)
51
-
52
- ## [0.1.3](https://github.com/ClipboardHealth/cbh-core/compare/rules-engine-0.1.2...rules-engine-0.1.3) (2024-07-11)
53
-
54
- ## [0.1.2](https://github.com/ClipboardHealth/cbh-core/compare/rules-engine-0.1.1...rules-engine-0.1.2) (2024-02-27)
55
-
56
-
57
- ### Bug Fixes
58
-
59
- * **deps:** update dependency type-fest to v4 ([#531](https://github.com/ClipboardHealth/cbh-core/issues/531)) ([f366907](https://github.com/ClipboardHealth/cbh-core/commit/f36690743f2373fc6c62a589a6b50fa7f660bbae))
60
-
61
- ## [0.1.1](https://github.com/ClipboardHealth/cbh-core/compare/rules-engine-0.1.0...rules-engine-0.1.1) (2023-12-22)
62
-
63
- ## 0.1.0 (2023-12-20)
64
-
65
-
66
- ### Features
67
-
68
- * **PRI-290:** Add rules-engine lib ([#477](https://github.com/ClipboardHealth/cbh-core/issues/477)) ([d7aa2ba](https://github.com/ClipboardHealth/cbh-core/commit/d7aa2ba3c698511c053a2b31dfe4b5e0e4a6081d))
package/src/index.d.ts DELETED
@@ -1,5 +0,0 @@
1
- export * from "./lib/append-output";
2
- export * from "./lib/rule";
3
- export * from "./lib/runners/all";
4
- export * from "./lib/runners/first-match";
5
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../packages/rules-engine/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC"}
package/src/index.js DELETED
@@ -1,8 +0,0 @@
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/all"), exports);
7
- tslib_1.__exportStar(require("./lib/runners/first-match"), exports);
8
- //# sourceMappingURL=index.js.map
package/src/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/rules-engine/src/index.ts"],"names":[],"mappings":";;;AAAA,8DAAoC;AACpC,qDAA2B;AAC3B,4DAAkC;AAClC,oEAA0C"}
@@ -1,7 +0,0 @@
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>;
7
- //# sourceMappingURL=append-output.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"append-output.d.ts","sourceRoot":"","sources":["../../../../../packages/rules-engine/src/lib/append-output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAE1C;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAC1C,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC,GAC5B,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAK9B"}
@@ -1,13 +0,0 @@
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
@@ -1 +0,0 @@
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"}
package/src/lib/rule.d.ts DELETED
@@ -1,30 +0,0 @@
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
- }
30
- //# sourceMappingURL=rule.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../../../../../packages/rules-engine/src/lib/rule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,MAAM,WAAW,WAAW,CAAC,MAAM,EAAE,OAAO;IAC1C;;OAEG;IACH,KAAK,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAE5B;;;;OAIG;IACH,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,IAAI,CACnB,MAAM,EACN,OAAO,EACP,QAAQ,SAAS,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC;IAE5E;;;;;OAKG;IACH,KAAK,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC;IAEhD;;;;;OAKG;IACH,GAAG,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,QAAQ,CAAC;CACtC"}
package/src/lib/rule.js DELETED
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=rule.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rule.js","sourceRoot":"","sources":["../../../../../packages/rules-engine/src/lib/rule.ts"],"names":[],"mappings":""}
@@ -1,8 +0,0 @@
1
- import { type Rule, type RuleContext } from "../rule";
2
- /**
3
- * Runs 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>;
8
- //# sourceMappingURL=all.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"all.d.ts","sourceRoot":"","sources":["../../../../../../packages/rules-engine/src/lib/runners/all.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtD;;;;GAIG;AACH,wBAAgB,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,SAAS,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,EAChF,GAAG,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,GAC/C,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAQjC"}
@@ -1,17 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.all = all;
4
- /**
5
- * Runs 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
@@ -1 +0,0 @@
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"}
@@ -1,8 +0,0 @@
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>;
8
- //# sourceMappingURL=first-match.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"first-match.d.ts","sourceRoot":"","sources":["../../../../../../packages/rules-engine/src/lib/runners/first-match.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,SAAS,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,EACvF,GAAG,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,GAC/C,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAQjC"}
@@ -1,18 +0,0 @@
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
@@ -1 +0,0 @@
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"}