# flamegraph _(no submodules)_ ## Purpose `FlameGraphGenerator` builds a flame-graph data structure from `ProfileEntry` arrays by nesting entries on start/end-time containment. The output is a `FlameNode` tree compatible with `d3-flame-graph` and similar visualisers; SVG/HTML rendering is intentionally out of scope (a downstream concern), but `toD3Format` produces the exact JSON shape these libraries expect. ## Features - Pure containment algorithm: an entry whose `[startTime, endTime]` interval is fully inside another's becomes a child of it. - Tie-breaking on equal start times: wider spans first so they own the narrower children. - Self-time computation: `selfTime = value - sum(children.value)`, never negative. - `collapseRecursive(node)` merges consecutive same-name parent/child pairs, useful for cleaning up tail-recursive call patterns before rendering. - `toD3Format(node)` strips internal fields (`selfTime`, `startTime`, `endTime`) so the JSON is exactly `{ name, value, children }`. ## Usage: Basic ```ts import { FlameGraphGenerator } from "@suaveplan/profiler"; const gen = new FlameGraphGenerator(); const tree = gen.generate(profiler.getEntries()); const d3Json = gen.toD3Format(tree); ``` ## Usage: Advanced ```ts import { FlameGraphGenerator } from "@suaveplan/profiler"; const gen = new FlameGraphGenerator(); const rawTree = gen.generate(entries); const collapsed = gen.collapseRecursive(rawTree); // rawTree shows the full recursion stack; collapsed flattens // `parser → parser → parser → leaf` into `parser → leaf`. const json = gen.toD3Format(collapsed); await writeFile("flame.json", JSON.stringify(json)); ``` ## API Reference - `class FlameGraphGenerator` — no constructor args (stateless). - Methods: - `generate(entries: readonly ProfileEntry[]): FlameNode` - `toD3Format(node: FlameNode): { name, value, children }` - `collapseRecursive(node: FlameNode): FlameNode` ## Implementation Notes The internal `MutableFlameNode` carries `startTime`/`endTime` for the duration of tree construction so containment checks remain O(1) per node-pair; the final `freeze` step drops these fields and returns the immutable `FlameNode` shape. When a new entry is inserted, the algorithm first checks for a containing existing child (recursing into it) and otherwise creates a new node, absorbing any existing siblings the new entry contains. This handles arbitrary insertion order — the input is sorted by start-time ascending, ties broken by wider span first, before insertion starts.