fallow 2.96.0 → 2.98.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fallow",
3
- "version": "2.96.0",
3
+ "version": "2.98.0",
4
4
  "description": "Deterministic codebase intelligence for TypeScript and JavaScript. Quality, risk, architecture, dependencies, duplication, and safe cleanup evidence for humans, CI, and agents. Optional runtime intelligence layer (Fallow Runtime) adds production execution evidence. Rust-native, sub-second, zero-config framework support.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -80,16 +80,16 @@
80
80
  "detect-libc": "2.1.2"
81
81
  },
82
82
  "devDependencies": {
83
- "@tanstack/intent": "0.0.41"
83
+ "@tanstack/intent": "0.0.42"
84
84
  },
85
85
  "optionalDependencies": {
86
- "@fallow-cli/darwin-arm64": "2.96.0",
87
- "@fallow-cli/darwin-x64": "2.96.0",
88
- "@fallow-cli/linux-x64-gnu": "2.96.0",
89
- "@fallow-cli/linux-arm64-gnu": "2.96.0",
90
- "@fallow-cli/linux-x64-musl": "2.96.0",
91
- "@fallow-cli/linux-arm64-musl": "2.96.0",
92
- "@fallow-cli/win32-arm64-msvc": "2.96.0",
93
- "@fallow-cli/win32-x64-msvc": "2.96.0"
86
+ "@fallow-cli/darwin-arm64": "2.98.0",
87
+ "@fallow-cli/darwin-x64": "2.98.0",
88
+ "@fallow-cli/linux-x64-gnu": "2.98.0",
89
+ "@fallow-cli/linux-arm64-gnu": "2.98.0",
90
+ "@fallow-cli/linux-x64-musl": "2.98.0",
91
+ "@fallow-cli/linux-arm64-musl": "2.98.0",
92
+ "@fallow-cli/win32-arm64-msvc": "2.98.0",
93
+ "@fallow-cli/win32-x64-msvc": "2.98.0"
94
94
  }
95
95
  }
package/schema.json CHANGED
@@ -154,6 +154,19 @@
154
154
  "unused-optional-dependencies": "warn",
155
155
  "unused-enum-members": "error",
156
156
  "unused-class-members": "error",
157
+ "unused-store-members": "warn",
158
+ "unprovided-injects": "warn",
159
+ "unrendered-components": "warn",
160
+ "unused-component-props": "warn",
161
+ "unused-component-emits": "warn",
162
+ "unused-component-inputs": "warn",
163
+ "unused-component-outputs": "warn",
164
+ "unused-svelte-events": "warn",
165
+ "unused-server-actions": "warn",
166
+ "unused-load-data-keys": "warn",
167
+ "prop-drilling": "off",
168
+ "thin-wrapper": "off",
169
+ "duplicate-prop-shape": "off",
157
170
  "unresolved-imports": "error",
158
171
  "unlisted-dependencies": "error",
159
172
  "duplicate-exports": "error",
@@ -172,7 +185,12 @@
172
185
  "misconfigured-dependency-overrides": "error",
173
186
  "security-client-server-leak": "off",
174
187
  "security-sink": "off",
175
- "policy-violation": "warn"
188
+ "policy-violation": "warn",
189
+ "invalid-client-export": "warn",
190
+ "mixed-client-server-barrel": "warn",
191
+ "misplaced-directive": "warn",
192
+ "route-collision": "error",
193
+ "dynamic-segment-name-conflict": "error"
176
194
  }
177
195
  },
178
196
  "boundaries": {
@@ -697,7 +715,7 @@
697
715
  "default": false
698
716
  },
699
717
  "ignoreImports": {
700
- "description": "Exclude ES `import` declarations from clone detection.\n\nDefaults to `true`: token-identical sorted import blocks are a structural\nproperty of well-formatted code, not copy-paste, so they should not\nsurface as clone groups. Set to `false` to count import blocks again.\nWhen enabled, all `import` statements (value imports, type imports, and\nside-effect imports) are stripped from the token stream before clone\ndetection. Only affects ES `import` declarations; CommonJS `require()`\ncalls and `export ... from` re-export blocks are still counted.",
718
+ "description": "Exclude module-wiring declarations from clone detection.\n\nDefaults to `true`: token-identical module wiring is a structural\nproperty of well-formatted code, not copy-paste, so it should not\nsurface as clone groups. Set to `false` to count module wiring again.\nWhen enabled, ES imports, re-export declarations, and top-level static\nCommonJS `require(\"...\")` binding declarations are stripped from the\ntoken stream before clone detection. Dynamic imports, side-effect\n`require()` calls, nested `require()` calls, dynamic require arguments,\nand mixed declarations are still counted.",
701
719
  "type": "boolean",
702
720
  "default": true
703
721
  },
@@ -1012,6 +1030,71 @@
1012
1030
  "$ref": "#/$defs/Severity",
1013
1031
  "default": "error"
1014
1032
  },
