Skip to content

feat(eslint): Move to ESLint 10 and npm trusted publishing - #308

Merged
TheCodeDestroyer merged 5 commits into
mainfrom
feat/eslint-10
Sep 22, 2026
Merged

TheCodeDestroyer merged 5 commits into
mainfrom
feat/eslint-10

Conversation

@TheCodeDestroyer

@TheCodeDestroyer TheCodeDestroyer commented Sep 22, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Move all ESLint configs and presets to ESLint 10. Breaking: ESLint 9 is no longer supported.
  • Remove package entry points that point to files the build does not create, and add publint so this cannot happen again.
  • Fix turbo so unit tests run against a fresh build of the package under test.
  • Publish to npm with trusted publishing (OIDC), because npm classic tokens no longer work.

Changes

ESLint 10

  • eslint peer range is now ^10.0.0 in all configs and presets. @tcd-devkit/scripts allows ^9.0.0 || ^10.0.0.
  • Update @eslint/js, @eslint/compat, typescript-eslint (8.70), eslint-plugin-import-x, eslint-import-resolver-typescript, eslint-plugin-react-hooks and globals.
  • Wrap eslint-plugin-react with fixupConfigRules, because it calls context APIs that ESLint 10 removed. eslint-plugin-jsx-a11y runs as is. Both have no ESLint 10 release yet, so the READMEs show how to hide the pnpm peer warning (tracked in devkit-91a.7).
  • radix now always requires a radix, because ESLint 10 removed as-needed.
  • Drop the deprecated @typescript-eslint/no-loop-func and use the core no-loop-func rule.
  • includeIgnoreFile now comes from eslint/config.

Package entry points

  • Remove the ./rule-overrides export from eslint-config-next and eslint-config-a11y. These packages have no rules file.
  • Presets and tsup-config: remove the require export and point main to the ESM file. The build makes ESM only.
  • Add a lint:package (publint) task that runs after build, in turbo and in CI.
  • READMEs: drop .cjs from the config file examples.

Build

  • unit and unit:watch now depend on build instead of ^build.

Release (trusted publishing)

  • Release workflow: remove NPM_TOKEN. Add id-token: write, contents: write and pull-requests: write. Install npm 11 before publishing, because OIDC needs npm 11.5.1 or later and pnpm publish runs the npm CLI.
  • The workflow stays on changesets/action@v1. v1.7 and later support OIDC, and v2 needs Changesets CLI v3.
  • package.json URLs now use TheCodeDestroyer. npm compares repository.url with the OIDC claims and the comparison is case-sensitive.

Test plan

  • pnpm turbo build lint:package lint:types unit //#root-lint:eslint //#root-lint:prettier: 58 of 58 tasks pass
  • Real-project test in Tripora (Next.js + Convex), using pnpm pack tarballs of all packages and eslint 10.10.0:
    • Install works with no peer warnings. The config loads, including @convex-dev/eslint-plugin.
    • tsc and prettier --check pass.
    • Lint shows 16 new errors, all listed in the changeset: radix (9), max-nested-callbacks (3, a change in ESLint 10 for TS files), no-unnecessary-type-assertion (4, from typescript-eslint 8.70).
  • Trusted publisher set up on npmjs.com for all 17 packages (TheCodeDestroyer/devkit, release.yml)
  • After merge, merge the "Version Packages" PR. Check that the publish works and that the packages show provenance on npm.

🤖 Generated with Claude Code

TheCodeDestroyer and others added 4 commits September 22, 2026 21:14
- Change unit and unit:watch to depend on build instead of ^build
- Package #* imports resolve to ./dist at runtime, so tests ran against a
  stale or missing dist of the package under test
- build still depends on ^build, so dependency order is unchanged

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
- Set the eslint peer range to ^10.0.0 in all configs and presets and
  allow ^9.0.0 || ^10.0.0 in scripts
- Update @eslint/js, @eslint/compat, typescript-eslint, eslint-plugin-import-x,
  eslint-import-resolver-typescript, eslint-plugin-react-hooks and globals
- Wrap eslint-plugin-react with fixupConfigRules because it calls context
  APIs that ESLint 10 removed; eslint-plugin-jsx-a11y runs as is
- Allow the eslint 10 peer for both plugins in pnpm-workspace.yaml and
  document the pnpm peer-warning workaround in the READMEs
- radix now always requires a radix, since ESLint 10 drops as-needed
- Drop deprecated @typescript-eslint/no-loop-func in favor of the core rule
- Import includeIgnoreFile from eslint/config and drop @eslint/compat from
  the base config
- Fix import-x rule option types for the new defaultOptions typing
- Add changesets for the configs, presets and scripts

BREAKING CHANGE: ESLint 9 is no longer supported. parseInt without a radix
is now an error.

Refs devkit-91a.7

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
- Remove the ./rule-overrides export from eslint-config-next and
  eslint-config-a11y; neither package ever had a rules file (copied in Init)
- Drop the require export and point main to the ESM file in the three
  presets and tsup-config; tsup builds ESM only, so .cjs never existed
- Add publint as a lint:package task in every published package, run
  after build in turbo and in CI, so a broken exports or main entry fails
- Fix the tsup-config README: it builds ESM only and is used through
  @tcd-devkit/tsup-config/lib
- Add a patch changeset for the six affected packages

Closes devkit-j65

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
- The ESLint configs and presets are ESM-only and export only the import
  condition, so an eslint.config.cjs file cannot load them
- Change "(or .mjs/.cjs)" to "(or .mjs)" in all eleven READMEs

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@changeset-bot

changeset-bot Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6a091d3

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

This PR includes changesets to release 13 packages
Name Type
@tcd-devkit/eslint-config Minor
@tcd-devkit/eslint-config-ts Minor
@tcd-devkit/eslint-config-import Minor
@tcd-devkit/eslint-config-import-ts Minor
@tcd-devkit/eslint-config-react Minor
@tcd-devkit/eslint-config-react-hooks Minor
@tcd-devkit/eslint-config-a11y Minor
@tcd-devkit/eslint-config-next Minor
@tcd-devkit/eslint-preset-node Minor
@tcd-devkit/eslint-preset-react Minor
@tcd-devkit/eslint-preset-next Minor
@tcd-devkit/tsup-config Patch
@tcd-devkit/scripts Patch

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

- Remove NPM_TOKEN; npm classic tokens are gone and changesets/action
  v1.7+ publishes through OIDC when no token is set
- Add id-token: write, plus contents and pull-requests write that the
  action needs, as job permissions
- Install npm 11 before publish; trusted publishing needs npm 11.5.1+
  and pnpm publish runs the npm CLI
- Use the exact GitHub owner case (TheCodeDestroyer) in package.json
  repository, homepage and bugs URLs, because npm matches
  repository.url against the OIDC claims case-sensitively

Refs devkit-uur

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@TheCodeDestroyer TheCodeDestroyer changed the title feat(eslint): Move ESLint configs and presets to ESLint 10 feat(eslint): Move to ESLint 10 and npm trusted publishing Sep 22, 2026
@TheCodeDestroyer
TheCodeDestroyer merged commit c00da8c into main Sep 22, 2026
2 checks passed
@TheCodeDestroyer
TheCodeDestroyer deleted the feat/eslint-10 branch September 22, 2026 20:07
@github-actions github-actions Bot mentioned this pull request Sep 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant