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

crap-ts

v0.1.1

Published

Small CRAP-score audit helper for TypeScript projects.

Downloads

5,158

Readme

crap-ts

Small CRAP-score audit helper for TypeScript projects.

crap-ts computes CRAP scores from TypeScript cyclomatic complexity plus Istanbul/V8 coverage data.

CRAP stands for Change Risk Anti-Patterns, from Alberto Savoia and Bob Evans' work on combining cyclomatic complexity with test coverage. Savoia explains the metric in Google's testing blog post, "This Code is CRAP", and the old Crap4J FAQ uses the same expansion. Risky code plus weak tests, now with a name your manager will remember.

Works Out Of The Box With

  • TypeScript source files listed in an Istanbul-style coverage-final.json
  • Consumer-provided TypeScript versions >=5.9 <8, including TypeScript 7
  • Vitest V8 coverage, Jest coverage, or nyc/Istanbul coverage that includes function maps
  • npm, Bun, pnpm, or any runner that can produce coverage before crap-ts reads it

No Biome required. No framework plugin. Bring coverage JSON, get CRAP. Very glamorous work, obviously.

Install

npm install --save-dev crap-ts

crap-ts uses your project's installed TypeScript peer dependency, so TypeScript 7 projects do not get a nested TypeScript 5.x install.

Usage

Run the built-in TypeScript AST audit against coverage-final data:

npx crap-ts score --coverage-command "npm run test:coverage -- --coverage.reporter=json" --coverage-file coverage/unit/coverage-final.json --include src

Add package scripts:

{
  "scripts": {
    "check:crap": "crap-ts score --report-only",
    "check:crap:strict": "crap-ts score"
  }
}

check:crap is useful while calibrating. check:crap:strict is the gate.

Put the long bits in .crap-ts.json:

{
  "coverageCommand": "npm run test:coverage -- --coverage.reporter=json --coverage.reporter=json-summary",
  "coverageFile": "coverage/unit/coverage-final.json",
  "include": ["src"],
  "max": 30,
  "minLines": 10,
  "limit": 20
}

You can also compute CRAP scores from an external metrics file and coverage summary:

npx crap-ts --metrics fixtures/complexity-metrics.json --coverage-file fixtures/coverage-summary.json

Workflow

The direct CRAP audit:

  • reads function coverage from Istanbul/V8 coverage-final.json
  • calculates function cyclomatic complexity from the TypeScript AST
  • prints the highest-risk functions
  • fails strict mode when any score is above the configured threshold

CRAP combines complexity and coverage:

crap = complexity^2 * (1 - coverage)^3 + complexity

For direct audits, coverage is function coverage from coverage-final.json. For metrics-file scoring, coverage is read from an Istanbul-style coverage-summary.json file.

When the complexity or CRAP check flags a hotspot:

  1. Name the affected function or file in the review.
  2. Confirm there is direct test coverage for that path.
  3. Add or tighten tests if behavior is unclear.
  4. Refactor only after the expected behavior is pinned down.

The point is not to chase a number for sport. The point is to make hard-to-read branching visible before it becomes a maintenance tax.

CLI

crap-ts score [--coverage-file coverage/unit/coverage-final.json] [--coverage-command "npm run test:coverage"]
crap-ts --metrics complexity-metrics.json --coverage-file coverage/coverage-summary.json

Options:

  • --config <path>: read config from a JSON file. Defaults to .crap-ts.json when present.
  • --coverage-file <path>: read coverage from a coverage JSON file.
  • --coverage-command <cmd>: run a coverage command before scoring.
  • --all: print every analyzed function instead of applying --limit.
  • --include <text>: only analyze coverage files whose path contains this text.
  • --limit <n>: number of report rows to print. Defaults to 20.
  • --max <n>: strict CRAP threshold for direct audit. Defaults to 30.
  • --min-lines <n>: ignore functions shorter than this. Defaults to 10.
  • --metrics <path>: read complexity metrics from JSON.
  • --report-only: print CRAP results without failing on threshold.
  • --skip-coverage: use an existing coverage file.

Metrics files use this shape:

[
  {
    "file": "src/example.ts",
    "name": "chooseValue",
    "complexity": 12
  }
]

Config files use camelCase keys:

{
  "coverageCommand": "npm run test:coverage",
  "coverageFile": "coverage/unit/coverage-final.json",
  "include": ["src"],
  "all": false,
  "limit": 20,
  "max": 30,
  "minLines": 10,
  "reportOnly": false,
  "skipCoverage": false
}

CLI flags override config. Naturally. The command line gets the last word, because you'd be mad at me if it didn't, and I'd also be mad at me.

Replacing Local CRAP Scripts

For a Bun/Vitest app that already writes coverage to coverage/unit, local scripts can usually shrink to:

{
  "scripts": {
    "check:crap": "crap-ts score --report-only",
    "check:crap:strict": "crap-ts score"
  }
}

With .crap-ts.json:

{
  "coverageCommand": "bun x vitest run --coverage --coverage.reporter=json --coverage.reporter=json-summary",
  "coverageFile": "coverage/unit/coverage-final.json",
  "include": ["/app/", "/scripts/"]
}

After that, repo-local CRAP analyzer scripts and tests can be deleted. Keep the project's coverage test config; that remains the source of truth for coverage instrumentation.

Contributing

Pull requests are welcome. Keep them focused, add tests when behavior changes, and see CONTRIBUTING.md sullying my code ;)

License

MIT