Dflow

A minimal Dataflow programming engine

Features

Expressive and simple API
It is easy to create nodes
Written in TypeScript
Whole implementation is in this dflow.ts file. It is roughly 4kb once minified.
Minimal type system
It is possible to connect an output to an input only if the data types are matching.

Notice that you must implement your own nodes. For example a node "addition" could be implemented using BigInt or some arbitrary-precision library, according to your needs. You can find example nodes implementing basic JavaScript features in the examples/nodes/ folder.

How it works

A node is a block of code that can have inputs and outputs.

A link connects an input to an output.

A graph represents a program. It can contain nodes and links. Nodes are executed, sorted by their connections.

API

A Dflow represents a program as an executable graph.

A graph can contain nodes and links. Nodes are executed, sorted by their connections.

Constructor

Dflow constructor requires a list of node definitions.


import { Dflow, type DflowNode } from "dflow";

// Node definition.
const helloWorld: DflowNode = {
  kind: "hello",
  run: () => console.log("Hello, World!")
}

// Create a dflow instance.
const dflow = new Dflow([helloWorld]);

// Add a node to the graph.
dflow.node("hello")

// Run the dflow graph.
dflow.run()
      

Methods

dflow.node(kind)

Create a new node. Returns node id.

dflow.link(source, target)

Create a new link and connect two nodes. Returns link id.

If source or target position is omitted, then it defaults to 0 i.e. the first position.

dflow.data(value)

Create a new data node. Returns node id.

If value is not a valid DflowData, it will be set to undefined.

dflow.run()

Execute all nodes, sorted by their connections.

dflow.delete(itemId)

Delete node or link with given id.

Getters

dflow.graph

A graph contains nodes and links.

A DflowGraph has the following attributes:

node: Record<string, string>
Key is node id, value is node kind
link: Record<string, DflowLink>
Key is link id
data: Record<string, DflowData>
Data nodes: key is node id, value is node kind

dflow.error

Get error messages from last run, indexed by node id.

dflow.out

Get output data of last run, indexed by node id.

Static methods

Dflow.input()

Helper to define inputs.

Dflow.output()

Helper to define outputs.

Define an output named π (PI) for a constant node


const MathPI: DflowNode = {
  kind: "mathPI",
  outputs: [Dflow.output("number", { name: "π" })],
  run: () => Math.PI
}
      

Types

DflowData

Includes JSON data types and undefined

The DflowData can be one of the following:

DflowDataType

The DflowDataType is a literal type; it can be one of the following:

DflowInput

A DflowInput has the following attributes:

name?: string
Ignored by Dflow, but could be used by UI.
types: DflowDataType[]
An input can be connected to an output only if the data types match.
optional?: boolean
Any input is required by default, i.e. not optional. If an input is not optional and it has no data, then its node will not be executed. If an input is optional, then its node will be executed even if the input has no data.

DflowOutput

A DflowOutput has the following attributes:

name?: string
Ignored by Dflow, but could be used by UI.
types: DflowDataType[]
An output can be connected to an input only if the data types match.

Connects two nodes in the graph.

DflowNode

Defines a block of code: it can have inputs and outputs.

A DflowNode has the following attributes:

kind: string
inputs?: DflowInput[]
outputs?: DflowOutput[]
run(inputs): outputs

Define a "sum" node.


import { Dflow, type DflowNode } from "dflow";

const Sum: DflowNode = {
  kind: "sum",
  inputs: [Dflow.input("number"), Dflow.input("number")];
  outputs: [Dflow.output("number")];
  run(a: number, b: number) {
    return a + b;
  }
}