Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BREAKING] Support ESLint v9 in plugin, config and next lint #71218

Merged
merged 42 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e401e37
[DO NOT MERGE] ESLint
devjiwonchoi Oct 13, 2024
a87173a
delete on the fly unsupported when is >= 9
devjiwonchoi Oct 13, 2024
e7ba144
fix: eslint v9 plugins value is object
devjiwonchoi Oct 13, 2024
0d43541
fix: eslint v9 config files don't start with dot
devjiwonchoi Oct 13, 2024
66ed5fc
Merge branch 'canary' into 10-13-_do_not_merge_eslint
devjiwonchoi Oct 13, 2024
aa4fa4b
chore: bump plugins for v9
devjiwonchoi Oct 13, 2024
4ea7adb
refactor condition
devjiwonchoi Oct 13, 2024
e790cbc
fix: look for v9 configs first
devjiwonchoi Oct 13, 2024
bfabfb9
frozen lock file
devjiwonchoi Oct 13, 2024
362a2ff
chore: ts extensions are experymental
devjiwonchoi Oct 13, 2024
23d0a93
ncc-compiled
devjiwonchoi Oct 13, 2024
1e4534a
test: pin eslint to 8 for first time setup testing
devjiwonchoi Oct 13, 2024
2245269
test: add v8 and v9 for next build and lint
devjiwonchoi Oct 14, 2024
f61fe67
Update packages/eslint-config-next/package.json
devjiwonchoi Oct 14, 2024
8925753
frozen lockfile
devjiwonchoi Oct 14, 2024
9b382be
test: improve linting
devjiwonchoi Oct 13, 2024
ef1b68c
test: update
devjiwonchoi Oct 13, 2024
c608bf1
install v9
devjiwonchoi Oct 13, 2024
87ca73b
delete _v9
devjiwonchoi Oct 13, 2024
547e6e7
test: with v8
devjiwonchoi Oct 13, 2024
57366a2
test: with v8 and remove path as it duplicates test
devjiwonchoi Oct 13, 2024
ad53745
test: add v9 tests that was missed
devjiwonchoi Oct 14, 2024
e2278fc
default eslint to v9
devjiwonchoi Oct 14, 2024
f576bac
update lint-staged
devjiwonchoi Oct 14, 2024
9b51be9
for eslint, use .eslintrc.cli.json
devjiwonchoi Oct 14, 2024
3eb3494
Merge branch '10-13-_do_not_merge_eslint' of github.com:vercel/next.j…
devjiwonchoi Oct 14, 2024
23dd9c1
eslint-v8 and eslint 9 is default
devjiwonchoi Oct 14, 2024
ca961e1
Merge branch 'canary' of github.com:vercel/next.js into 10-13-_do_not…
devjiwonchoi Oct 14, 2024
3650648
fix: allow user to pass
devjiwonchoi Oct 14, 2024
f390079
Merge branch '10-13-_do_not_merge_eslint' into 10-14-test_improve_lin…
devjiwonchoi Oct 14, 2024
f0b7f4a
update snapshot
devjiwonchoi Oct 14, 2024
29436b6
upgrade repo eslint to v9
devjiwonchoi Oct 14, 2024
b9dd477
Merge branch '10-13-_do_not_merge_eslint' of github.com:vercel/next.j…
devjiwonchoi Oct 14, 2024
0c8c0e5
test: add comments based on the previous test
devjiwonchoi Oct 14, 2024
aea3112
Disable rules less broadly
eps1lon Oct 14, 2024
ec1d385
Update lint-staged.config.js
eps1lon Oct 14, 2024
418e359
Merge branch 'canary' of github.com:vercel/next.js into 10-13-_do_not…
devjiwonchoi Oct 14, 2024
85e118b
chore: use legacy eslint unless config v9 was found
devjiwonchoi Oct 14, 2024
23362e3
test: skip tests that require eslint-formatter-compact
devjiwonchoi Oct 14, 2024
4dbb080
fix: remove unsupported options only when using flat config with v9
devjiwonchoi Oct 14, 2024
1f8b07a
test: move v8 specific test to development isolated
devjiwonchoi Oct 14, 2024
515ee54
add next-lint-formatter-compact test to eslintignore for lint staged
devjiwonchoi Oct 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ packages/next-swc/docs/assets/**/*
test/lib/amp-validator-wasm.js
test/production/pages-dir/production/fixture/amp-validator-wasm.js
test/e2e/async-modules/amp-validator-wasm.js
test/development/next-lint-eslint-formatter-compact/**/*.js