1033
+ "unused-store-members": {
1034
+ "description": "Store members (Pinia `state` / `getters` / `actions` key, or a\nsetup-store returned key) declared but never accessed by any consumer\nproject-wide. Defaults to `warn`, not `error` like the closed-set\nclass/enum member rules: a store has an OPEN declaration surface\n(plugins, `$onAction`, dynamic dispatch) so analyzer confidence is\ngenuinely lower; warn encodes that without failing CI. Promotable to\n`error` once validated on a codebase.",
1035
+ "$ref": "#/$defs/Severity",
1036
+ "default": "error"
1037
+ },
1038
+ "unprovided-injects": {
1039
+ "description": "Vue `inject(KEY)` / Svelte `getContext(KEY)` whose symbol KEY is\n`provide`/`setContext`'d nowhere in the project (the\ninjected-never-provided dead-half). Defaults to `warn`, not `error`:\na DI key has an open provide surface (plugins, app-level provide) so\nanalyzer confidence is lower; warn encodes that without failing CI.",
1040
+ "$ref": "#/$defs/Severity",
1041
+ "default": "error"
1042
+ },
1043
+ "unrendered-components": {
1044
+ "description": "Vue/Svelte single-file component reachable in the module graph but\nrendered nowhere in the project (the imported-but-never-rendered\ndead-half). Defaults to `warn`, not `error`: a component can be rendered\nreflectively (dynamic `<component :is>`), so analyzer confidence is\nlower; warn encodes that without failing CI.",
1045
+ "$ref": "#/$defs/Severity",
1046
+ "default": "error"
1047
+ },
1048
+ "unused-component-props": {
1049
+ "description": "Vue `<script setup>` `defineProps` declared prop referenced nowhere\ninside its own single-file component (neither `<script>` nor\n`<template>`). The single-file dead-input direction. Defaults to `warn`,\nnot `error`: a prop can be part of a deliberately-stable public component\nAPI, so analyzer confidence is lower; warn encodes that without failing\nCI.",
1050
+ "$ref": "#/$defs/Severity",
1051
+ "default": "error"
1052
+ },
1053
+ "unused-component-emits": {
1054
+ "description": "Vue `<script setup>` `defineEmits` declared event emitted nowhere inside\nits own single-file component (no `emit('<name>')` call). The single-file\ndead-input direction. Defaults to `warn`, not `error`: an emit can be part\nof a deliberately-stable public component API, so analyzer confidence is\nlower; warn encodes that without failing CI.",
1055
+ "$ref": "#/$defs/Severity",
1056
+ "default": "error"
1057
+ },
1058
+ "unused-component-inputs": {
1059
+ "description": "Angular `@Input()` / signal `input()` / `model()` declared input read\nnowhere inside its own component (neither the inline/external template nor\nthe class body). The single-file dead-input direction, the Angular\nanalogue of `unused-component-prop`. Defaults to `warn`, not `error`: an\ninput can be part of a deliberately-stable public component API, so\nanalyzer confidence is lower; warn encodes that without failing CI.",
1060
+ "$ref": "#/$defs/Severity",
1061
+ "default": "error"
1062
+ },
1063
+ "unused-component-outputs": {
1064
+ "description": "Angular `@Output()` / signal `output()` declared output emitted nowhere\ninside its own component (no `this.<output>.emit(...)`). The single-file\ndead-output direction, the Angular analogue of `unused-component-emit`.\nDefaults to `warn`, not `error`: an output can be part of a\ndeliberately-stable public component API, so analyzer confidence is lower;\nwarn encodes that without failing CI.",
1065
+ "$ref": "#/$defs/Severity",
1066
+ "default": "error"
1067
+ },
1068
+ "unused-svelte-events": {
1069
+ "description": "Svelte component dispatching a custom event via `createEventDispatcher()`\nwhose event name is listened to nowhere in the analyzed project. The\ncross-file dead-output direction (no eslint-plugin-svelte / svelte-check\nrule covers the listener side). Defaults to `warn`, not `error`: a\ndispatched event can be part of a deliberately-stable public component\nAPI, or a listener may be added later, so analyzer confidence is lower;\nwarn encodes that without failing CI.",
1070
+ "$ref": "#/$defs/Severity",
1071
+ "default": "warn"
1072
+ },
1073
+ "unused-server-actions": {
1074
+ "description": "Next.js Server Action (an export of a `\"use server\"` file) referenced by\nno code in the project: no import-and-call, no `action={fn}` binding, no\n`<form action={fn}>`. Cross-graph dead-export direction, reclassified out\nof `unused-export` for `\"use server\"` files. Defaults to `warn`, not\n`error`: the rule is new and false-negative-preferring, and reflective\naction-dispatch shapes can hide a real consumer; warn encodes that\nwithout failing CI until corpus-validated.",
1075
+ "$ref": "#/$defs/Severity",
1076
+ "default": "error"
1077
+ },
1078
+ "unused-load-data-keys": {
1079
+ "description": "SvelteKit `+page.{ts,server.ts,js,server.js}` `load()` return-object key\nread by no consumer: not off the sibling `+page.svelte`'s `data.<key>`,\nnor project-wide via `page.data.<key>` / `$page.data.<key>`. Cross-file\ndead-input direction. Defaults to `warn`, not `error`: the rule is new and\nfalse-negative-preferring (a whole-object `data` pass abstains), and a\nload fetch can have side effects so deletion is a human call; warn encodes\nthat without failing CI until corpus-validated.",
1080
+ "$ref": "#/$defs/Severity",
1081
+ "default": "warn"
1082
+ },
1083
+ "prop-drilling": {
1084
+ "description": "React/Preact prop forwarded unchanged through `>= N` intermediate\npass-through components until a component that substantively consumes it.\nA graph-derived health signal. Defaults to `off` (opt-in), like\n`private-type-leak` / `security-*`: the located per-chain records and the\nsmall capped health penalty are dormant until the user enables the rule.",
1085
+ "$ref": "#/$defs/Severity",
1086
+ "default": "off"
1087
+ },
1088
+ "thin-wrapper": {
1089
+ "description": "A React/Preact component whose entire body is `return <Child {...props}/>`\n(pure structural indirection, a candidate for inlining). A graph-derived\nhealth signal. Defaults to `off` (opt-in), like `prop-drilling`: the\nlocated per-wrapper records are dormant until the user enables the rule.",
1090
+ "$ref": "#/$defs/Severity",
1091
+ "default": "off"
1092
+ },
1093
+ "duplicate-prop-shape": {
1094
+ "description": "Three or more React/Preact components across two or more files whose\nstatically-harvested prop NAME set is identical after stripping ubiquitous\nDOM / passthrough names (a missing shared `Props` type / base component).\nA graph-derived structural-refactor health signal. Defaults to `off`\n(opt-in), like `thin-wrapper`: the located per-component records are\ndormant until the user enables the rule.",
1095
+ "$ref": "#/$defs/Severity",
1096
+ "default": "off"
1097
+ },
1015
1098
  "unresolved-imports": {
1016
1099
  "$ref": "#/$defs/Severity",
1017
1100
  "default": "error"
@@ -1090,6 +1173,31 @@
1090
1173
  "description": "Master severity for rule-pack findings (`rulePacks` config). Defaults\nto `warn` so enabling a brand-new policy pack never hard-fails CI on\nits first run; individual pack rules opt up via `\"severity\": \"error\"`.\n`off` is a kill switch that disables the whole evaluator (per-rule\nseverity cannot resurrect it).",
1091
1174
  "$ref": "#/$defs/Severity",
1092
1175
  "default": "warn"
1176
+ },
1177
+ "invalid-client-export": {
1178
+ "description": "A `\"use client\"` file that exports a Next.js server-only /\nroute-segment config name (e.g. `metadata`, `revalidate`, `GET`).\nNext.js rejects this at build time; fallow catches it statically.\nDefaults to `warn`.",
1179
+ "$ref": "#/$defs/Severity",
1180
+ "default": "warn"
1181
+ },
1182
+ "mixed-client-server-barrel": {
1183
+ "description": "A barrel file that re-exports BOTH a `\"use client\"` origin module AND a\nserver-only origin module. Importing one name from such a barrel drags\nthe other's directive context across the React Server Components\nboundary (the Next.js App Router footgun). Defaults to `warn`.",
1184
+ "$ref": "#/$defs/Severity",
1185
+ "default": "warn"
1186
+ },
1187
+ "misplaced-directive": {
1188
+ "description": "A `\"use client\"` / `\"use server\"` directive written as an expression\nstatement after a non-directive statement (an import, a const), so the\nRSC bundler parses it as an ordinary string and silently ignores it.\nThe intended client/server boundary never takes effect. Defaults to\n`warn`.",
1189
+ "$ref": "#/$defs/Severity",
1190
+ "default": "warn"
1191
+ },
1192
+ "route-collision": {
1193
+ "description": "Two or more Next.js App Router route files that resolve to the same URL\nwithin one app-root. Next.js fails the build (\"You cannot have two\nparallel pages that resolve to the same path\"); fallow catches it\nstatically and names every colliding file. Defaults to `error`: the\nproject already fails `next build`, so flagging it as an error aligns\nfallow's exit code with the build it mirrors.",
1194
+ "$ref": "#/$defs/Severity",
1195
+ "default": "error"
1196
+ },
1197
+ "dynamic-segment-name-conflict": {
1198
+ "description": "Sibling Next.js dynamic route segments at one tree position using\ndifferent param spellings (`[id]` vs `[slug]`). Next.js throws \"You\ncannot use different slug names for the same dynamic path\" at dev and\nproduction runtime when the position is hit; `next build` does NOT catch\nit (the build succeeds), so CI passes while the route crashes on its\nfirst request. fallow catches it statically. Defaults to `error`: the\nroute is a deterministic runtime crash on first request, so failing CI\nis the honest signal even though `next build` stays green (this is the\n\"error-runtime\" severity tier, shared with `route-collision`).",
1199
+ "$ref": "#/$defs/Severity",
1200
+ "default": "error"
1093
1201
  }
