ts-modularity
v0.1.0
Published
TypeScript dependency graph generator with interactive visualization
Downloads
227
Maintainers
Readme
ts-modularity
Scan a TypeScript codebase, build a dependency graph, and serve an interactive visualization — all in one command.
npx ts-modularityNo install required. Opens a browser at http://localhost:3008.
Features
- Five views — Chord diagram, Force graph, DAG layout, Coupling matrix, Move Suggestions
- Modularity score per cluster (0 = cohesive, 1 = coupled)
- Move suggestions — per-file refactor candidates with confidence rating and ready-to-run
git mvcommands - Bidirectional cycle detection highlighted in the matrix view
- tsconfig path aliases resolved automatically
- Optional config file to define explicit module boundaries
- Zero runtime dependencies
Usage
# Scan ./src, serve on port 3008
npx ts-modularity
# Custom source dir
npx ts-modularity --src ./packages/app/src
# Write files only, no server
npx ts-modularity --no-serve
# All options
npx ts-modularity --src ./src --out ./dep-graph-out --depth 1 --port 3008Options
| Flag | Default | Description |
|------|---------|-------------|
| --src <dir> | . | Directory to scan for .ts / .tsx files |
| --out <dir> | ./dep-graph-out | Output directory for graph.json and index.html |
| --depth <n> | 1 | Cluster grouping depth when no config file is present |
| --port <n> | 3008 | Preferred HTTP port (falls back to a random port if unavailable) |
| --no-serve | — | Write output files and exit without starting the server |
| --help | — | Print help |
Output files
| File | Description |
|------|-------------|
| dep-graph-out/graph.json | Raw graph data — clusters, edges, modularity metrics |
| dep-graph-out/index.html | Self-contained interactive visualization |
Config file
Create dep-graph.config.json in your project root to define explicit module boundaries.
{
"excludeOther": true,
"modularityThreshold": 0.4,
"modules": [
"src/api/*",
"src/app/*",
"src/services/*",
"src/store/*",
"src/utils/*",
"src/components"
]
}Module rule syntax
Rules are relative to the project root (where dep-graph.config.json lives), not --src.
| Pattern | Behavior |
|---------|----------|
| "src/api/*" | Each direct child of src/api/ becomes its own cluster (api/checkout, api/user, …) |
| "src/components" | Entire src/components/ is one cluster |
| "src/store/auth" | Exactly src/store/auth/ is one cluster |
| "packages/*" | Each package in a monorepo becomes its own cluster |
Rules are matched in order — first match wins. Files that match no rule:
excludeOther: false(default) — grouped into an<other>clusterexcludeOther: true— excluded from the graph entirely
Config fields
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| modules | string[] | [] | Module boundary rules (see syntax above) |
| excludeOther | boolean | false | Drop files that match no rule |
| modularityThreshold | number | 0.4 | Informational — clusters above this score are flagged |
Understanding the metrics
Modularity score measures how self-contained a cluster is:
modularity = internal_edges / (internal_edges + external_edges)| Score | Meaning |
|-------|---------|
| 1.0 | Fully modular — all dependencies are internal |
| 0.5 | Equal internal and external coupling |
| 0.0 | Fully coupled — no internal dependencies |
Color coding in the UI: green ≥ 0.67, amber ≥ 0.34, red < 0.34.
Views
Chord
Default view. Arcs represent clusters; ribbons show inter-cluster imports weighted by import count.
Force graph
Physics simulation. Node size scales with file count; the instability arc shows the modularity score. Drag nodes to explore.
DAG layout
Layered top-down layout grouped by modularity bucket. Orthogonal edge routing. Use the Sort dropdown to reorder by modularity, file count, in-deps, or name.
Coupling matrix
Heatmap where row A, column B = number of imports from cluster A into cluster B. Bidirectional cells (cycle risk) are highlighted in red.
Move suggestions
Lists files whose external coupling points strongly to a different cluster. Each suggestion includes:
- Source and destination cluster
- Confidence rating (
high/medium/low) based on affinity score - A
git mvcommand block you can copy and run directly
Adjust the threshold input and click Run to re-compute at any value. Files with score < 2 (too diffuse to have a dominant destination) are omitted.
Programmatic API
import { buildGraph, serve, computeSuggestions, loadModuleConfig, loadAliases } from 'ts-modularity';
const root = process.cwd();
const moduleConfig = loadModuleConfig(root); // reads dep-graph.config.json
const aliases = loadAliases(root); // reads tsconfig.json paths
const graph = buildGraph(root, './src', './out', 1, moduleConfig, aliases);
// graph.clusters — ClusterNode[]
// graph.files — FileNode[]
// graph.edges — Edge[]
// graph.clusterEdges — ClusterEdge[]
await serve(graph, 'src', 3008);
// Compute move suggestions programmatically
const result = computeSuggestions(graph, 0.4);
// result.badClusters — ClusterSuggestions[]
// result.gitMvCommands — string[] (ready to run)
console.log(result.gitMvCommands.join('\n'));Types
interface ClusterNode {
id: string;
label: string;
files: number;
outEdges: number;
inEdges: number;
internalEdges: number;
modularity: number; // 0–1
coupling: number;
cohesion: number;
}
interface FileNode {
id: string;
label: string;
path: string;
cluster: string;
imports: number;
importedBy: number;
}
interface MoveSuggestion {
file: string;
fromCluster: string;
fromLabel: string;
toCluster: string;
toLabel: string;
score: number;
affinity: number;
confidence: 'high' | 'medium' | 'low';
}
interface SuggestionsResult {
threshold: number;
badClusters: { cluster: ClusterNode; suggestions: MoveSuggestion[] }[];
gitMvCommands: string[];
}Full type definitions are exported from the package (dist/index.d.ts).
Requirements
- Node.js 18+
- TypeScript project with
.ts/.tsxsource files
License
MIT
