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

code-gauge

v1.9.0

Published

Measure code metrics with tree-sitter.

Readme

code-gauge

Test semantic-release

A command-line tool for measuring code metrics with tree-sitter. It scans a project and reports high-risk files, functions, and React components so you can spot code that is worth refactoring. A programmatic API is also available.

Getting started

# Run without installing
npx code-gauge path/to/project

# Or install globally
npm install -g code-gauge
code-gauge path/to/project

The CLI scans JavaScript, JSX, TypeScript, TSX, Python, Go, and Rust files. By default it skips generated, vendor, test, and tool directories, prints a summary, and lists the highest-risk findings. TypeScript project metrics and React component classification turn on automatically when a tsconfig.json is found.

Options

| Option | Description | | -------------------------- | --------------------------------------------------------------------------- | | --config <path> | Use this config file instead of the auto-detected code-gauge.config.json. | | --include-tests | Include test files and test directories. | | --tsconfig <path> | Use this tsconfig.json instead of the auto-detected one. | | --max-findings <n> | Maximum number of findings to print (default: 20). | | --largest-files <n> | List the n largest files by code LOC (config key: largestFiles). | | --json | Print machine-readable JSON. | | --fail-on-risk | Exit with code 1 when any high-risk finding is reported. | | --fail-on-error | Exit with code 1 when any file or directory cannot be scanned. | | --<metric>-threshold <n> | Override a risk threshold (see below). |

Risk thresholds

A finding is reported when a measured value is greater than or equal to its threshold. Every threshold can be set on the command line (e.g. --file-loc-threshold 400) or in a config file; the command line wins over the config file, which wins over the defaults.

code-gauge looks for code-gauge.config.json by walking up from the target directory (override with --config). The following config reproduces every built-in default:

{
  "thresholds": {
    "fileLoc": 500,
    "functionLoc": 120,
    "componentLoc": 350,
    "cognitive": 25,
    "cyclomatic": 20,
    "call": 50,
    "import": 25,
    "fanOut": 10,
    "parameter": 8,
    "duplicateBlock": 2,
    "transitiveDependency": 25,
    "structuralBreadth": 8,
    "structuralCoordination": 300,
    "stateMutation": 50,
    "duplicateSymbolGroup": 5
  },
  "languageThresholds": {
    "python": { "stateMutation": 90, "structuralCoordination": 350 },
    "react": { "import": 30 }
  },
  "maxFindings": 20,
  "includeTests": false,
  "failOnRisk": false,
  "failOnError": false
}

| Threshold | CLI flag | Reports when a … | | ------------------------ | ------------------------------------- | ------------------------------------------------ | | fileLoc | --file-loc-threshold | file's code LOC is large. | | functionLoc | --function-loc-threshold | function's physical LOC span is large. | | componentLoc | --component-loc-threshold | React component's physical LOC span is large. | | cognitive | --cognitive-threshold | function's cognitive complexity is high. | | cyclomatic | --cyclomatic-threshold | function's cyclomatic complexity is high. | | call | --call-threshold | function makes many calls. | | import | --import-threshold | file has many unique import sources. | | fanOut | --fan-out-threshold | function calls many other in-file functions. | | parameter | --parameter-threshold | function declares many parameters. | | duplicateBlock | --duplicate-block-threshold | file contains copy-pasted code blocks. | | transitiveDependency | --transitive-dependency-threshold | file transitively reaches many local files. | | structuralBreadth | --structural-breadth-threshold | file coordinates many structural concerns. | | structuralCoordination | --structural-coordination-threshold | file's structural coordination score is high. | | stateMutation | --state-mutation-threshold | file mutates state heavily. | | duplicateSymbolGroup | --duplicate-symbol-group-threshold | file shares many duplicated symbols with others. |

Per-language thresholds

Some metrics distribute very differently by language or file type, so a single global threshold either over-flags one language or under-flags another. languageThresholds overrides individual thresholds for a profile without repeating the whole set. Each file resolves its thresholds as base → its language profile → the react profile (the last applies when the file contains a React component), so later profiles win.

Valid profile keys are javascript, jsx, typescript, tsx, python, go, rust, and react. Built-in overrides raise stateMutation and structuralCoordination for Python (every binding is an assignment, so these run far higher than in TypeScript) and raise import for React files (which pull in many components). Anything you specify is merged on top of the built-in overrides, so { "python": { "stateMutation": 8 } } restores the global value for Python while keeping the other built-in adjustments.

{
  "languageThresholds": {
    "python": { "stateMutation": 120 },
    "react": { "componentLoc": 400, "import": 35 }
  }
}

Command-line --<metric>-threshold flags set the global base only; use the config file for per-language tuning.

Metrics

  • Physical LOC, code lines, comment-only lines, and blank lines
  • Function and class counts
  • Cyclomatic and cognitive complexity (per function and maximum)
  • Nesting depth
  • Intra-file call graph metrics: call counts, fan-in/fan-out, recursion, call depth, and parameter counts
  • Within-file structural duplication: copy-pasted code blocks (distinct from cross-file duplicate symbol names)
  • File coupling (imports/exports) and cohesion (shared function identifiers)
  • Architecture metrics: transitive local dependencies, structural coordination and breadth, state mutation, and cross-file duplicate symbols
  • TypeScript type-shape metrics: annotations, aliases, interfaces, generics, unions, intersections, assertions, and conditional types
  • Halstead metrics and the maintainability index

Supported languages

Built-in parsers cover JavaScript, JSX, TypeScript, TSX, Python, Go, and Rust. Additional tree-sitter grammars can be registered with TreeMeasurer.registerLanguage.

Programmatic API

import { measureCode } from 'code-gauge';

const metrics = measureCode(
  `
function score(value) {
  if (value < 0 || value == null) {
    return 0;
  }
  return value > 10 ? 10 : value;
}
`,
  { language: 'javascript' }
);

console.log(metrics.cyclomaticComplexity);