1094
1202
  }
1095
1203
  },
@@ -1591,6 +1699,136 @@
1591
1699
  }
1592
1700
  ]
1593
1701
  },
1702
+ "unused-store-members": {
1703
+ "anyOf": [
1704
+ {
1705
+ "$ref": "#/$defs/Severity"
1706
+ },
1707
+ {
1708
+ "type": "null"
1709
+ }
1710
+ ]
1711
+ },
1712
+ "unprovided-injects": {
1713
+ "anyOf": [
1714
+ {
1715
+ "$ref": "#/$defs/Severity"
1716
+ },
1717
+ {
1718
+ "type": "null"
1719
+ }
1720
+ ]
1721
+ },
1722
+ "unrendered-components": {
1723
+ "anyOf": [
1724
+ {
1725
+ "$ref": "#/$defs/Severity"
1726
+ },
1727
+ {
1728
+ "type": "null"
1729
+ }
1730
+ ]
1731
+ },
1732
+ "unused-component-props": {
1733
+ "anyOf": [
1734
+ {
1735
+ "$ref": "#/$defs/Severity"
1736
+ },
1737
+ {
1738
+ "type": "null"
1739
+ }
1740
+ ]
1741
+ },
1742
+ "unused-component-emits": {
1743
+ "anyOf": [
1744
+ {
1745
+ "$ref": "#/$defs/Severity"
1746
+ },
1747
+ {
1748
+ "type": "null"
1749
+ }
1750
+ ]
1751
+ },
1752
+ "unused-component-inputs": {
1753
+ "anyOf": [
1754
+ {
1755
+ "$ref": "#/$defs/Severity"
1756
+ },
1757
+ {
1758
+ "type": "null"
1759
+ }
1760
+ ]
1761
+ },
1762
+ "unused-component-outputs": {
1763
+ "anyOf": [
1764
+ {
1765
+ "$ref": "#/$defs/Severity"
1766
+ },
1767
+ {
1768
+ "type": "null"
1769
+ }
1770
+ ]
1771
+ },
1772
+ "unused-svelte-events": {
1773
+ "anyOf": [
1774
+ {
1775
+ "$ref": "#/$defs/Severity"
1776
+ },
1777
+ {
1778
+ "type": "null"
1779
+ }
1780
+ ]
1781
+ },
1782
+ "unused-server-actions": {
1783
+ "anyOf": [
1784
+ {
1785
+ "$ref": "#/$defs/Severity"
1786
+ },
1787
+ {
1788
+ "type": "null"
1789
+ }
1790
+ ]
1791
+ },
1792
+ "unused-load-data-keys": {
1793
+ "anyOf": [
1794
+ {
1795
+ "$ref": "#/$defs/Severity"
1796
+ },
1797
+ {
1798
+ "type": "null"
1799
+ }
1800
+ ]
1801
+ },
1802
+ "prop-drilling": {
1803
+ "anyOf": [
1804
+ {
1805
+ "$ref": "#/$defs/Severity"
1806
+ },
1807
+ {
1808
+ "type": "null"
1809
+ }
1810
+ ]
1811
+ },
1812
+ "thin-wrapper": {
1813
+ "anyOf": [
1814
+ {
1815
+ "$ref": "#/$defs/Severity"
1816
+ },
1817
+ {
1818
+ "type": "null"
1819
+ }
1820
+ ]
1821
+ },
1822
+ "duplicate-prop-shape": {
1823
+ "anyOf": [
1824
+ {
1825
+ "$ref": "#/$defs/Severity"
1826
+ },
1827
+ {
1828
+ "type": "null"
1829
+ }
1830
+ ]
1831
+ },
1594
1832
  "unresolved-imports": {
1595
1833
  "anyOf": [
1596
1834
  {
@@ -1780,6 +2018,56 @@
1780
2018
  "type": "null"
1781
2019
  }
1782
2020
  ]
2021
+ },
2022
+ "invalid-client-export": {
2023
+ "anyOf": [
2024
+ {
2025
+ "$ref": "#/$defs/Severity"
2026
+ },
2027
+ {
2028
+ "type": "null"
2029
+ }
2030
+ ]
2031
+ },
2032
+ "mixed-client-server-barrel": {
2033
+ "anyOf": [
2034
+ {
2035
+ "$ref": "#/$defs/Severity"
2036
+ },
2037
+ {
2038
+ "type": "null"
2039
+ }
2040
+ ]
2041
+ },
2042
+ "misplaced-directive": {
2043
+ "anyOf": [
2044
+ {
2045
+ "$ref": "#/$defs/Severity"
2046
+ },
2047
+ {
2048
+ "type": "null"
2049
+ }
2050
+ ]
2051
+ },
2052
+ "route-collision": {
2053
+ "anyOf": [
2054
+ {
2055
+ "$ref": "#/$defs/Severity"
2056
+ },
2057
+ {
2058
+ "type": "null"
2059
+ }
2060
+ ]
2061
+ },
2062
+ "dynamic-segment-name-conflict": {
2063
+ "anyOf": [
2064
+ {
2065
+ "$ref": "#/$defs/Severity"
2066
+ },
2067
+ {
2068
+ "type": "null"
2069
+ }
2070
+ ]
1783
2071
  }
