npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

bluebird-nestjs

v0.1.22

Published

Diagnose and improve NestJS project health

Readme

Bluebird

Static analysis CLI for NestJS projects

npm version Build Status codecov TypeScript Node

Stability

Bluebird is production-ready for NestJS static analysis. The project maintains:

  • 944+ tests with comprehensive coverage across 23 test files
  • 95%+ line coverage (statements, branches, functions)
  • Semantic versioning for predictable upgrades
  • CI/CD integration with SARIF output for code scanning
  • Active maintenance with regular security updates

The API surface (diagnose, runEslint, analyseFiles, formatters) is stable. Breaking changes will only occur in major version bumps with migration guides.

Bluebird is a static analysis CLI for NestJS projects. It parses TypeScript source files, runs 38 purpose-built rules across architecture, security, performance, correctness, and API design, and produces a health score useful both locally and in CI.

Why Bluebird?

NestJS projects can accumulate technical debt silently. Bluebird catches issues that generic linters miss:

  • Security issues — Hardcoded secrets, SQL injection, missing validation pipes
  • Architectural problems — Circular dependencies, god controllers/services, DI bypasses
  • Performance blockers — Sync filesystem operations, blocking crypto, N+1 queries
  • Common mistakes — Missing decorators, lifecycle hook interfaces, duplicate routes
  • API design flaws — Missing Swagger docs, entities exposed directly, inconsistent HTTP status

Unlike generic linters, Bluebird understands NestJS patterns, decorators, and module structure.

Installation

From npm (recommended)

# Install globally
npm install -g bluebird-nestjs
bluebird --help

# Or add to your project
npm install --save-dev bluebird-nestjs
npx bluebird

From source

# Clone and install
git clone https://github.com/endpointclosing/bluebird.git
cd bluebird
pnpm install
pnpm build

# Link the CLI globally (run from packages/bluebird directory)
cd packages/bluebird
npm link

# Now you can use bluebird globally from any directory
cd /path/to/your-nestjs-project
bluebird --help

Troubleshooting Installation

If you encounter issues:

  1. "husky: command not found" - This is safe to ignore. The prepare script handles this gracefully.

  2. "bluebird: command not found" after npm link:

    # Make sure you're in the packages/bluebird directory
    cd /path/to/bluebird/packages/bluebird
    npm link
    
    # Verify the link was created
    npm list -g bluebird-nestjs
  3. Permission errors on macOS/Linux:

    sudo npm link
  4. Still not working? Check that the build completed:

    ls packages/bluebird/dist/cli.js  # Should exist

Getting Started in 60 Seconds

# 1. Install globally
npm install -g bluebird-nestjs

# 2. Run analysis on your NestJS project
cd /path/to/your-nestjs-project
bluebird

# 3. Generate a config file (optional)
bluebird init

# 4. Create a baseline for existing issues (optional)
bluebird --baseline

That's it! Bluebird auto-detects your NestJS setup and runs 38 purpose-built rules.

Quick Start

# Run against a NestJS project
bluebird

# Watch mode — re-run on file changes
bluebird --watch

# Fast mode — run passes in parallel
bluebird --fast

# Diff mode — only check changed files
bluebird --diff main

# Output formats for different use cases
bluebird --format text   # Terminal (default)
bluebird --format json   # CI/CD integration
bluebird --format sarif  # GitHub Code Scanning
bluebird --format html   # Shareable dashboard

# Include heuristic (opt-in) rules
bluebird --include-heuristic

# Get detailed info about a specific rule
bluebird explain no-hardcoded-secrets

# List all available rules
bluebird explain --list

Example Output

