check-rule-mate
v0.5.8
Published
Rule-based, extensible and async-friendly data validation engine for complex forms and business rules.
Maintainers
Readme
check-rule-mate
Rule-based, extensible and async-friendly data validation engine for complex forms and business rules.
Overview
check-rule-mate is a lightweight rule-driven validation engine for JavaScript. Instead of coupling validation logic directly to schemas or fields, check-rule-mate separates concerns into rules, schemas, validators, and error messages, allowing you to build highly reusable, composable, and context-aware validations.
It is designed for scenarios where traditional schema-based validators start to feel limiting, especially when you need:
- Cross-field validation
- Contextual rules
- Async checks
- Reusable validation logic across multiple forms
- Full control over execution flow and error handling
- Lifecycle Hooks
Github repository: check-rule-mate repository
Examples of how implement check-rule-mate: check-rule-mate examples
Test the core functionalities here: check-rule-mate demo (Note: Creating or modifying custom validators is not supported in the demo, as it requires JavaScript implementation.)
Why check-rule-mate?
Use check-rule-mate if you:
- Need reusable validation logic across different forms and contexts
- Have complex or conditional validation rules
- Want full control over how validation runs
- Need async validations (API calls, database checks, etc.)
- Prefer rule-driven validation instead of tightly coupled schemas
- Want clean separation between rules, data, and messages
- You want to have auto documentation of your forms
Core Concepts
check-rule-mate is built around four main concepts:
- Rules: How data is validated
- Schema: What should be validated
- Validation Helpers: How rules are executed
- Error Messages: How errors are communicated
This separation makes the system flexible, scalable, and easy to maintain.
Features
- Rule-based validation engine
- Reusable validation rules
- Modifiers for contextual rule extensions
- Cross-field validation using dynamic parameters
- Async validation support
- Abort early or collect all errors
- Strict or loose schema matching
- i18n-ready error messages
- Framework-agnostic (frontend or backend)
- Auto documentation (automatic generated by a CLI command)
- Template checker (automatic checked by a CLI command)
Table of Contents
Getting Started
Installation
If you are in NPM use this:
npm install check-rule-mateRepository - Installation
If you downloaded the repository you can install using:
npm install
npm startRepository - Running Tests
Execute the test suite with:
npm testHow It Works
Basic Usage
import MY_RULES from './rules/myValidatorRules.json' with { type: 'json' };
import CONTACT_US from './schemas/contactUs.json' with { type: 'json' };
import ERROR_MESSAGES from './i18n/en_US/errors.json' with { type: 'json' };
import { createValidator } from 'check-rule-mate';
import { myValidator } from './validators/myValidator.js';
const fields = {
name: 'John',
lastName: 'Doe',
email: '[email protected]',
emailConfirm: '[email protected]',
phone: '',
subject: 'I need a coffee',
message: 'Give me coffee'
};
async function runFormValidate() {
const validator = createValidator(fields, {
validationHelpers: myValidator,
rules: MY_RULES,
schema: CONTACT_US,
errorMessages: ERROR_MESSAGES,
options: {
cache: true,
abortEarly: false,
propertiesMustMatch: true,
}
});
const result = await validator.validate();
// This should return { ok: true }
console.log(result);
}
runFormValidate();Validation Result
A validation result follows this structure:
When is valid:
{ ok: true }When is invalid and has errors:
{
error: true,
errors: {
[field: string]: {
name: string,
type: string,
message: string,
code: string,
}[];
};
}Lifecycle Hooks
The check-rule-mate lifecycle hooks allow you to observe, extend and react to the validation process without coupling logic to rules or helpers.
Hooks are especially useful for:
- Logging and debugging
- Analytics and metrics
- Custom side-effects
- Integrating validation with UI or external systems
- Advanced error handling and reporting
- They provide fine-grained control over the validation lifecycle.
hooks?: {
onValidateStart?: (payload) => void;
onValidateFieldStart?: (payload) => void;
onValidateFieldError?: (payload) => void;
onValidateFieldSuccess?: (payload) => void;
onValidateEnd?: (payload) => void;
}Hook Payloads
onValidateStart
Triggered once before validation begins.
onValidateStart: ({ data }) => voidPayload:
data: Full form data object being validated
onValidateFieldStart
Triggered before validating each field.
onValidateFieldStart: ({ field, value, schemaField }) => voidPayload:
field: Field namevalue: Field valueschemaField: Schema configuration for the field (ornullif missing)
onValidateFieldError
Triggered when a field fails validation.
onValidateFieldError: ({ field, value, schemaField, error }) => voidPayload:
field: Field namevalue: Field valueschemaField: Schema configuration for the field (ornullif missing)error: Validation error object
onValidateFieldSuccess
Triggered when a field is successfully validated.
onValidateFieldSuccess: ({ field, value, schemaField }) => voidPayload:
field: Field namevalue: Field valueschemaField: Schema configuration for the field (ornullif missing)
onValidateEnd
Triggered once after validation finishes.
onValidateEnd: ({ data, errors }) => voidPayload:
data: Full form data object being validatederrors: Validation errors (if any) If no errors occurred,errorsmay beundefined.
Hooks - Example Usage
const validator = createValidator(fields, {
validationHelpers: myValidator,
rules: MY_RULES,
schema: CONTACT_US,
errorMessages: ERROR_MESSAGES,
hooks: {
onValidateStart: ({ data }) => {
console.log('Validation started', data);
},
onValidateFieldStart: ({ field, value }) => {
console.log(`Validating ${field}`, value);
},
onValidateFieldError: ({ field, error }) => {
console.error(`Error on ${field}`, error);
},
onValidateFieldSuccess: ({ field }) => {
console.log(`${field} validated successfully`);
},
onValidateEnd: ({ data, errors }) => {
if (errors) {
console.log('Validation finished with errors', errors);
} else {
console.log('Validation finished successfully');
}
}
}
});
await validator.validate();Auto Documentation
check-rule-mate contains a script to generate automatic documentation based in your rules, schemas and error messages.
To use that it is simple, you only need to run this command:
npx check-rule-mate-auto-docs --rules {rules path} --schemas {schemas path} --errors {errors path} --out {file.html}This will generate a HTML file containing the rules, schemas and errors.
[Experimental] Documentation Playground
⚠️ The playground executes bundled client-side JavaScript. Do not use untrusted validation code.
The Docs Playground allows you to generate an interactive HTML page where you can test your schemas, rules, and validators directly in the browser.
This feature is experimental and intended mainly for development and exploration purposes. It bundles your validation logic into a client-side format, enabling real-time validation without any backend setup.
⚠️ Since this feature is experimental, APIs and behavior may change.
Requirements
The playground generator depends on optional dependencies that are not installed by default.
Before using it, make sure you have the required optional dependencies installed:
npm install esbuildUsage
Run the playground generator using the CLI:
npx check-rule-mate-auto-docs-playground-experimental \
--rules {rules-path} \
--schemas {schemas-path} \
--errors {errors-path} \
--options {options-path} \
--out {output-file.html}This command will generate a self-contained HTML file with:
- Documentation for your rules and schemas
- A playground to test validation behavior in real time
Options File
The playground requires an options file to map validator names to their source files.
Example:
{
"validators": {
"myValidator": "./examples/vanilla/src/check-rule-mate-rules/validators/validators.js",
"nameValidator": "./examples/vanilla/src/check-rule-mate-rules/validators/validators.js",
"myValidator2": "./examples/vanilla/src/check-rule-mate-rules/validators/validator2.js"
}
}How it works:
- Keys represent the exported object/function/class name of your validator
- Values are paths to the files where those validators are defined
- These validators are bundled and made available inside the playground
This explicit mapping ensures predictable builds and avoids magic imports.
Auto Checker for Templates
You can auto check if your template it is working properly with all necessary properties or have something missing.
It is works with: Schemas, Rules and Errors
npx check-rule-mate-verify-templates --rules {rules path} --schemas {schemas path} --errors {errors path}If everything it is working properly this should be your message:
✔ Schemas loaded: 4
✔ Rules loaded: 6
✔ Errors loaded: 6
✔ No issues foundElse if some error was found could be something like that:
✔ Schemas loaded: 4
✔ Rules loaded: 6
✔ Errors loaded: 6
❌ Validation failed
❌ Schema "contactUs.json" → field "phone" references rule "cellphone" which does not existDefining Validation
Defining a Schema (What to validate)
Schemas map data fields to rules.
{
"name": {
"rule": "name",
"required": true
},
"email": {
"rule": "email",
"required": true,
"cache": false,
},
"emailConfirm": {
"rule": "email--confirm",
"required": true,
"cache": false,
},
"phone": {
"rule": "phone",
"required": false
}
}Schema Properties
- rule: Rule name (supports modifiers via
rule--modifier) - required: Whether the field must exist and not be empty
- cache: if this field will have cache or not
Defining Rules (How to validate)
Rules define validation logic, independent of any specific form.
{
"name": {
"validate": ["hasText"],
"error": { "hasText": "common.hasText" }
},
"email": {
"regex": "/^[a-z0-9.]+@[a-z0-9]+\\.[a-z]+(\\.[a-z]+)?$/i",
"validate": ["regex"],
"error": { "regex": "email.regex" },
"modifier": {
"confirm": {
"validate": ["regex", "equals"],
"params": { "equals": ["$email"] },
"error": { "equals": "email.equals" }
}
}
},
"date": {
"regex": "/^\\d{4}[\/\\-](0?[1-9]|1[012])[\/\\-](0?[1-9]|[12][0-9]|3[01])$/",
"validate": ["regex", "validDate"],
"error": {
"regex": "common.dateFormat",
"validDate": "date.validDate"
},
"modifier": {
"age": {
"validate": ["regex", "validateAge"],
"params": {
"validateAge": [18, 130]
},
"error": {
"regex": "common.dateFormat",
"validateAge": "date.modifier.age.validateAge"
}
}
}
}
}Rule Properties
- validate: Ordered list of validation functions
- regex: Optional regex used by the regex helper
- error: Error keys mapped to validation functions
- modifier: Contextual rule extensions
- params: Parameters passed to validation helpers
Modifiers (Contextual Rules)
Modifiers allow extending a rule without duplicating logic.
Example:
"email--confirm"Internally:
- Base rule: email
- Modifier: confirm
Modifiers can override:
- validate
- params
- regex
- error
This makes rules highly reusable and expressive.
Dynamic Parameters ($field)
Rules can reference other fields dynamically:
"params": {
"equals": ["$email"]
}At runtime:
$emailresolves todata.email- Enables cross-field validation
Validation Helpers (Execution Layer)
Validation helpers are the runtime implementation of rules.
const myValidator = function (value, rule, modifier = null, data = null) {
function regex() {
const regexTemplate = rule.modifier?.[modifier]?.regex || rule.regex;
const regex = new RegExp(regexTemplate);
return regex.test(value);
}
function hasText() {
return value.trim().length > 0;
}
function equals(key) {
return value === data[key];
}
async function isDataFetched() {
try {
let result = await new Promise((resolve, reject) => {
setTimeout(() => {
const success = !!value;
if (success) {
resolve('Data fetched successfully!');
} else {
reject('Error fetching data');
}
}, 2000);
});
return !!result;
} catch (error) {
return false;
}
}
return { regex, hasText, equals, isDataFetched };
};Helper Signature
(value, rule, modifier?, data?) => Record<string, Function>Helpers:
- Can be sync or async
- Are stateless
- Do not know about schemas or error messages
Error Messages (i18n-ready)
Errors are resolved via keys, not hardcoded strings.
{
"common": {
"hasText": "Please fill the field"
},
"email": {
"regex": "Please enter a valid email",
"equals": "Emails do not match"
}
}This makes localization and message customization straightforward.
Validation Options
options: {
cache?: boolean, // If cache is enabled or not
abortEarly?: boolean, // Stop on first error
propertiesMustMatch?: boolean, // Schema vs data strictness
}Example Usage
Explore examples in the examples folder folder. Before execute any test change the type in package.json for module instead commonjs
Examples folder: Github repo examples folder.
Vanilla
Here you are free to test anything you want about form validation, also We have a lot of tests scenarios in tests which could be a great start.
Command to run Vanilla example:
npm run example:vanillaVanilla example: Github repo vanilla file.
tests
Command to run tests:
npm run testUnit tests examples: Github repo unit tests file.
Express:
See how the check-rule-mate works in back-end using a middleware.
Command to run Express example:
npm run example:expressExpress example: Github repo express file.
Frontend:
Here you can found the DEMO page and it's a type of "playground" to test how RULES works and validations works. (Here you can't create customized javascript so custom validatorHelpers are disabled by default)
Frontend example: check-rule-mate demo.
When NOT to use check-rule-mate
- Simple one-off forms
- Basic required-only validation
- When schema-based validation is enough
License
- ISC
