Skip to content

Validation and Composition

analyzeFlow returns all detected graph diagnostics without throwing:

const analysis = analyzeFlow({ flow, fnList });
for (const diagnostic of analysis.diagnostics) {
if (diagnostic.severity === "error") {
console.error(diagnostic.code, diagnostic.message);
} else {
console.warn(diagnostic.code, diagnostic.message);
}
}

Each diagnostic has an error or warning severity and can identify a nodeId, edgeId, or numeric handle. analysis.valid depends only on errors. compileFlow performs the same analysis and returns the same diagnostics.

Warnings remain available even when the flow is valid:

const warnings = analysis.diagnostics.filter(
(diagnostic) => diagnostic.severity === "warning",
);

When an editor needs both diagnostics and a compiled function, call compileFlow to inspect the graph once. Invalid graphs return valid: false with diagnostics; valid graphs also include compiled:

import { compileFlow } from "@fn-sphere/flow";
const result = compileFlow({ flow, fnList });
if (result.valid) {
const run = result.compiled.define.implement(result.compiled.implement);
// Reuse run when only input values change; recompile when the graph changes.
}

A version 1 executable flow must satisfy these rules:

  • Node IDs and edge IDs are unique.
  • Every output-reachable fnName resolves to a function in fnList.
  • There is exactly one input node and one output node.
  • Output-reachable function schemas use fixed tuple inputs; variadic array inputs are unsupported.
  • Every output-reachable function input handle has exactly one incoming edge.
  • Each active flow input handle has one consumer, and active handles form a contiguous zero-based tuple.
  • Function output and output-node handles are 0.
  • Connected schemas in the executable slice are compatible.
  • Output-reachable function nodes form an acyclic graph.
  • Unreachable function nodes produce warnings and are excluded from the compiled function.

A valid result’s compiled is a StandardFnSchema, so it can be added to another flow’s function list. The outer graph references the inner flow by its compiled name:

const formula = compileFlow({ flow: formulaSpec, fnList: arithmeticFns });
if (!formula.valid) throw new Error("Invalid formula flow");
const outer = compileFlow({
flow: outerSpec,
fnList: [...arithmeticFns, formula.compiled],
});

The example composes (a + b) * c as one function node, then adds d:

((1 + 2) × 3) + 4 = 13

FlowSpec is a compile-time type. Use flowSpecSchema to validate untrusted JSON before analysis or compilation:

const flow = flowSpecSchema.parse(JSON.parse(serialized));
const analysis = analyzeFlow({ flow, fnList });