another-json-rules-engine
Version:
Another Json Rules Engine: a flexible rules engine for validating JSON objects in Node.js and browser.
235 lines (189 loc) • 6.84 kB
Markdown
A flexible, generic rules engine for JSON objects. Supports complex conditions, array traversal, date-based rule activation, and a wide range of operators. Works in both Node.js and browser environments.
```bash
npm install another-json-rules-engine
```
```js
import { validateRules } from 'another-json-rules-engine';
```
```js
const { validateRules } = require('another-json-rules-engine');
```
```js
const document = {
name: 'John Doe',
age: 22,
tags: ['blue_eyed', 'blind'],
alive: true,
score: 10,
minScore: 5,
};
const contextObj = {
userType: 'admin',
meta: { active: true, score: 10, minScore: 5 },
refValue: 'foo',
};
const rules = [
// Fixed value comparison
{
id: 1,
type: 'ERROR',
description: 'Age must be greater than 18',
conditions: [
{ ref: 'age', operator: '<', comparisonValue: 18 }
]
},
// Compare two fields from document
{
id: 2,
type: 'REF',
description: 'Score must be equal to minScore',
conditions: [
{ ref: 'score', operator: '<>', comparisonRef: 'minScore' }
]
},
// Compare document field with context field
{
id: 3,
type: 'CTX',
description: 'Score must be equal to context meta.score',
conditions: [
{ ref: 'score', operator: '<>', comparisonRef: '_context.meta.score' }
]
},
// Compare two fields from context
{
id: 4,
type: 'CTX',
description: 'Context meta.score must be >= context meta.minScore',
conditions: [
{ ref: '_context.meta.score', operator: '<', comparisonRef: '_context.meta.minScore' }
]
},
// Use contextObj directly
{
id: 5,
type: 'CTX',
description: 'User type must be admin',
conditions: [
{ ref: '_context.userType', operator: '<>', comparisonValue: 'admin' }
]
}
];
const result = validateRules(document, rules, contextObj);
console.log(result);
```
The function returns an array of rules for which **all conditions were satisfied** (that is, all conditions returned true for the given document/context). If a rule does not have all its conditions satisfied, it will not appear in the result.
- **documentJson**:
The JSON object to be validated.
- **rules**:
Array of rules in the format described in the "Rule Format" section.
- **contextObj** (optional):
Additional context object. Allows using references like `_context.path` in conditions.
- **options** (optional):
Configuration object with the following attributes:
- **contextLimit**: Maximum number of contexts (array combinations) allowed per rule.
*Default: 10000*
- **timeLimit**: Maximum time (in seconds) for context generation per rule.
*Default: 200*
- **returnAllContexts**: If true (default), returns all valid contexts for each rule. If false, stops and returns only the first valid context found for each rule (improves performance in large datasets).
*Default: true*
**Example:**
```js
const result = validateRules(document, rules, contextObj, { contextLimit: 5000, timeLimit: 60, returnAllContexts: false });
```
---
The function returns an array of objects, one for each rule that was evaluated (and passed or generated an error/warning):
```js
[
{
id: 'rule1',
type: 'ERROR',
message: 'Description of the rule',
conditions: [ /* details of the contexts/conditions that passed */ ],
keyword: 'conditional', // or 'context_limit' if limit reached
errors: [ /* array of errors/warnings, if any */ ]
},
// ... other rules
]
```
- **conditions**:
Details of the contexts/conditions that passed for that rule.
- **keyword**:
- `'conditional'`: rule evaluated normally.
- `'context_limit'`: rule not fully evaluated due to context or time limit.
- **errors**:
Array of objects with error or warning details (e.g., context limit reached, invalid operator, etc).
---
### Example output with context limit error
```js
[
{
id: 'limitTest',
type: 'ERROR',
message: 'Test context limit',
keyword: 'context_limit',
errors: [
{ cause: 'Context limit reached', context: 'The number of contexts exceeded the limit (10000).' }
]
}
]
```
Each rule is an object with the following structure:
```js
{
id: 'unique_rule_id',
type: 'ERROR' | 'WARNING' | 'INFO' | '...',
description: 'Rule description',
initialDate: '2024-01-01T00:00:00Z', // (optional) rule is active from this date
endDate: '2024-12-31T23:59:59Z', // (optional) rule is active until this date
conditions: [
{
ref: 'path.to.value' | '_context.path.to.value',
operator: '=',
// One of the following:
comparisonValue: 'expectedValue', // fixed value
comparisonRef: 'other.path' | '_context.other.path' // reference to another field
},
// ... more conditions
]
}
```
- If `comparisonValue` is present, the value will be compared to it.
- If `comparisonRef` is present, the value will be compared to the referenced field (from document or context).
- If both are present, the rule will return an error for that condition.
## Supported Operators
- `=`: equal
- `<>`: not equal
- `<`, `<=`, `>`, `>=`: numeric/string comparison
- `contains`: left includes right
- `does_not_contains`: left does not include right
- `is_contained`: right includes left
- `in`: right (array) includes left
- `not_in`: right (array) does not include left
- `exists`: value exists
- `does_not_exists`: value does not exist
- `is_empty`: value is empty (array/string)
- `is_not_empty`: value is not empty (array/string)
## Array and Context Support
You can use array traversal in conditions, e.g. `items[].price` to apply rules to each item in an array. The engine will evaluate the rule in all relevant contexts.
To reference the context object, use the prefix `_context.` in `ref` or `comparisonRef`.
## Advanced Usage
- **Date-based rules:** Use `initialDate` and/or `endDate` to activate rules only in a specific period.
- **Nested arrays:** The engine supports rules for deeply nested arrays.
- **Comparison between fields:** Use `comparisonRef` to compare two fields (from document or context).
## Error Handling
If a rule or condition is invalid (e.g., both `comparisonValue` and `comparisonRef` are present), the result will include an `errors` field with details.
## License
MIT