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.
@@ -61,6 +61,16 @@ Common global flags for this command: [`--format`](#global-flags), [`--quiet`](#
61
61
  | `--private-type-leaks` | Opt-in API hygiene check (default `off`) for exported signatures that reference same-file private types. Storybook `*.stories.*` story files and framework routing convention files (Next.js App + Pages Router, Gatsby, Remix v2, TanStack Router, Expo Router) are skipped to avoid noise. Enable via this flag or `private-type-leaks: "warn"` / `"error"` in [`rules`](#rules-configuration). |
62
62
  | `--unused-enum-members` | Unused enum members |
63
63
  | `--unused-class-members` | Unused class members |
64
+ | `--unused-store-members` | Unused Pinia store members |
65
+ | `--unprovided-injects` | inject() / getContext() reads a key that no provide() / setContext() supplies |
66
+ | `--unrendered-components` | A Vue / Svelte component is reachable through a barrel but rendered nowhere |
67
+ | `--unused-component-props` | A Vue defineProps prop or React component prop is referenced nowhere in its own component |
68
+ | `--unused-component-emits` | A Vue <script setup> defineEmits event is emitted nowhere in its own component |
69
+ | `--unused-component-inputs` | An Angular @Input() / signal input() / model() is read nowhere in its own component (class body or template); needs `@angular/core` dep |
70
+ | `--unused-component-outputs` | An Angular @Output() / signal output() is emitted (.emit()) nowhere in its own component; needs `@angular/core` dep |
71
+ | `--unused-svelte-events` | A Svelte createEventDispatcher event is listened to nowhere in the project |
72
+ | `--unused-server-actions` | A Next.js Server Action exported from a "use server" file is referenced by no code in the project |
73
+ | `--unused-load-data-keys` | A SvelteKit load() return-object key is read by no consumer |
64
74
  | `--unresolved-imports` | Unresolved imports |
65
75
  | `--unlisted-deps` | Unlisted dependencies |
66
76
  | `--duplicate-exports` | Duplicate exports |
@@ -146,8 +156,8 @@ By default, `fallow dupes` skips generated framework output matching `**/.next/*
146
156
  | `--threshold` | `string` | - | Fail if duplication exceeds this percentage |
147
157
  | `--skip-local` | `bool` | `false` | Only report cross-directory duplicates |
148
158
  | `--cross-language` | `bool` | `false` | Strip type annotations for TS↔JS matching |
149
- | `--ignore-imports` | `bool` | `false` | Exclude import declarations from clone detection |
150
- | `--no-ignore-imports` | `bool` | `false` | Count import declarations as clone candidates (opt out of the default import exclusion) |
159
+ | `--ignore-imports` | `bool` | `false` | Exclude module wiring from clone detection |
160
+ | `--no-ignore-imports` | `bool` | `false` | Count module wiring as clone candidates (opt out of the default exclusion) |
151
161
  | `--top` | `string` | - | Show only the N most-duplicated clone groups (sorted by instance count desc, tiebreak: line count desc, then path/line). Summary stats reflect the full project. |
152
162
  | `--trace` | `string` | - | Deep-dive clones. `FILE:LINE` traces all clones at a location; `dup:<id>` traces a clone group by the stable fingerprint shown in the listing and on `clone_groups[].fingerprint` in JSON. Fingerprints are usually `dup:<8hex>` and widen only on rare report collisions. Trace output adds an extract-function suggestion, estimated savings, and a best-effort proposed name per group |
153
163
 
@@ -384,6 +394,7 @@ Angular templates contribute synthetic `<template>` complexity findings whenever
384
394
  | `--ownership` | `bool` | `false` | Attach ownership signals to hotspot entries: bus factor (Avelino truck factor), contributor count, top contributor with stale-days, recent contributors (top-3), `suggested_reviewers`, declared CODEOWNERS owner, `ownership_state`, ownership drift, unowned-hotspot detection. Human output gains a project-level summary line. JSON adds `low-bus-factor`, `unowned-hotspot`, `ownership-drift` action types. Test files get a `[test]` tag. Implies `--hotspots`. Requires git. |
385
395
  | `--ownership-emails` | `raw\|handle\|anonymized\|hash` | - | Privacy mode for author emails. `handle` shows the local-part only (default, with GitHub noreply unwrap and deterministic same-handle disambiguation). `anonymized` emits stable `xxh3:` pseudonyms; `hash` remains accepted as the legacy spelling. `raw` shows full addresses. Use `anonymized` in regulated environments. Implies `--ownership`. Configure default via `health.ownership.emailMode`. |
386
396
  | `--targets` | `bool` | `false` | Show only refactoring targets: ranked recommendations based on complexity, coupling, churn, and dead code signals. Categories: churn+complexity, circular dep, high impact, dead code, complexity, coupling. When no section flags are set, all sections are shown by default. Each target's JSON can include `direct_callers[]` (direct importers with the symbols they import) and `clone_siblings[]` (duplicate-code siblings with stable `dup:<8hex>` fingerprints for `fallow dupes --trace`); both omitted when empty. Human output adds `importers:` / `clones:` lines only when that evidence is present. |
397
+ | `--css` | `bool` | `false` | Add structural CSS analytics: specificity hotspots, !important density, over-complex selectors, deep nesting, and conservative cleanup candidates. Standard CSS is parsed structurally; preprocessor sources are scanned only where fallow can avoid expanding Sass/Less semantics. |
387
398
  | `--effort` | `low\|medium\|high` | - | Filter refactoring targets by effort level. Implies `--targets`. |
388
399
  | `--score` | `bool` | `false` | Show only the project health score (0-100) with letter grade (A/B/C/D/F). The score is included by default when no section flags are set. JSON includes `health_score` object with `score`, `grade`, and `penalties` breakdown. As of v2.55.0, plain `--score` skips the churn-backed hotspot penalty so it does not run a `git log` shell-out per invocation; pass `--hotspots` (or `--targets` with `--score`) to include the hotspot penalty. Snapshot (`--save-snapshot`) and trend (`--trend`) flows still trigger hotspot vital signs so saved data stays complete. |
389
400
  | `--min-score` | `string` | - | Fail (exit 1) only when the health score is below this threshold. Implies `--score`. Authoritative CI quality gate: when set, complexity findings are demoted to informational and the exit code is driven solely by the score, so `--min-score 0` always exits 0. Composes with `--min-severity`. |
@@ -493,7 +504,7 @@ fallow health --format json --quiet --trend
493
504
  {
494
505
  "kind": "health",
495
506
  "schema_version": 7,
496
- "version": "2.96.0",
507
+ "version": "2.98.0",
497
508
  "elapsed_ms": 32,
498
509
  "summary": {
499
510
  "files_analyzed": 482,
@@ -880,7 +891,7 @@ fallow audit \
880
891
  {
881
892
  "kind": "audit",
882
893
  "schema_version": 7,
883
- "version": "2.96.0",
894
+ "version": "2.98.0",
884
895
  "command": "audit",
885
896
  "verdict": "fail",
886
897
  "changed_files_count": 12,
@@ -955,7 +966,7 @@ fallow flags --format json --quiet --workspace my-package
955
966
  ```json
956
967
  {
957
968
  "schema_version": 7,
958
- "version": "2.96.0",
969
+ "version": "2.98.0",
959
970
  "elapsed_ms": 116,
960
971
  "feature_flags": [],
961
972
  "total_flags": 0
@@ -1055,7 +1066,7 @@ fallow security --gate newly-reachable --changed-since origin/main
1055
1066
  {
1056
1067
  "kind": "security",
1057
1068
  "schema_version": "4",
1058
- "version": "2.96.0",
1069
+ "version": "2.98.0",
1059
1070
  "elapsed_ms": 42,
1060
1071
  "config": {
1061
1072
  "rules": {
@@ -1084,7 +1095,7 @@ fallow security --gate newly-reachable --changed-since origin/main
1084
1095
  {
1085
1096
  "kind": "security",
1086
1097
  "schema_version": "4",
1087
- "version": "2.96.0",
1098
+ "version": "2.98.0",
1088
1099
  "elapsed_ms": 42,
1089
1100
  "config": {
1090
1101
  "rules": {
@@ -1545,8 +1556,8 @@ Available on all commands:
1545
1556
  | `--dupes-min-occurrences` | `string` | - | Override the minimum clone occurrences in combined mode (must be >= 2) |
1546
1557
  | `--dupes-skip-local` | `bool` | `false` | Only report cross-directory duplicates in combined mode |
1547
1558
  | `--dupes-cross-language` | `bool` | `false` | Enable cross-language duplicate detection in combined mode |
1548
- | `--dupes-ignore-imports` | `bool` | `false` | Exclude import declarations from duplicate detection in combined mode |
1549
- | `--dupes-no-ignore-imports` | `bool` | `false` | Count import declarations as clone candidates in combined mode (opt out of the default import exclusion) |
1559
+ | `--dupes-ignore-imports` | `bool` | `false` | Exclude module wiring from duplicate detection in combined mode |
1560
+ | `--dupes-no-ignore-imports` | `bool` | `false` | Count module wiring as clone candidates in combined mode (opt out of the default exclusion) |
1550
1561
  | `--score` | `bool` | `false` | Compute health score (0-100 with letter grade) in combined mode. Enables the health delta header in PR comments. JSON includes `health_score` object with `score`, `grade`, and `penalties` breakdown |
1551
1562
  | `--trend` | `bool` | `false` | Compare current health metrics against saved snapshot. Implies `--score`. Shows per-metric deltas with directional indicators. Requires at least one saved snapshot in `.fallow/snapshots/` |
1552
1563
  | `--save-snapshot` | `string` | - | Save vital signs snapshot for trend tracking. Default path: `.fallow/snapshots/<timestamp>.json`. Forces file-scores + hotspot computation |
@@ -1574,7 +1585,7 @@ Available on all commands:
1574
1585
  | `--dupes-min-occurrences` | `string` | - | Override the minimum clone occurrences in combined mode (must be >= 2) |
1575
1586
  | `--dupes-skip-local` | `bool` | `false` | Only report cross-directory duplicates in combined mode |
1576
1587
  | `--dupes-cross-language` | `bool` | `false` | Enable cross-language duplicate detection in combined mode |
1577
- | `--dupes-ignore-imports` | `bool` | `false` | Exclude import declarations from duplicate detection in combined mode |
1588
+ | `--dupes-ignore-imports` | `bool` | `false` | Exclude module wiring from duplicate detection in combined mode |
1578
1589
  | `--score` | `bool` | `false` | Compute health score in combined mode |
1579
1590
  | `--trend` | `bool` | `false` | Compare current health metrics against the most recent saved snapshot |
1580
1591
  | `--save-snapshot` | `string` | - | Save a vital signs snapshot for trend tracking in combined mode. Provide a path or omit for the default `.fallow/snapshots/` location |
@@ -1701,7 +1712,7 @@ The HTTP layer mirrors the bash `gh_api_retry` / `curl_retry` helpers: `FALLOW_A
1701
1712
  {
1702
1713
  "kind": "dead-code",
1703
1714
  "schema_version": 7,
1704
- "version": "2.96.0",
1715
+ "version": "2.98.0",
1705
1716
  "elapsed_ms": 45,
1706
1717
  "total_issues": 12,
1707
1718
  "entry_points": {
@@ -1861,7 +1872,7 @@ When `--baseline` is used in combined output, the JSON includes a `baseline_delt
1861
1872
  {
1862
1873
  "kind": "dupes",
1863
1874
  "schema_version": 7,
1864
- "version": "2.96.0",
1875
+ "version": "2.98.0",
1865
1876
  "elapsed_ms": 82,
1866
1877
  "total_clones": 15,
1867
1878
  "total_lines_duplicated": 230,
@@ -1905,11 +1916,11 @@ When running `fallow` with no subcommand (all analyses), the JSON output combine
1905
1916
  {
1906
1917
  "kind": "combined",
1907
1918
  "schema_version": 7,
1908
- "version": "2.96.0",
1919
+ "version": "2.98.0",
1909
1920
  "elapsed_ms": 159,
1910
1921
  "check": {
1911
1922
  "schema_version": 7,
1912
- "version": "2.96.0",
1923
+ "version": "2.98.0",
1913
1924
  "elapsed_ms": 45,
1914
1925
  "total_issues": 12,
1915
1926
  "unused_files": [],
@@ -2131,4 +2142,4 @@ preset = "bulletproof"
2131
2142
 
2132
2143
  ### Valid Issue Type Tokens
2133
2144
 
2134
- `unused-file`, `unused-export`, `unused-type`, `unused-dependency`, `unused-dev-dependency`, `unused-enum-member`, `unused-class-member`, `unresolved-import`, `unlisted-dependency`, `duplicate-export`, `circular-dependency`, `re-export-cycle`, `boundary-violation`, `policy-violation`, `unused-optional-dependency`, `type-only-dependency`, `test-only-dependency`, `code-duplication`
2145
+ `unused-file`, `unused-export`, `unused-type`, `unused-dependency`, `unused-dev-dependency`, `unused-enum-member`, `unused-class-member`, `unused-store-member`, `unresolved-import`, `unlisted-dependency`, `duplicate-export`, `circular-dependency`, `re-export-cycle`, `boundary-violation`, `policy-violation`, `unused-optional-dependency`, `type-only-dependency`, `test-only-dependency`, `code-duplication`
@@ -78,6 +78,18 @@ Don't use `--changed-since` when auditing the full project. Use it for PR checks
78
78
 
79
79
  ---
80
80
 
81
+ ## Svelte Event Findings Are Project-Wide Listener Checks
82
+
83
+ `unused-svelte-event` reports a Svelte `createEventDispatcher` event that has no reachable listener in the project. This is different from `unused-component-emit`, which checks whether a Vue component ever emits its declared event.
84
+
85
+ ```bash
86
+ fallow dead-code --format json --quiet --unused-svelte-events
87
+ ```
88
+
89
+ Dynamic event names, dispatcher values that escape the component, and projects without a declared Svelte dependency are abstained to avoid false positives.
90
+
91
+ ---
92
+
81
93
  ## Filter Flags Are Additive
82
94
 
83
95
  Issue type filter flags (`--unused-exports`, `--unused-files`, etc.) are inclusive. They select which issue types to show. Using multiple flags shows the union.
@@ -323,6 +335,10 @@ Conservative semantics: a method carrying any decorator NOT in the list still ge
323
335
 
324
336
  The default empty list preserves today's skip-all behavior, so existing NestJS / Angular / TypeORM projects see no change.
325
337
 
338
+ ### Angular `@Input()` / `@Output()` are still covered by the component rules
339
+
340
+ The skip above applies only to generic `unused-class-member` detection. The dedicated Angular component rules (`unused-component-input` for `@Input()` / signal `input()` / `model()`, and `unused-component-output` for `@Output()` / signal `output()`, both default `warn`, gated on `@angular/core`) scope usage to the component itself: an input is dead when it is read by no code in its own class body or template (inline `template` or external `templateUrl`), and an output is dead when it is emitted (`.emit()`) nowhere in its own component. The scope is the component, not the project: an input that a parent binds via `[input]="..."` but the component itself never reads IS flagged, because the parent binding is satisfied while the value goes unused inside the component. These rules abstain on the whole component for any `extends` clause, a `{...this}` spread, JS-reserved-word names, accessor (`get` / `set`) inputs, and observable-stream `@Output`s (only `new EventEmitter()` initializers are harvested); `model()` is treated as input-only. Suppress an individual finding with `// fallow-ignore-next-line unused-component-input` or `-output`.
341
+
326
342
  ---
327
343
 
328
344
  ## JSDoc Visibility Tags Keep Exports Alive
@@ -462,6 +478,18 @@ Fallow marks `src/fragments/user-fields.graphql` or `src/fragments/user-fields.g
462
478
 
463
479
  ---
464
480
 
481
+ ## Tailwind v4 `@theme` Tokens Are Conservative Cleanup Candidates
482
+
483
+ When `fallow health --css` reports `css_analytics.unused_theme_tokens`, treat the rows as dead-design-token candidates, not as auto-fix instructions. A Tailwind v4 `@theme` token such as `--color-brand` is considered used when fallow sees a generated utility suffix such as `bg-brand` or `text-brand`, a `var(--color-brand)` read, an `@apply` utility, a Tailwind arbitrary value such as `rounded-[--radius-card]`, or another `@theme` token that references it.
484
+
485
+ The detector intentionally abstains when a Tailwind plugin or published CSS surface could consume tokens invisibly. Always run the row's `actions[].command` verification before deleting a token, and do not run `fallow fix` for these rows.
486
+
487
+ ## CSS Health Candidates Are Advisory
488
+
489
+ `fallow health --css` also emits advisory cleanup and typo candidates in `css_analytics.unreferenced_css_classes` (a plain-CSS class defined but matched by no `class`/`className` in project markup), `css_analytics.unresolved_class_references` (the reverse: a markup class one edit away from a defined class, a likely typo), `css_analytics.unused_font_faces`, `css_analytics.undefined_keyframes`, and `css_analytics.font_size_unit_mix`. Treat them like review prompts, not confirmed defects. Run each row's `actions[].command` before changing CSS, because fonts, classes, animations, and type scales can be driven by inline styles, JavaScript, CMS templates, or preprocessor expansion that static analysis intentionally does not execute.
490
+
491
+ ---
492
+
465
493
  ## Library Packages: Use `publicPackages` Instead of Visibility Tags
466
494
 
467
495
  In monorepos, shared library packages have exported APIs consumed by external consumers not visible to fallow. Instead of annotating every export with `/** @public */` (or `@internal`, `@beta`, `@alpha`), use the `publicPackages` config to mark entire workspace packages as public libraries. Exports and exported enum/class members from these packages are excluded from unused API detection.