UNPKG

@thi.ng/rstream-dot

Version:

Graphviz DOT conversion of @thi.ng/rstream dataflow graph topologies

88 lines (87 loc) 2.8 kB
import { StreamMerge } from "@thi.ng/rstream/merge"; import { Stream } from "@thi.ng/rstream/stream"; import { StreamSync } from "@thi.ng/rstream/sync"; import { truncate } from "@thi.ng/strings/truncate"; import { map } from "@thi.ng/transducers/map"; export * from "./api.js"; const __getNodeType = (sub) => sub instanceof Stream ? "Stream" : sub instanceof StreamSync ? "StreamSync" : sub instanceof StreamMerge ? "StreamMerge" : void 0; const __getChildren = (sub) => { let children = []; if (sub.subs) children.push(...sub.subs); if (sub.__owner) children.push(sub.__owner); if (sub.wrapped) children.push(...__getChildren(sub.wrapped)); return children; }; const __dotNode = (s, opts) => { let res = `s${s.id}[label="`; res += s.type ? `${s.label}\\n(${s.type})` : `${s.label}`; if (s.body !== void 0) { res += `\\n${s.body.replace(/"/g, `'`).replace(/\n/g, "\\n")}`; } res += `", color="`; res += s.type && opts.color[s.type.toLowerCase()] || (s.label === "<noid>" ? opts.color.noid : opts.color.default); return res + `"];`; }; const __dotEdge = (a, b, _) => `s${a.id} -> s${b.id}${b.xform ? `[label="xform"]` : ""};`; const __subValue = (sub) => { const res = JSON.stringify(sub.deref ? sub.deref() : void 0); return res ? truncate(64, "...")(res) : res; }; const traverse = (subs, opts, state) => { opts || (opts = {}); state || (state = { id: 0, subs: /* @__PURE__ */ new Map(), rels: [] }); for (let sub of subs) { if (state.subs.get(sub)) return state; const id = state.id; const desc = { id, label: sub.id || "<noid>", type: __getNodeType(sub), xform: !!sub.xform, body: opts.values ? __subValue(sub) : void 0 }; state.subs.set(sub, desc); state.id++; const children = __getChildren(sub); if (children.length) { traverse(children, opts, state); for (let c of children) { const childNode = state.subs.get(c); childNode && state.rels.push([desc, childNode]); } } } return state; }; const toDot = (state, opts) => { opts = { dir: "LR", font: "sans-serif", fontsize: 10, text: "white", ...opts }; opts.color = { default: "black", noid: "gray", stream: "blue", streammerge: "red", streamsync: "red", ...opts.color }; return [ "digraph g {", `rankdir=${opts.dir};`, `node[fontname="${opts.font}",fontsize=${opts.fontsize},style=filled,fontcolor=${opts.text}];`, `edge[fontname="${opts.font}",fontsize=${opts.fontsize}];`, ...map((n) => __dotNode(n, opts), state.subs.values()), ...map((r) => __dotEdge(r[0], r[1], opts), state.rels), "}" ].join("\n"); }; const serialize = (subs, opts) => toDot(traverse(subs, opts), opts); export { serialize, toDot, traverse };