> ## 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.

# JDM Editor

> Embed the GoRules decision editor in your React application.

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.

<Card title="GitHub Repository" icon="github" href="https://github.com/gorules/jdm-editor">
  View source, report issues, and contribute
</Card>

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @gorules/jdm-editor
  ```

  ```bash yarn theme={null}
  yarn add @gorules/jdm-editor
  ```

  ```bash pnpm theme={null}
  pnpm add @gorules/jdm-editor
  ```
</CodeGroup>

## Quick start

The `DecisionGraph` component requires a `JdmConfigProvider` wrapper:

```tsx theme={null}
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:

```tsx theme={null}
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);
```

<Note>
  WASM requires these headers on your server for `SharedArrayBuffer` support:

  ```
  Cross-Origin-Embedder-Policy: require-corp
  Cross-Origin-Opener-Policy: same-origin
  ```
</Note>

## 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:

```tsx theme={null}
<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.

<Tabs>
  <Tab title="API (Backend)">
    Call your backend to evaluate the decision:

    ```tsx theme={null}
    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 } });
                  }}
                />
              ),
            },
          ]}
        />
      );
    }
    ```
  </Tab>

  <Tab title="WASM (Browser-only)">
    Evaluate decisions entirely in the browser using the ZEN Engine WASM build:

    ```tsx theme={null}
    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 } });
                  }}
                />
              ),
            },
          ]}
        />
      );
    }
    ```

    <Note>
      WASM requires these headers on your server for `SharedArrayBuffer` support:

      ```
      Cross-Origin-Embedder-Policy: require-corp
      Cross-Origin-Opener-Policy: same-origin
      ```
    </Note>
  </Tab>
</Tabs>

## 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:

```tsx theme={null}
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                                           |
| ---------- | -------------------------------------------------- |
| `standard` | General expressions that return a value            |
| `unary`    | Boolean conditions for decision table cells        |
| `template` | String templates with `{expression}` interpolation |

```tsx theme={null}
// 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:

```tsx theme={null}
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:

```tsx theme={null}
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:

```tsx theme={null}
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:full`   | Full editing capabilities (default)              |
| `edit:rules`  | Edit rule values only, cannot add/remove columns |
| `edit:values` | Edit cell values only, cannot modify structure   |

```tsx theme={null}
<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:

```tsx theme={null}
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:

```tsx theme={null}
import type {
  DecisionGraphType,
  DecisionNode,
  DecisionEdge,
  DecisionTableType,
  SchemaSelectProps,
} from '@gorules/jdm-editor';

const decision: DecisionGraphType = {
  nodes: [],
  edges: [],
};
```

## Extracting JDM output

The editor produces JDM (JSON Decision Model) format that the ZEN Engine can execute:

```tsx theme={null}
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](/developers/tools/standalone-editor) — a self-hosted Docker image with the full visual editor.
