Data Flow Analysis
The data flow analyzer builds a graph of value and service dependencies between steps in your Effect program. It tracks which steps produce values, which steps consume them, and identifies issues like undefined reads or duplicate writes.
Building a Data Flow Graph
Section titled “Building a Data Flow Graph”import { analyze, buildDataFlowGraph } from "effect-analyzer"import { Effect } from "effect"
const ir = await Effect.runPromise(analyze("./src/transfer.ts").single())const graph = buildDataFlowGraph(ir)
console.log(graph.nodes.length) // Number of data flow nodesconsole.log(graph.edges.length) // Number of dependency edgesconsole.log(graph.undefinedReads) // Reads with no matching producerconsole.log(graph.duplicateWrites) // Keys written by multiple stepsGraph Structure
Section titled “Graph Structure”The DataFlowGraph contains:
| Field | Type | Description |
|---|---|---|
nodes | DataFlowNode[] | One node per effect step |
edges | DataFlowEdge[] | Edges from producer to consumer |
producedKeys | Set<string> | All keys that have a producer |
undefinedReads | UndefinedRead[] | Reads where no producer was found |
duplicateWrites | DuplicateWrite[] | Keys written by more than one step |
Each DataFlowNode records:
| Field | Type | Description |
|---|---|---|
id | string | Node identifier (matches IR node ID) |
name | string | undefined | Human-readable step name |
writes | string | undefined | The success type this step produces |
reads | string[] | Service IDs this step reads from Context |
Querying Producers and Consumers
Section titled “Querying Producers and Consumers”Find which steps produce or consume a given key:
import { getProducers, getConsumers } from "effect-analyzer"
// Who produces the "balance" value?const producers = getProducers(graph, "balance")
// Who consumes "AccountService"?const consumers = getConsumers(graph, "AccountService")Transitive Dependencies
Section titled “Transitive Dependencies”Trace the full dependency chain for a node:
import { getTransitiveDependencies } from "effect-analyzer"
const deps = getTransitiveDependencies(graph, "step-4")// All nodes that step-4 transitively depends onFinding Cycles
Section titled “Finding Cycles”Detect circular dependencies in the data flow:
import { findCycles } from "effect-analyzer"
const cycles = findCycles(graph)if (cycles.length > 0) { console.log("Circular dependencies found:", cycles)}Validating Data Flow
Section titled “Validating Data Flow”Run a comprehensive validation that checks for undefined reads, duplicate writes, and other issues:
import { validateDataFlow } from "effect-analyzer"
const validation = validateDataFlow(graph)
console.log(validation.undefinedReads) // Reads with no producerconsole.log(validation.duplicateWrites) // Keys with multiple producersExecution Order
Section titled “Execution Order”Get the topological order of data flow nodes - the order in which they must execute based on their dependencies:
import { getDataFlowOrder } from "effect-analyzer"
const order = getDataFlowOrder(graph)// Returns node IDs in dependency-respecting orderMermaid Visualization
Section titled “Mermaid Visualization”Render the data flow as a Mermaid diagram:
npx effect-analyze ./src/transfer.ts --format mermaid-dataflowLibrary API
Section titled “Library API”import { buildDataFlowGraph, renderDataFlowMermaid } from "effect-analyzer"
const graph = buildDataFlowGraph(ir)const diagram = renderDataFlowMermaid(graph)
console.log(diagram)The diagram shows nodes as boxes with their produced types, and edges indicating which values flow between steps.
Related
Section titled “Related”- Error Analysis - track error flow instead of value flow
- Complexity Metrics - overall program complexity
- All Formats -
mermaid-dataflowformat reference