rule-based-dynamic-json
v1.0.0
Published
CSV rule-driven dynamic JSON generator and validator for Node.js
Downloads
169
Maintainers
Readme
rule-based-dynamic-json
A headless Node.js 18+ module that uses parsed CSV rule rows to generate a new, rule-only JSON document and validate the generated result.
The engine does not mutate the input, does not preserve unknown fields, and does
not use eval() or new Function().
Install
npm install rule-based-dynamic-jsonPublic API
import { UniversalRuleEngine } from "rule-based-dynamic-json";
const engine = new UniversalRuleEngine(csvRuleObjects);
const result = engine.evaluate(inputData);evaluate() returns exactly:
{
isValid: boolean,
errors: [{ path: string, message: string }],
nextRequiredFields: [string],
processedData: object
}Only data described by active rules is copied into processedData. Invalid
rule-addressed values remain in processedData so callers can display and
correct them, but an invalid result must not be persisted.
CSV rule columns
| Column | Meaning |
| --- | --- |
| keyname | Unique business-field identifier |
| path | Output path using dot notation and optional [*] wildcards |
| type | string, number, boolean, array, or object |
| condition | Safe activation expression |
| defaultvalue | Typed fallback used when the active input value is missing |
| allowedvalue | Comma-separated primitive values |
| isrequired | Boolean or the string true / false |
| regex | Safe regular-expression source for string values |
The constructor accepts rows already parsed from CSV. CSV parsing is intentionally kept outside the engine so applications can choose their preferred parser, streaming strategy, delimiter, encoding, and storage mechanism.
Complete nested example
Equivalent CSV:
keyname,path,type,condition,defaultvalue,allowedvalue,isrequired,regex
projectName,project.name,string,,,,true,^[A-Z][A-Za-z ]+$
category,category,string,,Residential,"Residential, Commercial",true,
blockName,blocks[*].name,string,,,,true,
unitType,blocks[*].units[*].type,string,,,"Apartment, Penthouse, Studio",true,
unitArea,blocks[*].units[*].areaSqft,number,,,,true,
furnished,blocks[*].units[*].furnished,boolean,,false,,false,
status,blocks[*].units[*].status,string,,Available,"Available, Reserved",true,
terrace,blocks[*].units[*].terraceSqft,number,"type === 'Penthouse' && category === 'Residential'",,,true,Rules after CSV parsing:
const rules = [
{
keyname: "projectName",
path: "project.name",
type: "string",
isrequired: true,
regex: "^[A-Z][A-Za-z ]+$"
},
{
keyname: "category",
path: "category",
type: "string",
defaultvalue: "Residential",
allowedvalue: "Residential, Commercial",
isrequired: true
},
{
keyname: "blockName",
path: "blocks[*].name",
type: "string",
isrequired: true
},
{
keyname: "unitType",
path: "blocks[*].units[*].type",
type: "string",
allowedvalue: "Apartment, Penthouse, Studio",
isrequired: true
},
{
keyname: "unitArea",
path: "blocks[*].units[*].areaSqft",
type: "number",
isrequired: true
},
{
keyname: "furnished",
path: "blocks[*].units[*].furnished",
type: "boolean",
defaultvalue: "false"
},
{
keyname: "status",
path: "blocks[*].units[*].status",
type: "string",
defaultvalue: "Available",
allowedvalue: "Available, Reserved",
isrequired: true
},
{
keyname: "terrace",
path: "blocks[*].units[*].terraceSqft",
type: "number",
condition: "type === 'Penthouse' && category === 'Residential'",
isrequired: true
}
];
const input = {
project: { name: "Sky Gardens", internalCode: "discarded" },
category: "Residential",
blocks: [
{
name: "Block A",
units: [
{
type: "Penthouse",
areaSqft: "1450",
furnished: "true",
terraceSqft: "250"
},
{
type: "Studio",
areaSqft: "450",
terraceSqft: 90
}
]
}
],
unknownField: "discarded"
};
const engine = new UniversalRuleEngine(rules);
const result = engine.evaluate(input);The generated processedData is:
{
"category": "Residential",
"project": {
"name": "Sky Gardens"
},
"blocks": [
{
"name": "Block A",
"units": [
{
"areaSqft": 1450,
"furnished": true,
"status": "Available",
"terraceSqft": 250,
"type": "Penthouse"
},
{
"areaSqft": 450,
"furnished": false,
"status": "Available",
"type": "Studio"
}
]
}
]
}The Studio unit's obsolete terraceSqft is removed, numeric and boolean strings
are coerced, defaults are generated, and unknown fields are discarded.
Conditions
The embedded expression parser supports:
- String, number, boolean,
null, andundefinedliterals - Nested identifiers such as
project.category - Parentheses and unary
! ===,!==,==,!=,>,>=,<, and<=&&and||with short-circuit evaluation
Function calls, assignments, computed property access, object/array literals, and prototype-related identifiers are rejected during construction.
For a path such as blocks[0].units[1].terraceSqft, identifier lookup uses:
- Generated values in
blocks[0].units[1] - Input values in
blocks[0].units[1] - Generated top-level values
- Input top-level values
Generation and validation rules
- Arrays are input-driven.
[*]never invents new elements. - Multiple wildcards are recursively expanded to concrete indexed paths.
- Empty source arrays are preserved as empty generated arrays.
undefined,null, and empty strings are treated as missing.- Numeric strings are converted only when they represent finite numbers.
- Boolean strings are converted only when they equal
trueorfalse, case-insensitively. - Array and object defaults may be provided as JSON strings.
- Input arrays and objects must already have their declared structural type.
- Conditions and defaults are evaluated in stabilization rounds, so CSV row order does not control the result.
- Cyclic/non-converging conditions produce an invalid deterministic result.
- Regex patterns are screened with
safe-regex2; regex input is capped at 10,000 characters.
An array or object rule authorizes the full value at that exact path.
Applications requiring field-level projection inside a structure should define
rules for its child paths instead of defining a rule for the whole parent.
Run tests
npm testThe test suite covers nested wildcard generation, contextual conditions, coercion, defaults, pruning, required-field discovery, enum and regex errors, input immutability, malicious expressions and paths, unsafe regexes, duplicate rules, and non-converging conditions.