1784
2072
  }
1785
2073
  },
@@ -111,7 +111,7 @@ Route by intent before reaching for the big analysis commands. Same matrix as `f
111
111
  | `flags` | Detect feature flag patterns (env vars, SDK calls, config objects) | `--top` |
112
112
  | `explain` | Explain one issue type without running analysis | `<issue-type>`, `--format json` |
113
113
  | `audit` | Combined dead-code + complexity + duplication for changed files | `--base`, `--gate`, `--production`, `--production-dead-code`, `--production-health`, `--production-dupes`, `--workspace`, `--changed-workspaces`, `--ci`, `--fail-on-issues`, `--explain`, `--explain-skipped`, `--dead-code-baseline`, `--health-baseline`, `--dupes-baseline`, `--max-crap`, `--coverage`, `--coverage-root`, `--include-entry-exports` |
114
- | `impact` | Show what fallow has done for you: how many issues it is surfacing, the trend since the last recorded run, and how many commits it contained at the pre-commit gate | |
114
+ | `impact` | Show what fallow has done for you: how many issues it is surfacing, the trend since the last recorded run, and how many commits it contained at the pre-commit gate | `--all`, `--sort`, `--limit` |
115
115
  | `security` | Surface opt-in local security candidates for agent verification (not confirmed vulnerabilities). Rule families include the graph rule `client-server-leak`, a data-driven `tainted-sink` catalogue, and the include-required `hardcoded-secret` category for provider-prefix credentials and high-entropy literals assigned to secret-shaped identifiers. Most catalogue rows require non-literal input; narrowly literal-aware rows flag deterministic unsafe literals. Rules default off; suppress a file with `// fallow-ignore-file security-sink`; scope categories with `security.categories`. Add project-local request object names with `security.requestReceivers`; it extends the built-in `req` / `request` / `ctx` / `context` / `event` allowlist for HTTP `query`, `params`, and `body` reads. `hardcoded-secret` runs only when listed in `security.categories.include`. | `--format human\|json\|sarif`, `--changed-since`, `--file`, `--diff-file`, `--workspace`, `--changed-workspaces`, `--surface`, `--ci`, `--fail-on-issues`, `--sarif-file`, `--summary` |
