Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions analysis/dead-code.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Fallow reports these core issue types:
| **Test-only dependencies** | Production dependencies that only test files import (move them to devDependencies) |
| **Stale suppressions** | `fallow-ignore` comments or `@expected-unused` JSDoc tags that no longer match any issue |

Fallow also has framework-specific rules, such as unused component props and route collisions, and opt-in rules, such as private type leaks. To set the severity of a rule, see [Rules & severity](/configuration/rules). To see the filter flag of each issue type, run `fallow dead-code --help`. For circular dependencies, boundary violations, and the other architecture findings, use [`fallow architecture`](/cli/architecture).
Fallow also has framework-specific rules, such as unused component props and route collisions, rules for [Effect](https://effect.website) projects, such as [unused Effect layers](/explanations/dead-code#unused-effect-layers), and opt-in rules, such as private type leaks. To set the severity of a rule, see [Rules & severity](/configuration/rules). To see the filter flag of each issue type, run `fallow dead-code --help`. For circular dependencies, boundary violations, and the other architecture findings, use [`fallow architecture`](/cli/architecture).

Typical output with more than one issue type:

Expand Down Expand Up @@ -172,7 +172,7 @@ Fallow reports candidates only when it knows at least one reachable caller and c
{
"kind": "dead-code",
"schema_version": 10,
"version": "3.33.1",
"version": "3.34.0",
"elapsed_ms": 160,
"total_issues": 401,
"unused_files": [
Expand Down Expand Up @@ -220,7 +220,7 @@ Fallow reports candidates only when it knows at least one reachable caller and c
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"version": "2.1.0",
"runs": [{
"tool": { "driver": { "name": "fallow", "version": "3.33.1" } },
"tool": { "driver": { "name": "fallow", "version": "3.34.0" } },
"results": [
{
"ruleId": "fallow/unused-export",
Expand Down
2 changes: 1 addition & 1 deletion cli/audit.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ added-suppression:src/index.ts:2:@ts-ignore,severity=warn
{
"kind": "audit",
"schema_version": 13,
"version": "3.33.1",
"version": "3.34.0",
"command": "audit",
"verdict": "fail",
"changed_files_count": 12,
Expand Down
3 changes: 3 additions & 0 deletions cli/dead-code.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ fallow check # Hidden alias for fallow dead-code
| `--unused-svelte-events` | Report only unused Svelte dispatched events |
| `--unused-server-actions` | Report only unused server actions |
| `--unused-load-data-keys` | Report only unused SvelteKit `load()` data keys |
| `--unused-effect-layers` | Report only [unused Effect layers](/explanations/dead-code#unused-effect-layers): layers that only unused layers compose |
| `--unused-tagged-errors` | Report only [unused tagged errors](/explanations/dead-code#unused-tagged-errors): Effect tagged errors that no code produces |
| `--unproduced-catch-tags` | Report only [unproduced catch tags](/explanations/dead-code#unproduced-catch-tags): `catchTag` handlers for a tag that no code produces |
| `--unresolved-imports` | Report only unresolved imports |
| `--unlisted-deps` | Report only unlisted dependencies |
| `--duplicate-exports` | Report only duplicate exports |
Expand Down
2 changes: 1 addition & 1 deletion cli/decision-surface.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ When the change has no structural decision, the output is `Decisions: none (no c
{
"kind": "decision-surface",
"schema_version": 1,
"version": "3.33.1",
"version": "3.34.0",
"command": "decision-surface",
"decisions": [
{
Expand Down
2 changes: 1 addition & 1 deletion cli/doctor.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ The last line gives the status: `ready`, `ready with warnings`, or `not ready`.
{
"kind": "doctor",
"schema_version": 2,
"version": "3.33.1",
"version": "3.34.0",
"root": ".",
"status": "warn",
"summary": {
Expand Down
2 changes: 1 addition & 1 deletion cli/flags.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ fallow flags --production
{
"kind": "feature-flags",
"schema_version": 8,
"version": "3.33.1",
"version": "3.34.0",
"elapsed_ms": 116,
"feature_flags": [],
"total_flags": 0
Expand Down
16 changes: 8 additions & 8 deletions cli/health.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ Snapshots let you track the health of your codebase across builds, sprints, or r
```json title="snapshot.json"
{
"snapshot_schema_version": 12,
"version": "3.33.1",
"version": "3.34.0",
"timestamp": "2026-03-25T14:30:00Z",
"git_sha": "a1b2c3d",
"git_branch": "main",
Expand Down Expand Up @@ -818,7 +818,7 @@ Fallow writes every entry with or without `--quiet`, so a CI job that drops stde
```json title="$ fallow health --format json --top 2"
{
"schema_version": 12,
"version": "3.33.1",
"version": "3.34.0",
"elapsed_ms": 140,
"summary": {
"files_analyzed": 252,
Expand Down Expand Up @@ -911,7 +911,7 @@ With `--file-scores`, the JSON output has more fields:
```json title="$ fallow health --file-scores --format json --top 2"
{
"schema_version": 12,
"version": "3.33.1",
"version": "3.34.0",
"elapsed_ms": 320,
"summary": {
"files_analyzed": 252,
Expand Down Expand Up @@ -970,7 +970,7 @@ With `--hotspots`, the JSON output has a `hotspots` array and a `hotspot_summary
```json title="$ fallow health --hotspots --format json --top 2"
{
"schema_version": 12,
"version": "3.33.1",
"version": "3.34.0",
"elapsed_ms": 480,
"summary": {
"files_analyzed": 252,
Expand Down Expand Up @@ -1035,7 +1035,7 @@ With `--targets`, the JSON output has a `targets` array:
```json title="$ fallow health --targets --format json --top 2"
{
"schema_version": 12,
"version": "3.33.1",
"version": "3.34.0",
"elapsed_ms": 520,
"summary": {
"files_analyzed": 252,
Expand Down Expand Up @@ -1305,7 +1305,7 @@ coverage-gaps = "warn"
```json title="$ fallow health --coverage-gaps --format json"
{
"schema_version": 12,
"version": "3.33.1",
"version": "3.34.0",
"elapsed_ms": 280,
"coverage_gaps": {
"summary": {
Expand Down Expand Up @@ -1384,7 +1384,7 @@ Runtime coverage shows which code production actually runs. With `--runtime-cove
```json title="$ fallow health --runtime-coverage ./coverage --format json"
{
"schema_version": 12,
"version": "3.33.1",
"version": "3.34.0",
"elapsed_ms": 412,
"runtime_coverage": {
"verdict": "hot-path-touched",
Expand Down Expand Up @@ -1500,7 +1500,7 @@ fallow health --format sarif
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"version": "2.1.0",
"runs": [{
"tool": { "driver": { "name": "fallow", "version": "3.33.1" } },
"tool": { "driver": { "name": "fallow", "version": "3.34.0" } },
"results": [
{
"ruleId": "fallow/high-cyclomatic-complexity",
Expand Down
2 changes: 1 addition & 1 deletion cli/security.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ The editor diagnostics and [`fallow viz`](/cli/viz) show the same result. The ba
{
"kind": "security",
"schema_version": 8,
"version": "3.33.1",
"version": "3.34.0",
"elapsed_ms": 42,
"config": {
"rules": {
Expand Down
13 changes: 11 additions & 2 deletions configuration/rules.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ Start with all rules as `warn`. Promote one type at a time to `error` when you h

When you do not configure a rule, it uses its default severity. The **Default** column in [Available rule names](#available-rule-names) shows the default of each rule. The defaults by group:

- Default `off` (opt-in): `private-type-leaks`, `deprecated-exports-in-use`, `absent-component-props`, `prop-drilling`, `thin-wrapper`, `duplicate-prop-shape`, `coverage-gaps`, `feature-flags`, `require-suppression-reason`, `security-client-server-leak`, and `security-sink`.
- Default `off` (opt-in): `private-type-leaks`, `deprecated-exports-in-use`, `absent-component-props`, `prop-drilling`, `thin-wrapper`, `duplicate-prop-shape`, `coverage-gaps`, `feature-flags`, `require-suppression-reason`, `security-client-server-leak`, `security-sink`, `diverged-clone-sibling`, and `added-dependency`.
- Default `warn`:
- Dependency hygiene: `unused-dev-dependencies`, `unused-optional-dependencies`, `type-only-dependencies`, `test-only-dependencies`, and `dev-dependencies-in-production`.
- Framework components: `unused-store-members`, `unprovided-injects`, `unrendered-components`, `unused-component-props`, `unused-component-emits`, `unused-component-inputs`, `unused-component-outputs`, `unused-svelte-events`, `unused-server-actions`, and `unused-load-data-keys`.
- Effect: `unused-effect-layers`, `unused-tagged-errors`, and `unproduced-catch-tags`.
- Audit diff risk: `weakened-tests`, `added-suppression`, and `test-only-branch`.
- Client and server directives: `invalid-client-export`, `mixed-client-server-barrel`, and `misplaced-directive`.
- Styling: `css-token-drift`, `css-duplicate-block`, `css-selector-complexity`, `css-dead-surface`, and `css-broken-reference`.
- pnpm cleanup: `unused-catalog-entries`, `empty-catalog-groups`, and `unused-dependency-overrides`.
Expand Down Expand Up @@ -115,6 +117,9 @@ stale-suppressions = "warn"
| `unused-svelte-events` | `warn` | A Svelte `createEventDispatcher` event that no code in the project listens to |
| `unused-server-actions` | `warn` | A Next.js Server Action, exported from a `"use server"` file, that no code references |
| `unused-load-data-keys` | `warn` | A key of a SvelteKit `load()` return object that no consumer reads |
| `unused-effect-layers` | `warn` | An Effect layer that only unused layers compose. Runs only when `effect` is a dependency. Fallow also accepts `unused-effect-layer`. See [Unused Effect layers](/explanations/dead-code#unused-effect-layers) |
| `unused-tagged-errors` | `warn` | A `Data.TaggedError` or `Schema.TaggedError` class that no code constructs, fails with, or decodes. Runs only when `effect` is a dependency. See [Unused tagged errors](/explanations/dead-code#unused-tagged-errors) |
| `unproduced-catch-tags` | `warn` | A `catchTag` handler for a project tag that no code produces. Runs only when `effect` is a dependency. See [Unproduced catch tags](/explanations/dead-code#unproduced-catch-tags) |
| `prop-drilling` | `off` | A React or Preact prop that passes unchanged through 3 or more components to a distant consumer |
| `thin-wrapper` | `off` | A React or Preact component whose whole body renders one child with spread props (a candidate for inlining) |
| `duplicate-prop-shape` | `off` | Three or more React or Preact components, in two or more files, that declare the same set of prop names (a missing shared `Props` type) |
Expand Down Expand Up @@ -213,7 +218,11 @@ With the default rules, a `moderate` complexity finding is an `::error` annotati

Each dead-code and complexity finding in the JSON output has the optional `effective_severity` field. `fallow report --from` reads it, so a saved report gives the same levels as the direct run. A saved report from an older version has no `effective_severity`. For such a report, `report --from` uses the earlier levels.

`prop-drilling`, `thin-wrapper`, and `duplicate-prop-shape` findings never fail the run. Their SARIF level is `warning` at most, also when the rule is `error`. The `human`, `json`, `sarif`, `compact`, and `markdown` reports list these findings, and the editor shows them as hints. The pull request formats (`codeclimate`, `github-annotations`, `github-summary`, and the comment and review formats) do not list them.
`prop-drilling` defaults to `off`. Set it to `error` to fail CI for a finding, or `warn` to keep it advisory even with `--fail-on-issues`. Error findings use the configured error level in CI formats. The editor still shows prop drilling as a hint. Saved JSON reports preserve their effective severity when rendered with `fallow report --from`.

Earlier versions treated `prop-drilling: "error"` as advisory. If you used that setting for non-gating reports, change it to `warn` when upgrading. This affects future analysis runs. An archived JSON report with `effective_severity: "error"` renders as an error even after you change the current config to `warn`.

`thin-wrapper` and `duplicate-prop-shape` findings stay advisory, also when their rules are `error`. Their SARIF level is `warning` at most. The `human`, `json`, `sarif`, `compact`, and `markdown` reports list these findings, and the editor shows them as hints. The pull request formats (`codeclimate`, `github-annotations`, `github-summary`, and the comment and review formats) do not list them.

<Accordion title="Incremental adoption strategy">
In an existing codebase, adopt fallow in steps:
Expand Down
6 changes: 5 additions & 1 deletion explanations/dead-code.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,11 @@ A React or Preact prop that two or more intermediate components pass on without
|:---------|:--------|
| Off (opt-in) | Yes |

This rule is off by default. To enable it, set `prop-drilling: "warn"` (or `"error"`) under `rules`. Fallow then reports one chain per drilled prop. The chain shows the source component that owns the value, each pass-through hop, and the component that uses the prop, each with file, line, and component name. To stay false-positive-safe, fallow skips the whole chain when it cannot prove a clean pass-through: any `{...props}` or `{...rest}` spread, a `cloneElement` call, a component passed as a prop, render prop, or function-as-children, a matching context `*.Provider` in the subtree (where drilling can be a deliberate choice), or any dynamic or unresolvable hop. The rule runs only when `react`, `react-dom`, `next`, or `preact` is a declared dependency. When you enable it, it also adds a small, capped penalty to the health score: one point per chain, with a cap of five. With the rule off, the health score does not change.
This rule is off by default. Set `prop-drilling: "warn"` under `rules` for advisory findings, or `"error"` to fail CI when fallow finds a chain. A `warn` finding stays advisory even with `--fail-on-issues`. Fallow then reports one chain per drilled prop. The chain shows the source component that owns the value, each pass-through hop, and the component that uses the prop, each with file, line, and component name. To stay false-positive-safe, fallow skips the whole chain when it cannot prove a clean pass-through: any `{...props}` or `{...rest}` spread, a `cloneElement` call, a component passed as a prop, render prop, or function-as-children, a matching context `*.Provider` in the subtree (where drilling can be a deliberate choice), or any dynamic or unresolvable hop. The rule runs only when `react`, `react-dom`, `next`, or `preact` is a declared dependency. When you enable it, it also adds a small, capped penalty to the health score: one point per chain, with a cap of five. With the rule off, the health score does not change.

You can save existing chains with `--save-baseline` and gate later runs with `--baseline`. Fallow identifies a chain by its source path, component, and prop. A change to the route or depth of the same source chain stays inherited. `fallow audit --gate new-only` gates new source identities; use `--gate all` to include inherited findings.

Changed-file and changed-line scopes retain an enforced (`error`) chain when any downstream hop changes, while the reported location stays at the source. Changed-file scopes retain an advisory (`warn`) chain only when its source file changes. In the editor, both levels remain hints.

**When to act:** Move the component that uses the prop next to the data, move the value to a React context or provider at a hop in the middle of the chain, or compose the components so that the intermediate components no longer pass the prop. There is no auto-fix, because the right refactor is a design choice. To suppress one chain, use `// fallow-ignore-next-line prop-drilling`, or set the rule to `off`.

Expand Down
2 changes: 1 addition & 1 deletion explanations/telemetry.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ When you enable telemetry, fallow records one small, high-level event per analys
{
"schema_version": 2,
"event": "workflow_completed",
"fallow_version": "3.33.1",
"fallow_version": "3.34.0",
"workflow": "audit",
"integration_surface": "mcp",
"invocation_context": "agent",
Expand Down
2 changes: 1 addition & 1 deletion frameworks/react.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ When you enable the rule, it reports one chain for each drilled prop. The chain
Off by default.

<Note>
To enable it, set `prop-drilling: "warn"` (or `"error"`) under `rules`. The enabled rule also adds a small penalty to the health score: one point for each chain, with a maximum of five. When the rule is off, the health score does not change.
Set `prop-drilling: "warn"` under `rules` for advisory findings, or `"error"` to make findings fail CI. A `warn` finding stays advisory even with `--fail-on-issues`. The enabled rule also adds a small penalty to the health score: one point for each chain, with a maximum of five. When the rule is off, the health score does not change.
</Note>

See [prop drilling](/explanations/dead-code#prop-drilling).
Expand Down
2 changes: 1 addition & 1 deletion integrations/claude-hooks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export FALLOW_GATE_MIN_VERSION=3.0.0
export FALLOW_GATE_MIN_VERSION=
```

Each block logs the path and version of the binary that ran, for example `fallow-gate: blocked by fallow 3.33.1 at /usr/local/bin/fallow`. You can see which binary ran without more debugging. The header of the installed script also has `# Installer version: X.Y.Z`. Use it when the gate does not agree with your current `fallow --version`.
Each block logs the path and version of the binary that ran, for example `fallow-gate: blocked by fallow 3.34.0 at /usr/local/bin/fallow`. You can see which binary ran without more debugging. The header of the installed script also has `# Installer version: X.Y.Z`. Use it when the gate does not agree with your current `fallow --version`.

## Inspect hook state

Expand Down
2 changes: 1 addition & 1 deletion integrations/mcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ When the response `capabilities` array has `function_identity_v2`, cloud runtime
{
"kind": "dead-code",
"schema_version": 10,
"version": "3.33.1",
"version": "3.34.0",
"elapsed_ms": 42,
"total_issues": 1,
"unused_exports": [
Expand Down
5 changes: 4 additions & 1 deletion migration/from-knip.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ The `fallow migrate` command translates your knip configuration to a fallow conf
| `ignoreDependencies` | `ignoreDependencies` (a regex becomes a glob when a glob matches the same packages, see [Warnings and caveats](#warnings-and-caveats)) |
| `ignoreExportsUsedInFile` | `ignoreExportsUsedInFile` (boolean and `{ type, interface }` object form both supported) |
| `rules`, `include`, `exclude` | `rules` (knip issue types map to fallow rule names) |
| `ignoreBinaries` | -- (not applicable) |
| `ignoreBinaries`, `ignoreGlobalBinaries` | -- (not applicable) |
| `cycles` | -- (no allow-list for exact cycle paths. The warning suggests `circularDependencies.ignoreLazyImports` or a `// fallow-ignore-next-line circular-dependency` comment) |
| `preprocessor`, `preprocessorOptions` | -- (not supported. The warning suggests to post-process the `fallow --format json` output) |
| `compilers`, `asyncCompilers` | -- (fallow parses with Oxc and has no custom compilers) |
| Plugin configs | -- (fallow's built-in plugins detect the framework; the migration warns you to remove the section) |

## Warnings and caveats
Expand Down
Loading