
| Statements |
Functions |
Lines |
 |
 |
 |
JsonRules Engine
A rule engine for JavaScript & TypeScript
Define business logic with JSON rules

Overview
JsonRules is a rule engine that allows you to define business logic as JSON and evaluate it against data. It provides a simple way to externalize decision-making logic from your application code.
Use Cases
- E-commerce: Pricing rules, discount eligibility, shipping calculations
- User Management: Access control, feature flags, user segmentation
- Content: Filtering, moderation, recommendations
- Workflows: Approval processes, notifications
- Configuration: A/B testing, feature rollouts
Features
- Type-safe with full TypeScript support
- 40+ built-in operators for common operations
- Support for complex nested conditions
- Template variables for dynamic rules
- Validation for rule structure and syntax
- Works in Node.js and browsers
Installation
npm install @ivandt/json-rules
Dependencies
This library has one dependency:
validator - Used for advanced validation operators (email, URL, phone numbers, etc.)
Quick Start
import { JsonRules, Rule } from "@ivandt/json-rules";
// Define a rule
const rule: Rule = {
conditions: {
all: [
{ field: "age", operator: "is greater than or equal", value: 18 },
{ field: "country", operator: "is equal", value: "US" }
]
}
};
// Evaluate against data
const user = { age: 25, country: "US" };
const result = JsonRules.evaluate(rule, user);
console.log(result); // true
Operators
JsonRules provides operators for common data operations:
Equality & Comparison
| Operator |
Description |
Accepts |
Example |
is equal |
Equal to |
string | number | boolean | Date | null |
{ field: "status", operator: "is equal", value: "active" } |
is not equal |
Not equal to |
string | number | boolean | Date | null |
{ field: "status", operator: "is not equal", value: "banned" } |
is greater than |
Greater than comparison |
string | number | Date |
{ field: "age", operator: "is greater than", value: 18 } |
is less than |
Less than comparison |
string | number | Date |
{ field: "price", operator: "is less than", value: 100 } |
is greater than or equal |
Greater than or equal |
string | number | Date |
{ field: "score", operator: "is greater than or equal", value: 80 } |
is less than or equal |
Less than or equal |
string | number | Date |
{ field: "items", operator: "is less than or equal", value: 10 } |
Range & Between
| Operator |
Description |
Accepts |
Example |
is between numbers |
Number within range (inclusive) |
[number, number] |
{ field: "age", operator: "is between numbers", value: [18, 65] } |
is not between numbers |
Number outside range |
[number, number] |
{ field: "temperature", operator: "is not between numbers", value: [32, 100] } |
is between dates |
Date within range (inclusive) |
[Date, Date] |
{ field: "eventDate", operator: "is between dates", value: [startDate, endDate] } |
is not between dates |
Date outside range |
[Date, Date] |
{ field: "blackoutDate", operator: "is not between dates", value: [holiday1, holiday2] } |
Collection & Array
| Operator |
Description |
Accepts |
Example |
in |
Value exists in array |
(string | number | boolean | object | null)[] |
{ field: "country", operator: "in", value: ["US", "CA", "UK"] } |
not in |
Value not in array |
(string | number | boolean | object | null)[] |
{ field: "status", operator: "not in", value: ["banned", "suspended"] } |
array contains |
Array field contains value |
string | number | boolean | object | null |
{ field: "skills", operator: "array contains", value: "javascript" } |
array no contains |
Array field doesn't contain value |
string | number | boolean | object | null |
{ field: "permissions", operator: "array no contains", value: "admin" } |
String Operations
| Operator |
Description |
Accepts |
Example |
contains |
String contains substring |
string |
{ field: "email", operator: "contains", value: "@company.com" } |
not contains |
String doesn't contain substring |
string |
{ field: "message", operator: "not contains", value: "spam" } |
contains any |
String contains any substring |
string[] |
{ field: "title", operator: "contains any", value: ["urgent", "critical"] } |
not contains any |
String contains none of substrings |
string[] |
{ field: "content", operator: "not contains any", value: ["spam", "scam"] } |
starts with |
String starts with prefix |
string |
{ field: "productCode", operator: "starts with", value: "PRD-" } |
ends with |
String ends with suffix |
string |
{ field: "filename", operator: "ends with", value: ".pdf" } |
Pattern Matching
| Operator |
Description |
Accepts |
Example |
matches |
Matches regex pattern |
{ regex: string, flags?: string } |
{ field: "email", operator: "matches", value: { regex: "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$" } } |
not matches |
Doesn't match regex pattern |
{ regex: string, flags?: string } |
{ field: "username", operator: "not matches", value: { regex: "^(admin|root)$", flags: "i" } } |
Date Operations
| Operator |
Description |
Accepts |
Example |
is before |
Date is before specified date |
string | number | Date |
{ field: "expiry", operator: "is before", value: new Date('2024-12-31') } |
is after |
Date is after specified date |
string | number | Date |
{ field: "startDate", operator: "is after", value: new Date('2024-01-01') } |
is on or before |
Date is on or before specified date |
string | number | Date |
{ field: "deadline", operator: "is on or before", value: new Date() } |
is on or after |
Date is on or after specified date |
string | number | Date |
{ field: "validFrom", operator: "is on or after", value: new Date() } |
Math & Number Validation
| Operator |
Description |
Accepts |
Example |
is even |
Number is even |
none |
{ field: "quantity", operator: "is even" } |
is odd |
Number is odd |
none |
{ field: "productId", operator: "is odd" } |
is positive |
Number is positive (> 0) |
none |
{ field: "balance", operator: "is positive" } |
is negative |
Number is negative (< 0) |
none |
{ field: "adjustment", operator: "is negative" } |
is empty |
Value is null, undefined, or empty string/array |
none |
{ field: "optionalField", operator: "is empty" } |
is not empty |
Value is not empty |
none |
{ field: "requiredField", operator: "is not empty" } |
Data Validation
| Operator |
Description |
Accepts |
Example |
is valid email |
Valid email address |
EmailValidationConfig (optional) |
{ field: "email", operator: "is valid email" } |
is valid phone |
Valid phone number |
PhoneValidationConfig |
{ field: "phone", operator: "is valid phone", value: { locale: "us" } } |
is URL |
Valid URL |
URLValidationConfig |
{ field: "website", operator: "is URL", value: { requireTld: false } } |
is UUID |
Valid UUID |
UUIDValidationConfig |
{ field: "id", operator: "is UUID", value: { version: 4 } } |
is EAN |
Valid EAN barcode |
none |
{ field: "barcode", operator: "is EAN" } |
is IMEI |
Valid IMEI number |
IMEIValidationConfig |
{ field: "deviceId", operator: "is IMEI", value: { allowHyphens: true } } |
is unit |
Valid unit of measurement |
UnitType |
{ field: "distance", operator: "is unit", value: "length" } |
is country |
Valid country identifier |
CountryValidationConfig |
{ field: "country", operator: "is country", value: { format: "iso2" } } |
is domain |
Valid domain name |
DomainValidationConfig |
{ field: "domain", operator: "is domain", value: { requireTld: true } } |
Rule Structure
Basic Rule
interface Rule {
conditions: Condition | Condition[];
default?: any;
}
Conditions
Rules support three logical operators:
| Type |
Logic |
Description |
all |
AND |
All constraints must be true |
any |
OR |
At least one constraint must be true |
none |
NOT |
No constraints should be true |
Constraints
{
field: string, // Property path (supports dot notation)
operator: string, // Comparison operator
value: any // Expected value or template reference
}
Examples
Basic Example
const rule: Rule = {
conditions: {
all: [
{ field: "age", operator: "is greater than or equal", value: 21 },
{ field: "country", operator: "in", value: ["US", "CA"] }
]
}
};
const user = { age: 25, country: "US" };
const result = JsonRules.evaluate(rule, user); // true
Complex Conditions
const complexRule: Rule = {
conditions: {
any: [
{
all: [
{ field: "membershipTier", operator: "is equal", value: "premium" },
{ field: "accountAge", operator: "is greater than", value: 365 }
]
},
{
all: [
{ field: "totalSpent", operator: "is greater than", value: 1000 },
{ field: "lastPurchase", operator: "is after", value: new Date('2024-01-01') }
]
}
]
}
};
Validation Operators
const validationRule: Rule = {
conditions: {
all: [
{ field: "email", operator: "is valid email", value: null },
{ field: "phone", operator: "is valid phone", value: { locale: "us" } },
{ field: "website", operator: "is URL", value: { protocols: ["https"] } }
]
}
};
Template Variables
const dynamicRule: Rule = {
conditions: {
all: [
{ field: "endDate", operator: "is after", value: "{startDate}" },
{ field: "price", operator: "is less than", value: "{maxBudget}" }
]
}
};
API Reference
JsonRules.evaluate()
static evaluate<T>(
rule: Rule,
criteria: object | object[],
trustRule?: boolean
): T | boolean
JsonRules.validate()
static validate(rule: Rule): ValidationResult
ValidationResult
interface ValidationResult {
isValid: boolean;
error?: ValidationError;
}
Phone Number Validation
To use phone validation, import the specific locale validators:
// Import specific locales
import "@ivandt/json-rules/validators/phone/us";
import "@ivandt/json-rules/validators/phone/gb";
import "@ivandt/json-rules/validators/phone/de";
const rule: Rule = {
conditions: {
all: [
{ field: "phone", operator: "is valid phone", value: { locale: "us" } }
]
}
};
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/new-feature
- Make your changes with tests
- Run the test suite:
npm test
- Submit a pull request
License
MIT License - see LICENSE file for details.