✔ Project detected  NestJS 10.3.0 · express · 235 files · swagger, config
✔ Lint analysis      0.4s  (30 diagnostics)
✔ Graph analysis     0.1s  (0 diagnostics)
✔ Dead code analysis 1.2s  (15 diagnostics)

    __
 __( o>  Bluebird
(___/   NestJS Health Report

┌──────────────────────────────────────────────┐
│  Score: 89/100  ██████████████████░░  Great  │
└──────────────────────────────────────────────┘

  2 errors · 43 warnings

  By Category:
    Security      ⚠ 5
    Correctness   ⚠ 12
    Architecture  ✖ 2  ⚠ 3
    API Design    ⚠ 8
    Dead Code     ⚠ 15

  Top Issues:
    ✖ bluebird/no-hardcoded-dependency    (2)   Inject via constructor
    ⚠ bluebird/missing-swagger-decorators (8)   Add @ApiOperation/@ApiResponse
    ⚠ bluebird/no-console-log             (7)   Use NestJS Logger service
    ⚠ knip/exports                        (10)  Unused export
    ⚠ bluebird/no-process-env-direct      (5)   Use ConfigService.get()

  Run with --verbose to see all 45 diagnostics

Logic Flow

flowchart LR
  A["CLI (`bluebird` command)"] --> B["Parse Flags (`verbose`, `diff`, `format`, pass toggles)"]
  B --> C["Scan Orchestrator (`scan.ts`)"]
  C --> D["Load Config + Merge with CLI Options"]
  D --> E["Discover Project (`discover-project.ts`)"]
  E --> F["Build `ProjectInfo` (adapter, ORM, features, strict mode, tests)"]
  F --> G["Resolve Enabled Rules (`getEnabledRules`)"]
  G --> H["Run File-Level Checkers (`fileCheckers`)"]
  G --> I["Run Graph-Level Checkers (`graphCheckers`)"]
  G --> J["Run Dead-Code Pass (`knip`)"]
  H --> K["Collect Diagnostics"]
  I --> K
  J --> K
  K --> L["Apply Ignore/Waiver Filtering"]
  L --> L2["Apply Baseline Filtering"]
  L2 --> M["Calculate Score (`calculate-score.ts`)"]
  M --> N["Format Output (`text` | `json` | `sarif` | `html`)"]
  N --> O["Print CLI Summary + Exit Code"]

CLI Options

| Flag | Description | |:---|:---| | -v, --verbose | Show all diagnostics | | -q, --quiet | Suppress output, only set exit code | | -p, --project <path> | Path to the NestJS project (default: cwd) | | -w, --watch | Watch mode: re-run analysis on file changes | | -s, --score | Output only the numeric health score | | --diff <branch> | Only check files changed from branch | | --format <fmt> | Output format: text, json, sarif, html (default: text) | | --fail-on <threshold> | Exit-code threshold: error, warning, none (default: error) | | --fail-on-score <score> | Exit with code 1 when score is below this value (0–100) | | --no-lint | Skip the lint (file-level) analysis pass | | --no-dead-code | Skip the dead code analysis pass | | --no-graph-analysis | Skip the graph (cross-file) analysis pass | | --include-heuristic | Include heuristic-confidence rules | | --baseline | Generate a baseline snapshot of current diagnostics | | --update-baseline | Update the baseline snapshot after fixes | | --fast | Run analysis passes in parallel for faster execution | | -o, --open | Open HTML report in browser (use with --format html) |

Initialize Configuration

Generate a bluebird.config.json config file interactively:

bluebird init

The init wizard prompts for:

  • Rules to ignore globally
  • File patterns to exclude
  • Whether to enable heuristic rules

Non-Interactive Mode

For CI/CD or scripted setups, use the --yes flag:

# Accept all defaults
bluebird init --yes

# Customize options
bluebird init --yes --heuristic --skip-graph

# Ignore specific rules
bluebird init --yes --ignore-rules "bluebird/no-god-service,bluebird/no-console-log"

# Ignore file patterns
bluebird init --yes --ignore-files "src/legacy/**,src/generated/**"

Explain Rules

Get detailed information about any rule:

# Explain a specific rule
bluebird explain no-hardcoded-secrets

# List all available rules
bluebird explain --list

# Filter rules by category
bluebird explain --category security

The explain command shows:

  • Rule description and severity
  • How to fix the issue
  • How to ignore or waive the rule

Baseline

Baseline lets you adopt Bluebird on an existing codebase without drowning in legacy diagnostics. It captures a snapshot of current issues so subsequent runs only report new violations.

# Create a baseline from the current state
bluebird --baseline

# After fixing some issues, update the baseline
bluebird --update-baseline

The baseline is stored in .bluebird-baseline.json and can be committed to version control. Diagnostics matching the baseline (same rule, file, and line) are excluded from the output and score. New violations introduced after the baseline are always surfaced.

Baseline Workflow

A typical workflow for adopting Bluebird on an existing codebase:

  1. Create initial baseline to snapshot existing issues:

    bluebird --baseline
    git add .bluebird-baseline.json
    git commit -m "chore: add bluebird baseline"
  2. Run in CI — only new violations will fail the build:

    bluebird --fail-on error
  3. Fix issues incrementally and update baseline:

    # After fixing some issues
    bluebird --update-baseline
    git add .bluebird-baseline.json
    git commit -m "chore: update bluebird baseline after fixes"
  4. Prevent new debt — CI catches any new violations not in the baseline

Watch Mode

Watch mode monitors your source files and automatically re-runs analysis when changes are detected. Perfect for development workflows.

# Start watch mode
bluebird --watch

# Or use the short flag
bluebird -w

# Combine with other options
bluebird --watch --include-heuristic

Watch mode features:

  • Debounced re-runs — Waits 500ms after the last change before re-running
  • File change detection — Monitors .ts and .tsx files
  • Automatic ignore — Skips node_modules, dist, build, .git, and coverage
  • Graceful shutdown — Press Ctrl+C to exit

HTML Reports

Generate standalone HTML dashboards for sharing analysis results with your team.

# Generate and open HTML report in browser (recommended)
bluebird --format html --open

# Or save to a specific file
bluebird --format html > report.html

The HTML report includes:

  • Score gauge — Circular progress indicator with color-coded score
  • Project details — NestJS version, adapter, ORM, file count, features
  • Category chart — Horizontal bar chart showing issues by category
  • Top issues table — Most frequent rules with fix suggestions
  • All diagnostics — Collapsible sections with full file paths and messages
  • Dark theme — Modern UI that looks great when shared
  • Self-contained — Single HTML file with inline CSS, no external dependencies

CI/CD Integration

Bluebird integrates easily into CI/CD pipelines. Use --format sarif for GitHub Code Scanning, --format json for custom integrations, or --format html for artifact reports.

GitHub Actions

name: Bluebird Analysis

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

jobs:
  bluebird:
    runs-on: ubuntu-latest
    permissions:
      security-events: write  # Required for SARIF upload
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci

      - name: Install Bluebird
        run: npm install -g bluebird-nestjs

      - name: Run Bluebird
        run: bluebird --format sarif > bluebird.sarif
        continue-on-error: true

      - name: Upload SARIF
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: bluebird.sarif

GitLab CI

bluebird:
  stage: test
  image: node:20-alpine
  script:
    - npm ci
    - npm install -g bluebird-nestjs
    - bluebird --format json > bluebird.json
    - bluebird --fail-on error
  artifacts:
    reports:
      codequality: bluebird.json
    paths:
      - bluebird.json
    when: always

Generic SARIF Workflow

For other CI systems that support SARIF:

# Generate SARIF report
bluebird --format sarif > bluebird.sarif

# Fail on errors (exit code 1 if errors found)
bluebird --fail-on error

# Fail if score drops below threshold
bluebird --fail-on-score 80

Diff Mode for PRs

Run analysis only on changed files for faster PR checks:

# Compare against main branch
bluebird --diff main

# Compare against specific commit
bluebird --diff HEAD~1

Rules

Bluebird ships 38 rules split into two confidence tiers:

  • Deterministic (25 rules) — statically provable, always enabled
  • Heuristic (13 rules) — context-dependent, opt-in via --include-heuristic

Rules run in one of three analysis passes:

| Pass | Scope | Description | |:---|:---|:---| | eslint | Single file | AST-based checks on each .ts file | | graph | Cross-file | Whole-project analysis (module graph, route map) | | knip | Cross-file | Dead-code detection (unused files, exports, types, duplicates) |

Architecture (4 rules)

| Rule | Severity | Confidence | Description | |:---|:---|:---|:---| | no-circular-dependency | error | deterministic | Circular module imports detected | | no-god-controller | warning | deterministic | Controller exceeds route threshold | | no-god-service | warning | deterministic | Service exceeds line threshold | | no-hardcoded-dependency | error | deterministic | Direct instantiation instead of DI |

Security (5 deterministic + 4 heuristic)

| Rule | Severity | Confidence | Description | |:---|:---|:---|:---| | missing-class-validator | warning | deterministic | DTO property without validation decorators | | missing-csrf-protection | warning | heuristic | No CSRF middleware configured | | missing-global-guard | warning | heuristic | No global auth guard | | missing-helmet | warning | heuristic | No helmet middleware | | missing-rate-limiting | warning | heuristic | No throttling configured | | missing-validation-pipe | warning | deterministic | No global ValidationPipe configured | | no-any-in-dto | warning | deterministic | DTO property typed as any | | no-hardcoded-secrets | error | deterministic | Hardcoded credentials in source | | no-raw-sql | error | deterministic | SQL template without parameterization |

Correctness (8 deterministic + 2 heuristic)

| Rule | Severity | Confidence | Description | |:---|:---|:---|:---| | lifecycle-hook-interface | warning | deterministic | Lifecycle method without interface | | missing-config-validation | warning | heuristic | ConfigModule without validation schema | | missing-exception-filter | warning | heuristic | No global exception filter | | missing-injectable | error | deterministic | Provider class missing @Injectable() | | missing-parse-pipe | warning | deterministic | Route param without parsing pipe | | no-console-log | warning | deterministic | Direct console usage instead of Logger | | no-constructor-side-effects | warning | deterministic | Side effects in constructor | | no-duplicate-route | error | deterministic | Duplicate HTTP method + path | | no-nested-controller-decorator | error | deterministic | @Controller() on non-top-level class | | no-process-env-direct | warning | deterministic | Direct process.env instead of ConfigService |

API Design (3 deterministic + 2 heuristic)

| Rule | Severity | Confidence | Description | |:---|:---|:---|:---| | missing-swagger-decorators | warning | deterministic | Missing @ApiOperation/@ApiResponse | | no-entity-as-response | warning | deterministic | ORM entity returned directly | | no-generic-exception | warning | deterministic | Throwing Error instead of HttpException | | no-inconsistent-http-status | warning | heuristic | HTTP status doesn't match method | | prefer-pagination | warning | heuristic | List endpoint without pagination |

Performance (2 deterministic + 2 heuristic)

| Rule | Severity | Confidence | Description | |:---|:---|:---|:---| | missing-caching | warning | heuristic | No caching strategy detected | | no-blocking-crypto | warning | deterministic | Blocking crypto operations | | no-n-plus-one | warning | heuristic | Potential N+1 query pattern | | no-sync-fs-operations | warning | deterministic | Sync fs operations block event loop |

Database (2 heuristic)

| Rule | Severity | Confidence | Description | |:---|:---|:---|:---| | missing-indexes | warning | heuristic | Query patterns without indexes | | missing-migration | warning | heuristic | Schema changes without migrations |

Testing (1 heuristic)

| Rule | Severity | Confidence | Description | |:---|:---|:---|:---| | low-test-coverage | warning | heuristic | Missing spec files for providers |

GraphQL (1 deterministic, feature-gated)

| Rule | Severity | Confidence | Description | |:---|:---|:---|:---| | missing-resolver-decorator | warning | deterministic | Resolver method without @Query/@Mutation |

Microservices (1 deterministic, feature-gated)

| Rule | Severity | Confidence | Description | |:---|:---|:---|:---| | missing-message-pattern | warning | deterministic | Handler without @MessagePattern/@EventPattern |

WebSockets (1 deterministic, feature-gated)

| Rule | Severity | Confidence | Description | |:---|:---|:---|:---| | missing-websocket-decorator | warning | deterministic | Gateway method without @SubscribeMessage |

Note: Feature-gated rules only run when Bluebird detects the corresponding feature in your project (e.g., @nestjs/graphql, @nestjs/microservices, @nestjs/websockets).

Rule Examples

// ❌ Bad - Hardcoded secret
@Injectable()
export class AuthService {
  private readonly jwtSecret = 'super-secret-key-123';
}

// ✅ Good - Use environment variables
@Injectable()
export class AuthService {
  constructor(private config: ConfigService) {}

  private get jwtSecret() {
    return this.config.get<string>('JWT_SECRET');
  }
}
// ❌ Bad - Missing @Injectable()
export class UserRepository {
  findAll() { /* ... */ }
}

// ✅ Good - Has @Injectable()
@Injectable()
export class UserRepository {
  findAll() { /* ... */ }
}
// ❌ Bad - Direct instantiation bypasses DI
@Injectable()
export class OrderService {
  private logger = new Logger(); // Creates tight coupling

  process() {
    this.logger.log('Processing...');
  }
}

// ✅ Good - Inject dependencies
@Injectable()
export class OrderService {
  constructor(private readonly logger: Logger) {}

  process() {
    this.logger.log('Processing...');
  }
}
// ❌ Bad - No input validation
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}

// ✅ Good - Global ValidationPipe enabled
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe({
    whitelist: true,
    forbidNonWhitelisted: true,
    transform: true,
  }));
  await app.listen(3000);
}
// ❌ Bad - SQL injection risk
async findByEmail(email: string) {
  return this.db.query(`SELECT * FROM users WHERE email = '${email}'`);
}

