Pipeline overview

How nestjs-doctor works from CLI invocation to final output.

Flow

Directory map

DirectoryResponsibility
src/cli/CLI flags, entry point, output formatters, and the scan worker entry
src/engine/Config loading, project detection, file collection, AST parsing, module graph, provider resolution, rule execution, diagnostic filtering, scoring
src/engine/rules/definitions/All 52 rules organized by category (security/, correctness/, architecture/, performance/, schema/)
src/report/HTML report generation (interactive dashboard, module graph, schema ER diagram)
src/common/Shared type definitions (Diagnostic, Config, Result, errors)

Stages

The pipeline has 10 stages. In a monorepo, stages 1-9 run once per sub-project.

#StageSourceScope
1Config loadingsrc/engine/config/loader.tsRoot, then per project
2Project detectionsrc/engine/project-detector.tsPer project
3File collectionsrc/engine/file-collector.tsPer project
4AST parsingsrc/engine/graph/ast-parser.tsPer project
5Module graph buildingsrc/engine/graph/module-graph.tsPer project
6Provider resolutionsrc/engine/graph/type-resolver.tsPer project
7Rule executionsrc/engine/rule-runner.tsPer project
8Diagnostic filteringsrc/engine/filter-diagnostics.tsPer project
9Scoringsrc/engine/scorer/index.tsPer project + combined
10Outputsrc/cli/formatters/Once

Orchestrator

The autoScan() and scanMonorepo() functions in src/engine/scanner.ts wire these stages together. The CLI calls one of these, and the Node.js API (diagnose(), diagnoseMonorepo()) wraps them with path validation.

Parallel execution

Stages that do not depend on each other run concurrently:

  • Single-project mode: config loading and custom rule resolution run first. Project detection and file collection then run together via Promise.all. The remaining stages run in order, from AST parsing through scoring.
  • Monorepo mode: file collection for every sub-project runs in parallel via Promise.all. The sub-projects themselves are then built one at a time. Each context is dropped before the next one is built, so peak memory stays close to a single project.

Where the scan runs

An interactive terminal run executes the engine middle in a worker thread, so the spinner and progress bar keep painting while rules run. CI, every machine-readable format, and --score scans run in process. If the worker cannot start or fails mid-scan, the scan reruns in process and a warning goes to stderr.