116
116
  | `schema` | Dump CLI definition as JSON | |
117
117
  | `ci-template` | Print or vendor CI integration templates | |
@@ -141,6 +141,7 @@ Run `fallow <command> --help` for the full flag list per command (see also refer
141
141
  | `test-only-dependency` | `--unused-deps` | - | - | Production deps only imported from test files (should be devDependencies) |
142
142
  | `unused-enum-member` | `--unused-enum-members` | yes | `// fallow-ignore-next-line unused-enum-member` | Enum values never referenced |
143
143
  | `unused-class-member` | `--unused-class-members` | - | `// fallow-ignore-next-line unused-class-member` | Methods and properties |
144
+ | `unused-store-member` | `--unused-store-members` | - | `// fallow-ignore-next-line unused-store-member` | Pinia store state/getter/action (needs `pinia` dep) |
144
145
  | `unresolved-import` | `--unresolved-imports` | - | `// fallow-ignore-next-line unresolved-import` | Imports that can't be resolved |
145
146
  | `unlisted-dependency` | `--unlisted-deps` | - | - | Used packages missing from package.json. In monorepos, importing a workspace package from a workspace whose own `package.json` does not list it is reported here too; self-references stay allowed without requiring a package to depend on itself. |
146
147
  | `duplicate-export` | `--duplicate-exports` | - | `// fallow-ignore-file duplicate-export` | Same symbol exported from multiple modules |
@@ -156,6 +157,23 @@ Run `fallow <command> --help` for the full flag list per command (see also refer
156
157
  | `unresolved-catalog-reference` | `--unresolved-catalog-references` | - | - | `package.json` references to `catalog:` / `catalog:<name>` whose catalog does not declare the package; `pnpm install` would fail. Default `error`. Suppress via `ignoreCatalogReferences: [{ package, catalog?, consumer? }]` in fallow config (package.json has no comment syntax). |
157
158
  | `unused-dependency-override` | `--unused-dependency-overrides` | - | - | `pnpm-workspace.yaml#overrides` / `package.json#pnpm.overrides` entries whose target package is not declared by any workspace `package.json` and is not present in `pnpm-lock.yaml`. Default `warn`. When the lockfile is missing or unreadable the check degrades to a manifest-only fallback and every finding carries a `hint` reminding consumers to verify before removal. Suppress via `ignoreDependencyOverrides: [{ package, source? }]` in fallow config. |
158
159
  | `misconfigured-dependency-override` | `--misconfigured-dependency-overrides` | - | - | `pnpm.overrides` entries whose key is unparsable (empty, dangling separators, malformed selectors) or value is missing/empty. `pnpm install` would fail. Default `error`. Suppression: same `ignoreDependencyOverrides` config rule. |
160
+ | `invalid-client-export` | - | - | `// fallow-ignore-next-line invalid-client-export` | "use client" file exports a server-only / route-config name; Requires the project to declare next |
161
+ | `mixed-client-server-barrel` | - | - | `// fallow-ignore-next-line mixed-client-server-barrel` | Barrel re-exports both a "use client" module and a server-only module; Requires the project to declare next |
162
+ | `misplaced-directive` | - | - | `// fallow-ignore-next-line misplaced-directive` | "use client" / "use server" directive is not in the leading position and is ignored; Requires the project to declare next |
163
+ | `unprovided-inject` | `--unprovided-injects` | - | `// fallow-ignore-next-line unprovided-inject` | inject() / getContext() reads a key that no provide() / setContext() supplies |
164
+ | `unrendered-component` | `--unrendered-components` | - | `// fallow-ignore-next-line unrendered-component` | A Vue / Svelte component is reachable through a barrel but rendered nowhere |
165
+ | `unused-component-prop` | `--unused-component-props` | - | `// fallow-ignore-next-line unused-component-prop` | A Vue defineProps prop or React component prop is referenced nowhere in its own component |
166
+ | `unused-component-emit` | `--unused-component-emits` | - | `// fallow-ignore-next-line unused-component-emit` | A Vue <script setup> defineEmits event is emitted nowhere in its own component |
167
+ | `unused-component-input` | `--unused-component-inputs` | - | `// fallow-ignore-next-line unused-component-input` | An Angular @Input() / signal input() / model() is read nowhere in its own component (class body or template); needs `@angular/core` dep |
168
+ | `unused-component-output` | `--unused-component-outputs` | - | `// fallow-ignore-next-line unused-component-output` | An Angular @Output() / signal output() is emitted (.emit()) nowhere in its own component; needs `@angular/core` dep |
169
+ | `unused-svelte-event` | `--unused-svelte-events` | - | `// fallow-ignore-next-line unused-svelte-event` | A Svelte createEventDispatcher event is listened to nowhere in the project; needs `svelte` dep |
170
+ | `unused-server-action` | `--unused-server-actions` | - | `// fallow-ignore-next-line unused-server-action` | A Next.js Server Action exported from a "use server" file is referenced by no code in the project |
171
+ | `unused-load-data-key` | `--unused-load-data-keys` | - | `// fallow-ignore-next-line unused-load-data-key` | A SvelteKit load() return-object key is read by no consumer (needs @sveltejs/kit dep) |
172
+ | `prop-drilling` | - | - | `// fallow-ignore-next-line prop-drilling` | A React/Preact prop is forwarded unchanged through 3+ pass-through components to a distant consumer; Opt-in: set rules.prop-drilling to warn or error to enable. Defaults to off. |
173
+ | `thin-wrapper` | - | - | `// fallow-ignore-next-line thin-wrapper` | A React/Preact component whose whole body is a single spread-forwarded child render (a candidate for inlining); Opt-in: set rules.thin-wrapper to warn or error to enable. Defaults to off. |
174
+ | `duplicate-prop-shape` | - | - | `// fallow-ignore-next-line duplicate-prop-shape` | Three or more React/Preact components across two or more files declare an identical prop-name set (a missing shared Props type); Opt-in: set rules.duplicate-prop-shape to warn or error to enable. Defaults to off. |
175
+ | `route-collision` | - | - | - | Two or more Next.js App Router route files resolve to the same URL |
176
+ | `dynamic-segment-name-conflict` | - | - | - | Sibling Next.js dynamic route segments use different slug names at the same position |
159
177
  | `high-cyclomatic-complexity` | `--complexity` | - | `// fallow-ignore-next-line complexity` | Function has high cyclomatic complexity |
160
178
  | `high-cognitive-complexity` | `--complexity` | - | `// fallow-ignore-next-line complexity` | Function has high cognitive complexity |
161
179
  | `high-complexity` | `--complexity` | - | `// fallow-ignore-next-line complexity` | Function exceeds both complexity thresholds |
@@ -199,6 +217,7 @@ When using fallow via MCP (`fallow-mcp`), the following tools are available:
199
217
  | `list_boundaries` | introspection | free | - | Architecture boundary zones, access rules, and pre-expansion `autoDiscover` `logical_groups[]` (user-authored parent name, verbatim paths, discovered children, `status` enum, summed `file_count`). Returns `{"configured": false}` if no boundaries configured |
200
218
  | `feature_flags` | analysis | free | `workspace`, `production` | Detect feature flag patterns (env vars, SDK calls, config objects). Set `top` to limit results |
201
219
  | `impact` | introspection | free | `root` | Read the local, opt-in Fallow Impact value report (`fallow impact --format json`). Runs no analysis: current surfacing counts, trend since the last recorded run, pre-commit gate containment, and (on impact v1.5+) resolved/suppressed attribution. History is read from a per-project file in the user's private config dir (never inside the repo). Read-only and `root`-only; the mutating `enable` / `disable` / `default` lifecycle is not exposed. A never-enabled project returns a populated `{"enabled": false, ...}` report (never `{}`); branch on `enabled` and `enabled_source` (`project` / `user` / `default`) then `record_count`, recommending `fallow impact enable` only when `explicit_decision` is `false` (never asked) and staying silent when `true` (deliberately disabled here). Local-developer signal: fallow never records in CI, so empty there and not a CI metric |
220
+ | `impact_all` | introspection | free | `sort`, `limit` | Roll every tracked fallow project on this machine into one cross-repo value report (hashed keys plus basename labels, never paths; local-dev only) |
202
221
  | `trace_export` | trace | free | `file`, `export_name` | Trace why an export is used or unused (`fallow dead-code --trace FILE:EXPORT_NAME --format json`). Required `file` and `export_name`. Returns file reachability, entry-point status, direct references, re-export chains, and a reason string. Use before deleting a supposedly-unused export |
203
222
  | `trace_file` | trace | free | `file` | Trace all graph edges for a file (`fallow dead-code --trace-file PATH --format json`). Required `file`. Returns reachability, exports, imports-from, imported-by, and re-exports. Use to decide whether a file is isolated, barrel-only, or imported by live entry points |
204
223
  | `trace_dependency` | trace | free | `package_name` | Trace where a dependency is imported (`fallow dead-code --trace-dependency PACKAGE --format json`). Required `package_name`. Returns importing files, type-only importers, total import count, `used_in_scripts` (true when invoked from package.json scripts or CI configs), and `is_used` (combined import + script signal; mirrors the unused-deps detector so build tools like `microbundle` or `vitest` are not falsely flagged as unused). Use before removing a dependency or moving between `dependencies` and `devDependencies` |
@@ -234,7 +253,6 @@ Embedding fallow in a Node.js process (editor extensions, servers, custom toolin
234
253
  ## Common Workflows
235
254
 
236
255
  ### Audit a project for cleanup opportunities
237
-
238
256
  ```bash
239
257
  fallow dead-code --format json --quiet
240
258
  ```
@@ -242,13 +260,11 @@ fallow dead-code --format json --quiet
242
260
  Parse the JSON output. It contains arrays for each issue type (`unused_files`, `unused_exports`, `unused_types`, `unused_dependencies`, etc.) plus `total_issues` and `elapsed_ms` metadata. Each issue object includes an `actions` array with structured fix suggestions (action type, `auto_fixable` flag, description, and optional suppression comment). For dependency findings, a non-empty `used_in_workspaces` array means the package is imported elsewhere in the monorepo; treat it as a workspace placement issue and do not auto-remove it.
243
261
 
244
262
  ### Find only unused exports (smaller output)
245
-
246
263
  ```bash
247
264
  fallow dead-code --format json --quiet --unused-exports
248
265
  ```
249
266
 
250
267
  ### Check if a PR introduces quality risk
251
-
252
268
  ```bash
253
269
  fallow audit --format json --quiet --base main
254
270
  ```
@@ -256,7 +272,6 @@ fallow audit --format json --quiet --base main
256
272
  Returns a pass/warn/fail verdict for issues introduced by the PR. Only analyzes files changed since the `main` branch.
257
273
 
258
274
  ### Find code duplication
259
-
260
275
  ```bash
261
276
  fallow dupes --format json --quiet
262
277
  fallow dupes --format json --quiet --mode semantic
@@ -265,7 +280,6 @@ fallow dupes --format json --quiet --mode semantic
265
280
  The `semantic` mode detects renamed variables. Other modes: `strict` (exact), `mild` (default, syntax normalized), `weak` (different literals).
266
281
 
267
282
  ### Safe auto-fix cycle
268
-
269
283
  ```bash
270
284
  fallow fix --dry-run --format json --quiet # 1. preview what will be removed
271
285
  fallow fix --yes --format json --quiet # 2. review the preview, then apply
@@ -275,7 +289,6 @@ fallow dead-code --format json --quiet # 3. verify the fix worked
275
289
  The `--yes` flag is required in non-TTY environments (agent subprocesses). Without it, `fix` exits with code 2.
276
290
 
277
291
  ### Discover project structure
278
-
279
292
  ```bash
280
293
  fallow list --entry-points --format json --quiet
281
294
  fallow list --plugins --format json --quiet
@@ -284,7 +297,6 @@ fallow list --plugins --format json --quiet
284
297
  Shows detected entry points and active framework plugins (122 built-in: Next.js, Vite, Ember, Wuchale, Jest, Storybook, Tailwind, PandaCSS, Contentlayer, tap, tsd, etc.).
285
298
 
286
299
  ### Production-only analysis
287
-
288
300
  ```bash
289
301
  fallow dead-code --format json --quiet --production
290
302
  ```
@@ -292,7 +304,6 @@ fallow dead-code --format json --quiet --production
292
304
  Excludes test/dev files (`*.test.*`, `*.spec.*`, `*.stories.*`) and only analyzes production scripts.
293
305
 
294
306
  ### Analyze specific workspaces
295
-
296
307
  ```bash
297
308
  fallow dead-code --format json --quiet --workspace my-package # single package (lists: web,admin)
298
309
  fallow dead-code --format json --quiet --workspace 'apps/*,!apps/legacy' # glob + !-exclude
@@ -302,7 +313,6 @@ fallow dead-code --format json --quiet --changed-workspaces origin/main # CI
302
313
  Scopes output while keeping the full cross-workspace graph. Patterns are tested against BOTH the package name AND the workspace path relative to the repo root; either match counts. `--changed-workspaces <REF>` auto-derives the set from `git diff` (the CI primitive; mutually exclusive with `--workspace`); a missing ref or non-git directory is a hard error (exit 2) rather than a silent full-scope fallback.
303
314
 
304
315
  ### Scope to specific files (lint-staged)
305
-
306
316
  ```bash
307
317
  fallow dead-code --format json --quiet --file src/utils.ts --file src/helpers.ts
308
318
  ```
@@ -310,7 +320,6 @@ fallow dead-code --format json --quiet --file src/utils.ts --file src/helpers.ts
310
320
  Only reports issues in the specified files. Project-wide dependency issues are suppressed. Warns on non-existent paths.
311
321
 
312
322
  ### Catch typos in entry file exports
313
-
314
323
  ```bash
315
324
  fallow dead-code --format json --quiet --include-entry-exports
316
325
  ```
@@ -318,7 +327,6 @@ fallow dead-code --format json --quiet --include-entry-exports
318
327
  Reports unused exports in entry files (package.json `main`/`exports`, framework pages). By default, exports in entry files are assumed externally consumed. This flag catches typos like `meatdata` instead of `metadata`.
319
328
 
320
329
  ### Detect feature flag patterns
321
-
322
330
  ```bash
323
331
  fallow flags --format json --quiet
324
332
  fallow flags --format json --quiet --top 20
@@ -327,7 +335,6 @@ fallow flags --format json --quiet --top 20
327
335
  Reports environment-variable gates (`process.env.FEATURE_*`), SDK calls from common flag providers, and config-object patterns, with flag locations, detection confidence, and a cross-reference against dead code. Only `--top N` is command-specific.
328
336
 
329
337
  ### Surface security candidates for verification
330
-
331
338
  ```bash
332
339
  fallow security --format json --quiet
333
340
  fallow security --format json --quiet --surface
@@ -338,7 +345,6 @@ git diff --cached --unified=0 | fallow security --gate new --diff-stdin --format
338
345
  These are unverified candidates, not confirmed vulnerabilities; an agent must verify trace, reachability, and evidence before editing. `--surface` adds a top-level `attack_surface[]` inventory for a verifier. The gate modes are `new` (candidates introduced on changed lines) and `newly-reachable` (candidates that became reachable from entry points, which needs `--changed-since <ref>`); there is no `all` mode by design. The gate fails with exit 8, distinct from the standard exit ladder.
339
346
 
340
347
  ### Find untested runtime-reachable code (coverage gaps)
341
-
342
348
  ```bash
343
349
  fallow health --format json --quiet --coverage-gaps
344
350
  ```
@@ -346,7 +352,6 @@ fallow health --format json --quiet --coverage-gaps
346
352
  Reports `untested-file` and `untested-export` findings: runtime-reachable code with no dependency path from any discovered test root. Opt-in and requires the full analysis pipeline.
347
353
 
348
354
  ### Find complexity hotspots, owners, and refactoring targets
349
-
350
355
  ```bash
351
356
  # Files that are both complex and frequently changing (needs a git repo)
352
357
  fallow health --format json --quiet --hotspots
@@ -361,7 +366,6 @@ fallow health --format json --quiet --hotspots --group-by owner
361
366
  `--ownership` implies `--hotspots` and `--effort` implies `--targets`. The global `--group-by` accepts `owner`, `directory`, `package`, or `section` (the `section` mode reads GitLab CODEOWNERS `[Section]` headers). Hotspots and ownership require a git repository.
362
367
 
363
368
  ### Explain why a complex function scored high
364
-
365
369
  ```bash
366
370
  fallow health --format json --quiet --complexity --complexity-breakdown
367
371
  ```
@@ -369,7 +373,6 @@ fallow health --format json --quiet --complexity --complexity-breakdown
369
373
  Adds a per-decision-point `contributions[]` array to every complexity finding (each `if`, `else-if`, loop, boolean operator, and `case` with its source line and cyclomatic/cognitive weight), so you can pinpoint the exact refactor target.
370
374
 
371
375
  ### Gate CI on regressions (baselines)
372
-
373
376
  ```bash
374
377
  # 1. Save the current issue counts as a regression baseline
375
378
  fallow dead-code --format json --quiet --save-regression-baseline .fallow/baseline.json
@@ -383,7 +386,6 @@ fallow dead-code --format json --quiet --baseline .fallow/snapshot.json
383
386
  `--save-regression-baseline` / `--regression-baseline` / `--fail-on-regression` / `--tolerance` are count-based gates; `--save-baseline` / `--baseline` are identity-based (track finding identity, fail on new). All six are global flags, so they also work on `health` and `dupes`. `audit` rejects the global baseline flags and uses `--dead-code-baseline` / `--health-baseline` / `--dupes-baseline` instead.
384
387
 
385
388
  ### Explain an issue type without running analysis
386
-
387
389
  ```bash
388
390
  fallow explain unused-export --format json
389
391
  fallow explain code-duplication
@@ -392,7 +394,6 @@ fallow explain code-duplication
392
394
  The issue type is a positional argument and accepts forms like `unused-export`, `fallow/unused-export`, `unused exports`, or `code duplication`. It runs no analysis and returns the rule rationale, a worked example, fix guidance, and the docs URL.
393
395
 
394
396
  ### Show what fallow has surfaced over time (Impact)
395
-
396
397
  ```bash
397
398
  # Enable once (local-only, opt-in, never uploads, never affects exit codes)
398
399
  fallow impact enable
@@ -403,7 +404,6 @@ fallow impact --format json --quiet
403
404
  `fallow impact enable` is a one-time, user-owned local action; the agent-facing line is the read step. History is stored per-project in the user's private config dir (never inside the repo, so no `.fallow/` or `.gitignore` changes); `fallow impact default on` enables it for every project at once. The report is read-only and is empty in CI (fallow never records there).
404
405
 
405
406
  ### Debug why something is flagged
406
-
407
407
  ```bash
408
408
  fallow dead-code --format json --quiet --trace src/utils.ts:myFunction # trace an export's usage chain
409
409
  fallow dead-code --format json --quiet --trace-file src/utils.ts # trace all edges for a file
@@ -411,7 +411,6 @@ fallow dead-code --format json --quiet --trace-dependency lodash # trace
411
411
  ```
412
412
 
413
413
  ### Migrate from knip or jscpd
414
-
415
414
  ```bash
416
415
  fallow migrate --dry-run # preview
417
416
  fallow migrate # apply; mirrors the source extension (knip.jsonc -> .fallowrc.jsonc); --jsonc / --toml force a format
@@ -420,7 +419,6 @@ fallow migrate # apply; mirrors the source extension (knip.jsonc ->
420
419
  Auto-detects `knip.json`, `knip.jsonc`, `.knip.json`, `.knip.jsonc`, `.jscpd.json`, and package.json embedded configs.
421
420
 
422
421
  ### Initialize a new config
423
-
424
422
  ```bash
425
423
  fallow init # creates .fallowrc.json, adds .fallow/ to .gitignore (--toml for fallow.toml)
426
424
  fallow init --agents # scaffolds a starter AGENTS.md prefilled from detected project info (never overwrites)
@@ -461,7 +459,6 @@ Fallow reads config from project root: `.fallowrc.json` > `.fallowrc.jsonc` > `f
461
459
  Rules: `"error"` (fail CI), `"warn"` (report only), `"off"` (skip detection). Other high-value fields: `ignoreDependencies`, `publicPackages` (public library packages whose exported API is never flagged), `cache.dir` / `cache.maxSizeMb`, `usedClassMembers` (extend the framework-invoked member allowlist), `resolve.conditions` (extra package.json export conditions). Field semantics and examples: [CLI Reference](references/cli-reference.md), "Configuration field notes".
462
460
 
463
461
  ### Inline suppression
464
-
465
462
  ```typescript
466
463
  // fallow-ignore-next-line
467
464
  export const keepThis = 1;