// ✅ Good - Parameterized query
async findByEmail(email: string) {
  return this.db.query('SELECT * FROM users WHERE email = $1', [email]);
}
// ❌ Bad - Missing interface
@Injectable()
export class StartupService {
  onModuleInit() {
    console.log('Starting...');
  }
}

// ✅ Good - Implements interface
@Injectable()
export class StartupService implements OnModuleInit {
  onModuleInit() {
    console.log('Starting...');
  }
}

Scoring

Each diagnostic carries a severity-based penalty. The health score starts at 100 and decreases per unique rule violation (capped at 10 instances per rule):

| Severity | Base penalty | Per-instance penalty | |:---|:---|:---| | error | 1.5 | 0.15 | | warning | 0.75 | 0.08 |

Score Interpretation

| Range | Label | Meaning | |:---|:---|:---| | 90–100 | Excellent | Production-ready, minimal issues | | 75–89 | Great | Good health, minor improvements needed | | 50–74 | Needs work | Significant issues requiring attention | | 0–49 | Critical | Major problems blocking production readiness |

What Each Range Means

90–100 (Excellent): Your codebase follows NestJS best practices. No security vulnerabilities, clean architecture, proper DI patterns. Ready for production deployment.

75–89 (Great): Generally healthy with some minor issues. Might have a few warnings about missing Swagger decorators, console.log usage, or optional optimizations. Safe for production but could benefit from cleanup.

