v2.76.0: --diff-file scopes every finding, schema-derive ladder lands, fallow_core deprecated
Highlights
-
--diff-filenow filters every finding, not just the runtime-coverage section. A single flag scopes unused-export, complexity hotspot, clone family, boundary violation, and runtime-coverage findings to lines inside an added hunk, so the JSONtotal_issuesalready matches what your PR introduces. CI pipelines previously running a downstream jq filter (filter-changed.jq) can drop it; the--diff-stdinalias acceptsgh pr diff | fallow audit --diff-file -. Closes #424. -
fallow fixknows about pnpm-catalog comment blocks. A newfix.catalog.deletePrecedingCommentsknob (autodefault, plusalways/never) deletes a contiguous YAML comment block when removing the catalog entry it documents, with two escape hatches: a# fallow-keepmarker on any line and anauto-policy banner heuristic for# === React 18 pins ===-style headers. The JSON action gains anentry_linefield alongsidelineso annotators can pick either anchor unambiguously. Closes #360. -
fallow fixcreates.fallowrc.jsonwhen no fallow config exists. Previously the duplicate-exportadd-to-configfix told you to runfallow initfirst, then re-runfallow fix --yes. Now the fixer materialises the same framework-aware scaffoldingfallow initwould emit, layers yourignoreExportsrules on top, and skips when invoked from a monorepo subpackage (with a targeted error pointing at the workspace root).--dry-runpreviews the write as a unified diff in both human and JSON modes. Closes #332. -
Architecture boundaries: opt-in
allowTypeOnlylets type-only imports cross zones.{ from: "featureB", allowTypeOnly: ["featureA"] }allowsimport type {...}, inlineimport { type Foo }(when every named specifier carries thetypequalifier), andexport type { Foo } from "..."across zones without a runtime dependency. Mixed-specifier imports still fire. Strictly additive: omitting the field preserves pre-feature behavior. Closes #365. Thanks @DrJonki. -
Angular component complexity rollup.
fallow health --complexity(andaudit,combined) now emits a synthetic<component>finding per Angular component whose class function findings AND template both cleared the cyclomatic / cognitive thresholds. The rollup sumsworst_class_method + templateand ships acomponent_rolluppayload so the breakdown stays visible. Component-inherited CRAP provenance also lands on synthetic<template>findings via the inversetemplateUrledge, withcoverage_source: "estimated_component_inherited"andinherited_fromon the wire. Closes #234. Refs #186 tier 1. -
autoDiscoverparent zones now auto-allow their discovered children. Top-level barrels (src/features/index.ts) can re-export feature modules without false-positive cross-zone violations. The Bulletproof preset gainspatterns: ["src/features/**"]on thefeatureszone so non-barrel top-level files (src/features/types.ts) classify under the parent zone and still obey thefeaturesrule. Closes #372. -
fallow list --boundaries --format jsonsurfaces the logical group name forautoDiscoverzones. Config UIs and Sankey renderers no longer need to reconstruct the grouping from thefeatures/<child>naming convention; a parallellogical_groups[]array carriesname,children,auto_discover,status,source_zone_index,file_count, plus byte-accurate config-patch metadata. Closes #373.
Schema-derive ladder shipped
Issue #384 closes in this release. Every object-shaped --format json envelope (AuditOutput, CheckOutput, CombinedOutput, DupesOutput, HealthOutput, ExplainOutput, CoverageSetupOutput, CoverageAnalyzeOutput, ReviewEnvelopeOutput, ReviewReconcileOutput, ListBoundariesOutput) is now a variant of a typed FallowOutput enum derived from Rust source via schemars. The document-root oneOf block in docs/output-schema.json is regenerated instead of hand-maintained, and every legacy inject_*_actions JSON post-pass in report/json.rs is retired in favour of typed *Finding envelope wrappers that flatten the bare payload and carry actions: T[] natively. Wire shape is byte-identical (verified against vue-core, vite, preact, zod, next.js); the codegen-derived TS contracts in editors/vscode/src/generated/output-contract.d.ts and npm/fallow/types/output-contract.d.ts expose FallowOutput as a discriminated union, plus backwards-compat aliases for the bare names that json-schema-to-typescript dedupes away.
fallow_core deprecated for external consumers
Per ADR-008, the top-level entry points (analyze, analyze_with_usages, analyze_with_trace, analyze_retaining_modules, analyze_with_parse_result, analyze_project), the fallow_core::analyze::* detector helpers, and the feature-flag helpers (collect_feature_flags, correlate_with_dead_code) now carry #[deprecated(since = "2.76.0")] annotations pointing external consumers at fallow_cli::programmatic. Workspace path-dependency callers continue to compile via #[expect(deprecated)]. The next minor release (target 2.77.0, no earlier than 2026-Q3) will flip publish = false on fallow-core; this release is the one-cycle warning window. See docs/fallow-core-migration.md for the function-by-function map. Closes #418.
Bug fixes
-
typeof import('./path').Xinside.d.tsambient declarations now traces the target file. unplugin-auto-import'sauto-imports.d.tsand unplugin-vue-components'components.d.tsno longer surface their composables and components asunused-files. Declaration files are also auto-promoted to entry points so module-augmentation interfaces likeGlobalComponentsskip unused-export checks (pass--include-entry-exportsto opt back in). Closes #396, #397. Thanks @wouterkroes. -
new URL('./', import.meta.url)no longer flags./as an unresolved import. Directory-only specifiers (./,../, paths ending in/) are now skipped because they construct a directory URL, not a file URL. File-pointing specifiers (./worker.js,./assets/foo.svg) are unaffected. Closes #399. Thanks @wouterkroes. -
Standalone
export default <template>...</template>in.gtsfiles now extracts imports and the default export. The v2.75.0 multi-template fix only treated single-byte expression delimiters as expression position, so the canonical template-only-component shape fell through and oxc dropped every import in the file. Closes #379. -
Abstract base-class methods called through a generic-constrained
this.<field>are credited. ABaseService<TClient extends BaseClient>withconstructor(client: TClient)and a body callingthis.client.fetchLatest(id)now resolves toBaseClient.fetchLatestthrough the existing bound-member-access pipeline. Closes #388. Thanks @vethman. -
Fluent-builder chains credit intermediate setters.
EventBuilder.createWithDefaults().setProcessId("x").setSubject("y").build()no longer flags every setter as unused; a newpropagate_fluent_chain_accessespass walks each chain step against the resolved class export and creditsis_self_returningmethods reached from anis_instance_returning_staticroot. Closes #387. Thanks @vethman. -
Class methods reached via a typed getter chain inside a Playwright fixture teardown are credited. Typed getter declarations now register as instance bindings, so a fixture pattern like
get processEventsService() { return container.resolve(ProcessEventsService); }followed byfixtures.processEventsService.clearLast()resolves through the bound-member pipeline. Closes #386. Thanks @vethman. -
PR comments no longer render empty when the only finding is a project-level dependency / catalog / override issue.
--format pr-comment-githuband--format pr-comment-gitlabpreviously appliedFALLOW_DIFF_FILTERto every finding, including those anchored at fixedpackage.json/pnpm-workspace.yamllines. Project-level rules now bypass the diff filter in the PR-comment path so the body always explains every CI-failure reason. Closes #381. Thanks @cloud-walker. -
Runtime coverage mapping is tightened across V8 offsets, source maps, and cloud coverage. Five-fix bundle: V8 coverage offsets map as source positions, partial source-map remaps are kept, owner segments are preserved in source-map project ids, cloud coverage requires a line match before attributing a hit, and scoped source-map repo names (
@scope/name) are accepted. PR #376. Thanks @M-Hassan-Raza. -
Duplication JSON output now emits
actions: []on every nestedCloneGroupinsideclone_families[].groups[]and on the combined dupes block. Closes #393. -
docs/output-schema.jsonregen no longer silently drops struct fields named after JSON Schema keywords.ContributorEntry.formatwas listed inrequiredbut missing frompropertiesbecause the schema normaliser stripped theformatkey recursively. Closes #394.
Documentation
-
TypeScript bare-name aliases ship in the npm-published
fallow/typescontract. The 17 dead-code bare aliases (UnusedExport,UnusedDependency,BoundaryViolation, etc.) plus 7 dupes/health aliases now live in the generatedoutput-contract.d.ts, soimport type { UnusedExport } from "fallow/types"type-checks after upgrading. Closes #415. -
fallow explainfor the three complexity rules now covers synthetic<template>and<component>Angular findings. Prose names both shapes, enumerates the template constructs that contribute to cyclomatic and cognitive, and explains the rollup math; flows through SARIFfullDescriptionand the MCPfallow_explaintool. Closes #404. -
auto_fixableis documented as per-finding, not per action type. Thefield_definitionsblock in_metacalls out per-instance evaluation explicitly and enumerates the four current per-instance flips. Closes #361.
Install
npx fallow # one-off
pnpm add -D fallow # project
cargo install fallow-cli # Rust usersFull Changelog: v2.75.0...v2.76.0