Documentation Index Fetch the complete documentation index at: https://docs.gorules.io/llms.txt
Use this file to discover all available pages before exploring further.
The JDM Editor is an open-source React component that provides a full-featured visual editor for creating and editing decision models. Embed it in your application to give users the ability to build rules without leaving your product.
GitHub Repository View source, report issues, and contribute
Installation
npm install @gorules/jdm-editor
Quick start
The DecisionGraph component requires a JdmConfigProvider wrapper:
import { useState } from 'react' ;
import { JdmConfigProvider , DecisionGraph } from '@gorules/jdm-editor' ;
import '@gorules/jdm-editor/dist/style.css' ;
function RuleEditor () {
const [ value , setValue ] = useState ({ nodes: [], edges: [] });
return (
< JdmConfigProvider >
< DecisionGraph
value = { value }
onChange = { setValue }
/>
</ JdmConfigProvider >
);
}
Loading WASM for code extensions
The editor uses WebAssembly for syntax highlighting, autocomplete, and expression validation. Load the WASM module at application startup using top-level await:
import * as ZenEngineWasm from '@gorules/zen-engine-wasm' ;
import wasmUrl from '@gorules/zen-engine-wasm/dist/zen_engine_wasm_bg.wasm?url' ;
await ZenEngineWasm . default ( wasmUrl );
WASM requires these headers on your server for SharedArrayBuffer support: Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
Features
The decision graph canvas lets you drag and drop nodes onto the canvas, connect nodes to define data flow, pan and zoom to navigate large graphs, and select and delete nodes.
The spreadsheet-like decision table editor supports adding input and output columns, defining conditions with unary operators, reordering rows by drag and drop, and hit policy configuration (first, collect).
The expression editor provides syntax highlighting for ZEN expressions, autocomplete for functions and fields, inline validation and error messages, and field path suggestions from input schema.
The JavaScript function editor includes Monaco editor with syntax highlighting, TypeScript type checking, built-in library support (dayjs, big.js, zod), and async/await support.
Configuration
Read-only mode
Display decisions without allowing edits:
< DecisionGraph
value = { value }
disabled
/>
Simulator integration
Add a simulator panel to test decisions directly in the editor. You can evaluate rules via your backend API or entirely in the browser using WASM.
API (Backend)
WASM (Browser-only)
Call your backend to evaluate the decision: import { DecisionGraph , GraphSimulator } from '@gorules/jdm-editor' ;
import { PlayCircleOutlined } from '@ant-design/icons' ;
function RuleEditor () {
const [ graph , setGraph ] = useState ({ nodes: [], edges: [] });
const [ simulation , setSimulation ] = useState ();
return (
< DecisionGraph
value = { graph }
onChange = { setGraph }
simulate = { simulation }
panels = { [
{
id: 'simulator' ,
title: 'Simulator' ,
icon: < PlayCircleOutlined /> ,
renderPanel : () => (
< GraphSimulator
onClear = { () => setSimulation ( undefined ) }
onRun = {async ({ graph , context }) => {
const response = await fetch ( '/api/evaluate' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({ context , content: graph })
});
const data = await response . json ();
setSimulation ({ result: { ... data , snapshot: graph } });
} }
/>
),
},
] }
/>
);
}
Evaluate decisions entirely in the browser using the ZEN Engine WASM build: import { DecisionGraph , GraphSimulator } from '@gorules/jdm-editor' ;
import { ZenEngine } from '@gorules/zen-engine' ;
import { PlayCircleOutlined } from '@ant-design/icons' ;
function RuleEditor () {
const [ graph , setGraph ] = useState ({ nodes: [], edges: [] });
const [ simulation , setSimulation ] = useState ();
return (
< DecisionGraph
value = { graph }
onChange = { setGraph }
simulate = { simulation }
panels = { [
{
id: 'simulator' ,
title: 'Simulator' ,
icon: < PlayCircleOutlined /> ,
renderPanel : () => (
< GraphSimulator
onClear = { () => setSimulation ( undefined ) }
onRun = {async ({ graph , context }) => {
const engine = new ZenEngine ();
const result = await engine . evaluate ( graph , context , { trace: true });
engine . dispose ();
setSimulation ({ result: { ... result , snapshot: graph } });
} }
/>
),
},
] }
/>
);
}
WASM requires these headers on your server for SharedArrayBuffer support: Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
Standalone components
Use individual editor components outside of the decision graph for custom integrations.
Code editor
The CodeEditor component provides standalone expression editing with syntax highlighting and validation:
import { useState } from 'react' ;
import { JdmConfigProvider , CodeEditor } from '@gorules/jdm-editor' ;
function ExpressionEditor () {
const [ expression , setExpression ] = useState ( 'customer.age >= 18' );
return (
< JdmConfigProvider >
< CodeEditor
value = { expression }
onChange = { setExpression }
type = "unary"
lint
/>
</ JdmConfigProvider >
);
}
Editor types
Type Use case standardGeneral expressions that return a value unaryBoolean conditions for decision table cells templateString templates with {expression} interpolation
// Standard expression
< CodeEditor type = "standard" value = "cart.total * 0.1" />
// Unary condition
< CodeEditor type = "unary" value = ">= 100" />
// Template string
< CodeEditor type = "template" value = "Hello, {customer.name}!" />
Type hints
Pass variableType and expectedVariableType to enable type checking and improved autocomplete. Types use the VariableTypeJson format:
import type { VariableTypeJson } from '@gorules/jdm-editor' ;
const variableType : VariableTypeJson = {
Object: {
customer: {
Object: {
name: 'String' ,
age: 'Number' ,
tier: { Enum: [ undefined , [ 'bronze' , 'silver' , 'gold' ]] }
}
},
order: {
Object: {
amount: 'Number' ,
items: { Array: 'Any' }
}
}
}
};
< CodeEditor
value = { expression }
onChange = { setExpression }
type = "standard"
lint
variableType = { variableType }
expectedVariableType = "Number"
/>
Available type variants:
Type Description 'Any'Any value 'Null'Null value 'Bool'Boolean 'String'String 'Number'Number { Const: string }Constant string value { Enum: [label, values] }Enumeration with optional label { Array: VariableTypeJson }Array of a specific type { Object: Record<string, VariableTypeJson> }Object with typed fields
Decision table
The DecisionTable component renders a standalone spreadsheet-style table editor:
import { useState } from 'react' ;
import { JdmConfigProvider , DecisionTable } from '@gorules/jdm-editor' ;
import type { DecisionTableType } from '@gorules/jdm-editor' ;
function TableEditor () {
const [ table , setTable ] = useState < DecisionTableType >({
hitPolicy: 'first' ,
inputs: [],
outputs: [],
rules: [],
});
return (
< JdmConfigProvider >
< DecisionTable
value = { table }
onChange = { setTable }
tableHeight = { 400 }
/>
</ JdmConfigProvider >
);
}
Schema-driven autocomplete
Pass inputsSchema and outputsSchema to provide field suggestions in the expression editor:
import type { SchemaSelectProps } from '@gorules/jdm-editor' ;
const inputsSchema : SchemaSelectProps [] = [
{ field: 'customer.tier' , name: 'Customer Tier' },
{ field: 'customer.region' , name: 'Region' },
{ field: 'order.amount' , name: 'Order Amount' },
{ field: 'order.quantity' , name: 'Quantity' },
];
const outputsSchema : SchemaSelectProps [] = [
{ field: 'discount' , name: 'Discount' },
{ field: 'shippingFee' , name: 'Shipping Fee' },
];
< DecisionTable
value = { table }
onChange = { setTable }
tableHeight = { 400 }
inputsSchema = { inputsSchema }
outputsSchema = { outputsSchema }
/>
Permission levels
Control editing capabilities with the permission prop:
Permission Description edit:fullFull editing capabilities (default) edit:rulesEdit rule values only, cannot add/remove columns edit:valuesEdit cell values only, cannot modify structure
< DecisionTable
value = { table }
onChange = { setTable }
tableHeight = { 400 }
permission = "edit:rules"
/>
Schema validation
Validate JDM files before loading them into the editor using the exported Zod schema:
import { decisionModelSchema } from '@gorules/jdm-editor/dist/schema' ;
async function handleFileUpload ( file : File ) {
const content = await file . text ();
const result = decisionModelSchema . safeParse ( JSON . parse ( content ));
if ( ! result . success ) {
console . error ( result . error );
alert ( 'Invalid decision file' );
return ;
}
setGraph ( result . data );
}
TypeScript support
The editor is fully typed. Import types for your integration:
import type {
DecisionGraphType ,
DecisionNode ,
DecisionEdge ,
DecisionTableType ,
SchemaSelectProps ,
} from '@gorules/jdm-editor' ;
const decision : DecisionGraphType = {
nodes: [],
edges: [],
};
The editor produces JDM (JSON Decision Model) format that the ZEN Engine can execute:
function SaveButton ({ value } : { value : DecisionGraphType }) {
const handleSave = async () => {
// value is already in JDM format
await fetch ( '/api/decisions' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ( value ),
});
};
return < button onClick = { handleSave } > Save Decision </ button > ;
}
Standalone editor
For non-React applications, use the Standalone Editor — a self-hosted Docker image with the full visual editor.