feat(lint): serve the Oxlint plugin API from vite-plus - #2328
Draft
fengmk2 wants to merge 2 commits into
Draft
Conversation
Vite+ bundles Oxlint, and `vp migrate` strips a standalone `oxlint` dependency. A project's own Oxlint JS plugins import the authoring API by name, so that import stops resolving and `vp lint` fails to load the plugin. Adding `@oxlint/plugins` back as a direct dependency works, but pins a second copy against whatever Oxlint the bundled linter runs, and it is not resolvable from a plugin file under pnpm's strict layout unless every package hosting one declares it. Expose the API from vite-plus instead, and repoint the imports at it: - `vite-plus/lint/plugins` re-exports `defineRule`, `definePlugin`, and `eslintCompatPlugin` from the `@oxlint/plugins` copy vite-plus already depends on, so the API always matches the bundled linter. - `vite-plus/lint/rule-tester` re-exports `RuleTester`, which moved to `oxlint/plugins-dev` and breaks the same way. - `vp migrate` rewrites `@oxlint/plugins` and `oxlint/plugins-dev` unconditionally, and bare `oxlint` only when the import names a binding outside Oxlint's config surface, so `defineConfig` / `OxlintConfig` / `OxlintOverride` imports are left alone. Default, namespace, and side-effect imports carry no discriminating name and are skipped. - Packages declaring `oxlint` or `@oxlint/plugins` in `dependencies` or `peerDependencies` are skipped entirely: that shape marks a published Oxlint plugin whose consumers may not be running Vite+. - `prefer-vite-plus-imports` mirrors the mapping so the codemod has a standing backstop.
✅ Deploy Preview for viteplus-preview canceled.
|
Contributor
|
✅ Staging deployment successful! Preview: https://viteplus-staging.void.app/ |
Contributor
Native binary sizes (
|
| Artifact | Format | Base | PR | Change |
|---|---|---|---|---|
vp (Linux x64) |
Binary | 10.52 MiB | 10.52 MiB | 0 B (0.00%) |
vp (Linux x64) |
gzip -9 | 4.55 MiB | 4.55 MiB | 0 B (0.00%) |
| NAPI (Linux x64) | Binary | 33.66 MiB | 33.66 MiB | +4.00 KiB (+0.01%) |
| NAPI (Linux x64) | gzip -9 | 13.05 MiB | 13.05 MiB | +844 B (+0.01%) |
vp (macOS ARM64) |
Binary | 7.84 MiB | 7.84 MiB | 0 B (0.00%) |
vp (macOS ARM64) |
gzip -9 | 3.96 MiB | 3.96 MiB | 0 B (0.00%) |
| NAPI (macOS ARM64) | Binary | 40.95 MiB | 40.95 MiB | 0 B (0.00%) |
| NAPI (macOS ARM64) | gzip -9 | 17.26 MiB | 17.26 MiB | +273 B (+0.00%) |
vp (Windows x64) |
Binary | 8.43 MiB | 8.43 MiB | 0 B (0.00%) |
vp (Windows x64) |
gzip -9 | 3.67 MiB | 3.67 MiB | -2 B (-0.00%) |
| NAPI (Windows x64) | Binary | 27.81 MiB | 27.81 MiB | +4.00 KiB (+0.01%) |
| NAPI (Windows x64) | gzip -9 | 10.88 MiB | 10.88 MiB | +323 B (+0.00%) |
| Trampoline (Windows x64) | Binary | 203.00 KiB | 203.00 KiB | 0 B (0.00%) |
| Trampoline (Windows x64) | gzip -9 | 97.91 KiB | 97.91 KiB | +1 B (+0.00%) |
| Installer (Windows x64) | Binary | 4.46 MiB | 4.46 MiB | 0 B (0.00%) |
| Installer (Windows x64) | gzip -9 | 2.09 MiB | 2.09 MiB | +1 B (+0.00%) |
Two PTY fixtures for the `vite-plus/lint/plugins` work: - `lint_oxlint_plugin_api`: a local JS plugin authored against `vite-plus/lint/plugins` with no `@oxlint/plugins` dependency of its own. A reported diagnostic proves the export resolves and loads under `vp lint`, which is the whole premise of the change. The same case covers the `prefer-vite-plus-imports` autofix for all three legacy authoring specifiers, and that the config surface stays clean. - `migration_oxlint_js_plugin_imports`: `vp migrate` rewriting a plugin, a rule module, and a rule test, while leaving `defineConfig` / `OxlintOverride` imports alone. The migrate snapshot also records a pre-existing gap unrelated to this change: `sanitizeMigratedOxlintConfig` derives a plugin's rule namespace from its package name, so rules belonging to a relative-path JS plugin are dropped during the `.oxlintrc.json` merge. Captured with a comment rather than papered over, so a fix shows up as a snapshot diff.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Vite+ bundles Oxlint, and
vp migratestrips a standaloneoxlintdependency. A project's own Oxlint JS plugins import the authoring API by name, so that import stops resolving after migration andvp lintfails to load the plugin:Adding
@oxlint/pluginsback as a direct dependency fixes it, but pins a second copy against whatever Oxlint the bundled linter runs (cloudflare/kumo#658 ended up pinning=1.73.0while the bundled Oxlint moved on), and it is not resolvable from a plugin file under pnpm's strict layout unless every package hosting one declares it. So this exposes the API from vite-plus instead, the same shape asvitesttovite-plus/test.vite-plus/lint/pluginsre-exportsdefineRule,definePlugin, andeslintCompatPluginfrom the@oxlint/pluginscopy vite-plus already carries as a real dependency, so the API always matches the bundled linter and there is nothing for the user to keep in sync.vite-plus/lint/rule-testerre-exportsRuleTester, which moved tooxlint/plugins-devand breaks the same way. Kept separate so the authoring API does not pull in a test-only utility.vp migraterewrites@oxlint/pluginsandoxlint/plugins-devunconditionally, and bareoxlintonly when the import names a binding outside Oxlint's config surface, sodefineConfig/OxlintConfig/OxlintOverrideimports are left alone. Default, namespace, and side-effect imports carry no discriminating name and are skipped rather than guessed at. Discriminating on the 11 config-surface names rather than an allowlist of ~60 plugin type names keeps the list small and stable, and an unrecognized name errs toward fixing the breakage.oxlintor@oxlint/pluginsindependenciesorpeerDependenciesare skipped entirely (newSkipPackages::skip_oxlint): that shape marks a published Oxlint plugin whose consumers may not be running Vite+. A devDependency is not a signal, since that is just how a project's own in-repo plugin gets its types.prefer-vite-plus-importsmirrors the mapping so the codemod has a standing backstop instead of being one-shot.Tests
Two PTY snapshot fixtures alongside the Rust and vitest units:
lint_oxlint_plugin_api: a local JS plugin authored againstvite-plus/lint/pluginswith no@oxlint/pluginsdependency of its own. A reported diagnostic proves the export resolves and loads under realvp lint, which is the premise of the whole change. The same case covers the autofix on all three legacy specifiers and that the config surface stays clean.migration_oxlint_js_plugin_imports:vp migraterewriting a plugin, a rule module, and a rule test, while leavingdefineConfig/OxlintOverridealone.321 Rust tests pass including 8 new ones, clippy clean; 946 vitest tests pass. Two unrelated failures reproduce identically on the base commit in the same worktree:
packages/core/__tests__/binding-resolution-layout.spec.ts(local install layout) and a batch of migration snapshot cases that time out when many run concurrently, each doing a real install.A pre-existing gap the migrate snapshot records
sanitizeMigratedOxlintConfigderives a plugin's rule namespace from its package name, so a relative-path JS plugin has none and every rule under its namespace is dropped during the.oxlintrc.jsonmerge. ThejsPluginsentry itself survives, so the plugin loads but none of its rules run. This is untouched by this PR and worth its own fix: it bites exactly the repos this PR is aimed at, since in-repo plugins are registered by path. Captured in the snapshot with a comment rather than papered over, so a fix shows up as a diff.One deliberate omission:
@oxlint/pluginsis not added toREMOVE_PACKAGES. Removal there is unconditional across all dependency groups, so it would strip the peer dep from published Oxlint plugins. A leftover unused devDependency after the rewrite is inert.