fallow 2.73.0 → 2.74.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.73.0",
3
+ "version": "2.74.0",
4
4
  "description": "Codebase intelligence for TypeScript and JavaScript. Finds unused code, duplication, circular dependencies, complexity hotspots, and architecture drift. Optional runtime intelligence layer (Fallow Runtime) adds production execution evidence. Rust-native, sub-second, 94 framework plugins.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -73,13 +73,13 @@
73
73
  "@tanstack/intent": "0.0.40"
74
74
  },
75
75
  "optionalDependencies": {
76
- "@fallow-cli/darwin-arm64": "2.73.0",
77
- "@fallow-cli/darwin-x64": "2.73.0",
78
- "@fallow-cli/linux-x64-gnu": "2.73.0",
79
- "@fallow-cli/linux-arm64-gnu": "2.73.0",
80
- "@fallow-cli/linux-x64-musl": "2.73.0",
81
- "@fallow-cli/linux-arm64-musl": "2.73.0",
82
- "@fallow-cli/win32-arm64-msvc": "2.73.0",
83
- "@fallow-cli/win32-x64-msvc": "2.73.0"
76
+ "@fallow-cli/darwin-arm64": "2.74.0",
77
+ "@fallow-cli/darwin-x64": "2.74.0",
78
+ "@fallow-cli/linux-x64-gnu": "2.74.0",
79
+ "@fallow-cli/linux-arm64-gnu": "2.74.0",
80
+ "@fallow-cli/linux-x64-musl": "2.74.0",
81
+ "@fallow-cli/linux-arm64-musl": "2.74.0",
82
+ "@fallow-cli/win32-arm64-msvc": "2.74.0",
83
+ "@fallow-cli/win32-x64-msvc": "2.74.0"
84
84
  }
85
85
  }
package/schema.json CHANGED
@@ -165,6 +165,7 @@
165
165
  "feature-flags": "off",
166
166
  "stale-suppressions": "warn",
167
167
  "unused-catalog-entries": "warn",
168
+ "empty-catalog-groups": "warn",
168
169
  "unresolved-catalog-references": "error",
169
170
  "unused-dependency-overrides": "warn",
170
171
  "misconfigured-dependency-overrides": "error"
@@ -953,6 +954,10 @@
953
954
  "$ref": "#/$defs/Severity",
954
955
  "default": "warn"
955
956
  },
957
+ "empty-catalog-groups": {
958
+ "$ref": "#/$defs/Severity",
959
+ "default": "warn"
960
+ },
956
961
  "unresolved-catalog-references": {
957
962
  "$ref": "#/$defs/Severity",
958
963
  "default": "error"
@@ -1039,7 +1044,7 @@
1039
1044
  "const": "feature-sliced"
1040
1045
  },
1041
1046
  {
1042
- "description": "Bulletproof React: app → features → shared + server.\nFeature modules are isolated from each other; shared utilities and server\ninfrastructure form the base layers.",
1047
+ "description": "Bulletproof React: app → features → shared + server.\nFeature modules are isolated from each other via `autoDiscover`: every\nimmediate child of `src/features/` becomes its own `features/<name>` zone,\nand cross-feature imports are reported as boundary violations.\n\n**Trade-off (intentional):** top-level files in `src/features/` (e.g.\n`src/features/index.ts` barrel, `src/features/types.ts`) do NOT match any\nchild pattern and are unclassified, meaning they are unrestricted by the\npreset. This is deliberate so feature barrels can re-export children\nwithout producing false-positive `features → features/<child>` violations.\nTo classify top-level files strictly, override the `features` zone with\nan explicit user definition that includes a `patterns` field.",
1043
1048
  "type": "string",
1044
1049
  "const": "bulletproof"
1045
1050
  }
@@ -1060,6 +1065,13 @@
1060
1065
  "type": "string"
1061
1066
  }
1062
1067
  },
