@hlang-tech/interpreter
Runs an hlang program (IGraph) in the current process. It builds the nodes, connects their ports, and runs the flow, with no code generation and no file access. It works in Node.js and in browsers.
Install
npm install @hlang-tech/interpreter @hlang-tech/runtime
The same build is published as @hlang-org/interpreter. ESM and CommonJS builds with type declarations.
Usage
import { Flow } from '@hlang-tech/runtime';
import { interpret, NodeRegistry } from '@hlang-tech/interpreter';
const registry = new NodeRegistry()
.register('numbers', Numbers) // classes that extend the runtime's node classes
.register('double', Double)
.register('log', Log);
const handle = interpret(graph, { registry, createFlow: () => new Flow() }, { env: 'prod' });
handle.onError(({ nodeId, error }) => console.error(nodeId, error));
handle.onActivity(({ nodeId, portId }) => highlight(nodeId, portId));
// Later: stop long-running nodes and release subscriptions.
handle.dispose();
What interpret does
- Validates the graph with
planGraphfrom@hlang-tech/ir. Invalid graphs throw aGraphError. - Constructs every node with
new NodeClass({ nodeId, flowId, env, middleware, config, signal }).configis the node'sbizData. - Subscribes the
@node/errorport of every Readable and Transform node. - Connects each connection as
source.O(port).connect(target.I(port)). - Runs every Readable root with a new
Flow.
@hlang-tech/compiler emits the same steps as an ES module.
API
interpret(graph, deps, options?)
| Argument | Description |
|---|---|
deps.registry | A NodeRegistry that maps each node code to a node class. |
deps.createFlow | Returns a new runtime Flow. |
options.flowId | Flow id passed to every node. Generated when omitted. |
options.env | Environment label passed to every node. Default 'prod'. |
options.middleware | Object passed to every node, for services such as a logger. |
It throws if a node code is not registered.
Execution handle
| Member | Description |
|---|---|
flowId | The flow id of this run. |
roots | The Readable root nodes. |
getNode(nodeId) | The constructed node, or undefined. |
onError(listener) | Errors sent on any @node/error port. Errors sent while the flow starts are buffered, so a listener added after interpret returns still receives them. Returns a disposable. |
onActivity(listener) | Fires when data passes a connection, for both the source port and the target node. Returns a disposable. |
dispose() | Stops the run: emits the stop signal, calls onStop callbacks, and unsubscribes the interpreter's observers. |
Stop signal
Every node receives signal in its constructor options. Bind long-running work to it:
interval(1000).pipe(takeUntil(this.opts.signal.observable)).subscribe(tick);
this.opts.signal.onStop(() => socket.close());
NodeRegistry
register(code, NodeClass) (chainable; the last registration wins), get(code), has(code), codes().
The package also re-exports planGraph, GraphError, and the IGraph types from @hlang-tech/ir.
Source and documentation: github.com/hlang-tech/hlang.
License
MIT