{"id":13902864,"url":"https://github.com/regevbr/json-expression-eval","last_synced_at":"2026-01-31T14:01:20.578Z","repository":{"id":40462154,"uuid":"136723976","full_name":"regevbr/json-expression-eval","owner":"regevbr","description":"json serializable rule engine / boolean expression evaluator","archived":false,"fork":false,"pushed_at":"2026-01-30T06:56:19.000Z","size":435,"stargazers_count":21,"open_issues_count":1,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-30T20:55:31.869Z","etag":null,"topics":["boolean","dynamic","engine","eval","expression","function","javascript","js","json","node","rule","rule-engine","serializable","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/regevbr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-06-09T13:07:05.000Z","updated_at":"2025-12-18T09:05:19.000Z","dependencies_parsed_at":"2025-12-17T22:02:07.007Z","dependency_job_id":null,"html_url":"https://github.com/regevbr/json-expression-eval","commit_stats":{"total_commits":67,"total_committers":2,"mean_commits":33.5,"dds":"0.11940298507462688","last_synced_commit":"e35e182573f5585c923995957aaa4f92fee5282c"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"purl":"pkg:github/regevbr/json-expression-eval","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/regevbr%2Fjson-expression-eval","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/regevbr%2Fjson-expression-eval/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/regevbr%2Fjson-expression-eval/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/regevbr%2Fjson-expression-eval/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/regevbr","download_url":"https://codeload.github.com/regevbr/json-expression-eval/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/regevbr%2Fjson-expression-eval/sbom","scorecard":{"id":768823,"data":{"date":"2025-08-11","repo":{"name":"github.com/regevbr/json-expression-eval","commit":"7c62ee971355f8d93317eb3b0e34d8d04a744586"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.3,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/20 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:38: update your workflow using https://app.stepsecurity.io/secureworkflow/regevbr/json-expression-eval/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:44: update your workflow using https://app.stepsecurity.io/secureworkflow/regevbr/json-expression-eval/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:53: update your workflow using https://app.stepsecurity.io/secureworkflow/regevbr/json-expression-eval/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:68: update your workflow using https://app.stepsecurity.io/secureworkflow/regevbr/json-expression-eval/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:79: update your workflow using https://app.stepsecurity.io/secureworkflow/regevbr/json-expression-eval/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:101: update your workflow using https://app.stepsecurity.io/secureworkflow/regevbr/json-expression-eval/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:108: update your workflow using https://app.stepsecurity.io/secureworkflow/regevbr/json-expression-eval/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:118: update your workflow using https://app.stepsecurity.io/secureworkflow/regevbr/json-expression-eval/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:132: update your workflow using https://app.stepsecurity.io/secureworkflow/regevbr/json-expression-eval/ci.yml/master?enable=pin","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":0,"reason":"dangerous workflow patterns detected","details":["Warn: script injection with untrusted input ' github.event.client_payload.head_ref || github.head_ref ': .github/workflows/ci.yml:30"],"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":10,"reason":"SAST tool detected","details":["Info: SAST configuration detected: Snyk","Warn: 0 commits out of 24 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":2,"reason":"8 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-4q6p-r6v2-jvc5","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-mwcw-c2x4-8c55","Warn: Project is vulnerable to: GHSA-76p7-773f-r4q5"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T01:39:30.353Z","repository_id":40462154,"created_at":"2025-08-23T01:39:30.354Z","updated_at":"2025-08-23T01:39:30.354Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28944789,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-31T13:02:32.153Z","status":"ssl_error","status_checked_at":"2026-01-31T13:00:07.528Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["boolean","dynamic","engine","eval","expression","function","javascript","js","json","node","rule","rule-engine","serializable","typescript"],"created_at":"2024-08-06T22:01:28.334Z","updated_at":"2026-01-31T14:01:20.565Z","avatar_url":"https://github.com/regevbr.png","language":"TypeScript","readme":"[![Npm Version](https://img.shields.io/npm/v/json-expression-eval.svg?style=popout)](https://www.npmjs.com/package/json-expression-eval)\n[![node](https://img.shields.io/node/v-lts/json-expression-eval)](https://www.npmjs.com/package/json-expression-eval)\n[![Build status](https://github.com/regevbr/json-expression-eval/actions/workflows/ci.yml/badge.svg?branch=master)](https://www.npmjs.com/package/json-expression-eval)\n[![Code Coverage](https://qlty.sh/gh/regevbr/projects/json-expression-eval/coverage.svg)](https://qlty.sh/gh/regevbr/projects/json-expression-eval)\n[![Maintainability](https://qlty.sh/gh/regevbr/projects/json-expression-eval/maintainability.svg)](https://qlty.sh/gh/regevbr/projects/json-expression-eval)\n[![Known Vulnerabilities](https://snyk.io/test/github/regevbr/json-expression-eval/badge.svg?targetFile=package.json)](https://snyk.io/test/github/regevbr/json-expression-eval?targetFile=package.json)\n\n# json-expression-eval (and rule engine)\nA Fully typed Node.js module that evaluates a json described boolean expressions using dynamic functions and a given context.\nExpressions can also be evaluated in a [`rule engine`](#rule-engine) manner.  \n\nThe module is strictly typed, ensuring that passed expressions are 100% valid at compile time.\n\nThis module is especially useful if you need to serialize complex expressions / rules (to be saved in a DB for example) \n  \n## Installation \n```sh\nnpm install json-expression-eval\n```\nOr\n```sh\nyarn add json-expression-eval\n```\n\n## Usage\n\n *Please see tests and examples dir for more usages and examples (under /src)* \n\n```typescript\nimport {evaluate, evaluateWithReason, Expression, ExpressionHandler, validate, ValidationContext, EvaluatorFuncRunOptions, EvaluationResult} from 'json-expression-eval';\nimport {Moment} from 'moment';\nimport moment = require('moment');\n\ninterface IExampleContext {\n    userId: string;\n    times: number | undefined;\n    date: Moment;\n    nested: {\n        value: number | null;\n        value4: number;\n        nested2: {\n            value2?: number;\n            value3: boolean;\n        };\n    };\n}\n\ntype IExampleContextIgnore = Moment;\n\ntype IExampleCustomEvaluatorFuncRunOptions = {dryRun: boolean};\n\ntype IExampleFunctionTable = {\n    countRange: ([min, max]: [min: number, max: number], ctx: { times: number | undefined },\n                 runOpts: EvaluatorFuncRunOptions\u003cIExampleCustomEvaluatorFuncRunOptions\u003e) =\u003e Promise\u003cboolean\u003e;\n}\n\ntype IExampleExpression = Expression\u003cIExampleContext, IExampleFunctionTable, IExampleContextIgnore, IExampleCustomEvaluatorFuncRunOptions\u003e; // We pass Moment here to avoid TS exhaustion\n\nconst context: IExampleContext = {\n    userId: 'a@b.com',\n    times: 3,\n    date: moment(),\n    nested: {\n        value: null,\n        value4: 5,\n        nested2: {\n            value3: true,\n        },\n    },\n};\n\n// For validation we must provide a full example context\nconst validationContext: ValidationContext\u003cIExampleContext, IExampleContextIgnore\u003e = {\n    userId: 'a@b.com',\n    times: 3,\n    date: moment(),\n    nested: {\n        value: 5,\n        value4: 6,\n        nested2: {\n            value2: 6,\n            value3: true,\n        },\n    },\n};\n\nconst functionsTable: IExampleFunctionTable = {\n    countRange: async ([min, max]: [min: number, max: number], ctx: { times: number | undefined },\n                       runOpts: EvaluatorFuncRunOptions\u003cIExampleCustomEvaluatorFuncRunOptions\u003e): Promise\u003cboolean\u003e =\u003e {\n        return ctx.times === undefined ? false : ctx.times \u003e= min \u0026\u0026 ctx.times \u003c max;\n    },\n};\n\nconst expression: IExampleExpression = {\n    or: [\n        {\n            userId: 'a@b.com',\n        },\n        {\n            times: {\n                lte: {\n                    op: '+',\n                    lhs: {\n                        ref: 'nested.value4',\n                    },\n                    rhs: 2,\n                },\n            },\n        },\n        {\n            and: [\n                {\n                    countRange: [2, 6],\n                },\n                {\n                    'nested.nested2.value3': true,\n                },\n                {\n                    times: {\n                        lte: {\n                            ref: 'nested.value4',\n                        },\n                    },\n                },\n            ],\n        },\n    ],\n};\n\n(async () =\u003e {\n    // Example usage 1\n    const handler =\n        new ExpressionHandler\u003cIExampleContext, IExampleFunctionTable, IExampleContextIgnore,\n            IExampleCustomEvaluatorFuncRunOptions\u003e(expression, functionsTable);\n    await handler.validate(validationContext, {dryRun: false}); // Should not throw\n    console.log(await handler.evaluate(context, {dryRun: true})); // true\n\n    // Example usage 2\n    await validate\u003cIExampleContext, IExampleFunctionTable, IExampleContextIgnore,\n        IExampleCustomEvaluatorFuncRunOptions\u003e(expression, validationContext, functionsTable, {dryRun: true}); // Should not throw\n    console.log(await evaluate\u003cIExampleContext, IExampleFunctionTable, IExampleContextIgnore, IExampleCustomEvaluatorFuncRunOptions\u003e(expression, context, functionsTable, {dryRun: true})); // true\n\n    // Example usage 3 - evaluateWithReason returns the minimal expression that led to the result\n    const resultWithReason = await evaluateWithReason\u003cIExampleContext, IExampleFunctionTable, IExampleContextIgnore, IExampleCustomEvaluatorFuncRunOptions\u003e(expression, context, functionsTable, {dryRun: true});\n    console.log(resultWithReason.result); // true\n    console.log(JSON.stringify(resultWithReason.reason)); // {\"or\":[{\"userId\":\"a@b.com\"}]} - the first matching condition in the OR\n\n    // Using ExpressionHandler\n    const handlerResult = await handler.evaluateWithReason(context, {dryRun: true});\n    console.log(handlerResult.result); // true\n    console.log(JSON.stringify(handlerResult.reason)); // {\"or\":[{\"userId\":\"a@b.com\"}]}\n})()\n```\n\n### evaluateWithReason\n\nThe `evaluateWithReason` function evaluates an expression and returns not only the boolean result, but also the minimal sub-expression that led to that result. This is useful for debugging and understanding why an expression evaluated to a specific value.\n\n```typescript\nconst result: EvaluationResult\u003c...\u003e = await evaluateWithReason(expression, context, functionsTable, runOptions);\n// result.result - boolean: the evaluation result\n// result.reason - Expression: the minimal expression that caused the result\n```\n\n**Behavior:**\n- For `or` expressions that evaluate to `true`: returns `{or: [reason]}` with the first sub-expression that evaluated to `true`\n- For `or` expressions that evaluate to `false`: returns `{or: [reasons...]}` with all sub-expressions (all failed)\n- For `and` expressions that evaluate to `false`: returns `{and: [reason]}` with the first sub-expression that evaluated to `false`\n- For `and` expressions that evaluate to `true`: returns `{and: [reasons...]}` with all sub-expressions (all passed)\n- For `not` expressions: returns `{not: reason}` wrapping the reason from the inner expression\n- For simple property comparisons and function calls: returns the expression itself\n\n### Expression\n\nThere are 4 types of operators you can use (evaluated in that order of precedence):\n- `and` - accepts a non-empty list of expressions\n- `or` - accepts a non-empty list of expressions\n- `not` - accepts another expressions\n- `\u003cuser defined funcs\u003e` - accepts any type of argument and evaluated by the user defined functions, and the given context (can be async) and run options (i.e. validation + custom defined value).\n- `\u003ccompare funcs\u003e` - operates on one of the context properties and compares it to a given value.\n    - `{property: {op: value}}`\n        - available ops:\n            - `gt` - \u003e\n            - `gte` - \u003e=\n            - `lt` - \u003c\n            - `lte` - \u003c=\n            - `eq` - ===\n            - `neq` - !==\n            - `regexp: RegExp` - True if matches the compiled regular expression.\n            - `regexpi: RegExp` - True if matches the compiled regular expression with the `i` flag set.\n            - `nin: any[]` - True if *not* in an array of values. Comparison is done using the `===` operator\n            - `inq: any[]` - True if in an array of values. Comparison is done using the `===` operator\n            - `between: readonly [number, number] (as const)` - True if the value is between the two specified values: greater than or equal to first value and less than or equal to second value.\n            - `exists: boolean` - True if the value is not null or undefined (when `exists: true`), or True if the value is null or undefined (when `exists: false`). Note: Falsy values like `0`, `false`, and `\"\"` are considered as existing.\n    - `{property: value}`\n        - compares the property to that value (shorthand to the `eq` op, without the option to user math or refs to other properties)\n\n\u003e Nested properties in the context can also be accessed using a dot notation (see example above)\n\n\u003e In each expression level, you can only define 1 operator, and 1 only\n\nThe right-hand side of compare (not user defined) functions can be a:\n- literal - number/string/boolean (depending on the left-hand side of the function)\n- reference to a property (or nested property) in the context.  \n  This can be achieved by using `{\"ref\":\"\u003cdot notation path\u003e\"}`\n- A math operation that can reference properties in the context.  \n  The valid operations are `+,-,*,/,%,pow`.  \n  This can be achieved by using  \n  ```json\n  {\n    \"op\": \"\u003c+,-,*,/,%,pow\u003e\",\n    \"lhs\": {\"ref\": \"\u003cdot notation path\u003e\"}, // or a number literal\n    \"rhs\": {\"ref\": \"\u003cdot notation path\u003e\"} // or a number literal\n  }\n  ```\n  which will be computed as `\u003clhs\u003e \u003cop\u003e \u003crhs\u003e` where lhs is left-hand-side and rhs is right-hand-side. So for example\n  ```json\n  {\n    \"op\": \"/\",\n    \"lhs\": 10,\n    \"rhs\": 2\n  }\n  ```\n  will equal `10 / 2 = 5`\n\n\nExample expressions, assuming we have the `user` and `maxCount` user defined functions in place can be:\n```json\n{  \n   \"or\":[  \n      {  \n         \"not\":{  \n            \"user\":\"a@b.com\"\n         }\n      },\n      {  \n         \"maxCount\":1\n      },\n      {  \n         \"times\": { \"eq\" : 5}\n      },\n      {  \n         \"times\": { \"eq\" : { \"ref\": \"nested.preoprty\"}}\n      },\n      {  \n         \"country\": \"USA\"\n      }\n   ]\n}\n```\n\n### Rule Engine\n\n*Please see tests and examples dir for more usages and examples (under /src)* \n\n```typescript\nimport {ValidationContext, validateRules, evaluateRules, RulesEngine, Rule, ResolvedConsequence, EngineRuleFuncRunOptions} from 'json-expression-eval';\nimport {Moment} from 'moment';\nimport moment = require('moment');\n\ninterface IExampleContext {\n    userId: string;\n    times: number | undefined;\n    date: Moment;\n    nested: {\n        value: number | null;\n        nested2: {\n            value2?: number;\n            value3: boolean;\n        };\n    };\n}\n\ntype IExampleContextIgnore = Moment;\n\ntype IExampleCustomEngineRuleFuncRunOptions = {dryRun: boolean};\n\ntype IExamplePayload = number;\n\ntype IExampleFunctionTable = {\n    countRange: ([min, max]: [min: number, max: number], ctx: { times: number | undefined },\n                 runOpts: EngineRuleFuncRunOptions\u003cIExampleCustomEngineRuleFuncRunOptions\u003e) =\u003e boolean;\n}\n\ntype IExampleRuleFunctionTable = {\n    userRule: (user: string, ctx: IExampleContext,\n               runOpts: EngineRuleFuncRunOptions\u003cIExampleCustomEngineRuleFuncRunOptions\u003e) =\u003e\n        Promise\u003cvoid | ResolvedConsequence\u003cIExamplePayload\u003e\u003e;\n}\n\ntype IExampleRule = Rule\u003cIExamplePayload, IExampleRuleFunctionTable, IExampleContext,\n    IExampleFunctionTable, IExampleContextIgnore, IExampleCustomEngineRuleFuncRunOptions\u003e;\n\nconst context: IExampleContext = {\n    userId: 'a@b.com',\n    times: 3,\n    date: moment(),\n    nested: {\n        value: null,\n        nested2: {\n            value3: true,\n        },\n    },\n};\n\n// For validation we must provide a full example context\nconst validationContext: ValidationContext\u003cIExampleContext, IExampleContextIgnore\u003e = {\n    userId: 'a@b.com',\n    times: 3,\n    date: moment(),\n    nested: {\n        value: 5,\n        nested2: {\n            value2: 6,\n            value3: true,\n        },\n    },\n};\n\nconst functionsTable: IExampleFunctionTable = {\n    countRange: ([min, max]: [min: number, max: number], ctx: { times: number | undefined },\n                 runOptions: EngineRuleFuncRunOptions\u003cIExampleCustomEngineRuleFuncRunOptions\u003e): boolean =\u003e {\n        return ctx.times === undefined ? false : ctx.times \u003e= min \u0026\u0026 ctx.times \u003c max;\n    },\n};\n\nconst ruleFunctionsTable: IExampleRuleFunctionTable = {\n    userRule: async (user: string, ctx: IExampleContext,\n                     runOptions: EngineRuleFuncRunOptions\u003cIExampleCustomEngineRuleFuncRunOptions\u003e)\n        : Promise\u003cvoid | ResolvedConsequence\u003cnumber\u003e\u003e =\u003e {\n        if (ctx.userId === user) {\n            return {\n                message: `Username ${user} is not allowed`,\n                custom: 543,\n            }\n        }\n    },\n};\n\nconst rules: IExampleRule[] = [\n    {\n        condition: {\n            or: [\n                {\n                    userId: 'a@b.com',\n                },\n                {\n                    and: [\n                        {\n                            countRange: [2, 6],\n                        },\n                        {\n                            'nested.nested2.value3': true,\n                        },\n                    ],\n                },\n            ],\n        },\n        consequence: {\n            message: ['user', {\n                ref: 'userId',\n            }, 'should not equal a@b.com'],\n            custom: 579,\n        },\n    },\n    {\n        userRule: 'b@c.com',\n    },\n];\n\n(async () =\u003e {\n    // Example usage 1\n    const engine = new RulesEngine\u003cIExamplePayload, IExampleContext, IExampleRuleFunctionTable,\n        IExampleFunctionTable, IExampleContextIgnore, IExampleCustomEngineRuleFuncRunOptions\u003e(\n        functionsTable, ruleFunctionsTable);\n    await engine.validate(rules, validationContext, {dryRun: false}); // Should not throw\n    console.log(JSON.stringify(await engine.evaluateAll(rules, context, {dryRun: false}))); // [{\"message\":\"user a@b.com should not equal a@b.com\",\"custom\":579}]\n\n    // Example usage 2\n    await validateRules\u003cIExamplePayload, IExampleContext, IExampleRuleFunctionTable,\n        IExampleFunctionTable, IExampleContextIgnore, IExampleCustomEngineRuleFuncRunOptions\u003e(\n        rules, validationContext, functionsTable, ruleFunctionsTable, {dryRun: false}); // Should not throw\n    console.log(JSON.stringify(await evaluateRules\u003cIExamplePayload, IExampleContext, IExampleRuleFunctionTable,\n        IExampleFunctionTable, IExampleContextIgnore, IExampleCustomEngineRuleFuncRunOptions\u003e(rules, context, functionsTable, ruleFunctionsTable, false, {dryRun: false}))); // [{\"message\":\"user a@b.com should not equal a@b.com\",\"custom\":579}]\n})();\n```\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fregevbr%2Fjson-expression-eval","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fregevbr%2Fjson-expression-eval","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fregevbr%2Fjson-expression-eval/lists"}