Core API
@visual-json/core is the headless engine behind visual-json. It converts raw JSON into an
immutable tree structure that you can traverse, manipulate, diff, search, and validate —
without any UI framework dependency.
npm install @visual-json/coreTree Model
The tree model converts any JSON value into a normalized TreeState with unique node IDs.
import { fromJson, toJson, findNode, findNodeByPath } from "@visual-json/core";
const state = fromJson({ name: "visual-json", version: 1 });
const json = toJson(state.root);
const node = findNode(state, "some-node-id");
const versionNode = findNodeByPath(state, "$.version");Types
| Type | Description |
|---|---|
JsonValue | string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue } |
NodeType | "string" | "number" | "boolean" | "null" | "object" | "array" |
TreeNode | A node in the tree with id, key, path, type, value, children, and parentId |
TreeState | Contains root: TreeNode and nodesById: Map<string, TreeNode> |
Operations
All operations are immutable — they return a new TreeState without mutating the original.
import {
setValue,
setKey,
addProperty,
removeNode,
moveNode,
reorderChildren,
changeType,
duplicateNode,
} from "@visual-json/core";
let state = fromJson({ items: [1, 2, 3] });
state = setValue(state, nodeId, "new value");
state = setKey(state, nodeId, "newKey");
state = addProperty(state, parentId, "count", 42);
state = removeNode(state, nodeId);
state = moveNode(state, nodeId, newParentId, 0);
state = reorderChildren(state, parentId, 0, 2);
state = changeType(state, nodeId, "string");
state = duplicateNode(state, nodeId);History
The History class provides undo/redo over tree states.
import { History } from "@visual-json/core";
const history = new History();
history.push(state);
const previous = history.undo();
const next = history.redo();
console.log(history.canUndo, history.canRedo);Schema
Resolve JSON Schemas from well-known filenames (e.g. package.json, tsconfig.json) and
navigate schema properties by path.
import { resolveSchema, getPropertySchema, clearSchemaCache } from "@visual-json/core";
const schema = await resolveSchema(json, "package.json");
if (schema) {
const propSchema = getPropertySchema(schema, "$.scripts.build");
console.log(propSchema?.description);
}Search
Search across keys and values in the tree.
import { searchNodes, getAncestorIds } from "@visual-json/core";
const matches = searchNodes(state, "version");
// [{ nodeId: "...", field: "key" }, { nodeId: "...", field: "value" }]
const ancestorIds = getAncestorIds(state, matches.map((m) => m.nodeId));Diff
Compare two JSON values and get a list of changes.
import { computeDiff, getDiffPaths } from "@visual-json/core";
const entries = computeDiff(originalJson, currentJson);
// [{ path: "$.name", type: "changed", oldValue: "old", newValue: "new" }]
const diffPaths = getDiffPaths(entries);
// Map<string, "added" | "removed" | "changed" | "unchanged">Validation
Validate a tree node against a JSON Schema property.
import { validateNode } from "@visual-json/core";
const result = validateNode(node, schemaProperty);
// { valid: boolean, errors: string[] }