Repository navigation
v3.36.0: redundant config entries, literal-membership complexity, dotenv plugin
Features
-
Fallow reports config entries that match something but change nothing in the dead-code run. Three new
workspace_diagnostics[].kindvalues name the config entry inpattern.entry-pattern-redundantmarks anentrypattern whose matched files are all entry points from another source, such aspackage.json, a plugin ordynamicallyLoaded.ignore-dependencies-entry-redundantmarks anignoreDependenciesentry that hid no finding.ignore-patterns-entry-redundantmarks anignorePatternsglob whose files a built-in ignore,.gitignoreor the file type filter already skips. The entries show up in JSON, SARIF, the human and CI formats, the PR comments and the LSP. A--productionrun reports none of them. The exit codes andschema_versiondo not change. Thanks @Smrtnyk for the request. (#3824) -
health.cyclomaticPolicy: "literal-membership"counts a literal membership chain as one predicate. With this policy,kind === "a" || kind === "b" || kind === "c"adds no cyclomatic increments for its||operators. Only strict equality checks of one identifier against string, number, bigint, boolean ornullliterals qualify. The policy applies to themaxCyclomaticgate and to every CRAP score. Findings report the policy value ascyclomaticand the standard value asstandard_cyclomatic. The summary names the policy, and--complexity-breakdownmarks the chain operators withliteral_membership. The default staysstandard, and the health score, complexity density and hotspots keep the standard count. Thanks @lebedev-nikita for the request. (#3781) -
Fallow has a built-in dotenv plugin. Scripts that call
dotenvxcredit@dotenvx/dotenvx, anddotenvx run -- <command>credits the wrapped command.fallow migratemaps thedotenvplugin key. Thanks @VariableVince for the patch in #3771. (#3762) -
Type-aware analysis has an experimental tsrs backend. Set
FALLOW_TYPE_AWARE_BACKEND=tsrsto run the semantic pass on tsrs, the Rust port of the TypeScript 7 checker. Install the pinnedtsrsversion next tofallow-type-aware.fallow type-aware statusand_meta.type_awarereport the backend that ran. TypeScript-Go stays the default.
Changed
-
A file that nests too deep to parse has its own workspace diagnostic. Fallow reported such a file as
source-parse-degraded, with a message about parser errors, although the file can be valid code. It is nowsource-nesting-too-deep, with the cap inlimit. The file still counts for theparse-errorgate, and its item ingate_outcomes["parse-error"].fileshasreason: "nesting-too-deep". A script or tool that filters onsource-parse-degradedmust also matchsource-nesting-too-deepto keep seeing these files. -
The agent gate prints a short block message. When the gate blocks a
git commitorgit push, stderr now holds one line for each finding that caused the block, the verdict, and the path of the full JSON report. Under the defaultgate = "new-only", the list holds only the introduced findings. The full report goes to.fallow/gate-report.jsonin the audited tree. SetFALLOW_GATE_REPORTto write it to another path, orFALLOW_GATE_OUTPUT=jsonto print the full report on stderr as before. The exit codes do not change. Runfallow agent installagain to update an installed gate. Thanks @ankoor7 for the report. (#3725) -
Every platform npm package now ships a
LICENSEfile and a full README. The README names the platform, the package to install instead, and how to verify the binary. -
A short TypeScript input no longer uses seconds of parse time. Such an input now stops at its syntax error at once, without gigabytes of memory. Analysis output for real projects does not change. The extraction, graph and duplication caches get a new version, so the first run after the upgrade is cold. The minimum Rust version of the Fallow crates goes from 1.96 to 1.97.
Bug fixes
-
unused-class-memberscredits parameter, nested, loop and instance destructures. These forms now creditService.mwithout--type-aware:- a parameter destructure or a destructuring assignment, such as
({ m }: Service) => m()and({ m } = service); - a nested destructure, such as
({ k: { m } } = holder).
These forms now credit
Service.mwith and without--type-aware:- a
for...ofdestructure, a parameter destructure with a default value, and a parameter annotated withtypeof; - a destructure of an imported instance or of a class field, such as
const { m } = this.service.
A local that provably holds no class instance no longer gives credit through a shadowed module instance. (#3798)
- a parameter destructure or a destructuring assignment, such as
-
fallow dead-code --type-awareno longer confirms a used member or export as unused when a shorthand name or a namespace object reads it. The check now finds shorthand destructures, shorthand object properties, and static reads of a namespace object. When the check cannot prove which exports a namespace use reads, for exampleconsole.log(ns)orns[key], it abstains withdynamic-behaviorfor every export of that module. This includes the exports that a barrel re-exports. For a computed destructure key of a class instance, the check abstains withdynamic-member-access. -
unused-exportsmarks every export of a namespace import as used when a destructure with a computed key reads the namespace. A computed key, such asconst { [name]: value } = ns, can read any export, so all exports ofnsare now used. -
Deep nesting no longer aborts a run. A file with thousands of nested brackets, or deep generics, JSX, ternaries and long chains, could overflow the stack and stop the process. Fallow now measures the bracket depth before it parses, and it parses each file on a stack sized from its length. A file past the limit shows as a file that failed to parse, and the analysis of the other files continues. The language server and the MCP
decision_surfacetool now use the same large analysis stack as the CLI. The thread count ofdecision_surfacenow follows thethreadsoption. Deeply nested stylesheets get the same protection in the CSS parser. -
Vite projects no longer report Sass files that Vite loads without an import as unused. An
@useincss.preprocessorOptions.scss.additionalDatanow follows the Sass partial and index rules. A Sass@useresolves through a Viteresolve.aliasentry. The file thatvite-plugin-vuetifyreads fromstyles.configFileis an entry point. Thanks @Smrtnyk for the three reports. (#3819, #3820, #3821) -
SCSS Modules no longer report Sass module members or view transition classes as unused. A namespaced call such as
math.div(100px, 10), a namespaced mixin such as@include utils.baz, and the argument of::view-transition-new(.demo)are no longer exported classes. Thanks @rothsandro for the reports. (#3839, #3840) -
fallow health --productionno longer marks tested functions as untested. The CRAP estimate, coverage gaps and runtime coverage evidence now read test reachability from a graph of the full project. Findings still come only from production files. A production health run builds this second graph, so it takes more time. Thanks @Smrtnyk for the report and the reproduction. (#3822) -
A private class method now takes coverage from its own record.
fallow health --coverageused to report a private method (#name() {}) asestimated. The V8 converter now writes a record for each private method, and Fallow uses a record with the same#namenear the method. Theistanbul-lib-instrumentpackage writes no record for a private method, so its reports do not change. Thanks @Jerc92 for the report. (#3816) -
fallow audit --gate new-onlyno longer reports an unchanged anonymous function as introduced when only its CRAP score changes. Audit now also matches on the cyclomatic and cognitive values before it uses line order. Thanks @Jerc92 for the report and the reproduction. (#3815) -
Bare
fallownow applies thecoverage-gapsrule, asfallow healthdoes. A rule aterrornow makes the human run exit 1, andgate_outcomesgets ahealth-coverage-gapsentry. The machine formats exit 1 on it only with--fail-on-issuesor--ci. Thanks @Smrtnyk for the report. (#3823) -
A suppression that only
--productionneeds is no longer stale in a run without--production. Afallow-ignore-next-line unused-exportcomment stays out ofstale-suppressionwhen every reference to the export comes from a file that production mode excludes. The comment stays stale when a package entry that production mode keeps re-exports the export. This applies tounused-exportandunused-type. Thanks @Smrtnyk for the report. (#3825) -
Workspace imports keep their credit after a build. When package
exportspoint intodist/src/, Fallow maps the output back to source through therootDirandoutDirof the package tsconfig. A warm cache now gives the same result as--no-cacheafter the build output appears or goes away. Thanks @Smrtnyk for the reports. (#3817, #3818) -
Fallow credits more alias forms and skips the dependencies of gitignored workspace members. These cases no longer give unused, unlisted or unresolved findings:
- an npm alias that installs a script binary, such as
"@typescript/native": "npm:typescript@~7.0.2"for atscscript; - a tsconfig
pathsalias that points intonode_modules, which now credits the package of the resolved file; - a
workspace:<name>@<range>alias, which now resolves to the aliased workspace package; - the dependencies of a gitignored workspace member, which Fallow no longer reports.
Thanks @waldoluisribeiro for the npm alias report. (#3844)
- an npm alias that installs a script binary, such as
-
A script that an Nx
run-commandstarget runs is no longer an unused file whenproject.jsonhas a comment. Fallow now readsproject.jsonas JSONC. Thanks @Pajn for the report and the reproduction. (#3704) -
fallow healthcounts runtime code in modules that export only types. Top-level calls, assignments,awaitand runtime declarations keep such a module in coverage gaps. Thanks @xiaofeilovecoding for the patch in #3578. (#3549) -
The GitHub Action no longer fails
command: auditon a default shallow checkout. On apull_requestevent, the Action now fetches the smallest history that gives a merge base.fetch-depth: 0stays the recommended setup. -
CI scripts named outside a
runvalue are no longer unused files. Fallow now reads${{ matrix.<path> }}steps,actions/github-scriptfile loads, and stepenventries that hold a workspace anchor. -
The napi-rs plugin finds a generated loader in a subdirectory. A build with
napi build --cwd bindingwrites the loader tobinding/index.cjs, and Fallow no longer reports the platform packages of the loader as unlisted dependencies. -
Fallow parses escaped spaces in CODEOWNERS and limits the wildcards. A pattern with an escaped space, such as
/docs/Security\ Release.md, now parses. On Windows, a backslash in a pattern is now an escape, as on other platforms, and no longer a path separator. A file with thousands of wildcards no longer stalls ownership lookups. Fallow rejects a pattern with more than 32 wildcards, or a file with more than 4096, with an error that names the limit. -
The agent gate audits only the worktree for a push that cannot send the session branch. Untracked build output in the session no longer blocks a strict push from a clean linked worktree. Run
fallow agent installagain to update an installed gate. -
The
--fail-on-issueshelp text now says where the flag changes the exit code. The exit codes do not change. Thanks @Smrtnyk for the report. (#3826)
Performance
-
Long chains are now linear to analyze. Long member,
await,+, JSX tag, fluent call and heritage chains used to take time or memory that grew with the square of their length. For example, 160000 nestedawaittook 33 seconds and now take 0.04 seconds. Fallow records a receiver name only up to 64 links, which real code does not reach. -
Deeply nested arrow functions no longer make extraction quadratic. Before, a chain of 160000 nested arrows took about 17 seconds. A function with more than 64 levels of nested functions below it now gets no runtime coverage
source_hash. Real code stays far below that, so every real function keeps the same hash. -
Public API entry resolution builds the module index one time for each package. On a large project, this removes several seconds from
fallow dead-codeand from the--type-awarerefinement. The results do not change.
Upgrade notes
- Several cache versions change, so the first run after the upgrade parses every file again.
- A script or tool that filters
workspace_diagnosticsonsource-parse-degradedmust also matchsource-nesting-too-deep. - Run
fallow agent installagain to get the new agent gate message and the worktree push fix. - On Windows, a backslash in a CODEOWNERS pattern is now an escape, not a path separator.
Full Changelog: v3.35.0...v3.36.0