Debugging

Use Inval's debug tools to trace invalidations and understand your graph.

Tracing with why()

When a node recomputes unexpectedly, use why() to trace the invalidation path back to the source.

debug-why.ts TYPESCRIPT
import { input, node, why } from '@blu3ph4ntom/inval'

const width = input(800)
const height = input(600)
const area = node({
  dependsOn: { w: width, h: height },
  compute: ({ w, h }) => w * h
})

width.set(1000)
why(area)  // ['area', 'width']

// The path tells you: area was invalidated because width changed

Inspecting Nodes

Use inspect() to see a node's current state, dirty flag, and connection count.

debug-inspect.ts TYPESCRIPT
const info = area.inspect()
// {
//   id: 'node_3',
//   name: 'area',
//   type: 'computed',
//   value: 600000,
//   dirty: false,
//   dependencyCount: 2,
//   dependentCount: 0
// }

Visualizing with toDot()

Export your graph as Graphviz DOT format and visualize it online.

debug-dot.ts TYPESCRIPT
import { input, node, toDot } from '@blu3ph4ntom/inval'

const a = input(1)
const b = input(2)
const c = node({ dependsOn: { a, b }, compute: ({ a, b }) => a + b })

console.log(toDot([c]))
// digraph G {
//   "a" -> "c"
//   "b" -> "c"
// }

// Paste output into graphviz.online to see the graph visually

Monitoring with stats()

Track graph size and compute calls to monitor performance.

debug-stats.ts TYPESCRIPT
import { stats } from '@blu3ph4ntom/inval'

const s = stats([root])
// {
//   nodeCount: 15,
//   inputCount: 5,
//   computedCount: 10,
//   edgeCount: 20,
//   totalComputeCalls: 42
// }

Tip

Call stats() before and after operations to measure how many computations were triggered. A well-designed graph minimizes totalComputeCalls.