# turbopack crates
turbopack/crates/*/tests/**
Expand Down
9 changes: 8 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@
"@typescript-eslint/array-type": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-tslint-comment": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/no-empty-object-type": "off",
Copy link
Member

Choose a reason for hiding this comment

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

"@typescript-eslint/no-restricted-types": "off",
"@typescript-eslint/no-unsafe-function-type": "off",
"@typescript-eslint/no-wrapper-object-types": "off",
Comment on lines +70 to +72
Copy link
Member

Choose a reason for hiding this comment

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

"@typescript-eslint/class-literal-property-style": "off",
"@typescript-eslint/consistent-generic-constructors": "off",
"@typescript-eslint/consistent-indexed-object-style": "off",
Expand All @@ -77,6 +80,7 @@
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-inferrable-types": "off",
"@typescript-eslint/no-require-imports": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/prefer-for-of": "off",
"@typescript-eslint/prefer-function-type": "off",
Expand Down Expand Up @@ -104,6 +108,7 @@
"args": "none",
"ignoreRestSiblings": true,
"argsIgnorePattern": "^_",
"caughtErrors": "none",
Copy link
Member

Choose a reason for hiding this comment

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

Restore v8 behavior

"caughtErrorsIgnorePattern": "^_",
"destructuredArrayIgnorePattern": "^_",
"varsIgnorePattern": "^_"
Expand Down Expand Up @@ -178,6 +183,7 @@
{
"args": "all",
"argsIgnorePattern": "^_",
"caughtErrors": "none",
"ignoreRestSiblings": true
}
]
Expand Down Expand Up @@ -308,6 +314,7 @@
"error",
{
"args": "none",
"caughtErrors": "none",
"ignoreRestSiblings": true
}
],
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ dist
target
packages/next/wasm/@next
tarballs/
packages/next/*.tgz
packages/**/*.tgz
devjiwonchoi marked this conversation as resolved.
Show resolved Hide resolved

