biome-anti-slop
v0.1.0
Published
Opinionated Biome (GritQL) lint rules that reject low-evidence and low-signal TypeScript and JavaScript patterns. A port of oxlint-plugin-anti-slop.
Maintainers
Readme
biome-anti-slop
Opinionated Biome lint rules that reject low-evidence TypeScript and JavaScript patterns:
unknown smuggled through contracts, type assertions that fabricate evidence, dictionary types
that erase their values, module mocks standing in for real seams.
A port of dmmulroy/anti-slop from Oxlint's JavaScript
plugin API to Biome's GritQL plugins. The rules and opinions are upstream's; the implementations
are new.
Biome plugins have no scope analysis, type information, or dataflow, so some rules catch less than the Oxlint originals. Every divergence is measured in docs/PARITY.md.
Install
npm install --save-dev biome-anti-slop
npx biome-anti-slop initinit adds one line to biome.json:
{
"extends": ["biome-anti-slop"]
}Then verify the rules load:
npx biome-anti-slop doctorRequires Biome 2.5.0+ and a node_modules directory.
Start smaller
recommended drops the five noisiest rules:
{
"extends": ["biome-anti-slop/recommended"]
}Or list rules individually:
{
"plugins": [
"./node_modules/biome-anti-slop/plugins/no-unknown-returns.grit",
"./node_modules/biome-anti-slop/plugins/no-chained-type-assertions.grit"
]
}Write paths from the project root, ./node_modules/ prefix included. Biome resolves plugin paths
against the consuming project, not against the config that declares them.
Vendor instead
npx biome-anti-slop vendor biome/anti-slopCopies the .grit files into your repo and prints the plugins array. The files are then yours to
edit.
With a coding agent
skills/install-biome-anti-slop/ installs, verifies, and reports the new diagnostic count per rule.
Rules
| Rule | Rejects | Parity |
| --- | --- | --- |
| no-chained-type-assertions | nested assertions that fabricate evidence, input as object as User | full |
| no-conditional-empty-object-spread | conditional spreads that use {} to omit fields | approximate |
| no-known-value-widening | broad target types that discard known value evidence | partial |
| no-module-mocking | Vitest and Jest module mocks in place of real dependency seams | partial |
| no-object-parameters | the broad object type on function inputs | partial |
| no-reflect-apply | Reflect.apply in place of typed function calls | partial |
| no-reflect-get | Reflect.get in place of typed property access | partial |
| no-runtime-typeof | ad hoc typeof narrowing instead of boundary parsing | partial |
| no-shape-in-symbol-names | shape in symbol names, interface UserShape | partial |
| no-unknown-parameters | unknown inputs, except the explicit cause convention | partial |
| no-unknown-returns | contracts returning unknown or Promise<unknown> | partial |
| no-unknown-type-aliases | aliases that merely conceal unknown | partial |
| no-unsafe-dictionary-type | dictionaries valued by unknown, any, object, {} | partial |
| no-widen-then-assert | flows that widen known values and later assert them back | partial |
| require-safety-comment-for-type-assertion | assertions that do not document their checked invariant | partial |
recommended excludes no-known-value-widening, no-runtime-typeof, no-shape-in-symbol-names,
no-widen-then-assert, and require-safety-comment-for-type-assertion.
Suppressing a diagnostic
// biome-ignore lint: parsed by the boundary schema directly above
const config = raw as Config;Biome puts every plugin diagnostic in one plugin category, so a suppression comment silences all
anti-slop rules on that line. There is no per-rule suppression, and rules cannot be toggled through
linter.rules. Granularity comes from which plugins you enable.
Troubleshooting
Run npx biome-anti-slop doctor first.
Error(s) during loading of plugins: Cannot read file means the package is not resolvable from
the project root.
- pnpm: works for a direct dependency. If it is only transitive, add it directly.
- Monorepos: install it in the package whose
biome.jsonyou are editing. - Yarn PnP: no
node_modulesto point at, so usenpx biome-anti-slop vendor.
A plugin that fails to load aborts the entire lint run: Biome lints nothing and --reporter=json
emits no JSON. Do not read a quiet run as a clean one.
No diagnostics at all: check extends contains biome-anti-slop, and that files.includes
covers the code you expect to lint.
Development
npm install
npm testnpm run test:rulesruns every rule against its fixtures. Fixtures mark expected violations with a trailing//~ error; the harness fails on false negatives and false positives, and treats a plugin that fails to compile as a hard failure. 924 violation cases, ~1,900 lines of valid code.npm run test:robustnessruns every rule against hostile constructs (destructuring, braceless switch cases, deep parens, JSX, generated-size files) under a time budget. Both failure modes it catches are silent: a rule that aborts reports nothing and looks like a clean codebase, and an accidentally quadratic rule fails as a hang rather than a wrong answer. Neither shows up in a rule's own fixtures, and both shipped once.npm run test:clicovers the installer, including that it never clobbers an existing config.npm run test:installbuilds a throwaway consumer project and proves the install resolves.npm run checkverifies plugins, presets, fixtures, and docs have not drifted apart.
Read docs/GRITQL-NOTES.md before changing a rule. It records what Biome's GritQL engine can and cannot express, verified empirically.
License
MIT. Ported from dmmulroy/anti-slop (MIT, © Dillon
Mulroy).
