Skip to content

v3.29.0: raw V8 coverage, parse-error gate, complexity rule levels, deprecated export consumers

Choose a tag to compare

@BartWaardenburg BartWaardenburg released this 26 Sep 05:04
· 30 commits to main since this release
Immutable release. Only release title and notes can be modified.
v3.29.0
08ce24a

Features

  • health --coverage reads raw V8 coverage. Give it a NODE_V8_COVERAGE directory or one V8 coverage JSON file, and CRAP scores use measured coverage without a conversion step. The dumps of all test processes add up. A transpiled script maps back to its sources through the source map in the dump. health.coverage, FALLOW_COVERAGE, fallow audit and the MCP tools take the same inputs. The new summary.coverage_input_format field is istanbul or v8 (#2906).
  • A run can fail when fallow cannot parse a source file. The new --fail-on-parse-error flag and the failOnParseError config key add a parse-error gate on dead-code, health, audit and bare fallow. The gate is off by default, and gate_outcomes["parse-error"] names each file with its parser error count. Thanks @fpresta0607 for the report (#2727).
  • Complexity findings can warn without failing the run. The new rules complexity-cyclomatic, complexity-cognitive and complexity-crap accept error (the default), warn or off, also per file through overrides[].rules. Each complexity finding in the JSON output gets an optional effective_severity. Thanks @jwenger-notion for the report (#2783).
  • fallow dead-code can list the files that still use @deprecated exports. The opt-in deprecated-export-in-use finding gives a consumer_count, a sample of up to 10 consumers and the deprecation message. Turn it on with "deprecated-exports-in-use": "warn" in rules or --deprecated-exports-in-use. An unused deprecated export now has deprecated: true on its unused-export finding (#2598).
  • The review brief shows how many CODEOWNERS owner groups a change touches. fallow review and fallow audit --brief get an ownership section when the project has a CODEOWNERS file. It gives owner group counts, unowned changed files and independent slices. The brief schema_version moves from 10 to 11 (#2599).
  • Module Federation credits shared packages and runtime remotes, and traces name the config. A package that shared names is no longer an unused dependency (#2794). Literal registerRemotes and loadRemote calls register their remotes in a file that imports them from @module-federation/runtime or @module-federation/enhanced/runtime (#2795). --trace-file and --trace-dependency name the Federation config and key in a new sources array (#2796).
  • --changed-since states how many analyzed files it kept. The changed-since entry of request_outcomes now has scope_size, so a change to a README only gives scope_size: 0. The GitHub Action, the GitLab template, the PR and MR comments and the MCP warning state the empty scope (#2800).
  • A foreign baseline names the command that wrote it. baseline_staleness now has saved_by next to unrecognised_format: true. The GitHub Action has a new baseline-saved-by output (#2801).
  • Security candidates record strict origin checks. fallow security records an origin-equality-guard control when a file on the import trace compares .origin strictly with a known string and exits on a mismatch. The control is a hint for verification, not proof. It does not suppress a candidate or lower its severity.

Changed

  • The rule, not the band, sets the CI level of a complexity finding. error gives ::error, SARIF error and CodeClimate major. warn gives ::warning, SARIF warning and CodeClimate minor. The band stays in the title and the message (#2783).
  • --fail-on-issues also raises warn complexity findings to error. This applies to fallow health and bare fallow, also through --ci. fallow audit keeps its own verdict (#2824).
  • JSON output always states whether the run passed. Bare fallow, dead-code, check, health, security and audit now always include gate_outcomes with the default rule of the command and its status. No exit code changes.
  • The GitHub Action flags the legacy summary renderer, and a failed native render no longer falls back to it. For fallow before 3.4.2, the step log shows a notice and the job summary shows a footnote. The legacy renderers get no new finding types. On 3.4.2 or later, a failed native render writes a warning.

Bug fixes

  • Dockerfiles with non-ASCII text no longer crash the run. A short line with a multi-byte character, for example in an embedded SQL seed script, now counts as an ordinary line. Thanks @ga-h-usuba for the report (#2896).
  • CI formats state the rule severity of each dead-code finding. A finding with rule error now gives ::error in github-annotations, and SARIF and CodeClimate read the per-file overrides[].rules severity. Error annotations come first, so the max-annotations cap keeps them. Thanks @jwenger-notion for the report (#2782).
  • Severity levels agree across commands and saved reports. fallow dead-code now uses the overrides[].rules entry for catalog and dependency-override findings, the same as fallow audit. Prop-drilling, thin-wrapper and duplicate-prop-shape findings show as SARIF warning at most, because they never fail the run (#2826). fallow report --from keeps the saved level of each finding (#2827).
  • Nuxt autoImports credits global components, local layers and OG image templates. Global components and @nuxt/content components are now entry points, also when a package layer such as docus registers @nuxt/content (#2847, #2851). Fallow now credits OG image templates that a string names (#2849). Local layers are part of the project, and auto-import names from #components namespace imports now credit their files (#2752). A name now credits only the files of the app that uses it and of its layers.
  • Module Federation reads more config shapes. Fallow now reads options behind an export const, a spread, Object.assign, a wrapper call or a relative import (#2757). An exposes target in a sibling workspace is an entry point, and fallow reads runtime calls in .vue and .svelte scripts (#2757, #2876). A shape that fallow cannot read records a plugin-config-unreadable diagnostic.
  • Bundler entries resolve like the bundler resolves them. A bare rollup, rolldown or vite input such as my-lib/client credits its package. An entry without an extension matches the file or the directory index (#2753). Fallow now reads webpack configs in config/, build/ or webpack/, and applies rspack context and rsbuild root to entries (#2753). Fallow reads an absolute config path under the project root as that path (#2806).
  • Storybook stories patterns resolve against the .storybook/ directory. A pattern such as ../src/**/*.mdx now matches, and @(ts|tsx) groups work (#2831). A central docs app now credits stories in a sibling workspace, and fallow now reads the object form { directory, files, titlePrefix } (#2842).
  • Save and report files stay inside allowed directories. The save flags, --output-file and --sarif-file exit 2 when the resolved file is outside the allowed directories (#2805, #2861). These are the project root, its Git work tree, the CI workspace, RUNNER_TEMP and the system temp directory. -o /dev/null still discards a report, and -o NUL now discards it on Windows (#2877). When .fallow resolves outside the project, the run does not use the cache and prints a note (#2861).
  • Flags that did nothing now exit 2. --baseline and --save-baseline on a subcommand without a baseline, such as fallow list, now exit 2 (#2802, #2807). dupes, health and a bare run without dead-code reject --sarif-file and point to --format sarif --output-file (#2861, #2877).
  • Bare fallow now applies dupes and health baselines. Use fallow --dupes-baseline <file> and fallow --health-baseline <file>. --fail-on-stale-baseline now checks all three baselines.
  • Export tags attach to the right export. A JSDoc block before a decorator now attaches to the decorated export (#2835). In code without semicolons, a tag such as @public no longer applies to later exports.
  • A re-export through an unresolved import counts as used when a file imports the name. Before, the re-exported name was also an unused export. A re-exported name that no file imports is still an unused export (#2870).
  • Inline suppressions work for component events. A fallow-ignore-next-line or fallow-ignore-file comment for unused-component-emit, unused-component-input, unused-component-output or unused-svelte-event now drops the finding.
  • Template complexity counts operators inside a template literal. In an Angular, Vue or Svelte template, a ternary, &&, || or ?? inside ${} now adds complexity (#2798).
  • fallow audit shows a dependency finding only when its manifest changed. The changeset must touch the package.json or the catalog file that declares the dependency. An edit that only removes a tag such as @expected-unused or @public now counts the finding as introduced. The MCP audit tool treats findings in renamed files as inherited, the same as the CLI.
  • The MCP tools and the Node API match the CLI. A bad FALLOW_DIFF_FILE or FALLOW_CHANGED_SINCE now gives a not-applied entry in request_outcomes, not isError (#2799). Clone groups across workspaces and hidden duplicate exports now follow the CLI. The four MCP tools that can write a baseline declare readOnlyHint: false, and code_execute refuses the save parameters (#2755).
  • Health reports cover more repository layouts. health --hotspots works when the project root is a subdirectory of the Git repository. A branch without commits gives a hotspots-skipped diagnostic with the cause no-commits (#2803). With --type-aware-require complete, gate_outcomes of health and audit now show a failed check.
  • fallow list names the entry points that the analysis uses. On a Nuxt project with autoImports: true, fallow list --entry-points no longer names every component as an entry point (#2804).
  • The human summary line follows the result of the run. A run that passes with warn findings now shows a yellow ⚠, and the red ✗ shows only when a gate fails (#2824). The health headers print 1 file for a count of one (#2808).
  • Editor complexity lenses match fallow health. The code lens now applies health.thresholdOverrides and the complexity-cyclomatic and complexity-cognitive rules with overrides[].rules (#2825).
  • Security candidates need a complete URL authority and skip constant writeHead headers. A server-side request forgery candidate now needs a complete URL authority in the fixed prefix. A writeHead call with constant headers is no longer a header-injection candidate. Findings for different sinks on the same line have distinct IDs.
  • The VS Code extension keeps working before its release is published. The previous verified binary stays in place until the new one downloads. With fallow.autoDownload on, the extension retries in the background.
  • Other fixes. report --from renders a clean --group-by run (#2830). The GitHub Action checks the baseline input for control characters (#2756). The git hook falls back to origin/main, then origin/master (#2758). The hidden-directory message gives a remedy that fixes the run (#2797). Traces pick the file at the exact path you name, and programmatic duplication follows the dupes production mode. Fallow no longer warns that a circular-dependency override has no effect.

Performance

  • fallow guard compiles each rule-pack scope once per run. Zone validation no longer compiles the boundary zone globs a second time.

Upgrade notes

  • Strict JSON validators: the dead-code summary has the required key deprecated_exports_in_use, and the envelope has a deprecated_exports_in_use array. schema_version does not change.
  • This release invalidates the parse, extraction, graph and churn caches, so the first run after the upgrade is cold.
  • Complexity findings with the default rules change CI level. A moderate finding is now ::error and SARIF error. CodeClimate critical and minor become major. Set a complexity-* rule to warn to keep them as warnings.
  • Dead-code findings with rule error now give ::error in github-annotations.
  • gate_outcomes is now always in the JSON output. The GitHub Action output gates-failed and the GitLab FALLOW_GATES_FAILED variable are non-empty on every run with findings, also when the job stays green. Check the gate names, not a non-empty value.
  • Every security finding ID changes. Regenerate candidate files and their verdicts together. SARIF alerts can reopen once.
  • These flags now exit 2: --baseline and --save-baseline on subcommands that do not use them, and --sarif-file on dupes, health or a bare run without dead-code. --dupes-baseline and --health-baseline with a subcommand also exit 2.
  • A save or report file outside the allowed directories now exits 2 before the analysis. Move the path into the project root, the CI workspace or a temp directory.
  • New findings can appear: unused-export in code without semicolons, unused files in Nuxt projects with autoImports on, and higher template complexity. fallow audit no longer reports a dependency finding when the manifest did not change. Run fallow dead-code to see it.
  • An older fallow rejects failOnParseError as an unknown key. Set minimumVersion when you commit it.
  • After you turn a complexity kind off, save the health baseline again.
  • MCP: code_execute now refuses save_baseline, save_regression_baseline and save_snapshot. Call the standalone tool for the write.

Full Changelog: v3.28.0...v3.29.0