1068
+ "autoDiscover": {
1069
+ "description": "Directories whose immediate child directories should become separate\nzones under this logical group.\n\nFor example, `{ \"name\": \"features\", \"autoDiscover\": [\"src/features\"] }`\ncreates zones such as `features/auth` and `features/billing`, each with\na pattern for its own subtree. Rules that reference `features` expand to\nevery discovered child zone. If `patterns` is also set, the parent zone\nremains as a fallback after discovered child zones.",
1070
+ "type": "array",
1071
+ "items": {
1072
+ "type": "string"
1073
+ }
1074
+ },
1063
1075
  "root": {
1064
1076
  "description": "Optional subtree scope for monorepo per-package boundaries.\n\nWhen set, the zone's `patterns` are matched against paths *relative*\nto this directory rather than the project root. At classification\ntime, fallow checks that a candidate path starts with `root` and\nstrips that prefix before glob-matching the patterns against the\nremainder. Files outside the subtree never match the zone.\n\nUseful for monorepos where each package has the same internal\ndirectory layout: instead of writing `packages/app/src/**` and\n`packages/core/src/**` (which collide on shared zone names), set\n`root: \"packages/app/\"` and `patterns: [\"src/**\"]` per package.\n\nTrailing slash and leading `./` are normalized; backslashes are\nconverted to forward slashes. Patterns must NOT redundantly include\nthe root prefix: `root: \"packages/app/\"` with\n`patterns: [\"packages/app/src/**\"]` is rejected with\n`FALLOW-BOUNDARY-ROOT-REDUNDANT-PREFIX` because patterns are\nresolved relative to the root.",
1065
1077
  "type": [
@@ -1069,8 +1081,7 @@
1069
1081
  }
1070
1082
  },
1071
1083
  "required": [
1072
- "name",
1073
- "patterns"
1084
+ "name"
1074
1085
  ]
1075
1086
  },
1076
1087
  "BoundaryRule": {
@@ -1419,6 +1430,16 @@
1419
1430
  }
1420
1431
  ]
1421
1432
  },
