Skip to content
LogoLogo

Unused code

Three rules find code that nothing uses. The design follows Knip. The rules are in the nursery category, so they are off by default.

RuleWhat it reports
unused-exportsExports that no module imports, members of enums and namespaces that no code reads, and bindings that a module exports under two names.
unused-packagesPackages that a package.json declares and that none of its modules imports.
unused-modulesSource modules that no path from an entry point reaches.

Enable the rules

{
  "rules": {
    "unused-exports": "warn",
    "unused-packages": "error",
    "unused-modules": "error"
  }
}

This is the output for a small project:

error[unused-packages]: `unused-dep` is in `dependencies` but no module imports it
  --> package.json:6:5
   |
 6 |     "unused-dep": "1.0.0",
   |     ^

error[unused-modules]: this module cannot be reached from any entry point
  --> src/orphan.ts

warn[unused-exports]: unused export `renamed`
  --> src/api.ts:5:20
   |
 5 | export { helper as renamed };
   |                    ^

warn[unused-exports]: unused member `Color.Green`
  --> src/util.ts:8:3
   |
 8 |   Green,
   |   ^

Entry points

An entry point is a module whose exports are public. The unused-exports rule does not report the exports of an entry point. The unused-modules rule starts at the entry points and reports the modules that no path from them reaches. Oxcruise finds entry points from these sources:

  • The files that each package.json publishes: main, module, types, bin and exports. Oxcruise maps build output back to source with the outDir and rootDir of the tsconfig.
  • index, main and cli files, only at the package root or in its src folder.
  • Files that the tools in package.json load by convention, such as tests, routes and configuration files.
  • The entries option of the rules and the entries of plugins.
  • Modules that have the // oxcruise-ignore-file comment.

The unused-exports rule has one more source of entry points: the modules that no other module imports. The unused-modules rule does not use this source, because then it would report no module that nothing imports.

Conventions

A convention is a small entry in a table. It says which files a tool loads and which packages it uses. A convention is active in a package.json that declares one of its packages. The conventions table lists all of them. Use the conventions option of a rule to switch conventions off or to select some.

Production mode

Run npx oxcruise --production or set production: true in the options of the rules. In production mode, tests are not entry points and do not count as users of an export. The unused-packages rule also skips devDependencies. An export that only a test uses is then a violation.

Exports and symbols

unused-exports needs the exports of each module and the names that each import uses. Oxcruise calls these symbols. It extracts them in the same pass as the dependencies, but only when something needs them:

  • a rule that needs them is on, such as unused-exports
  • a plugin declares needs: ["symbols"]
  • you use --symbols, the symbols config key or cruise({ symbols: true })

Without symbols, nothing changes in speed or output. With symbols, the json format lists the exports of each module and the names of each dependency.

Limits

  • A module that you import in a way that Oxcruise cannot follow counts as a user of all its exports. Examples are require, a dynamic import() and a namespace that code passes as a value.
  • Single-file components (Vue, Svelte and Astro) are never narrowed. Their templates use bindings that the script block does not mention.
  • Oxcruise does not check class members, catalogs, binaries or JSDoc visibility tags.
  • A violation of unused-packages is in a package.json. A comment cannot suppress it. Use the ignore option.

To suppress one export, put // oxcruise-ignore-next-line unused-exports above it. Use --fix to repair some violations automatically.