Skip to content

Migrate plugin-kit and the monorepo from prettier/eslint to oxfmt/oxlint#1565

Open
stipsan wants to merge 8 commits into
mainfrom
cursor/plugin-kit-oxfmt-migration-99d1
Open

Migrate plugin-kit and the monorepo from prettier/eslint to oxfmt/oxlint#1565
stipsan wants to merge 8 commits into
mainfrom
cursor/plugin-kit-oxfmt-migration-99d1

Conversation

@stipsan

@stipsan stipsan commented Jul 13, 2026

Copy link
Copy Markdown
Member

Description

Drops prettier and eslint support from @sanity/plugin-kit entirely, replacing them with oxfmt and oxlint, shipping the monorepo's own settings as reusable configs (inspired by @epic-web/config). plugin-kit also stops pushing tsc type-check runs (the shared oxlint config has type-aware rules and TypeScript type checking via oxlint-tsgolint enabled, with warnings denied), and the Sanity v2 imports check is removed entirely — v2-era imports are no longer linted for.

Shared configs shipped by plugin-kit (both authored in src/, typed, built to plain JS in dist/ so Node never type-strips under node_modules)

  • @sanity/plugin-kit/oxfmt: oxfmt preset with the exact settings previously in the root .oxfmtrc.json.
  • @sanity/plugin-kit/oxlint: oxlint config (typed OxlintConfig) matching the monorepo's previous .oxlintrc.json minus workspace-specific ignores/overrides — same plugins, typeAware/typeCheck/denyWarnings/reportUnusedDisableDirectives options, categories and rules (verified semantically identical, plus identical lint file lists and diagnostics before/after).
  • Both are consumed the same way, via TS config files (extends supports imported config objects in oxlint.config.ts):
    • root oxfmt.config.ts: export {default} from '@sanity/plugin-kit/oxfmt'
    • root oxlint.config.ts: defineConfig({extends: [sanityPluginKitOxlint], ignorePatterns: [...shared, ...workspace], overrides: [...workspace]})

Scaffolding (init / inject)

  • Scaffolds oxfmt.config.ts + oxlint.config.ts (both plain re-exports of the shared configs), oxfmt/oxlint/oxlint-tsgolint devDependencies and format/lint scripts. No prettier or eslint packages at all.
  • --no-prettier--no-oxfmt, --no-eslint--no-oxlint; the --no-typescript flag now actually controls TypeScript scaffolding (it previously piggybacked on the eslint flag).
  • The semver-workflow preset's lint-staged config runs oxfmt + oxlint instead of eslint + tsc --build.