1433
+ "empty-catalog-groups": {
1434
+ "anyOf": [
1435
+ {
1436
+ "$ref": "#/$defs/Severity"
1437
+ },
1438
+ {
1439
+ "type": "null"
1440
+ }
1441
+ ]
1442
+ },
1422
1443
  "unresolved-catalog-references": {
1423
1444
  "anyOf": [
1424
1445
  {
@@ -100,6 +100,8 @@ cargo install fallow-cli # build from source
100
100
  | Test-only dependencies | n/a | Production deps only imported from test files (should be devDependencies) |
101
101
  | Unused pnpm catalog entries | `--unused-catalog-entries` | `pnpm-workspace.yaml` entries no workspace package.json references via `catalog:` (default `warn`) |
102
102
  | Unresolved pnpm catalog references | `--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). |
103
+ | Unused pnpm dependency overrides | `--unused-dependency-overrides` | `pnpm-workspace.yaml#overrides` / `package.json#pnpm.overrides` entries forcing a version no workspace package depends on. Default `warn`; the `hint` field flags entries that may be intentional pins for transitive CVEs. Suppress via `ignoreDependencyOverrides: [{ package, source? }]` in fallow config. |
104
+ | Misconfigured pnpm dependency overrides | `--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. |
103
105
 
104
106
  ## MCP Tools
105
107
 
@@ -192,7 +192,7 @@ fallow dupes --format json --quiet --baseline fallow-baselines/dupes.json --thre
192
192
 
193
193
  ## `fix`: Auto-Remove Unused Code
194
194
 
195
- Auto-removes unused exports and dependencies.
195
+ Auto-removes unused exports, dependencies, enum members, and pnpm catalog entries.
196
196
 
197
197
  ### Flags
198
198
 
@@ -204,6 +204,13 @@ Auto-removes unused exports and dependencies.
204
204
  | `--format` | `human\|json` | `human` | Output format |
205
205
  | `--quiet` | bool | `false` | Suppress progress bars |
206
206
 
207
+ ### What gets fixed
208
+
209
+ - Unused exports (removes the `export` keyword; whole-enum block when every member is unused)
210
+ - Unused dependencies (removed from `package.json`)
211
+ - Unused enum members (removed from the declaration)
212
+ - Unused pnpm catalog entries (removed from `pnpm-workspace.yaml` by line-aware deletion; comments preserved). When the last entry of a catalog group is removed, the header is rewritten to `catalog: {}` / `<name>: {}` so pnpm doesn't reject the resulting null value. Entries with non-empty `hardcoded_consumers` are skipped to avoid breaking `pnpm install`; the skip is surfaced in the JSON fix output as `{"type": "remove_catalog_entry", "applied": false, "skipped": true, "skip_reason": "hardcoded_consumers", "consumers": [...]}`. After a successful catalog edit the CLI emits a one-line `Run pnpm install to refresh pnpm-lock.yaml` reminder. The JSON envelope carries a top-level `"skipped"` count alongside `"total_fixed"` for partial-fix gating.
213
+
207
214
  ### Examples
208
215
 
209
216
  ```bash
@@ -425,7 +432,7 @@ fallow health --format json --quiet --trend
425
432
  ```json
426
433
  {
427
434
  "schema_version": 3,
428
- "version": "2.72.0",
435
+ "version": "2.73.0",
429
436
  "elapsed_ms": 32,
430
437
  "summary": {
431
438
  "files_analyzed": 482,
@@ -811,7 +818,7 @@ fallow audit \
811
818
  ```json
812
819
  {
813
820
  "schema_version": 3,
814
- "version": "2.72.0",
821
+ "version": "2.73.0",
815
822
  "command": "audit",
816
823
  "verdict": "fail",
817
824
  "changed_files_count": 12,
@@ -884,7 +891,7 @@ fallow flags --format json --quiet --workspace my-package
884
891
  ```json
885
892
  {
886
893
  "schema_version": 3,
887
- "version": "2.72.0",
894
+ "version": "2.73.0",
888
895
  "elapsed_ms": 116,
889
896
  "feature_flags": [],
890
897
  "total_flags": 0
@@ -1303,7 +1310,7 @@ The HTTP layer mirrors the bash `gh_api_retry` / `curl_retry` helpers: `FALLOW_A
1303
1310
  ```json
1304
1311
  {
1305
1312
  "schema_version": 3,
1306
- "version": "2.72.0",
1313
+ "version": "2.73.0",
1307
1314
  "elapsed_ms": 45,
1308
1315
  "total_issues": 12,
1309
1316
  "entry_points": {
@@ -1450,7 +1457,7 @@ When `--baseline` is used in combined output, the JSON includes a `baseline_delt
1450
1457
  ```json
1451
1458
  {
1452
1459
  "schema_version": 3,
1453
- "version": "2.72.0",
1460
+ "version": "2.73.0",
1454
1461
  "elapsed_ms": 82,
1455
1462
  "total_clones": 15,
1456
1463
  "total_lines_duplicated": 230,
@@ -1494,7 +1501,7 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
1494
1501
  {
1495
1502
  "check": {
1496
1503
  "schema_version": 3,
1497
- "version": "2.72.0",
1504
+ "version": "2.73.0",
1498
1505
  "elapsed_ms": 45,
1499
1506
  "total_issues": 12,
1500
1507
  "unused_files": [],
@@ -1516,7 +1523,7 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
1516
1523
  },
1517
1524
  "dupes": {
1518
1525
  "schema_version": 3,
1519
- "version": "2.72.0",
1526
+ "version": "2.73.0",
1520
1527
  "elapsed_ms": 82,
1521
1528
  "total_clones": 15,
1522
1529
  "total_lines_duplicated": 230,
@@ -1525,7 +1532,7 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
1525
1532
  },
1526
1533
  "health": {
1527
1534
  "schema_version": 3,
1528
- "version": "2.72.0",
1535
+ "version": "2.73.0",
1529
1536
  "elapsed_ms": 32,
1530
1537
  "summary": {},
1531
1538
  "findings": [],
@@ -117,12 +117,16 @@ stale_suppressions: StaleSuppression[]
117
117
  * Entries in pnpm-workspace.yaml's catalog: or catalogs: sections not referenced by any workspace package via the catalog: protocol.
118
118
  */
119
119
  unused_catalog_entries?: UnusedCatalogEntry[]
120
+ /**
121
+ * Named groups under pnpm-workspace.yaml's catalogs: section that declare no package entries. The top-level catalog: map is not reported.
122
+ */
123
+ empty_catalog_groups?: EmptyCatalogGroup[]
120
124
  /**
121
125
  * Workspace package.json references to catalogs (catalog: or catalog:<name>) that do not declare the consumed package. pnpm install will error until the named catalog grows to include the package or the reference is switched / removed.
122
126
  */
123
127
  unresolved_catalog_references?: UnresolvedCatalogReference[]
124
128
  /**
125
- * Entries in pnpm-workspace.yaml's overrides: section, or package.json's pnpm.overrides block, whose target package no workspace package depends on. Default severity is warn because some entries are intentional pins for transitive CVEs; the hint field flags the cases the conservative algorithm cannot disambiguate.
129
+ * Entries in pnpm-workspace.yaml's overrides: section, or package.json's pnpm.overrides block, whose target package is not declared by any workspace package and is not present in pnpm-lock.yaml. Default severity is warn because projects without a readable lockfile fall back to manifest-only checks; the hint field flags those conservative cases.
126
130
  */
127
131
  unused_dependency_overrides?: UnusedDependencyOverride[]
128
132
  /**
@@ -151,7 +155,7 @@ export interface FixAction {
151
155
  /**
152
156
  * Kebab-case identifier for the fix action.
153
157
  */
154
- type: ("remove-export" | "delete-file" | "remove-dependency" | "move-dependency" | "remove-enum-member" | "remove-class-member" | "resolve-import" | "install-dependency" | "remove-duplicate" | "move-to-dev" | "refactor-cycle" | "refactor-boundary" | "export-type" | "remove-catalog-entry" | "update-catalog-reference" | "add-catalog-entry" | "remove-catalog-reference" | "remove-dependency-override" | "fix-dependency-override")
158
+ type: ("remove-export" | "delete-file" | "remove-dependency" | "move-dependency" | "remove-enum-member" | "remove-class-member" | "resolve-import" | "install-dependency" | "remove-duplicate" | "move-to-dev" | "refactor-cycle" | "refactor-boundary" | "export-type" | "remove-catalog-entry" | "remove-empty-catalog-group" | "update-catalog-reference" | "add-catalog-entry" | "remove-catalog-reference" | "remove-dependency-override" | "fix-dependency-override")
155
159
  /**
156
160
  * Whether `fallow fix` can apply this fix automatically.
157
161
  */
@@ -215,9 +219,9 @@ export interface AddToConfigAction {
215
219
  */
216
220
  type: "add-to-config"
217
221
  /**
218
- * Always false for config actions.
222
+ * True when `fallow fix` can apply this config action automatically for the current action type. `ignoreExports` duplicate-export actions are auto-fixable when a config file exists; older scalar config-ignore actions remain manual.
219
223
  */
220
- auto_fixable: false
224
+ auto_fixable: boolean
221
225
  /**
222
226
  * Human-readable description of the config change.
223
227
  */
@@ -604,6 +608,25 @@ hardcoded_consumers?: string[]
604
608
  actions?: IssueAction[]
605
609
  introduced?: AuditIntroduced
606
610
  }
611
+ /**
612
+ * A named pnpm catalog group under catalogs: with no package entries.
613
+ */
614
+ export interface EmptyCatalogGroup {
615
+ /**
616
+ * Named catalog group under the top-level catalogs: map.
617
+ */
618
+ catalog_name: string
619
+ /**
620
+ * Relative path to pnpm-workspace.yaml.
621
+ */
622
+ path: string
623
+ /**
624
+ * 1-based line number of the empty catalog group header.
625
+ */
626
+ line: number
627
+ actions?: IssueAction[]
628
+ introduced?: AuditIntroduced
629
+ }
607
630
  /**
608
631
  * A workspace package.json reference (catalog: or catalog:<name>) pointing at a catalog that does not declare the consumed package. `pnpm install` will fail with ERR_PNPM_CATALOG_ENTRY_NOT_FOUND_FOR_CATALOG_PROTOCOL.
609
632
  */
@@ -668,7 +691,7 @@ path: string
668
691
  */
669
692
  line: number
670
693
  /**
671
- * Soft hint for cases the conservative algorithm cannot disambiguate (e.g. a transitive CVE pin not visible to static analysis). Omitted when absent.
694
+ * Soft hint reminding consumers to verify the override before removal. Present because projects without a readable lockfile use the conservative package-manifest fallback. Omitted when absent.
672
695
  */
673
696
  hint?: string
674
697
  actions?: IssueAction[]
@@ -739,6 +762,7 @@ circular_dependencies?: number
739
762
  boundary_violations?: number
740
763
  stale_suppressions?: number
741
764
  unused_catalog_entries?: number
765
+ empty_catalog_groups?: number
742
766
  unresolved_catalog_references?: number
743
767
  unused_dependency_overrides?: number
744
768
  misconfigured_dependency_overrides?: number