50–74 (Needs Work): Has notable issues that should be addressed. May include security warnings, architectural concerns (god controllers/services), or missing validation. Prioritize fixing errors before deploying.

0–49 (Critical): Serious problems detected. Likely includes hardcoded secrets, SQL injection risks, circular dependencies, or severe architectural issues. Address these before deploying to production.

Improving Your Score

  1. Fix errors first — they have higher penalties and often indicate security or correctness issues
  2. Use baseline to track progress on existing codebases
  3. Enable heuristic rules (--include-heuristic) for additional insights
  4. Use waivers sparingly for intentional deviations with documented reasons

Configuration

Bluebird loads configuration from the first source found:

  1. bluebird.config.json in the project root
  2. A "bluebird" key inside package.json

If neither exists, all defaults apply. CLI flags always take precedence over config file values.

{
  "ignore": {
    "rules": ["bluebird/no-god-service"],
    "files": ["src/legacy/**"]
  },
  "lint": true,
  "deadCode": true,
  "graphAnalysis": true,
  "includeHeuristic": false,
  "diff": "main",
  "waivers": [
    {
      "rule": "bluebird/no-inconsistent-http-status",
      "file": "src/controllers/legacy.controller.ts",
      "reason": "Legacy API intentionally returns 200 from DELETE"
    }
  ]
}