verify-package / verify-studio

  • The post-check tsc --build run is gone (tsc check key removed) — oxlint type-checks as part of linting.
  • The Sanity v2 imports check (eslintImports) is removed entirely, along with the import-linter module; verify-studio now checks studio config and dependencies only.
  • New monorepo-aware oxfmt and oxlint checks: walk up for a workspace root (pnpm-workspace.yaml / workspaces field); the config is expected there (or next to the plugin's package.json outside monorepos) and must use the shared plugin-kit config. Leftover prettier/eslint configuration fails with migration instructions; .oxfmtrc.json / .oxlintrc.json files are flagged since JSON configs cannot import the shared configs.
  • Peer dependencies are now @sanity/pkg-utils, oxfmt and oxlint (the eslint and typescript peers are gone, and oxlint is not a runtime dependency of plugin-kit).

Housekeeping

  • dev/test-studio now pins typescript (catalog) so the sanity peer keeps resolving to the catalog version now that plugin-kit no longer contributes eslint/typescript peers to the graph.
  • Fixtures/tests migrated (obsolete invalid-eslint fixture removed; the init→verify→build integration test now runs type-aware oxlint in the scaffold instead of tsc --build), unit tests for both config-location checks, snapshots regenerated.
  • knip.jsonc, AGENTS.md, plugin-kit README updated; single major changeset.
  • Note: pnpm format and pnpm lint now require Node >=22.18 (^20.19 also works for oxfmt) to load the TypeScript configs. CI uses lts/*, so it is unaffected.

Testing

  • pnpm format, pnpm lint, pnpm knip, pnpm build, pnpm test run (169 files / 917 tests) all pass.
  • Config-equivalence proof: identical lint file lists and identical diagnostics on a multi-violation scratch file across the .oxlintrc.json → shared-config → oxlint.config.ts refactors; semantic JSON diff of rules/options/categories/overrides is empty.
  • End-to-end with a packed tarball, standalone and pnpm-workspace layouts: scaffold → npm run lint (proved typescript(TS2322) type errors and no-floating-promises fire through the published dist/oxlint.js re-export) → npm run formatverify-package (pass + legacy-eslint / JSON-config / multiple-config / missing-config failure modes) → npm run build; in the monorepo layout, proved root defineConfig({extends}) merges shared rules with workspace overrides.

Notes

  • Requires review from the prompter before marking ready for team review.
Open in Web Open in Cursor 

- Ship the monorepo's oxfmt settings as a @sanity/plugin-kit/oxfmt preset
- Re-export the preset from the root oxfmt.config.ts (replaces .oxfmtrc.json)
- init/inject scaffold oxfmt (config, devDependency, format script) instead
  of prettier; --no-prettier is now --no-oxfmt
- verify-package: replace the duplicate-prettier-config check with a
  monorepo-aware oxfmt check that expects the config at the workspace root
  (or next to package.json outside monorepos) and flags leftover prettier
  configuration with migration instructions
@changeset-bot

changeset-bot Bot commented Jul 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2162be8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@sanity/plugin-kit Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
plugins-studio Ready Ready Preview, Comment Jul 14, 2026 6:55pm

Request Review

- Ship the monorepo's oxlint settings as @sanity/plugin-kit/oxlint-config.json
  (type-aware rules, type checking via oxlint-tsgolint, warnings denied); the
  root .oxlintrc.json extends it and keeps only workspace-specific ignores and
  overrides
- init/inject scaffold oxlint (.oxlintrc.json, oxlint + oxlint-tsgolint
  devDependencies, lint script) instead of eslint; --no-eslint is now
  --no-oxlint, and the typescript flag now controls TypeScript scaffolding
  instead of piggybacking on the eslint flag
- verify-package: drop the tsc run (oxlint type-checks as part of linting) and
  the duplicate-eslint-config check; add a monorepo-aware oxlint config check
  with legacy eslint detection; the v2-imports check (eslintImports -> imports)
  now runs a bundled oxlint pass instead of the package's eslint
- pin typescript in dev/test-studio so the sanity peer keeps resolving to the
  catalog version now that plugin-kit no longer pulls eslint/typescript peers
@cursor cursor Bot changed the title Migrate plugin-kit and monorepo formatting from prettier to oxfmt Migrate plugin-kit and the monorepo from prettier/eslint to oxfmt/oxlint Jul 13, 2026
oxlint auto-switches to GitHub annotations format on CI; --format=agent keeps
the compact per-diagnostic output (including help: messages) everywhere
… pattern)

Replaces the oxlint-config.json + .oxlintrc.json extends-by-file-path setup
with a TS config module, mirroring the oxfmt preset: the shared config is
authored in src/oxlint.ts (typed OxlintConfig, built to plain JS in dist), the
root and scaffolded configs are oxlint.config.ts files that re-export or extend
it via defineConfig({extends: [...]})
v2-era imports are no longer linted for; with the bundled oxlint pass gone,
oxlint moves from a runtime dependency of plugin-kit to a dev/peer dependency
(it is only needed by consumers, which the scaffolding already installs)
@stipsan stipsan marked this pull request as ready for review July 14, 2026 00:56
@stipsan stipsan requested a review from a team as a code owner July 14, 2026 00:56
@stipsan stipsan requested review from Copilot and juice49 and removed request for a team and Copilot July 14, 2026 00:56
@stipsan stipsan enabled auto-merge (squash) July 14, 2026 00:56
Comment thread packages/@sanity/plugin-kit/src/npm/package.ts
Comment thread packages/@sanity/plugin-kit/src/constants.ts
…mt-migration-99d1

# Conflicts:
#	pnpm-lock.yaml
Copilot AI review requested due to automatic review settings July 14, 2026 02:01
@stipsan stipsan removed the request for review from Copilot July 14, 2026 02:01
Comment thread packages/@sanity/plugin-kit/src/actions/verify/validations.ts
Comment thread packages/@sanity/plugin-kit/src/actions/verify/validations.ts
…figs detected

- init/inject with --no-oxfmt/--no-oxlint now write the matching
  sanityPlugin.verifyPackage opt-outs, so the scaffolded build script
  (which runs verify-package) works out of the box
- the oxfmt/oxlint checks now also flag leftover prettier/eslint configs at
  the detected workspace root, not only next to the plugin's package.json
Copilot AI review requested due to automatic review settings July 14, 2026 13:55
@stipsan stipsan removed the request for review from Copilot July 14, 2026 13:55
juice49
juice49 previously approved these changes Jul 14, 2026

@juice49 juice49 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonderful! 🐂


if (primaryResult.ok) {
return errors
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nested config overrides go unchecked

Medium Severity

When a workspace-root oxfmt/oxlint config uses the shared preset, validateOxfmtConfig and validateOxlintConfig return early without inspecting a package-local config. Nested discovery means that local file overrides the root for that package, so verify can pass while the package is not using the shared preset.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 2a13403. Configure here.

Resolve test-studio package.json (devtools ^0.4.0 + typescript catalog pin) and regenerate pnpm-lock.yaml.
Copilot AI review requested due to automatic review settings July 14, 2026 18:54
@stipsan stipsan removed the request for review from Copilot July 14, 2026 18:54

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2162be8. Configure here.

'**/*.{js,jsx}': ['eslint'],
'**/*.{ts,tsx}': ['eslint', () => 'tsc --build'],
'**/*.{json,jsonc,md}': ['oxfmt'],
'**/*.{js,jsx,ts,tsx}': ['oxfmt', 'oxlint'],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semver preset configs fail lint

High Severity

The semver-workflow preset still scaffolds lint-staged.config.js and commitlint.config.js with module.exports, while the shared oxlint config enables import/no-commonjs and no longer ignores those files (the old .eslintignore did). A fresh init --preset semver-workflow therefore fails oxlint out of the box.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 2162be8. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants