Skip to content

mberneti/ts-modularity

Repository files navigation

ts-modularity

Scan a TypeScript codebase, build a dependency graph, and serve an interactive visualization — all in one command.

npx ts-modularity

No install required. Opens a browser at http://localhost:3008.


Demo

Chord diagram

Force graph

Move suggestions


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 mv commands
  • 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 3008

Options

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> cluster
  • excludeOther: 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 mv command 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 / .tsx source files

License

MIT

About

A CLI tool that scans TypeScript projects and visualizes module boundaries as interactive diagrams.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors