Skip to content

chore(deps): update dependency fallow to v3.36.0 - #955

Open
renovate[bot] wants to merge 1 commit into
masterfrom
renovate/fallow-3.x-lockfile
Open

renovate[bot] wants to merge 1 commit into
masterfrom
renovate/fallow-3.x-lockfile

Conversation

@renovate

@renovate renovate Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
fallow (source) 3.33.1 → 3.36.0 age confidence

Release Notes

fallow-rs/fallow (fallow)

v3.36.0

Compare Source

Added
  • Built-in dotenv CLI plugin support. fallow migrate now maps the
    dotenv plugin key. Scripts invoking dotenvx credit @dotenvx/dotenvx,
    and dotenvx run -- <command> credits the wrapped command, as
    varlock run -- already does. Thanks
    @​VariableVince for the patch in
    #​3771.
    (Closes #​3762)

  • Experimental tsrs backend for type-aware analysis. Set FALLOW_TYPE_AWARE_BACKEND=tsrs to run the semantic pass on tsrs, the Rust port of the TypeScript 7 checker, instead of TypeScript-Go. Install the pinned tsrs version next to fallow-type-aware. fallow type-aware status and _meta.type_aware report the backend that ran. TypeScript-Go stays the default.

  • health.cyclomaticPolicy: "literal-membership" counts a literal
    membership chain as one predicate.
    A chain such as
    kind === "a" || kind === "b" || kind === "c" then adds no cyclomatic
    increments for its || operators. Only strict equality checks of one
    identifier against string, number, bigint, boolean, or null literals
    qualify. The policy applies to the maxCyclomatic gate and to every CRAP
    score. Findings report the policy value as cyclomatic and the standard
    value as standard_cyclomatic, the summary names the policy, and
    --complexity-breakdown marks the chain operators with
    literal_membership. The default stays standard. The health score,
    complexity density, and hotspots keep the standard count. The parse cache
    version changes because the cached breakdown has the new flag.
    (Closes #​3781)

  • Fallow reports config entries that match something but change nothing in the dead-code run. Three new kinds in workspace_diagnostics[].kind carry these entries, each with the config entry in pattern:

    • entry-pattern-redundant: an entry pattern whose matched files are all runtime entry points from another source, for example package.json fields and scripts, a plugin, an infrastructure config or dynamicallyLoaded.
    • ignore-dependencies-entry-redundant: an ignoreDependencies entry that hid no dependency finding. A glob that matches no declared dependency keeps the ignore-dependencies-glob-unmatched kind and is not reported twice.
    • ignore-patterns-entry-redundant: an ignorePatterns glob that excluded no file that a built-in ignore, .gitignore or the file type filter does not already skip. A glob for build output has an effect only after a build, and the message says so.

    The entries reach JSON, SARIF toolConfigurationNotifications[], the stderr note in human, compact, CodeClimate and github-annotations, and the LSP information diagnostic on the config entry. Markdown, github-summary, the PR comments and the review summary add a separate Redundant config entries section after Unmatched config patterns. A --production run reports none of the three kinds, because that run checks fewer files and dependency sections. No exit code changes, and no schema_version changes, because workspace_diagnostics[].kind is an open set.
    (Closes #​3824)

Changed
  • Every platform npm package now ships a LICENSE file and a full README.
    This covers the @fallow-cli/<platform> CLI binaries, the
    @fallow-cli/fallow-similar-code-<platform> sidecar binaries, the
    @fallow-cli/fallow-node-<platform> addons and @fallow-cli/fallow-node.
    The README names the platform and the package to install instead, and says
    how the binary is verified. The fallow-similar-code platform packages now
    also have a description.

  • A file that nests too deep to parse has its own workspace diagnostic. Fallow does not parse a file that nests brackets past the parser cap, or that needs more stack than fallow reserves. Such a file was reported as source-parse-degraded, with a message about parser errors, although the file can be valid code. It is now reported as source-nesting-too-deep, with the cap in limit. The message says that fallow fix holds back its actions while the file is reachable, and that ignoreFindings takes a generated file out of the run. The file still counts for the parse-error gate, and its item in gate_outcomes["parse-error"].files carries the new optional reason: "nesting-too-deep". The human report, the GitHub Action and the GitLab template name that reason instead of "1 parser error". workspace_diagnostics[].kind is an open set, so no schema version changes, but a consumer that filters on source-parse-degraded must also match source-nesting-too-deep to keep seeing these files.

  • Fallow now parses with Oxc 0.155 and converts coverage with oxc_coverage_instrument 0.17.0.
    A short TypeScript input that made the parser use seconds of time and
    gigabytes of memory (oxc-project/oxc#27637) now stops at its syntax error at
    once. Analysis output for real projects does not change. A string with a
    lone surrogate now keeps it as \uXXXX, so the extraction, graph and
    duplication caches get a new version and the first run after the upgrade
    is cold. Oxc 0.155 needs Rust 1.97, so the minimum Rust version of the
    Fallow crates goes from 1.96 to 1.97.

  • The agent gate prints a short block message. When the gate that
    fallow agent install and fallow hooks install --target agent write
    blocks a git commit or git 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 default gate = "new-only" the list holds only the
    introduced findings, so inherited findings no longer fill the context of
    the agent. The full report goes to .fallow/gate-report.json in the
    audited tree. Set FALLOW_GATE_REPORT to write it to another path, or
    FALLOW_GATE_OUTPUT=json to print the full report on stderr as before.
    The exit codes do not change. Run fallow agent install again to update an
    installed gate. Thanks @​ankoor7 for the report.
    (Closes #​3725)

Fixed
  • fallow dead-code --type-aware no longer confirms a used class member or
    export as unused when a shorthand name reads it.
    The type-aware check now
    finds a class member that a shorthand destructure reads, for example
    const { run } = service, ({ run }: Service) => run() or
    ({ run } = service), and a renamed assignment destructure, for example
    ({ run: local } = service). It also finds an export that a shorthand object
    property reads, for example { value }, and an export that a destructure of
    a namespace import reads, for example const { value } = ns. Before this
    fix, a used member that only a parameter destructure or an assignment
    destructure read could get a guarded remove-class-member fix. For an
    array or loop assignment destructure, and for a nested assignment
    destructure with a default value, the check now abstains with
    dynamic-member-access.

  • fallow health counts runtime code in modules that export only types.
    Top-level calls, assignments, await, and runtime declarations keep a module
    in coverage gaps. Pure type and ambient declarations remain excluded. The
    extraction cache version is bumped so warm caches pick up the new facts.
    Thanks @​xiaofeilovecoding for the
    patch in #​3578.
    (Closes #​3549)

  • unused-class-members credits members that a parameter destructure or a destructuring assignment reads. Without --type-aware, ({ m }: Service) => m() and ({ m } = service) did not credit Service.m, so Fallow reported a used member as unused. Fallow now credits these reads in the same way as const { m } = service. The parameter form works for arrow functions, function declarations and methods, with renamed keys, defaults and nested type literals such as ({ svc: { m } }: { svc: Service }). A rest element still marks the whole class as used.

  • The GitHub Action no longer fails command: audit on a default shallow checkout. On a pull_request event, a depth-1 checkout of the merge commit has no merge base with the PR base, so fallow audit --changed-since exited 2 with "no merge base". The Action now fetches the smallest history that gives a merge base: the base commit, then the parents of the merge commit, then a bounded deepen. A failed fetch does not fail the job. fetch-depth: 0 stays the recommended setup.

  • The napi-rs plugin finds a generated loader in a subdirectory. A build with napi build --cwd binding writes the loader to binding/index.cjs, but the napi config stays in the package manifest. Fallow read only the package directory, so it reported each platform package of the loader as an unlisted dependency. Fallow now also reads the direct subdirectories of the package, except node_modules, target, dist, build, out, hidden directories, and directories with more than 32 script files. The WASI workers and browser.js next to such a loader count as generated too.

  • CI scripts named outside a run value are no longer unused files. Fallow now reads three more GitHub Actions forms. A step that runs only ${{ matrix.<path> }} runs the values of that key path in the matrix of its job. An actions/github-script step loads the files after ${process.env.GITHUB_WORKSPACE}/ or ${{ github.workspace }}/, and the files of require('./path'). A step env entry whose whole value is ${{ github.action_path }} or another workspace anchor makes "$NAME/script.mjs" resolve like that anchor.

  • fallow dead-code no longer reports the dependencies of a gitignored workspace member. A pnpm workspace can declare a directory that CI fills with a clone of an upstream repository, for example vite or rolldown. Source discovery does not read the files of a gitignored member, so the run cannot prove that its dependencies are unused. The member stays a workspace for imports and catalog references.

  • A workspace:<name>@<range> dependency alias resolves to the aliased workspace package. With "vite": "workspace:@scope/core@*", an import of vite/pack resolves through the exports map of @scope/core. Before, a workspace member with the name vite took the import, and the import was unresolved when that member had no ./pack export.

  • unused-class-members credits members that a nested destructure reads. Without --type-aware, ({ k: { m } } = { k: service }), ({ k: { m } } = holder) and ({ k: { m } = service } = {}) did not credit Service.m, so Fallow reported a used member as unused. The const forms had the same gap. Fallow now follows a nested pattern into an object literal property, a default value and a static member path. The member path form reads holder.k.m in the same way as the member expression, so it credits a member only when Fallow knows the class of holder.k.

  • fallow dead-code --type-aware no longer confirms an export as unused when
    a namespace object can read it.
    The type-aware check now credits an export
    that a static read of a namespace object reads, for example
    ({ value } = ns), const { "value": local } = ns,
    function run({ value } = ns), (ns as typeof ns).value,
    outer.inner.value after export * as inner, and m.value after
    import m = require("./values"). When the check cannot prove which exports
    a namespace use reads, for example console.log(ns), const copy = ns,
    export { ns }, const { ...rest } = ns, ns[key] or
    module.exports = require("./values"), it now abstains with
    dynamic-behavior for every export of that module, also the exports that a
    barrel re-exports. A destructure that can read a nested namespace, for
    example const { inner } = outer, abstains for the exports of the nested
    module. A dynamic import, for example import("./barrel"), now also
    abstains for the exports that the barrel re-exports. Before this fix, such an
    export could get a confirmed-no-static-references decision.

  • fallow dead-code --type-aware abstains for a class member that a computed
    destructure key can read.
    const { [key]: run } = service and
    ({ [key]: run } = service) now give dynamic-member-access, as
    service[key] already did. A string key, for example
    const { "run": local } = service, now credits the member.

  • tsconfig paths aliases that point into node_modules no longer become unlisted dependencies. A paths entry such as "@components/*": ["./node_modules/some-theme/src/components/*"] made Fallow report @components/shared as an unlisted dependency, because Fallow credited the specifier text and not the package that the alias resolves into. Fallow now treats each specifier that a paths pattern of the nearest tsconfig matches as an alias, as TypeScript does, and credits the package of the resolved file. This is also true when a real package has the same name as the pattern. A paths entry onto a declaration file, such as "react": ["./node_modules/@types/react"], still credits react. Without an install, an alias into a package directory that does not exist credits that package and is not an unresolved import.

  • A file with deeply nested brackets no longer aborts the run. A source with thousands of nested (, [, { or template substitutions overflowed the parser stack, and the stack overflow killed the whole fallow process. Fallow now measures the nesting before it parses a file. A file past the limit shows as a file that failed to parse, fallow dupes finds no clones in it, and the analysis of the other files continues. Brackets inside strings, comments and template text do not count. The extraction and duplication cache versions change, so the first run after the upgrade parses every file again. OSS-Fuzz found this.

  • unused-class-members no longer reports a used member as unused when one of these destructure forms is its only read. This applies with and without --type-aware. In each example, Service.m is now used:

    • A for...of destructure, such as for (const { k: { m } } of [{ k: service }]), for ({ m } of [service]), for (const { m } of services) with services: Service[] or for (const { m } of [...services]).
    • A parameter destructure with a default value, such as function run({ m } = service) or function run({ k: { m } } = { k: service }).
    • A parameter annotated with typeof, such as ({ k: { m } }: typeof holder) or ({ k: { m } }: { k: typeof service }).
    • A getter or a spread in the source object, such as { get k() { return service } } or { ...holder }.
  • unused-class-members no longer credits a class through a local shadow. Without --type-aware, a module instance const service = new Service() gave credit to Service.m for service.m, service['m'], const { m } = service and ({ m }: typeof service) inside a function that declares its own service. Fallow then missed an unused member. Fallow now ignores this credit when the nested service provably holds no class instance: an object literal of functions and primitives, a primitive or function value, or a parameter whose type annotation is a primitive, literal or function type. A type literal or a named type gives no proof, because a class instance can satisfy it. A class instance that the nested scope declares keeps its credit.
    (Closes #​3798)

  • unused-class-members no longer reports a used member as unused when a destructure of an imported instance or of a class field is its only read. This applies with and without --type-aware. In each example, Service.m is now used:

    • A destructure of an instance from another module, such as const { m } = service after import { service } from './service'.
    • A destructure of a class field, such as const { m } = this.service in a class with constructor(private service: Service).
    • The assignment, parameter default and typeof forms of these destructures, such as ({ m } = service), run({ m } = this.service) and ({ m }: typeof service) => m().
  • unused-exports no longer reports the exports of a namespace import as unused when a destructure with a computed key reads it. A computed key, such as const { [name]: value } = ns, can read any export, so all exports of ns are now used.

  • The language server and the MCP decision_surface tool no longer abort on nesting that the CLI survives. Both ran analysis on threads with a 2 MiB stack, so a deeply nested file overflowed that stack and stopped the process. The language server now gives its analysis threads the 16 MiB stack of the CLI workers. Its Tokio runtime uses two worker threads, because analysis runs on the blocking threads and the Rayon pool. decision_surface and run_decision_surface now parse on the analysis worker pool, as the other tools do. Their thread count now follows the threads option.

  • Deep nesting without brackets no longer aborts a run. TypeScript generics, JSX elements, class extends, ternaries, arrows, assignment chains and long member or call chains could overflow the stack, and the whole process stopped. Each parse of a source file now runs on a stack that is sized from the length of the file. A file up to about 15 KB still parses on the analysis worker. A larger file parses on its own thread with a stack of that size. This applies to every analysis that parses a file: dead code, duplication, health, similar code, mutation testing and the config file plugins.

  • Deeply nested arrow functions no longer make extraction quadratic. Each function hashed its whole source text for runtime coverage, so a chain of nested arrows took time that grew with the square of its length. 160000 levels took about 17 seconds. A function with more than 64 levels of nested functions below it now gets no source_hash. Real code stays far below that, so every real function keeps the same hash. The coverage inventory also computes columns in linear time for nested functions on one line, and it no longer sends the hash of empty input for a span that it cannot read.

  • A very large file no longer parses on a stack that is too small. The parse stack cap is now 64 GiB on 64-bit targets, which a source over 64 MB reaches in a release build. A file that needs more stack is reported as a failed parse, like a file with too deeply nested brackets. Before, such a file got a capped stack and could stop the run.

  • A deeply nested stylesheet no longer risks a stack overflow in the CSS parser. CSS Modules class extraction, fallow health --css analytics and color parsing now check the bracket depth before they call the CSS parser, and they run the parse on a stack sized for the stylesheet. A stylesheet past the limit falls back to the plain class scan, or is left out of the CSS analytics. The depth check now reads a stylesheet with CSS rules: a // inside url(//host/a.png), a CSS escape or an unquoted url() body no longer hides the rest of a minified file. The extraction cache version changes, so the first run after the upgrade parses every file again. OSS-Fuzz found this.

  • Bare fallow now applies the coverage-gaps rule, as fallow health does. Before, the combined run did not compute coverage gaps, so a coverage-gaps rule at error never failed it. Now an enabled rule shows the gaps in the health section, and a rule at error makes the human run exit 1. The JSON gate_outcomes object gets a health-coverage-gaps entry. Like the other findings rules of the combined run, the machine formats exit 1 on it only with --fail-on-issues or --ci. Thanks @​Smrtnyk for the report. (Closes #​3823)

  • A suppression that only --production needs is no longer reported stale
    in a run without --production.
    Production mode excludes test files. An
    export that only a test file imports is unused there, so its
    fallow-ignore-next-line unused-export comment is necessary. A run without
    --production credits the test import and does not use the comment. That
    run now keeps the comment out of stale-suppression when 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 to unused-export and unused-type. Thanks
    @​Smrtnyk for the report.
    (Closes #​3825)

  • Vite projects no longer report Sass files that Vite loads without an import as unused.
    Three cases caused false findings. An @use in
    css.preprocessorOptions.scss.additionalData now credits the file that Sass
    loads when the specifier has no extension, leaves out the _ of a partial, or
    names a directory with an _index or index file (#​3819). An @use in a Sass
    file now resolves through a Vite resolve.alias entry, with the Sass partial
    and directory-index rules. Before, Fallow reported the import as unresolved
    and the target partial as unused (#​3820). The Sass settings file that
    vite-plugin-vuetify reads from styles.configFile is now an entry. Fallow
    reads the path relative to the Vite root (#​3821). Thanks
    @​Smrtnyk for the three reports.
    (Closes #​3819, #​3820, #​3821)

  • A private class method now takes coverage from its own #name record.
    Before, fallow health --coverage always reported a private method
    (#name() {}) as estimated, also when the coverage data had a record for
    that method. Fallow now uses a record that has the same #name near the
    method. A record at the exact position of the method is used first. Near
    the method, the record must be the only one with that name. Fallow does not
    give a private method the coverage of the function that holds it or of a
    public method. istanbul-lib-instrument writes no record for a private
    method, so its reports do not change.
    Thanks @​Jerc92 for the report.
    (Refs #​3816)

  • A script that an Nx run-commands target runs is no longer reported as an unused file when project.json contains a comment.
    Fallow now reads project.json as JSONC, as Nx does. Line comments, block
    comments and trailing commas no longer hide the target commands. Thanks to
    @​Pajn for the report and the clear reproduction.
    (Closes #​3704)

  • fallow audit --gate new-only no longer reports an unchanged anonymous function as introduced when only its CRAP score changes. When a file has several anonymous functions, audit matches each head finding to a base finding. Before this fix, a CRAP change from estimated to measured coverage stopped the unchanged function from matching its own base finding. The line-order fallback then paired it with a different, smaller function, and audit reported it as introduced. Audit now also matches on the cyclomatic and cognitive values without the CRAP score before it uses line order. The matched pair still compares the CRAP score. Thanks @​Jerc92 for the report and the reproduction.
    (Closes #​3815)

  • A workspace import now keeps its credit when the package exports point into dist/src/ and the build output exists. A package with tsconfig rootDir: "./" and outDir: "./dist" emits src/index.ts as dist/src/index.js. Fallow now uses the rootDir and outDir of the package tsconfig to map that output back to src/index.ts. Before, the imported exports were reported as unused after a build. Thanks @​Smrtnyk for the report. (Closes #​3817)

  • A warm cache now gives the same result as --no-cache after the build output of a workspace package appears or goes away. The graph cache key now includes whether each static entry path in the project and workspace package.json files exists on disk. Thanks @​Smrtnyk for the report. (Closes #​3818)

  • fallow health --production no longer marks tested functions as untested in the CRAP estimate.
    Production mode keeps test files out of the analysis. The static coverage
    estimate used the same file set, so it found no tests. Each function with a
    cyclomatic complexity of 6 or more then failed the default maxCrap of 30.
    Coverage gaps also reported tested files and exports as untested. Fallow now
    reads test reachability from a graph of the full project, and findings still
    come only from production files. A production run now gives the same CRAP
    scores and coverage gaps as a full run for the files that it analyzes. A
    production health run builds this second graph, so it takes more time.
    Thanks @​Smrtnyk for the report and the
    reproduction. (Closes #​3822)

  • The --fail-on-issues help text now says where the flag changes the exit code.
    Bare fallow in a json, sarif or codeclimate format and fallow dupes exit
    0 on issues unless --fail-on-issues or --ci is set. The human, compact
    and markdown formats of a bare run, and the standalone analysis commands,
    already exit 1 on error-severity issues. The exit codes do not change.
    Thanks @​Smrtnyk for the report.
    (Refs #​3826)

  • fallow health --production --runtime-coverage no longer reports tested functions as not_covered.
    The fix for #​3822 gave the CRAP estimate and the coverage gaps the test files
    in production mode. The runtime coverage evidence still used the production
    graph, which has no test files, so evidence.test_coverage was
    not_covered for each function. The runtime coverage evidence now reads
    test reachability from the same full-project graph. A production health run
    builds this graph one time and uses it for file scores and for runtime
    coverage. A production run with runtime coverage and without file scores
    (for example --complexity with maxCrap: 0) now builds this graph too, so
    it takes more time.

  • An executed private class method now gets its measured coverage from native V8 coverage.
    Before, fallow health --coverage <NODE_V8_COVERAGE dir> reported a private
    method (#name() {}) as estimated and gave it a CRAP finding, also when
    Node ran every path of the method. Its public twin with the same body was
    measured and had no finding. The V8 converter now writes a record for each
    private method (#name, get #name, set #name) with its own call count,
    and Fallow uses that record. A private method that did not run stays at 0%.
    Thanks @​Jerc92 for the report.
    (Closes #​3816)

  • A script binary now credits the npm alias that installs it. A
    dependency such as "@typescript/native": "npm:typescript@~7.0.2" provides
    the binaries of typescript, so a tsc script no longer reports the alias
    as unused. When the same manifest also declares the aliased package under
    its own name, that declaration provides the binary, and an alias that
    nothing else uses is still reported. A plain declaration in another
    workspace does not change the result. Thanks
    @​waldoluisribeiro for the report. (Closes #​3844)

  • SCSS Modules no longer report Sass module members as unused classes.
    A namespaced function call such as math.div(100px, 10) or utils.bar(),
    and a namespaced mixin such as @include utils.baz, gave a false
    unused-export for div, bar and baz. The class scan now skips a
    .member that follows a namespace and comes before (, and the mixin name
    after @include. In .module.sass files, the scan also skips the mixin
    name in the +utils.baz include shorthand. A compound selector such as
    button.primary still
    exports primary. The extraction cache version changes, so the first run
    after the upgrade parses each file again.
    (Closes #​3839)

  • CSS Modules no longer report view transition class names as unused
    classes.
    In ::view-transition-new(.demo) and the other
    ::view-transition-*() pseudo-elements, .demo is a view transition class
    and not an element class. The SCSS class scan exported it, and fallow then
    gave a false unused-export for demo. The class scan now skips the
    argument of these pseudo-elements. The extraction cache version changes, so
    the first run after the upgrade parses each file again.
    (Closes #​3840)

  • The agent gate audits only the worktree for a push that cannot send the
    session branch.
    A strict git push from a linked worktree of the session
    repository also audited the session tree, because linked worktrees share
    refs. Untracked build output in the session thus blocked every push from a
    clean worktree. The gate now audits only the worktree when git shows that
    the push cannot send the session branch: the options are only -u, -q,
    --set-upstream, --force-with-lease and --force-if-includes, each
    refspec source is the checked-out branch of the worktree and not the
    session branch, and a push without a refspec has push.default unset or
    simple, current, upstream or nothing and no remote push or
    mirror setting. Any other push from a linked worktree, and any git error
    during the check, keeps the session audit. The strict push form now also
    accepts --force-if-includes. Run fallow agent install again to update an
    installed gate.

  • A CODEOWNERS file with thousands of wildcards no longer stalls ownership lookups.
    All CODEOWNERS rules match in one automaton, and its lookup time grows with
    the number of wildcards (*, ?, [, {). A 4 KB file with one
    *a*a*a… pattern took seconds for each lookup. Fallow now rejects a
    pattern with more than 32 wildcards, or a file with more than 4096, with an
    error that names the limit. Large public CODEOWNERS files use fewer than
    400. OSS-Fuzz found this.

  • A CODEOWNERS pattern with an escaped space now parses.
    GitLab writes a space in a path as \ , for example
    /docs/Security\ Release.md @owner. Before, Fallow split the line at that
    space, and --group-by owner and --group-by section failed with
    "dangling ''". GitLab's own CODEOWNERS file failed in this way. On Windows, a
    backslash in a pattern is now an escape, as on other platforms, and no
    longer a path separator. Thus \ and \# now work on Windows too.

Performance
  • Very long member chains extract much faster. Extraction built the dotted name of a member chain again at each link, and each build copied the name once per link. A file with a chain of 4000 links (a.b.b.b...) took several seconds to extract. Fallow now builds each name in one pass, so the same file takes a fraction of a second. Real code does not have chains this long, but generated or hostile input can. The extraction output does not change.

  • Public API entry resolution no longer resolves every module path again for each missed package entry.
    A package entry that exists on disk but is not in the module graph, such as
    an extensionless bin script, made Fallow resolve the real path of each
    module in the package. Fallow did this again for each candidate path that it
    probed. Fallow now builds the canonical module index one time for each
    package and resolves each parent directory one time. On a large project,
    this removes several seconds from fallow dead-code and from the
    --type-aware refinement. The results do not change.

  • A very long member chain no longer makes extraction slow and large. For a chain such as a.b.b.b with thousands of links, each link recorded the full name of its receiver, so the time and the cached output grew with the square of the chain length. Fallow now records a receiver name only up to 64 links. A link deeper than that records no member access. A fluent builder chain such as new Builder().a().b() now records each step name once, so a long chain keeps the credit for all of its steps, and a chain that repeats a method stays small. The extraction cache version changes, so the first run after the upgrade parses every file again. OSS-Fuzz found this.

  • Long member, await, +, JSX tag and fluent call chains are now linear
    to analyze.
    A file with a chain of many thousand links took minutes, or
    used gigabytes of memory, because several path builders copied the whole
    path at each link or scanned a growing list at each step. For example,
    160000 nested await took 33 seconds and now take 0.04 seconds, and a
    fluent chain of 4000 calls with different method names used 700 MB. A
    fluent chain now gives one fact for the chain instead of one fact for each
    call. A taint source path or a JSX tag receiver longer than 64 links is not
    recorded, the same limit that member access names use. The cache version
    changes, so the first run after the upgrade parses all files again.

  • Long heritage names and long dotted component tags in Astro and MDX files
    are now linear to analyze.
    Each level of interface X extends a.b.c... or
    <a.b.c... /> recorded the full name of its receiver, so the time and the
    output grew with the square of the name length. For example, an interface
    heritage name of 20000 links took 110 seconds and now takes 0.08 seconds. A
    receiver longer than 64 links is not recorded, the same limit that member
    access names use. The names of class C extends a.b.c... and
    implements A.B.C... are now built once, instead of a copy of the name at
    each link. The cache version changes, so the first run after the upgrade
    parses all files again.

v3.35.0

Compare Source

Added
  • fallow health --css reads server-side template files as class references. Before, a class that only a Shopify .liquid section applied was reported as an unreferenced-css-class. Fallow now reads files with the extensions liquid, njk, hbs, handlebars, twig, and blade.php, and any class-like word in them counts as used. Templates are more lenient than Markdown: the whole text of a template counts, so a common word such as hidden or title in a template also credits that class, while a Markdown file counts only when it has dynamic class syntax. A class prefix before a {{ echo, as in grid--{{ columns }}, also counts. {{ is a shared interpolation marker, so it also applies to .vue, .html, .md and .astro sources with dynamic class syntax, and these can report fewer classes too. The new top-level markupExtensions key adds other template extensions, for example ["tpl", "erb"]. A value that ends in a script, stylesheet, data or asset extension, such as module.css or d.ts, is a config error. The walk honors .gitignore, ignorePatterns and --max-file-size. These files do not join source discovery, so they never become unused files. Thanks @​james2doyle for the report. (Closes #​3917)

  • The npm package now ships rule-pack-schema.json. A rule pack can point $schema at ./node_modules/fallow/rule-pack-schema.json and get a schema that matches the installed Fallow version. The package also exports the file as fallow/rule-pack-schema.json. Thanks @​hckhanh for the report and @​tahodev for the change. (Closes #​3851)

  • An interrupted fallow mutation run keeps its finished results, and --resume continues it. Each run writes the killed and the retry-confirmed survived mutants to .fallow/mutation/journal.jsonl when each result is final, also with --no-cache. fallow mutation --resume reuses these results and runs only the other mutants. A journal of other inputs exits 2 with FALLOW_MUTATION_RESUME_MISMATCH and names each input that differs. A resumed mutant has resumed: true, and the report has a resume object. A complete run removes the journal, and a partial run keeps it. (Closes #​3783)

Changed
  • A bare machine run that exits 0 on a failing gate now says so on stderr. Bare fallow in --format json, sarif, codeclimate, the GitHub formats and the comment and review formats exits 0 on findings, while fallow dead-code --format json exits 1 on the same findings. Before, nothing showed why. Now such a run prints one stderr line, also under --quiet, that names each failing findings gate and the flag that enforces it: [W] Exit code 0: gate error-severity-findings (2 at or above error) failed, but bare fallow does not enforce it in --format json. To exit 1 on it, pass --fail-on-issues. The exit code and stdout do not change. Thanks @​Smrtnyk for the report. (Closes #​3826)

  • The exit-code contract no longer says that exit 0 means a clean run. fallow schema (exit_codes), the fallow skill, AGENTS.md and the npm README said that 0 means no error-severity findings. For bare fallow in a machine format, that was false. They now say that 0 means no enforced gate failed, that 1 means findings and not a tool failure, and that a bare machine run gates on findings only with --fail-on-issues. To see a failing gate that did not set the exit code, read gate_outcomes.

  • fallow mutation gives no mutant for a pure condition whose only effect is a logging call. An if statement such as if (count > 0) { console.info("Items", count); } gave mutants for its test that could only change which message was logged. The collector already skips each console.* and debug(...) call, and it now also skips such an if statement. The test must be pure, and each branch must hold only logging calls with pure arguments. An else if chain must meet the same conditions. The callee must be the global console or debug: a file that declares or imports one of these names keeps the conditions that call it. A condition with a call, an assignment or another statement in a branch keeps its mutants. (Closes #​3719)

Fixed
  • thin-wrapper and duplicate-prop-shape set to error now fail the gates. These rules count in issue totals, the dead-code and audit gates, and CI reports when their severity is error. Warnings stay advisory, also with --fail-on-issues. Per-file overrides and saved baselines use the component that owns each finding. Thanks @​luciocabrera for the report. (Closes #​3867)

  • A CommonJS postcss.config.cjs no longer reports its module.exports keys as unused exports. Since 3.35.0, Fallow credited only the default export of a PostCSS config. A tool that loads a CommonJS file reads module.exports as its default export. When a plugin credits only default for a CommonJS module, Fallow now credits every key of module.exports. This applies to the CommonJS config files of all plugins that read the default export. User ignoreExports rules do not change. Thanks @​waldoluisribeiro for the report. (Closes #​3876)

  • fallow security resolves a string enum member in the same module. It now reads the member like a const string. A template literal such as `<meta name="${MetaName.BUILD_NUMBER}">` that goes to an HTML sink is no longer reported as non-literal HTML. Enums and constants that you import from another module stay unresolved, because sink extraction reads one module at a time. The extraction cache version changes, so the first run after the update parses all files again. Thanks @​Smrtnyk for the report. (Closes #​3854)

  • Component export queries no longer stop type-aware refinement for the whole run. Vue, Astro, Svelte and MDX query files receive an unsupported-syntax abstention before the semantic backend opens them. Supported TypeScript and JavaScript queries continue to resolve in the same batch. (Closes #​3763)

  • fallow dead-code follows child_process.fork targets built from the module directory. A file that fork(path.join(path.dirname(fileURLToPath(import.meta.url)), "child.ts")) starts is no longer an unused file. Fallow also reads path.resolve, __dirname, import.meta.dirname and a constant that holds the module directory. A target with a computed segment stays unresolved. Thanks @​VariableVince for the report. (Closes #​3919)

  • Config values in a same-file constant are now read. A config can keep a
    part of its value in a top-level constant, for example
    const UNIT = { test: { setupFiles: [...] } } with projects: [UNIT], or
    setupFiles: SETUP and test: TEST. Fallow read only inline values, so it
    reported the setup files of such a Vitest project as unused files. The config
    parser now uses the value of the constant in each property value and array
    element that names it. This applies to all plugins that read config files. A
    constant that the file declares more than one time or writes to stays
    unresolved. Thanks @​Smrtnyk for the report.
    (Closes #​3852)

  • fallow dead-code no longer reports a class member as unused when an array pattern or a held getter is its only read. Without --type-aware, unused-class-members missed two destructure forms. The first is an array pattern around an object pattern, such as const [{ m }] = [service] or for (const [{ m }] of [[service]]). The second is a getter on an object literal that a variable holds, such as const src = { get k() { return service } } with a later src.k.m read or { k: { m } } = src destructure. Each form now credits the member. An array element after a spread, or a getter with more than one statement, gives no credit. The extraction cache version is 386. (Closes #​3799)

  • Package scripts and CI steps that run a local shell helper now credit the commands of that helper. For bash scripts/build.sh or ./scripts/release.sh, Fallow reads the helper without running it. A binary that the helper runs makes its package used, and a file that the helper runs with tsx or node becomes an entry. The helper path resolves in the package directory or in the working-directory of the CI step, and it must stay inside the project. Fallow follows nested helpers and stops at a cycle. It follows a cd to a literal directory or to the helper directory (cd "$(dirname "$0")/.."). After another cd, the remaining commands of the helper credit packages but do not add entries. Thanks @​VariableVince for the report in #​3918. (Closes #​3886)

  • fallow dead-code now credits a store member that a helper reads through a store alias declared in a function body. unused-store-member resolved type X = ReturnType<typeof useXStore> only at the top level of a module or through an import. An alias in a function body or a block now credits the store member for a parameter in the same scope. An inner type of the same name for another type still shadows the alias. A local non-store type alias also shadows a module-level store alias of the same name, so a read through the local type credits no store member. A parameter type resolves in the scope outside the function body, the same as in TypeScript. The extraction cache version is 386. (Closes #​3550)

  • Deeply nested defaults in an object pattern no longer make extraction hang. In a declaration such as const { k: { k: { m } = s } = s } = s, each default walked its left pattern again against the fallback. The work doubled at each level of nesting, so a short file could stop the analysis. A step budget now bounds the walk of one declaration.

  • fallow dead-code now credits Expo config plugins that come from a local array binding. An app config can hold its plugins list in a top-level const or let, such as const plugins = [...]; export default { plugins }. Fallow now reads that list, its spreads of array literals or other stable bindings, and entries or tuples that a binding holds. A push, unshift or splice call on the list adds its arguments, also inside a top-level block or if statement. An expo object with a type assertion, such as expo: { ... } satisfies ExpoConfig, is read too. Fallow credits nothing from a binding that the config reassigns, from a name that the config declares more than once, or from a dynamic value. (Closes #​3883)

  • --production --type-aware no longer credits an export that only a test file uses. A type-aware reference from a file outside the analysis scope, such as a test file that production mode excludes, no longer removes a dead-code finding. Thanks @​Smrtnyk for the report. (Closes #​3869)

  • Audit cleanup preserves unrelated Git worktree registrations. Removing legacy
    Fallow snapshots keeps user worktrees registered when their directories are
    temporarily unavailable.
    (Closes #​3884)

  • Astro extraction avoids repeated scans of malformed script and style tags. Quoted attributes retain their original source offsets and Unicode tag matching while incomplete tags no longer cause quadratic region scanning.

  • CODEOWNERS lookups avoid excessive memory use and slow matching with long patterns. Pattern batches bound regex fallback costs while preserving last-match precedence and GitLab section behavior.

  • Vue and Angular template extraction avoids repeated scans of incomplete tags. Recovery from an incomplete template tag or component interpolation no longer scans the same suffix again. Recovered references and source offsets stay the same.

  • MDX extraction avoids repeated parser runs on unfinished imports and exports. A multiline import or export that does not end no longer makes the parser try again for each line, and blank continuation lines are skipped.

  • Type-aware refinement on the tsrs backend no longer fails on public APIs with many non-generic interfaces. The semantic sidecar asked the checker for the type arguments of every type in the public API walk. On tsrs, each call on a type that is not a type reference panicked and wrote the panic to stderr. With enough such interfaces, stderr went past its 16384-byte limit and Fallow dropped the type-aware result. The sidecar now asks for type arguments only on type references, so tsrs gives the same result as typescript-go. Thanks to @​Smrtnyk for the report and the reproduction. (Closes #​3872)

  • Programmatic and MCP audits no longer show their base snapshot in git worktree list.
    The API, the MCP audit tool, and the decision surface now remove the Git
    registration of the base snapshot before the base analysis starts, as
    fallow audit does. They also remove the snapshots that a stopped process
    left behind. A snapshot stays when its owner process can still run, when
    Fallow cannot inspect that process, or when the snapshot is younger than one
    minute.
    (Closes #​3885)

  • fallow dead-code no longer reports the default export of a local Oxlint jsPlugins file. Oxlint loads the default export of each local plugin file. With includeEntryExports, fallow reported this export as unused. Fallow now credits the default export, as it does for the Oxlint config file. Other exports of the plugin file stay reportable. Thanks to @​Smrtnyk for the report.
    (Closes #​3871)

  • fallow dead-code no longer reports tsrs and fallow-type-aware as unused devDependencies. Fallow loads these type-aware backend packages at run time, so no script or import names them. The tooling catalogue now credits both packages by name. Thanks @​Smrtnyk for the report. (Closes #​3873)

  • fallow dead-code credits the packages in tsconfig contentMappers. TypeScript 7.1 loads each contentMappers[].package to map files such as .vue or .astro into the program. Fallow did not read this field, so it reported the mapper package as an unused dependency. The TypeScript plugin now credits the package name. Relative and absolute paths credit no dependency. Thanks to @​Smrtnyk for the report.
    (Closes #​3870)

  • fallow security follows per-path overrides for its dead-code note. A sink in a file where an override sets unused-files or unused-exports to off no longer shows the "also reported as unused-file" or "unused-export" note, and no longer gets the delete or remove action. Thanks to @​Smrtnyk for the report.
    (Closes #​3853)

  • fallow security no longer reports module-relative paths as path-traversal candidates. A path that starts from import.meta.url, import.meta.dirname, import.meta.filename, __dirname, __filename or process.cwd() and adds only literal segments cannot carry caller input. Examples are path.resolve(fileURLToPath(new URL(".", import.meta.url)), "..") and fs.readFileSync(path.join(__dirname, "template.html")). A module-scope const that holds such a path is also trusted. The rule applies to every sink argument, so res.sendFile(path.join(__dirname, "index.html")) is also clear. fileURLToPath(value) and new URL(value, import.meta.url) stay candidates when value is not known.
    (Closes #​3711)

  • fallow security now checks every path.join and path.resolve segment. Before, the path-traversal matcher checked only the first argument, so path.resolve(".", input) and path.join(".", input) gave no candidate. The matcher now checks each argument and reports one candidate for each call. A path.relative containment guard on the result still clears the call.
    (Closes #​3712)

  • fallow health --css credits classes that plain .js and .ts DOM code applies. Before, a class was reported as unreferenced-css-class when only a .js, .ts, .mjs or .cjs file applied it. Fallow now reads the values of el.className = ..., el.classList.add / remove / toggle / replace / contains(...), el.setAttribute('class', ...) and class: or className: object properties. A template value such as `panel-${kind}` credits its panel- prefix. Other strings in these files still do not credit a class. A .js file that holds JSX is now scanned the same as a .jsx file. Thanks to @​osazemeu for the report and the clear reproduction.
    (Closes #​3865)

  • fallow mutation now runs Vitest projects in a happy-dom or jsdom environment when the cache is outside the project. A client test environment loads the setup file of the mutation runtime through Vite. Vite refused that file when FALLOW_CACHE_DIR was outside the project, so the project failed its baseline with Cannot find module '/@fs/.../vitest-setup.mjs'. The Vitest adapter now adds the companion directory to server.fs.allow of the root server and of each inline project.
    (Closes #​3793)

  • fallow dead-code credits a member access on the declared return type of an instance method. A call such as manager.current()?.onDown?.(), where current(): Tool | undefined, now credits Tool.onDown. The implementer SelectTool.onDown is no longer reported as an unused class member. A class return type, such as manager.widget().paint() with widget(): Widget, now credits Widget.paint. Static, private, and method-generic return types give no credit. Thanks to @​Smrtnyk for the report.
    (Closes #​3868)

  • fallow dead-code no longer reports an aliased asset import as an unlisted dependency when the alias is in a referenced tsconfig. A solution-style root tsconfig.json can reference a config whose include starts with ./, for example `"./app/javascript/*

[!IMPORTANT]
✂ PR body was truncated to here.


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9c1244c0-679a-4828-b2af-d00d4ddfbe7e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@socket-security

socket-security Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedfallow@​3.33.1 ⏵ 3.36.0100100 +210096100

View full report

@pkg-pr-new

pkg-pr-new Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/node-modules/urllib@955

commit: 48821ec

@codecov

codecov Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.77%. Comparing base (e37325d) to head (48821ec).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #955   +/-   ##
=======================================
  Coverage   94.77%   94.77%           
=======================================
  Files          10       10           
  Lines         746      746           
  Branches      235      235           
=======================================
  Hits          707      707           
  Misses         36       36           
  Partials        3        3           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@renovate
renovate Bot force-pushed the renovate/fallow-3.x-lockfile branch from 712e1e2 to 33b7b10 Compare October 24, 2026 12:47
@renovate renovate Bot changed the title chore(deps): update dependency fallow to v3.34.0 chore(deps): update dependency fallow to v3.34.1 Oct 24, 2026
@renovate
renovate Bot force-pushed the renovate/fallow-3.x-lockfile branch from 33b7b10 to e065afc Compare October 25, 2026 13:43
@renovate renovate Bot changed the title chore(deps): update dependency fallow to v3.34.1 chore(deps): update dependency fallow to v3.35.0 Oct 25, 2026
@renovate
renovate Bot force-pushed the renovate/fallow-3.x-lockfile branch from e065afc to 48821ec Compare October 28, 2026 16:35
@renovate renovate Bot changed the title chore(deps): update dependency fallow to v3.35.0 chore(deps): update dependency fallow to v3.36.0 Oct 28, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants