@timmo001/oxlint-rules
v0.6.2
Published
Shared Oxlint plugins and configs with optional Effect rules.
Readme
Oxlint Rules
Shared Oxlint plugins and configs built around the unchanged
dmmulroy/anti-slop rules, with
locally owned generic rules under timmo and Effect rules under
timmo-effect.
This package targets the latest stable Oxlint toolchain. Oxlint's
JavaScript plugin API is alpha
and is outside its semver guarantees, so each rules release declares the exact
oxlint and @oxlint/plugins versions it has validated. Older toolchains and
untested future versions are not part of the support contract.
Install
Check the published rules package's peerDependencies against the official npm
latest versions of oxlint and @oxlint/plugins. If they differ, a validated
rules release is needed before upgrading. Do not bypass peer checks or override
Vite Plus's bundled dependencies to make an unsupported version fit.
Once the versions match, install from npm with the package manager already used by the repository:
bun add --dev --exact @timmo001/oxlint-rules oxlint @oxlint/pluginsExtend the generic config:
import { defineConfig } from "oxlint";
import recommended from "@timmo001/oxlint-rules/configs/recommended";
export default defineConfig({
extends: [recommended],
});Effect repositories can use the opt-in config instead:
import { defineConfig } from "oxlint";
import recommendedEffect from "@timmo001/oxlint-rules/configs/recommended-effect";
export default defineConfig({
extends: [recommendedEffect],
});Both configs can be installed from JSR with its npm compatibility support.
npmjs.org remains the default for package managers that resolve ordinary
package names from node_modules.
For type-aware linting, also pin the latest oxlint-tsgolint version that meets
Oxlint's declared peer requirement and has passed the package check. Enable
options: { typeAware: true } in the consumer's config. The shared configs do
not enable type-aware linting themselves.
Copy rules
Copy a reviewed snapshot when a repository should own the rule source:
npx --yes @timmo001/oxlint-rules copy tools/oxlint/timmo-rulesThe command prints every copied plugin entry point and the rule settings from
the package configs to merge into the target Oxlint config. Effect settings
remain opt-in. It excludes tests and repository metadata, and refuses to
replace an existing destination unless --force is passed.
Skills
install-timmo-oxlint-rules
guides agents through installing or copying these rules:
npx skills add timmo001/oxlint-rules --skill install-timmo-oxlint-rulesadd-oxlint-rule and
release-oxlint-rules are for
maintaining this package.
Rules
anti-slop and anti-slop-effect
See the upstream rule documentation.
The recommended configs disable
anti-slop/require-safety-comment-for-type-assertion in favour of
timmo/prefer-types-over-assertions. The upstream rule remains available for
explicit use.
Oxlint built-in rules
The recommended configs also enable typescript/no-non-null-assertion,
typescript/no-unnecessary-type-arguments,
typescript/no-unnecessary-type-assertion, and
typescript/no-unnecessary-type-parameters. The last three are type-aware, so
they only run when the consumer enables typeAware.
timmo
no-explicit-inferable-type-predicate: reports explicitx is Tpredicates on non-exported functions whose whole body is a null orundefinedexclusion, atypeofcomparison, or aninstanceofcheck. TypeScript 5.5 and later infer those predicates, and an explicit predicate is never checked against the body. Methods, exported functions, andassertspredicates are left alone.no-unchecked-query-selector-type: reports type arguments onquerySelector,querySelectorAll, andclosest, which cast the result without checking it. Check the element withinstanceof, use a checked lookup helper, or query a tag name so TypeScript infers the type. Static render-root queries in Lit elements are left toprefer-lit-query-decorators.no-untyped-custom-event: reportsCustomEventused as a type without a detail type, which leavesdetailasany. Reuse the project's typed event helper or add one.prefer-event-parameter-type: reports assertions on a handler parameter'starget,currentTarget, ordetail(including nesteddetailmembers). Express the type in the function signature instead so every use sees the same contract.prefer-lit-query-decorators: follows eslint-plugin-lit'sprefer-query-decorators, including its options andsettings.lit.elementBaseClasses. It also catches non-null, optional, and asserted render roots such asthis.shadowRoot!.querySelector(...), and resolvesthisso nested classes and plain functions are not reported. Only static selectors are reported, because a query decorator cannot express a selector built at runtime. Turn offlit/prefer-query-decoratorswhen using this rule.prefer-types-over-assertions: reports non-constTypeScript assertions, even when preceded by aSAFETY:comment. Type values where they enter the code, for example in function parameters or a checked DOM lookup helper that returnsnullwhen the element is missing or has the wrong type. Assertions thatprefer-event-parameter-typereports are skipped here.
timmo-effect
no-raw-gh: reports the rawexecute,jsonandstreammethods called on ayield* Ghbinding from@timmo001/effect-gh,Api.rawfrom that package, and calls that launch gh:"gh"followed by its arguments, such asexecutor.run("gh", ...), or an argument array starting with"gh"passed to a spawn, exec, run or command function, such asBun.spawn(["gh", ...]). Use the package's typed operations, and add one to effect-gh when a command has none. effect-gh's own relative imports are not reported.no-try-catch-in-effect-generators: diagnoses synchronoustry/catchowned by generators passed directly toEffect.genor the curriedEffect.fnform. It leaves ordinary async polling, nested callback boundaries, non-Effect generators, andtry/finallycleanup alone. The rule is diagnostic-only because catch bodies cannot be rewritten safely in general.prefer-platform-services: in modules that importeffect,effect/*, or@effect/*, reports Nodechild_processandfsimports and Bun'sspawn,spawnSync,$,file, andwrite. UseChildProcessSpawnerfromeffect/processand theFileSystemservice so cleanup, interruption, typed failures, and test layers apply.fetchis not reported.
Development
Initialise the upstream source and run the package checks:
git submodule update --init --recursive
mise run check ::: build
mise run test:package
npm pack --dry-run
bunx [email protected] publish --dry-run --allow-dirtybun run lint builds the local plugins before linting all maintained code,
including tests, tooling, the root config and packaged skill scripts. The root
config extends the local recommended-effect source config, enabling registered
rules in anti-slop, timmo, anti-slop-effect and timmo-effect except for
the upstream safety-comment requirement described above.
Plugin imports resolve through this package's exports to the fresh dist build.
Lint disables nested configs so the vendored submodule's config cannot override the root exclusions. Generated output, vendored source and agent directories remain excluded. RuleTester fixture strings retain their intentional violations; the surrounding test code is linted with the full rule set.
mise run test:package builds and packs once, then installs the tarball in an
isolated consumer using the exact toolchain pins from package.json and strict
peer checks. It verifies both recommended configs, diagnostics from all four
shared namespaces, and valid and invalid type-aware examples. CI runs this
through the existing package workflow's build step. It also requires matching,
exact Oxlint development and peer versions.
Toolchain updates and releases
Renovate's shared preset groups Oxlint, @oxlint/plugins and oxlint-tsgolint.
The local rule keeps both development and peer dependencies pinned instead of
widening peer ranges. For each update:
- Verify the official npm
latestversions and Oxlint's tsgolint peer requirement. Keep Oxlint and plugins on the same latest version and regenerate the lockfile with the selected tsgolint version. - Run the checks and package dry-runs above. Fix any API incompatibility before accepting the new pins; do not disable rules or bypass peer failures.
- Review and merge the validated update. Consumers need a separately approved version bump and release to receive the new peer contract. Publishing a GitHub release triggers the existing npm and JSR workflows; both must succeed before the update is available to consumers.
Advance vendor/anti-slop only by updating its Git submodule commit. Keep its
source and MIT licence unchanged, then run the full package checks so both
upstream exports and composed configs are verified.