# dependencies
node_modules
Expand Down
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"typescript",
"typescriptreact"
],
"eslint.useFlatConfig": false,
// Set Jest runMode to on-demand as otherwise it will start running all tests the first time.
// Equivalent to deprecated option "jest.autoRun": "off"
"jest.runMode": "on-demand",
Expand Down
2 changes: 1 addition & 1 deletion examples/with-supertokens/app/config/frontend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ThirdPartyReact from "supertokens-auth-react/recipe/thirdparty";
import EmailPasswordReact from "supertokens-auth-react/recipe/emailpassword";
import Session from "supertokens-auth-react/recipe/session";
import { appInfo } from "./appInfo";
import { useRouter } from "next/navigation";
import { type useRouter } from "next/navigation";
import { SuperTokensConfig } from "supertokens-auth-react/lib/build/types";
import { ThirdPartyPreBuiltUI } from "supertokens-auth-react/recipe/thirdparty/prebuiltui";
import { EmailPasswordPreBuiltUI } from "supertokens-auth-react/recipe/emailpassword/prebuiltui";
Expand Down
2 changes: 1 addition & 1 deletion lint-staged.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module.exports = {
'*.{js,jsx,mjs,ts,tsx,mts}': [
'prettier --with-node-modules --ignore-path .prettierignore --write',
'eslint --fix',
'cross-env ESLINT_USE_FLAT_CONFIG=false eslint --config .eslintrc.json --fix',
],
'*.{json,md,mdx,css,html,yml,yaml,scss}': [
'prettier --with-node-modules --ignore-path .prettierignore --write',
Expand Down
15 changes: 8 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"git-clean": "git clean -d -x -e node_modules -e packages -f",
"typescript": "tsc --noEmit",
"lint-typescript": "turbo run typescript",
"lint-eslint": "eslint . --ext js,jsx,ts,tsx --config .eslintrc.cli.json --no-eslintrc",
"lint-eslint": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint . --ext js,jsx,ts,tsx --config .eslintrc.cli.json --no-eslintrc",
"lint-ast-grep": "ast-grep scan",
"lint-no-typescript": "run-p prettier-check lint-eslint lint-language",
"types-and-precompiled": "run-p lint-typescript check-precompiled validate-externals-doc",
Expand Down Expand Up @@ -121,8 +121,8 @@
"@types/relay-runtime": "14.1.13",
"@types/string-hash": "1.1.1",
"@types/trusted-types": "2.0.3",
"@typescript-eslint/eslint-plugin": "7.16.0",
"@typescript-eslint/parser": "7.16.0",
"@typescript-eslint/eslint-plugin": "8.0.0",
"@typescript-eslint/parser": "8.0.0",
"@vercel/devlow-bench": "workspace:*",
"@vercel/fetch": "6.1.1",
"@vercel/og": "0.6.3",
Expand All @@ -144,15 +144,16 @@
"dd-trace": "4.12.0",
"es5-ext": "0.10.53",
"escape-string-regexp": "2.0.0",
"eslint": "8.56.0",
"eslint": "9.12.0",
"eslint-config-next": "workspace:*",
"eslint-formatter-codeframe": "7.32.1",
"eslint-plugin-eslint-plugin": "5.2.1",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-jest": "27.6.3",
"eslint-plugin-jsdoc": "48.0.4",
"eslint-plugin-react": "7.33.2",
"eslint-plugin-react-hooks": "4.6.0",
"eslint-plugin-react": "7.35.0",
"eslint-plugin-react-hooks": "5.0.0",
"eslint-v8": "npm:eslint@^8.57.0",
"event-stream": "4.0.1",
"execa": "2.0.3",
"expect-type": "0.14.2",
Expand Down
12 changes: 6 additions & 6 deletions packages/eslint-config-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@
"homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config",
"dependencies": {
"@next/eslint-plugin-next": "15.0.0-canary.190",
"@rushstack/eslint-patch": "^1.3.3",
"@rushstack/eslint-patch": "^1.10.3",
"@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
"@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
"eslint-import-resolver-node": "^0.3.6",
"eslint-import-resolver-typescript": "^3.5.2",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705"
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-a11y": "^6.10.0",
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^5.0.0"
},
"peerDependencies": {
"eslint": "^7.23.0 || ^8.0.0",
"eslint": "^7.23.0 || ^8.0.0 || ^9.0.0",
"typescript": ">=3.3.1"
},
"peerDependenciesMeta": {
Expand Down
12 changes: 7 additions & 5 deletions packages/next/src/cli/next-lint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,23 @@ export type NextLintOptions = {
config?: string
dir?: string[]
errorOnUnmatchedPattern?: boolean
ext: string[]
file?: string[]
fix?: boolean
fixType?: string
format?: string
ignore: boolean
ignorePath?: string
inlineConfig: boolean
maxWarnings: number
outputFile?: string
quiet?: boolean
strict?: boolean
// TODO(jiwon): ESLint v9 unsupported options
// we currently delete them at `runLintCheck` when used in v9
ext: string[]
ignorePath?: string
reportUnusedDisableDirectivesSeverity: 'error' | 'off' | 'warn'
resolvePluginsRelativeTo?: string
rulesdir?: string
strict?: boolean
inlineConfig: boolean
maxWarnings: number
}

const eslintOptions = (
Expand Down
4 changes: 2 additions & 2 deletions packages/next/src/compiled/assert/assert.js

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions packages/next/src/compiled/babel-packages/packages-bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/next/src/compiled/util/util.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export async function applyNextFixture(
const fixture = new NextFixtureImpl(testInfo, nextOptions, nextWorker, page)

await fixture.setup()
// eslint-disable-next-line react-hooks/rules-of-hooks -- not React.use()
await use(fixture)

fixture.teardown()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export async function applyNextWorkerFixture(
): Promise<void> {
const fixture = new NextWorkerFixtureImpl()
await fixture.setup()
// eslint-disable-next-line react-hooks/rules-of-hooks -- not React.use()
await use(fixture)
fixture.teardown()
}
62 changes: 59 additions & 3 deletions packages/next/src/lib/eslint/runLintCheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,25 @@ async function lint(

const mod = await Promise.resolve(require(deps.resolved.get('eslint')!))

const { ESLint } = mod
const useFlatConfig =
// If V9 config was found, use flat config, or else use legacy.
eslintrcFile?.startsWith('eslint.config.')

let ESLint
// loadESLint is >= 8.57.0
// PR https://github.com/eslint/eslint/pull/18098
// Release https://github.com/eslint/eslint/releases/tag/v8.57.0
if ('loadESLint' in mod) {
// By default, configType is `flat`. If `useFlatConfig` is false, the return value is `LegacyESLint`.
// https://github.com/eslint/eslint/blob/1def4cdfab1f067c5089df8b36242cdf912b0eb6/lib/types/index.d.ts#L1609-L1613
ESLint = await mod.loadESLint({
useFlatConfig,
})
} else {
// eslint < 8.57.0, use legacy ESLint
ESLint = mod.ESLint
}

let eslintVersion = ESLint?.version ?? mod.CLIEngine?.version

if (!eslintVersion || semver.lt(eslintVersion, '7.0.0')) {
Expand All @@ -155,6 +173,23 @@ async function lint(
...eslintOptions,
}

if (semver.gte(eslintVersion, '9.0.0') && useFlatConfig) {
for (const option of [
'useEslintrc',
'extensions',
'ignorePath',
'reportUnusedDisableDirectives',
'resolvePluginsRelativeTo',
'rulePaths',
'inlineConfig',
'maxWarnings',
]) {
if (option in options) {
delete options[option]
}
}
}

let eslint = new ESLint(options)

let nextEslintPluginIsEnabled = false
Expand All @@ -163,10 +198,20 @@ async function lint(
for (const configFile of [eslintrcFile, pkgJsonPath]) {
if (!configFile) continue

const completeConfig: Config =
const completeConfig: Config | undefined =
await eslint.calculateConfigForFile(configFile)
if (!completeConfig) continue

const plugins = completeConfig.plugins

const hasNextPlugin =
// in ESLint < 9, `plugins` value is string[]
Array.isArray(plugins)
? plugins.includes('@next/next')
: // in ESLint >= 9, `plugins` value is Record<string, unknown>
'@next/next' in plugins

if (completeConfig.plugins?.includes('@next/next')) {
if (hasNextPlugin) {
nextEslintPluginIsEnabled = true
for (const [name, [severity]] of Object.entries(completeConfig.rules)) {
if (!name.startsWith('@next/next/')) {
Expand Down Expand Up @@ -309,6 +354,17 @@ export async function runLintCheck(
const eslintrcFile =
(await findUp(
[
// eslint v9
'eslint.config.js',
'eslint.config.mjs',
'eslint.config.cjs',
// TODO(jiwon): Support when it's stable.
// TS extensions are experimental and requires to install another package `jiti`.
// https://eslint.org/docs/latest/use/configure/configuration-files#typescript-configuration-files
// 'eslint.config.ts',
// 'eslint.config.mts',
// 'eslint.config.cts',
// eslint <= v8
'.eslintrc.js',
'.eslintrc.cjs',
'.eslintrc.yaml',
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/lib/metadata/resolve-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ function inheritFromMetadata(
}
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const commonOgKeys = ['title', 'description', 'images'] as const
function postProcessMetadata(
metadata: ResolvedMetadata,
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/trace/report/to-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import path from 'path'
import { PHASE_DEVELOPMENT_SERVER } from '../../shared/lib/constants'
import type { TraceEvent } from '../types'

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const localEndpoint = {
serviceName: 'nextjs',
ipv4: '127.0.0.1',
Expand Down
Loading
Loading