Skip to content

v3.37.0: resumable mutation runs, CSS classes from template files, and signed Windows binaries

Latest

Choose a tag to compare

@BartWaardenburg BartWaardenburg released this 27 Oct 20:45
· 47 commits to main since this release
Immutable release. Only release title and notes can be modified.
v3.37.0
85fa327

Features

  • fallow health --css reads server-side template files as class references. Fallow now reads .liquid, .njk, .hbs, .handlebars, .twig and .blade.php files, and each class-like word in them counts as used. A class that only a Shopify Liquid section applies is no longer an unreferenced-css-class. A class prefix before a {{ echo, as in grid--{{ columns }}, also counts. The {{ rule also applies to .vue, .html, .md and .astro sources with dynamic class syntax, so these sources can report fewer classes. Use the new top-level markupExtensions key to add other template extensions, for example ["tpl", "erb"]. These files do not join source discovery, so they never become unused files. Thanks @james2doyle for the report. (#3917)

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

  • An interrupted fallow mutation run keeps its finished results, and --resume continues it. Each run writes each killed and retry-confirmed survived mutant to .fallow/mutation/journal.jsonl when its result is final, also with --no-cache. fallow mutation --resume reuses these results and runs only the other mutants. When the journal comes from other inputs, the run 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. (#3783)

Changed

  • A bare machine run that exits 0 on a failing gate now says so on stderr. Bare fallow in a machine format exits 0 on findings, but fallow dead-code --format json exits 1 on the same findings. Before, nothing showed why. Now the run prints one stderr line, also under --quiet, that names each failing findings gate and the flag that enforces it. The exit code and stdout do not change. Thanks @Smrtnyk for the report. (#3826)

  • The exit-code contract no longer says that exit 0 means a clean run. fallow schema (exit_codes), the fallow skill and the npm README now say that 0 means no enforced gate failed. Exit 1 means findings, not a tool failure. 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); } no longer gives mutants. The condition must be pure, and each branch must hold only console.* or debug(...) calls with pure arguments. In a file that declares or imports console or debug, the conditions that call that name keep their mutants. (#3719)

Bug fixes

  • thin-wrapper and duplicate-prop-shape set to error now fail the gates. At error, these rules count in issue totals, the dead-code and audit gates, and CI reports. A rule at warn does not fail a gate, also with --fail-on-issues. Thanks @luciocabrera for the report. (#3867)

  • A CommonJS postcss.config.cjs no longer reports its module.exports keys as unused exports. When a plugin credits only default for a CommonJS module, Fallow now credits every key of module.exports. The fix applies to the CommonJS config files of all plugins that read the default export. Thanks @waldoluisribeiro for the report. (#3876)

  • fallow security resolves a string enum member in the same module. Fallow no longer reports a template literal such as `<meta name="${MetaName.BUILD_NUMBER}">` that goes to an HTML sink as non-literal HTML. Enums and constants that you import from another module stay unresolved. The first run after the update parses all files again. Thanks @Smrtnyk for the report. (#3854)

  • Component export queries no longer stop type-aware refinement for the whole run. Fallow now gives Vue, Astro, Svelte and MDX query files an unsupported-syntax abstention. Supported TypeScript and JavaScript queries in the same batch continue to resolve. (#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. path.resolve, __dirname, import.meta.dirname and a constant that holds the module directory also work. Thanks @VariableVince for the report. (#3919)

  • Fallow now reads config values from a same-file constant. A config can keep part of its value in a top-level constant, for example projects: [UNIT]. Fallow now uses the value of the constant, so the setup files of such a Vitest project are no longer unused files. The fix applies to all plugins that read config files. Thanks @Smrtnyk for the report. (#3852)

  • fallow dead-code no longer reports a class member as unused when an array pattern or a getter on a held object is its only read. An array pattern around an object pattern, such as const [{ m }] = [service], now credits the member. Fallow also credits the member for a src.k.m read through a getter on an object literal that a variable holds. Both forms now credit the member without --type-aware. (#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. Fallow follows nested helpers and literal cd steps. Thanks @VariableVince for the report in #3918. (#3886)

  • fallow dead-code now credits a store member that a helper reads through a store alias declared in a function body. An alias such as type X = ReturnType<typeof useXStore> in a function body or block now credits the store member. An inner type of the same name still shadows the alias. (#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, the work doubled at each level of nesting. 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. Fallow now reads that list, its spreads, and push, unshift or splice calls on it. An expo object with a type assertion, such as satisfies ExpoConfig, now also counts. (#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 no longer removes a dead-code finding. Thanks @Smrtnyk for the report. (#3869)

  • Audit cleanup preserves unrelated Git worktree registrations. When Fallow removes old snapshots, it keeps each user worktree registered while its directory is temporarily unavailable. (#3884)

  • Extraction is no longer slow on malformed input. Incomplete script and style tags in Astro and incomplete template tags in Vue and Angular no longer cause repeated scans. An unfinished multiline import or export in MDX no longer makes the parser run again for each line. CODEOWNERS lookups with long patterns no longer use too much memory or time. Results and source offsets do not change.

  • Type-aware refinement on the tsrs backend no longer fails on public APIs with many non-generic interfaces. The semantic sidecar now asks for type arguments only on type references. tsrs now gives the same result as typescript-go. Thanks @Smrtnyk for the report and the reproduction. (#3872)

  • Programmatic and MCP audits no longer show their base snapshot in git worktree list. The API, the MCP audit tool and the pull-request decision output now remove the Git registration of the base snapshot, as fallow audit does. They also remove snapshots that a stopped process left behind. (#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, and now it credits the export. Other exports of the plugin file stay reportable. Thanks @Smrtnyk for the report. (#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, and now credits both by name. Thanks @Smrtnyk for the report. (#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. The TypeScript plugin now credits the package name. Thanks @Smrtnyk for the report. (#3870)

  • fallow security follows per-path overrides for its dead-code note. In a file where an override sets unused-files or unused-exports to off, a sink no longer shows the unused note or the delete action. Thanks @Smrtnyk for the report. (#3853)

  • fallow security no longer reports module-relative paths as path-traversal candidates. A path from import.meta.url, import.meta.dirname, import.meta.filename, __dirname, __filename or process.cwd() with only literal segments cannot contain caller input. An example is fs.readFileSync(path.join(__dirname, "template.html")). Fallow also trusts a module-scope const that holds such a path. (#3711)

  • fallow security now checks every path.join and path.resolve segment. Before, path.resolve(".", input) gave no candidate. The matcher now checks each argument and reports one candidate for each call. (#3712)

  • fallow health --css credits classes that plain .js and .ts DOM code applies. Fallow now reads el.className = ..., el.classList calls, el.setAttribute('class', ...) and class: or className: object properties. A template value such as `panel-${kind}` credits its panel- prefix. Fallow now scans a .js file that holds JSX the same as a .jsx file. Thanks @osazemeu for the report and the reproduction. (#3865)

  • fallow mutation now runs Vitest projects in a happy-dom or jsdom environment when the cache is outside the project. Before, such a project failed its baseline with Cannot find module '/@fs/.../vitest-setup.mjs' when FALLOW_CACHE_DIR was outside the project. (#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. SelectTool.onDown is no longer an unused class member. Thanks @Smrtnyk for the report. (#3868)

  • fallow dead-code no longer reports an aliased asset import as an unlisted dependency when the alias is in a referenced tsconfig. Fallow now removes ./ and .. segments from include and exclude patterns before it matches them. The paths of that config now apply. Thanks @agneym for the report and the public reproduction. (#3946)

  • A tsconfig in a directory whose name holds glob characters now applies to its files. A directory such as app/[id] or {a,b} no longer changes the meaning of an include pattern. As in tsc, only * and ? are wildcards in an entry.

Security

  • The Windows binaries now have an Authenticode signature from Fallow B.V. Windows 11 Smart App Control blocked the unsigned fallow.exe from the npm package. The release now signs each Windows executable and the Node addon. The signed files ship in the GitHub release archives, the npm packages and the VS Code extension. The Ed25519 signatures do not change. Thanks @Rednas83 for the report. (#3807)

  • Git commands in an audit base snapshot no longer read a repository from the base commit. A base commit could supply a repository whose config runs commands, for example through core.fsmonitor. The .git file now names an absolute path that cannot exist. Each Git command in a snapshot now gets a GIT_DIR that does not exist. Fallow also sets safe.bareRepository=explicit on every Git command that it starts.

  • fallow hooks install validates the detected default branch name. Without --branch, a crafted origin/HEAD name could put shell code into the generated hook. The command now applies the same ref validator as --branch. When the name fails, the command prints a warning and uses main.

Full Changelog: v3.36.0...v3.37.0