| Key | Type | Default | Description | |:---|:---|:---|:---| | ignore.rules | string[] | [] | Rule IDs to suppress globally | | ignore.files | string[] | [] | Glob patterns for files to skip | | lint | boolean | true | Enable the ESLint (file-level) pass | | deadCode | boolean | true | Enable the dead-code (knip) pass | | graphAnalysis | boolean | true | Enable the graph (cross-file) pass | | includeHeuristic | boolean | false | Include heuristic-confidence rules | | diff | string | — | Only check files changed from this branch | | waivers | Waiver[] | [] | Per-file rule exemptions with required reason |

JSON Schema

For IDE autocomplete and validation, reference the JSON schema in your config:

{
  "$schema": "https://raw.githubusercontent.com/endpointclosing/bluebird/main/packages/bluebird/bluebird.schema.json",
  "ignore": {
    "rules": ["bluebird/no-god-service"]
  }
}

The schema provides:

  • Autocomplete for all configuration options
  • Validation of rule IDs and waiver structure
  • Documentation on hover in VS Code and other editors

Inline Disable Comments

Suppress diagnostics directly in source code using comments:

// Disable a specific rule for the next line
// bluebird-disable-next-line no-hardcoded-secrets
const API_KEY = 'test-key-for-demo';

// Disable all rules for a block
// bluebird-disable
const legacyCode = doSomethingUnsafe();
// bluebird-enable

// Disable specific rules for a block
// bluebird-disable no-raw-sql, no-sync-fs-operations
await db.query(rawQuery);
fs.readFileSync(configPath);
// bluebird-enable

Supported comment formats:

  • bluebird-disable-next-line [rule1, rule2, ...] — suppress on the following line
  • bluebird-disable [rule1, rule2, ...] — start suppression block
  • bluebird-enable — end suppression block

Project Detection

Bluebird auto-detects project characteristics from package.json and source files:

  • NestJS version and HTTP adapter (Express / Fastify)
  • ORM (TypeORM, Prisma, Mongoose, Sequelize, MikroORM, Drizzle)
  • Features: GraphQL, WebSockets, Microservices, CQRS, Swagger, Bull, Config, Throttler, Cache
  • TypeScript strictness and test presence

Rules that depend on specific features (e.g. missing-swagger-decorators requires @nestjs/swagger) are automatically disabled when the feature is not detected.

strictTypeScript detection resolves tsconfig.json with extends support and reports the merged strict setting.

Programmatic API

import { diagnose } from "bluebird-nestjs";

const result = await diagnose({ format: "json", includeHeuristic: true });
// result.diagnostics — array of Diagnostic objects
// result.score       — { score: number, label: string }
// result.project     — detected ProjectInfo

ESLint Runner

The file-level analysis pass can be invoked directly via runEslint (filesystem-based) or analyseFiles (in-memory, no disk I/O). Both return a LintResult containing diagnostics and runner warnings:

import { runEslint, analyseFiles } from "bluebird-nestjs";
import type { LintResult } from "bluebird-nestjs";

// Filesystem — discovers .ts/.mts/.cts files, skips node_modules/dist/declarations
const { diagnostics, warnings } = await runEslint({ cwd: "/path/to/project", project });

// In-memory — pass a Map<relativePath, sourceText>
const files = new Map([["src/app.ts", sourceCode]]);
const { diagnostics, warnings } = analyseFiles(files, project);

// Warnings surface I/O failures and parse errors instead of silently ignoring them
for (const w of warnings) {
  console.warn(`[${w.type}] ${w.filePath}: ${w.message}`);
}

Graph Runner

