Getting started
Install hlang, write a graph in code, then run the same program as data.
Install
npm install @hlang-org/runtime @hlang-org/interpreterThe runtime is CommonJS with type declarations; ES modules import its named exports. The other packages ship ES modules and CommonJS.
Write three nodes
A node is a class. It declares its ports in the constructor and does its work in one method: _read for a Readable, _transform for a Transform, _write for a Writable.
// Three nodes, one of each kind. Each declares its ports in the constructor.
import { ReadableNode, TransformNode, WriteableNode, Port } from '@hlang-org/runtime';
/** R: sends one greeting on `out`. */
export class Greeting extends ReadableNode {
constructor(opts) {
super(opts);
Port.O('out').attach(this);
}
_read($o) {
$o('out').send('hello, hlang');
}
}
/** T: upper-cases every text it receives on `in` and sends it on `out`. */
export class Uppercase extends TransformNode {
constructor(opts) {
super(opts);
Port.I('in').attach(this);
Port.O('out').attach(this);
}
_transform($i, $o) {
$i('in').receive(text => $o('out').send(text.toUpperCase()));
}
}
/** W: prints every text it receives on `in`. */
export class Print extends WriteableNode {
constructor(opts) {
super(opts);
Port.I('in').attach(this);
}
_write($i) {
$i('in').receive(text => console.log(text));
}
}Wire them and run
Connect an output port to an input port, then run the flow from the Readable root.
import { Flow } from '@hlang-org/runtime';
import { Greeting, Uppercase, Print } from './lib/nodes.mjs';
const greeting = new Greeting();
const uppercase = new Uppercase();
const print = new Print();
// Wiring is always output to input.
greeting.O('out').connect(uppercase.I('in'));
uppercase.O('out').connect(print.I('in'));
// Run from the Readable root.
new Flow().run(greeting);HELLO, HLANGRun the same program as data
The same graph as JSON. Each node's code names a node class; the registry maps codes to classes.
// The same program as data: an IGraph. A connection's Output is the upstream
// port and its Input is the downstream port.
export const graph = {
nodeList: [
{ nodeId: 'a', code: 'greeting', name: 'Greeting', type: 'R' },
{ nodeId: 'b', code: 'uppercase', name: 'Uppercase', type: 'T' },
{ nodeId: 'c', code: 'print', name: 'Print', type: 'W' },
],
connections: [
{ Output: { nodeId: 'a', portConf: { id: 'out' } }, Input: { nodeId: 'b', portConf: { id: 'in' } } },
{ Output: { nodeId: 'b', portConf: { id: 'out' } }, Input: { nodeId: 'c', portConf: { id: 'in' } } },
],
};import { Flow } from '@hlang-org/runtime';
import { interpret, NodeRegistry } from '@hlang-org/interpreter';
import { Greeting, Uppercase, Print } from './lib/nodes.mjs';
import { graph } from './lib/graph.mjs';
// The registry maps each node `code` in the graph to a node class.
const registry = new NodeRegistry()
.register('greeting', Greeting)
.register('uppercase', Uppercase)
.register('print', Print);
const handle = interpret(graph, { registry, createFlow: () => new Flow() });
handle.onError(({ nodeId, error }) => console.error(nodeId, error));
// Stop every node and release its subscriptions.
handle.dispose();HELLO, HLANGEvery example on this site is a file in the repository that runs in CI. The output above is the output of that run.
Next: Nodes and ports, or compile the graph to a module.
The examples on this page run in CI. Edit this page on GitHub