basta 0.1.1

Dead code detection — unused files, exports, symbols and imports across JavaScript, TypeScript and Python
Documentation
# basta

Find dead code: unused files, exports, declarations and imports across
JavaScript, TypeScript and Python.

basta builds the import graph from a project's entry points, walks it, and
reports what it never reaches. It ships as its own `basta` command and inside
[jscpd](https://jscpd.dev) as `jscpd --dead-code`.

```bash
basta src
```

```
Unused files (1)
 - src/legacy-export.ts  certain 95%  11 lines

Unused exports (1)
 - function src/invoice.ts:21:17 renderReceipt  high 85%  3 lines

Unused symbols (1)
 - function src/invoice.ts:29:10 describeTotal  certain 90%  3 lines

Unused imports (1)
 - import src/invoice.ts:2:10 roundToCents  certain 100%  1 lines

Found 4 dead code findings in 4 files (31.6% of 57 lines).
Done in 12ms
```

## What makes it different

**It is a traversal, not a reference count.** A helper whose only caller is
itself dead is reported too. That cascade is most of what a reference-counting
linter misses.

**It tells you how sure it is.** Static analysis of JavaScript and Python
cannot be certain, so every finding carries a score from 0 to 100 and the
reasons it is not higher — a file that calls `eval` or `getattr`, an
unrecognised decorator, a wildcard re-export, a name that shows up in a string
literal. `--min-confidence` sets the floor; the default is 60.

**It knows the conventions.** A package's `__init__.py` re-exports are its API,
not unused imports. `from __future__ import annotations` is a directive, not a
binding. `# noqa: F401` and PEP 484's `import x as x` mean a deliberate
re-export. A `package.json` pointing at `dist/index.js` means `src/index.ts`.
CommonJS counts: `require('./x')`, `module.exports = { a }` and a literal
`import('./x')` are edges like any `import`. A shell script or CI workflow
that names a source file keeps it alive.

## Usage

```bash
basta [PATHS]...

  --categories <LIST>        unused-file, unused-export, unused-symbol,
                             unused-import, unused-member, or `all`
  --min-confidence <N>       drop findings below this score (default: 60)
  --entry <GLOB>             treat matching files as entry points (repeatable)
  --ignore <GLOB>            skip matching files (repeatable)
  --include-tests            report dead code inside test files
  --include-entry-exports    report exports of entry points
  --min-lines <N>            only report declarations this many lines or longer
  -r, --reporters <LIST>     console, json, sarif, html, markdown, csv, xml,
                             codeclimate, openmetrics, badge, xcode, ai, silent
  -o, --output <DIR>         where file reporters write (default: report)
  --threshold <PERCENT>      fail when dead code exceeds this share
  --exit-code <CODE>         exit with this code when anything is found
  --format <FORMAT>          restrict the scan (repeatable)
  --list                     print the formats basta analyzes
```

## Entry points

Every finding is the answer to *nothing reaches this*, so the entry points are
the whole basis of the result. basta finds them from `package.json`
(`main`, `module`, `bin`, `exports`, `files`, `scripts`), `pyproject.toml`
(`[project.scripts]` and entry-point tables), scripts in the tree (`*.sh`,
CI workflows, Makefiles, Dockerfiles) that name a source file, and
conventions: `src/index.ts`,
`__main__.py`, `manage.py`, framework routes under `pages/` and `app/`,
`*.config.ts`, `.d.ts` declarations, shebangs, `if __name__ == "__main__"`,
and every `__init__.py`.

When a project does something none of that covers, say so once:

```bash
basta src --entry 'src/handlers/**' --entry 'scripts/*.ts'
```

## Adding a language

One file under `src/lang/` implementing `Analyzer`, and one line in the
`ANALYZERS` registry. The trait is the only place a language is allowed to be
special: it parses one file into declarations, imports and references,
resolves that language's specifiers against the index of scanned modules,
and declares its entry-point conventions, manifests and path traits. The
walker, the graph, the confidence model, the classifier, the reporters and
both CLIs are language-agnostic and pick the new language up from the
registry.

[`docs/basta-extending.md`](../../../docs/basta-extending.md) is the
walk-through: how a run works, the contract an analyzer has to honour (each
rule there was a real false positive once), a worked skeleton, and how to
prove a new language right against real projects.

## License

MIT