The cross-file analysis pass can be invoked directly via runGraphAnalysis (filesystem-based) or analyseGraph (in-memory, no disk I/O). Both return a GraphAnalysisResult containing diagnostics and runner warnings:

import { runGraphAnalysis, analyseGraph } from "bluebird-nestjs";
import type { GraphAnalysisResult } from "bluebird-nestjs";

// Filesystem — discovers .ts/.mts/.cts files, skips node_modules/dist/declarations
const { diagnostics, warnings } = await runGraphAnalysis({ cwd: "/path/to/project", project });

// In-memory — pass a Map<relativePath, sourceText>
const files = new Map([["src/app.module.ts", moduleSource]]);
const { diagnostics, warnings } = analyseGraph(files, project);

Graph-level checkers receive the complete set of parsed source files, enabling cross-file analysis such as circular module dependency detection (no-circular-dependency) and duplicate route detection across controllers (no-duplicate-route).

Dead Code Runner

The dead-code analysis pass can be invoked directly via runKnip. It wraps knip to detect unused files, exports, types, and duplicate exports:

import { runKnip } from "bluebird-nestjs";
import type { KnipResult } from "bluebird-nestjs";

const { diagnostics, warnings } = await runKnip({ cwd: "/path/to/project" });

// Each diagnostic has category: 'dead-code' and a rule like knip/files, knip/exports, etc.
for (const d of diagnostics) {
  console.log(`[${d.rule}] ${d.filePath}: ${d.message}`);
}

The runner automatically detects monorepo setups (pnpm workspaces, Lerna, Nx, Rush) and scopes analysis to the correct workspace. It skips analysis gracefully when node_modules is not present and retries on plugin config-loading errors.

NestJS-Aware Entry Points

Bluebird automatically configures Knip with NestJS-aware entry patterns to reduce false positives:

  • NestJS bootstrap: main.ts, src/main.ts (application entry point, never imported)
  • OpenTelemetry instrumentation: instrumentation.ts (imported by main.ts before NestJS starts)
  • TypeORM CLI files: data-source.ts, ormconfig.ts (referenced by CLI, not imported)
  • Migration runners: run-migrations.ts, run-migration.ts (standalone entry points)
  • Seeder scripts: seed.ts, seeder.ts (standalone entry points)
  • TypeORM entities: **/entity/*.ts, **/entities/*.ts (loaded via glob patterns at runtime)
  • TypeORM migrations: **/migration/*.ts, **/migrations/*.ts (loaded via glob patterns)
  • TypeORM subscribers: **/subscriber/*.ts, **/subscribers/*.ts (loaded via glob patterns)
  • Integration/E2E tests: test/integration/**/*.ts, test/e2e/**/*.ts (test entry points)

These patterns prevent false "unused file" warnings for files that are consumed by TypeORM's runtime glob-based loading, referenced in package.json scripts, or serve as application/test entry points rather than being statically imported.

The conversion layer is also exported for direct use:

import { convertKnipIssues, findMonorepoRoot } from "bluebird-nestjs";

Output Formatters

Four output formatters are exported for programmatic use. Each accepts a ScanResult and returns a formatted string:

import { formatText, formatJson, formatSarif, formatHtml } from "bluebird-nestjs";
import type { JsonOutput } from "bluebird-nestjs";

const result = await diagnose();

// Terminal-friendly output with ANSI colors, score gauge, and grouped diagnostics
const text = formatText(result, /* verbose */ false);

// Structured JSON with score, counts, project metadata, and full diagnostics
const json = formatJson(result);
const parsed: JsonOutput = JSON.parse(json);

// SARIF 2.1.0 for CI integrations (GitHub Code Scanning, Azure DevOps, etc.)
const sarif = formatSarif(result);

// Standalone HTML dashboard with charts and collapsible diagnostics
const html = formatHtml(result);

The text formatter shows a category summary, top issues, and optional detailed diagnostics (with --verbose). The json formatter includes top-level errorCount/warningCount/baselinedCount fields for easy consumption. The sarif formatter produces a spec-compliant SARIF 2.1.0 log with deduplicated rule entries, physical locations, and score metadata in run properties. The html formatter generates a self-contained HTML dashboard with dark theme, score gauge, category charts, and collapsible diagnostic details.

Exported Types

import type {
  Diagnostic,
  ScanResult,
  ProjectInfo,
  RuleMeta,
  RuleCategory,
  Severity,
  RuleConfidence,
  BluebirdConfig,
  Waiver,
  RunEslintOptions,
  RunnerWarning,
  LintResult,
  RunGraphAnalysisOptions,
  GraphAnalysisResult,
  JsonOutput,
} from "bluebird-nestjs";

Registry Helpers

import {
  getAllRules,
  getEnabledRules,
  getRuleById,
  getRulesByCategory,
  getRulesByConfidence,
} from "bluebird-nestjs";

// Get all 38 rules
const allRules = getAllRules();

