`sanitizeMigratedOxlintConfig` removes rules whose namespace no surviving
plugin contributes. That removal is necessary — Oxlint refuses to start on a
rule naming a plugin it cannot resolve ("Plugin 'x' not found") — but it
happened silently, while dropped plugins and jsPlugins already warned.
A local jsPlugin makes this visible. Its real namespace comes from the
plugin's `meta.name`, which cannot be derived from a path specifier such as
`./lint/kumo.js`, so every `kumo/*` rule was filtered out of the migrated
config with no output at all.
Collect the removed rule keys and warn with them, pointing at the object
form (`{ name, specifier }`) that lets a user name the namespace explicitly.
Refs voidzero-dev#2231
Refs #2231. This fixes the "silently" half of that issue and deliberately leaves the namespace-resolution half open — see What this leaves for #2231 below.
Problem
When vp migrate merges .oxlintrc.json into vite.config.ts, sanitizeMigratedOxlintConfig removes every rule whose namespace no surviving plugin contributes. Dropped jsPlugins and dropped plugins each produce a warning; dropped rules produced nothing at all.
The case #2231 reports makes it concrete. A local plugin is kept by the sanitizer (partitionJsPlugins passes ./-style specifiers through, because Oxlint resolves them itself), but deriveJsPluginNamespace has only the path to work with and returns ./lint/kumo.js verbatim. No rule key can ever match that, so every kumo/* rule is filtered out of the migrated config and the user is told nothing.
Why the rules still have to be dropped
I checked what Oxlint actually does before assuming the filtering could simply be relaxed, using the bundled oxlint 1.79.0 on a scratch project.
A rule under a namespace no plugin backs is not a warning — it stops Oxlint from starting at all:
$ cat .oxlintrc.json { "jsPlugins": ["./lint/kumo.js"], "rules": { "kumo/no-foo": "error", "ghostplugin/some-rule": "error" } } $ oxlint a.js Failed to parse oxlint configuration file. x Plugin 'ghostplugin' not found $ echo $? 1So keeping unattributable rules would trade a silent config loss for vp lint failing outright on the whole project. Dropping them is the right behaviour; doing it without a word is not.
Two other things that same probe established, both of which shape the fix:
Changes
Behaviour is otherwise unchanged: the same rules are dropped as before, and nothing new is kept.
What this leaves for #2231
The issue suggests resolving the real namespace by importing the plugin and reading meta.name, which is exactly what Oxlint does. I have not done that here, because it is a design decision I do not think a contributor should make unilaterally:
Alternatives that avoid both — a synchronous require of the plugin, statically extracting meta.name, or having the migrator rewrite local jsPlugins into the object form so the namespace is recorded explicitly — each trade differently. Happy to implement whichever you prefer, here or as a follow-up. In the meantime this at least means the rules no longer vanish silently.
Testing
Three tests added next to the existing sanitizer tests in packages/cli/src/migration/__tests__/migrator.spec.ts: the #2231 local-plugin case, an override-rules case, and a negative case asserting no warning when nothing is dropped.
Verified in both directions — with migrator/eslint.ts reverted to main and the tests kept, the two positive tests fail (AssertionError: expected undefined to be defined); with the change applied they pass. The negative test passes either way, as it should.
Checks actually run on this branch:
One caveat on the lint run, in case anyone reproduces it: pnpm build generates an untracked packages/cli/src/migration/versions.ts, which in a local build carries only { vite, vitest }. While it is present, type-checking reports two errors in migrator/eslint.ts:139-141 (an unused @ts-expect-error and a missing versions.oxlint) that have nothing to do with this change — that code deliberately resolves versions.js from dist/ at runtime. With that generated file removed, both errors disappear and the only remaining diagnostics are 19 in the unbuilt docs/ workspace.
Not run: the PTY snapshot suite and ecosystem e2e. This changes no CLI command output beyond adding a migration warning, which is reported through MigrationReport and asserted directly in the tests.
AI assistance
Claude Opus 5 wrote the implementation, the tests, the oxlint probes, and this description. The change is agent-authored and has not had a separate human review. Every result quoted above is from an actual run on this branch, not an estimate.
Generated by Claude Code