first commit
This commit is contained in:
90
docs/devtools/tooling/overview/src/graph/graph.md
Normal file
90
docs/devtools/tooling/overview/src/graph/graph.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# `graph/graph.ts`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Implements the graph utilities that operate on a `WorkspaceGraph` built from a
|
||||
list of `PackageRecord`s. Covers the analyses every project tool eventually
|
||||
needs: build a forward / reverse adjacency map, compute a topological
|
||||
dependency-first order, detect cycles, gather transitive deps or dependents,
|
||||
and identify graph roots (no deps) and leaves (no dependents).
|
||||
|
||||
Edges where the target is not also a node are silently dropped at build time.
|
||||
This is the same posture as `scripts/folder-reorg/generate-manifest.ts` —
|
||||
necessary because Suaveplan migrates in waves and partial-manifest
|
||||
snapshots are routine.
|
||||
|
||||
## Features
|
||||
|
||||
- `buildGraph` — populates forward and reverse adjacency in one pass; emits
|
||||
`overview.graph_builds_total`
|
||||
- `topologicalOrder` — Kahn's algorithm with stable lexicographic tie-breaking;
|
||||
throws `OVERVIEW.CYCLE_DETECTED` on a cycle (error carries `context.cycle`)
|
||||
- `detectCycles` — Tarjan's SCC, returns every cycle as a sorted `string[]`
|
||||
- `transitiveDependencies` / `transitiveDependents` — BFS over the appropriate
|
||||
direction; throws `OVERVIEW.UNKNOWN_PACKAGE` for missing inputs
|
||||
- `leafPackages` — no dependents (no incoming edges)
|
||||
- `rootPackages` — no deps (no outgoing edges)
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { buildGraph, topologicalOrder } from "@suaveplan/overview";
|
||||
|
||||
const graph = buildGraph(records);
|
||||
const order = topologicalOrder(graph);
|
||||
// `order[0]` has no workspace deps; the last entry depends on everything.
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
buildGraph,
|
||||
detectCycles,
|
||||
transitiveDependencies,
|
||||
transitiveDependents,
|
||||
leafPackages,
|
||||
rootPackages,
|
||||
} from "@suaveplan/overview";
|
||||
|
||||
const graph = buildGraph(records);
|
||||
const cycles = detectCycles(graph);
|
||||
if (cycles.length > 0) {
|
||||
console.error("Cycles detected:", cycles);
|
||||
}
|
||||
|
||||
const blastRadius = transitiveDependents(graph, "@suaveplan/error");
|
||||
const supplyChain = transitiveDependencies(graph, "@suaveplan/api");
|
||||
const leaves = leafPackages(graph);
|
||||
const roots = rootPackages(graph);
|
||||
```
|
||||
|
||||
`topologicalOrder` is deterministic — two callers with the same graph see the
|
||||
same order — so it can drive reproducible build plans and CI fan-outs.
|
||||
|
||||
## API Reference
|
||||
|
||||
- `buildGraph(records): WorkspaceGraph`
|
||||
- `topologicalOrder(graph): string[]` — throws `OVERVIEW.CYCLE_DETECTED`
|
||||
- `detectCycles(graph): string[][]`
|
||||
- `transitiveDependencies(graph, pkg): string[]` — throws
|
||||
`OVERVIEW.UNKNOWN_PACKAGE`
|
||||
- `transitiveDependents(graph, pkg): string[]` — throws
|
||||
`OVERVIEW.UNKNOWN_PACKAGE`
|
||||
- `leafPackages(graph): string[]`
|
||||
- `rootPackages(graph): string[]`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`topologicalOrder` initialises a remaining-out-degree counter per node and
|
||||
drains nodes with zero out-degree first; the queue is kept sorted on insertion
|
||||
so the output is stable across runs. `detectCycles` uses a recursive
|
||||
Tarjan implementation — the workspace size is bounded (hundreds of packages),
|
||||
so the stack-depth budget is comfortable. BFS in `transitiveDependencies` /
|
||||
`transitiveDependents` uses an array-based queue with `Array.prototype.shift`
|
||||
— acceptable at workspace scale; if the package ever has to handle tens of
|
||||
thousands of nodes the queue can be swapped for a head/tail index pair.
|
||||
Reference in New Issue
Block a user