// Get rules enabled for a specific project
const enabledRules = getEnabledRules(project, /* includeHeuristic */ true);

// Look up a specific rule
const rule = getRuleById("no-hardcoded-secrets");

// Filter by category or confidence
const securityRules = getRulesByCategory("security");
const deterministicRules = getRulesByConfidence("deterministic");

Troubleshooting

"Cannot find module" errors

Ensure you've installed dependencies in your project:

npm install

Rules not detecting my NestJS features

Bluebird auto-detects features from package.json. Ensure your NestJS-related dependencies are listed:

{
  "dependencies": {
    "@nestjs/swagger": "^7.0.0",
    "@nestjs/graphql": "^12.0.0"
  }
}

Score seems too low

Use --verbose to see all violations and identify patterns:

bluebird --verbose

Common causes of low scores:

  • Missing @Injectable() decorators on services
  • Direct process.env access instead of ConfigService
  • Missing validation decorators on DTOs
  • Console.log instead of NestJS Logger

Baseline not filtering old violations

Ensure the baseline file exists and matches the current file paths:

# Regenerate baseline if file paths changed
bluebird --baseline

Feature-gated rules not running

Feature-gated rules (GraphQL, Microservices, WebSockets) only run when the corresponding package is detected. Check that your package.json includes the relevant @nestjs/* package.

Too many false positives

Consider using waivers for intentional deviations:

{
  "waivers": [
    {
      "rule": "bluebird/no-console-log",
      "file": "src/main.ts",
      "reason": "Console logging needed during bootstrap"
    }
  ]
}

Config files flagged as "unused"

Bluebird automatically ignores common configuration files (eslint.config.js, jest.config.ts, etc.). If you have custom config files being flagged, add them to ignore.files:

{
  "ignore": {
    "files": ["my-custom-config.js"]
  }
}

TypeORM entities/migrations flagged as "unused"

Bluebird automatically recognizes TypeORM's glob-based loading patterns (**/entity/*.ts, **/migrations/*.ts, etc.) and marks these as entry points. If you have entities in non-standard directories, add them to your knip config or use waivers:

{
  "ignore": {
    "files": ["src/custom-entities/**"]
  }
}

data-source.ts or run-migrations.ts flagged as "unused"

These files are CLI entry points referenced in package.json scripts, not imported by other code. Bluebird v0.1.12+ automatically recognizes these patterns. If you're on an older version, upgrade:

npm install -g bluebird-nestjs@latest

Analysis is slow on large projects

Try these optimizations:

# Run passes in parallel for ~8% faster execution
bluebird --fast

# Skip dead-code analysis (fastest improvement)
bluebird --no-dead-code

# Only check changed files
bluebird --diff main

# Skip graph analysis for single-file checks only
bluebird --no-graph-analysis

How do I understand a specific rule?

Use the explain command:

bluebird explain no-hardcoded-secrets

This shows the rule's purpose, severity, and how to fix violations.

How do I adopt Bluebird on an existing project?

Use the baseline workflow to avoid being overwhelmed by legacy issues:

# 1. Create baseline of existing issues
bluebird --baseline
git add .bluebird-baseline.json
git commit -m "chore: add bluebird baseline"

# 2. Run in CI - only new issues will fail
bluebird --fail-on error

# 3. Fix issues over time and update baseline
bluebird --update-baseline

How do I run Bluebird in CI without prompts?

Use the --yes flag with init, and standard flags for analysis:

# Non-interactive config generation
bluebird init --yes

# Quiet mode for CI (exit code only)
bluebird --quiet

# JSON output for parsing
bluebird --format json

ESLint Plugin

Bluebird includes an ESLint plugin for real-time feedback in your IDE. This surfaces Bluebird rules as you type, without running the full CLI.

Installation

The plugin is bundled with Bluebird:

npm install --save-dev bluebird-nestjs

Configuration

Add the plugin to your eslint.config.js (flat config):

import bluebird from 'bluebird-nestjs/eslint-plugin';

export default [
  // Your existing config...
  {
    plugins: {
      bluebird,
    },
    rules: {
      // Enable all Bluebird rules as warnings
      ...Object.fromEntries(
        Object.keys(bluebird.rules).map(rule => [`bluebird/${rule}`, 'warn'])
      ),

      // Or enable specific rules
      'bluebird/no-hardcoded-secrets': 'error',
      'bluebird/missing-injectable': 'error',
      'bluebird/no-console-log': 'warn',
    },
  },
];

Available Rules

All file-level Bluebird rules are available in the ESLint plugin. Graph-level rules (like no-circular-dependency and no-duplicate-route) require cross-file analysis and are only available via the CLI.

IDE Integration

Once configured, Bluebird rules will appear in:

  • VS Code with the ESLint extension
  • WebStorm/IntelliJ with built-in ESLint support
  • Neovim with nvim-lspconfig or ALE
  • Any editor with ESLint language server support

Docker

Bluebird provides a Docker image for containerized analysis:

# Build the image
docker build -t bluebird .

# Run analysis on current directory
docker run --rm -v $(pwd):/workspace bluebird

# JSON output
docker run --rm -v $(pwd):/workspace bluebird --format json

# Diff mode
docker run --rm -v $(pwd):/workspace bluebird --diff main

# With configuration file
docker run --rm -v $(pwd):/workspace bluebird --verbose

The container runs as a non-root user for security and mounts your project at /workspace.

Repository Structure

This is a pnpm monorepo. The main package is packages/bluebird.

packages/bluebird/
├── src/
│   ├── cli.ts                  # Commander-based CLI entrypoint
│   ├── scan.ts                 # Terminal UI orchestration (spinner, summary)
│   ├── watch.ts                # Watch mode implementation
│   ├── index.ts                # Public API surface (diagnose, exports)
│   ├── types.ts                # Shared type contracts
│   ├── constants.ts            # Scoring thresholds and penalties
│   ├── rules/
│   │   ├── index.ts            # Rule registry (38 rules, frozen metadata)
│   │   ├── checkers.ts         # Checker maps (36 file + 2 graph)
│   │   ├── ast-helpers.ts      # TypeScript AST utilities
│   │   ├── architecture.ts     # DI bypass, god controller/service
│   │   ├── security.ts         # Secrets, validation, DTO typing, SQL injection
│   │   ├── correctness.ts      # Injectable, lifecycle hooks, side effects
│   │   ├── api-design.ts       # Swagger, entity exposure, HTTP status
│   │   ├── performance.ts      # Sync fs/crypto blocking, caching, N+1
│   │   ├── database.ts         # Missing indexes, unsafe synchronize
│   │   ├── testing.ts          # Test coverage heuristics
│   │   └── graph-rules.ts      # Circular deps, duplicate routes
│   └── utils/
│       ├── run-eslint.ts             # File-level analysis runner (ESLint pass)
│       ├── run-graph-analysis.ts     # Cross-file analysis runner (graph pass)
│       ├── run-knip.ts               # Dead-code analysis runner (knip pass)
│       ├── discover-project.ts       # Auto-detect NestJS project metadata
│       ├── calculate-score.ts        # Hybrid health score computation
│       ├── load-config.ts            # Config file loading and validation
│       ├── init-config.ts            # Interactive config generation (bluebird init)
│       ├── filter-diagnostics.ts     # Ignore/waiver/glob filtering
│       ├── baseline.ts               # Baseline snapshot load/save/apply
│       ├── parse-disable-comments.ts # Inline disable comment parsing
│       ├── combine-diagnostics.ts
│       ├── orchestrate.ts            # Analysis orchestration with progress callbacks
│       ├── format-text.ts            # Text output formatter (terminal)
│       ├── format-json.ts            # JSON output formatter
│       ├── format-sarif.ts           # SARIF 2.1.0 output formatter
│       └── format-html.ts            # HTML dashboard formatter
└── tests/                            # 944 tests across 23 files
    ├── rules-checkers.test.ts        # Rule checker unit tests
    ├── run-eslint.test.ts            # ESLint runner tests
    ├── run-graph-analysis.test.ts    # Graph runner tests
    ├── run-knip.test.ts              # Dead-code runner tests
    ├── scan.test.ts                  # Scan orchestrator tests
    ├── diagnose.test.ts              # Integration tests
    └── ...

Development

# Install dependencies
pnpm install

# Run tests
pnpm --filter bluebird run test

# Watch mode
pnpm --filter bluebird run test:watch

# Type check
pnpm --filter bluebird run typecheck

# Lint
pnpm --filter bluebird run lint

# Build
pnpm --filter bluebird run build

Contributing

We welcome contributions! Please see our development setup above and ensure:

  1. All tests pass (pnpm --filter bluebird run test)
  2. Code is formatted (pnpm --filter bluebird run lint)
  3. Types check (pnpm --filter bluebird run typecheck)

Adding a New Rule

  1. Add the checker function to the appropriate file in src/rules/
  2. Add the rule metadata to src/rules/index.ts
  3. Register the checker in src/rules/checkers.ts
  4. Add tests in tests/rules-checkers.test.ts
  5. Update the rule counts in this README

Releasing to npm

Releases are automated via GitHub Actions when a version tag is pushed:

# 1. Update version in packages/bluebird/package.json
cd packages/bluebird
npm version patch  # or minor, major

# 2. Push the tag to trigger release
git push origin main --tags

The workflow will:

  1. Build and test
  2. Publish to npm as bluebird-nestjs

Prerequisites:

  • NPM_TOKEN secret must be configured in GitHub repository settings
  • npm account must have publish access to the bluebird-nestjs package

License

UNLICENSED