Use ESLint Flat Config (#84800)

This commit is contained in:
Sebastian "Sebbie" Silbermann
2025-10-13 10:43:51 +02:00
committed by GitHub
parent 0720d7c0d2
commit 3b4e4478d4
17 changed files with 1835 additions and 1202 deletions
+58
View File
@@ -0,0 +1,58 @@
import { globalIgnores } from 'eslint/config'
export default globalIgnores([
'**/.*/**/*', // Default of ESLint legacy config
'**/node_modules',
'**/.next/**/*',
'**/_next/**/*',
'**/.vscode/**/*',
'**/dist/**/*',
'e2e-tests/**/*',
'examples/cms-sanity/sanity.types.ts',
'examples/with-eslint/**/*',
'examples/with-typescript-eslint-jest/**/*',
'examples/with-kea/**/*',
'examples/with-custom-babel-config/**/*',
'examples/with-flow/**/*',
'examples/with-jest/**/*',
'examples/with-mobx-state-tree/**/*',
'examples/with-mobx/**/*',
'examples/with-tigris/db/models/todoItems.ts',
'packages/next/src/bundles/webpack/packages/*.runtime.js',
'packages/next/src/bundles/webpack/packages/lazy-compilation-*.js',
'packages/next/src/compiled/**/*',
'packages/next/wasm/@next',
'packages/react-refresh-utils/**/*.js',
'packages/react-dev-overlay/lib/**/*',
'**/__tmp__/**/*',
'.github/actions/next-stats-action/.work',
'packages/next-codemod/transforms/__testfixtures__/**/*',
'packages/next-codemod/transforms/__tests__/**/*',
'packages/next-codemod/bin/__testfixtures__/**/*',
'packages/next-codemod/**/*.js',
'packages/next-codemod/**/*.d.ts',
'packages/next-env/**/*.d.ts',
'packages/create-next-app/templates/**/*',
'test/integration/eslint/**/*.js',
'test/integration/script-loader/**/*.js',
'test/development/basic/legacy-decorators/**/*.js',
'test/production/emit-decorator-metadata/**/*.js',
'!test/**/*.test.*',
'test/e2e/app-dir/rsc-errors/app/swc/use-client/page.js',
'**/test-timings.json',
'crates/**/*',
'bench/nested-deps/**/*',
'bench/nested-deps-app-router/**/*',
'bench/heavy-npm-deps/**/*',
'packages/next-bundle-analyzer/index.d.ts',
'examples/with-typescript-graphql/lib/gql/',
'test/development/basic/hmr/components/parse-error.js',
'test/development/mcp-server/fixtures/default-template/app/build-error/page.tsx',
'packages/next-swc/docs/assets/**/*',
'test/e2e/app-dir/server-source-maps/fixtures/default/internal-pkg/sourcemapped.js',
'test/e2e/app-dir/server-source-maps/fixtures/default/external-pkg/sourcemapped.js',
'test/development/next-lint-eslint-formatter-compact/**/*.js',
'test/e2e/app-dir/app-external/app/mixed/import/mixed-mod.mjs',
'turbopack/crates/*/tests/**/*',
'turbopack/crates/*/js/src/compiled',
])
-55
View File
@@ -1,55 +0,0 @@
node_modules
**/.next/**
**/_next/**
**/.vscode/**
**/dist/**
e2e-tests/**
examples/cms-sanity/sanity.types.ts
examples/with-eslint/**
examples/with-typescript-eslint-jest/**
examples/with-kea/**
examples/with-custom-babel-config/**
examples/with-flow/**
examples/with-jest/**
examples/with-mobx-state-tree/**
examples/with-mobx/**
examples/with-tigris/db/models/todoItems.ts
packages/next/src/bundles/webpack/packages/*.runtime.js
packages/next/src/bundles/webpack/packages/lazy-compilation-*.js
packages/next/src/compiled/**/*
packages/next/wasm/@next
packages/react-refresh-utils/**/*.js
packages/react-dev-overlay/lib/**
**/__tmp__/**
.github/actions/next-stats-action/.work
packages/next-codemod/transforms/__testfixtures__/**/*
packages/next-codemod/transforms/__tests__/**/*
packages/next-codemod/bin/__testfixtures__/**/*
packages/next-codemod/**/*.js
packages/next-codemod/**/*.d.ts
packages/next-env/**/*.d.ts
packages/create-next-app/templates/**
test/integration/eslint/**/*.js
test/integration/script-loader/**/*.js
test/development/basic/legacy-decorators/**/*.js
test/production/emit-decorator-metadata/**/*.js
!test/**/*.test.*
test/e2e/app-dir/rsc-errors/app/swc/use-client/page.js
test-timings.json
crates/**
bench/nested-deps/**
bench/nested-deps-app-router/**
bench/heavy-npm-deps/**
packages/next-bundle-analyzer/index.d.ts
examples/with-typescript-graphql/lib/gql/
test/development/basic/hmr/components/parse-error.js
test/development/mcp-server/fixtures/default-template/app/build-error/page.tsx
packages/next-swc/docs/assets/**/*
test/e2e/app-dir/server-source-maps/fixtures/default/internal-pkg/sourcemapped.js
test/e2e/app-dir/server-source-maps/fixtures/default/external-pkg/sourcemapped.js
test/development/next-lint-eslint-formatter-compact/**/*.js
test/e2e/app-dir/app-external/app/mixed/import/mixed-mod.mjs
# turbopack crates
turbopack/crates/*/tests/**
turbopack/crates/*/js/src/compiled
-28
View File
@@ -1,28 +0,0 @@
{
"$schema": "https://json.schemastore.org/eslintrc",
"extends": [".eslintrc.json"],
"overrides": [
{
// This override adds type-checked rules.
"files": ["**/*.ts", "**/*.tsx"],
// Linting with type-checked rules is very slow and needs a lot of memory,
// so we exclude non-essential files.
"excludedFiles": [
"examples/**/*",
"test/**/*",
"**/*.d.ts",
"turbopack/**/*"
],
"parserOptions": {
"project": true
},
// These rules are added on top of the rules that are declared in
// .eslintrc.json for the matching files.
"rules": {
// TODO: enable in follow-up PR
"@typescript-eslint/no-floating-promises": "off",
"@typescript-eslint/switch-exhaustiveness-check": "error"
}
}
]
}
-429
View File
@@ -1,429 +0,0 @@
{
// This is the default eslint config that is used by IDEs. It does not use
// computation-heavy type-checked rules to ensure maximum responsiveness while
// writing code. In addition, there is .eslintrc.cli.json that does use
// type-checked rules in addition to the rules defined here, and it is used
// when running `pnpm lint-eslint` locally or in CI.
"$schema": "https://json.schemastore.org/eslintrc",
"root": true,
"parser": "@babel/eslint-parser",
"plugins": ["react", "react-hooks", "jest", "import", "jsdoc"],
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"node": true,
"jest": true,
"es2020": true
},
"parserOptions": {
"requireConfigFile": false,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
},
"babelOptions": {
"presets": ["next/babel"],
"caller": {
// Eslint supports top level await when a parser for it is included. We enable the parser by default for Babel.
"supportsTopLevelAwait": true
}
}
},
"settings": {
"react": {
"version": "detect"
},
"import/internal-regex": "^next/"
},
"overrides": [
{
"files": [
"test/**/*.js",
"test/**/*.ts",
"test/**/*.tsx",
"**/*.test.ts",
"**/*.test.tsx"
],
"excludedFiles": ["test/tmp/**"],
"extends": ["plugin:jest/recommended"],
"rules": {
"jest/expect-expect": "off",
"jest/no-disabled-tests": "off",
"jest/no-conditional-expect": "off",
"jest/valid-title": "off",
"jest/no-interpolation-in-snapshots": "off",
"jest/no-export": "off",
"jest/no-standalone-expect": [
"error",
{ "additionalTestBlockFunctions": ["retry", "itCI", "itHeaded"] }
]
}
},
{ "files": ["**/__tests__/**"], "env": { "jest": true } },
{
"extends": [
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/stylistic"
],
"files": ["**/*.ts", "**/*.tsx", "**/*.mts"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"sourceType": "module",
"warnOnUnsupportedTypeScriptVersion": false
},
"plugins": ["@typescript-eslint"],
"rules": {
// Todo: investigate, for each of these rules, whether we want them.
"@typescript-eslint/array-type": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-tslint-comment": "off",
"@typescript-eslint/no-empty-object-type": "off",
"@typescript-eslint/no-restricted-types": "off",
"@typescript-eslint/no-unsafe-function-type": "off",
"@typescript-eslint/no-wrapper-object-types": "off",
"@typescript-eslint/class-literal-property-style": "off",
"@typescript-eslint/consistent-generic-constructors": "off",
"@typescript-eslint/consistent-indexed-object-style": "off",
"@typescript-eslint/consistent-type-definitions": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-shadow": "off",
"@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",
"@typescript-eslint/no-this-alias": "off",
"@typescript-eslint/triple-slash-reference": "off",
"no-var": "off",
"prefer-const": "off",
"prefer-rest-params": "off",
"prefer-spread": "off",
// These off- or differently-configured rules work well for us.
"no-unused-expressions": "off",
"@typescript-eslint/no-unused-expressions": [
"error",
{
"allowShortCircuit": true,
"allowTernary": true,
"allowTaggedTemplates": true
}
],
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
"args": "none",
"ignoreRestSiblings": true,
"argsIgnorePattern": "^_",
"caughtErrors": "none",
"caughtErrorsIgnorePattern": "^_",
"destructuredArrayIgnorePattern": "^_",
"varsIgnorePattern": "^_"
}
],
"no-use-before-define": "off",
"no-useless-constructor": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-useless-constructor": "error",
"@typescript-eslint/prefer-literal-enum-member": "error"
}
},
{
"files": ["packages/**/*.ts", "packages/**/*.tsx"],
"plugins": ["@next/eslint-plugin-internal"],
"rules": {
"@next/internal/typechecked-require": "error",
"jsdoc/no-types": "error",
"jsdoc/no-undefined-types": "error"
}
},
{
"files": ["examples/**/*"],
"rules": {
"@typescript-eslint/no-use-before-define": [
"error",
{
"functions": true,
"classes": true,
"variables": true,
"enums": true,
"typedefs": true
}
],
"import/no-anonymous-default-export": [
"error",
{
// React components:
"allowArrowFunction": false,
"allowAnonymousClass": false,
"allowAnonymousFunction": false,
// Non-React stuff:
"allowArray": true,
"allowCallExpression": true,
"allowLiteral": true,
"allowObject": true
}
]
}
},
{
"files": ["packages/**"],
"excludedFiles": [
"packages/next/taskfile*.js",
"packages/next/next-devtools.webpack-config.js",
"packages/next/next-runtime.webpack-config.js"
],
"rules": {
"no-shadow": ["error", { "builtinGlobals": false }],
"import/no-extraneous-dependencies": [
"error",
{ "devDependencies": false }
]
}
},
{
"files": ["packages/**/*.tsx", "packages/**/*.ts"],
"rules": {
// Note: you must disable the base rule as it can report incorrect errors
"no-shadow": "off",
"@typescript-eslint/no-shadow": ["error", { "builtinGlobals": false }],
"@typescript-eslint/no-unused-vars": [
"error",
{
"args": "all",
"argsIgnorePattern": "^_",
"caughtErrors": "none",
"ignoreRestSiblings": true,
"varsIgnorePattern": "^_"
}
]
}
},
{
"files": [
"packages/eslint-plugin-next/**/*.js",
"test/unit/eslint-plugin-next/**/*.test.ts"
],
"extends": ["plugin:eslint-plugin/recommended"],
"parserOptions": {
"sourceType": "script"
},
"rules": {
"eslint-plugin/prefer-replace-text": "error",
"eslint-plugin/report-message-format": [
"error",
".+\\. See: https://nextjs.org/docs/messages/[a-z\\-]+$"
],
"eslint-plugin/require-meta-docs-description": [
"error",
{
"pattern": ".+"
}
],
"eslint-plugin/require-meta-docs-url": "error"
}
},
{
"files": ["packages/**/*.tsx", "packages/**/*.ts"],
"rules": {
"@typescript-eslint/consistent-type-imports": [
"error",
{
"disallowTypeAnnotations": false
}
],
"@typescript-eslint/no-import-type-side-effects": "error"
}
},
{
"files": ["*.mdx"],
"extends": ["plugin:mdx/recommended"],
"parser": "eslint-mdx",
"rules": {
"react/jsx-no-undef": "off"
}
},
{
"files": [
"packages/next/src/next-devtools/dev-overlay/**/*.tsx",
"packages/next/src/next-devtools/dev-overlay/**/*.ts"
],
"extends": ["plugin:react-hooks/recommended-legacy"],
"rules": {
"react-hooks/exhaustive-deps": "error"
}
}
],
"rules": {
"array-callback-return": "error",
"default-case": ["error", { "commentPattern": "^no default$" }],
"dot-location": ["error", "property"],
"eqeqeq": ["error", "smart"],
"new-parens": "error",
"no-array-constructor": "error",
"no-caller": "error",
"no-cond-assign": ["error", "except-parens"],
"no-const-assign": "error",
"no-control-regex": "error",
"no-delete-var": "error",
"no-dupe-args": "error",
"no-dupe-class-members": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty-character-class": "error",
"no-empty-pattern": "error",
"no-eval": "error",
"no-ex-assign": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-label": "error",
"no-fallthrough": "error",
"no-func-assign": "error",
"no-implied-eval": "error",
"no-invalid-regexp": "error",
"no-iterator": "error",
"no-label-var": "error",
"no-labels": ["error", { "allowLoop": true, "allowSwitch": false }],
"no-lone-blocks": "error",
"no-loop-func": "error",
"no-mixed-operators": [
"error",
{
"groups": [
["&", "|", "^", "~", "<<", ">>", ">>>"],
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
["&&", "||"],
["in", "instanceof"]
],
"allowSamePrecedence": false
}
],
"no-multi-str": "error",
"no-native-reassign": "error",
"no-negated-in-lhs": "error",
"no-new-func": "error",
"no-new-object": "error",
"no-new-symbol": "error",
"no-new-wrappers": "error",
"no-obj-calls": "error",
"no-octal": "error",
"no-octal-escape": "error",
"no-regex-spaces": "error",
"no-restricted-imports": [
"error",
{
"patterns": [
{
"group": ["*/next-devtools/dev-overlay*"],
"message": "Use `next/dist/compiled/next-devtools` (`src/next-devtools/dev-overlay/entrypoint.ts`) instead. Prefer `src/next-devtools/shared/` for shared utils."
}
]
}
],
"no-restricted-syntax": [
"error",
"WithStatement",
{
"message": "substr() is deprecated, use slice() or substring() instead",
"selector": "MemberExpression > Identifier[name='substr']"
},
// ban plain workUnitStore.type if statements and ternaries
{
"selector": "BinaryExpression[left.object.name='workUnitStore'][left.property.name='type'][operator=/^(?:===|!==)$/]",
"message": "Use an exhaustive switch on `workUnitStore.type` (with a `never`-based default) instead of using if statements or ternaries."
},
// ban optional-chained workUnitStore?.type if statements and ternaries
{
"selector": "BinaryExpression[left.type='ChainExpression'][left.expression.object.name='workUnitStore'][left.expression.property.name='type'][operator=/^(?:===|!==)$/]",
"message": "Use an exhaustive switch on `workUnitStore.type` (with a `never`-based default) instead of using if statements or ternaries."
}
],
"no-script-url": "error",
"no-self-assign": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-shadow-restricted-names": "error",
"no-sparse-arrays": "error",
"no-template-curly-in-string": "error",
"no-this-before-super": "error",
"no-throw-literal": "error",
"no-undef": "error",
"no-unexpected-multiline": "error",
"no-unreachable": "error",
"no-unused-expressions": [
"error",
{
"allowShortCircuit": true,
"allowTernary": true,
"allowTaggedTemplates": true
}
],
"no-unused-labels": "error",
"no-unused-vars": [
"error",
{
"args": "none",
"caughtErrors": "none",
"ignoreRestSiblings": true
}
],
"no-use-before-define": "off",
"no-useless-computed-key": "error",
"no-useless-concat": "error",
"no-useless-constructor": "error",
"no-useless-escape": "error",
"no-useless-rename": [
"error",
{
"ignoreDestructuring": false,
"ignoreImport": false,
"ignoreExport": false
}
],
"no-with": "error",
"no-whitespace-before-property": "error",
"react-hooks/exhaustive-deps": "error",
"require-yield": "error",
"rest-spread-spacing": ["error", "never"],
"strict": ["error", "never"],
"unicode-bom": ["error", "never"],
"use-isnan": "error",
"valid-typeof": "error",
"getter-return": "error",
"react/forbid-foreign-prop-types": ["error", { "allowInPropTypes": true }],
"react/jsx-no-comment-textnodes": "error",
"react/jsx-no-duplicate-props": "error",
"react/jsx-no-target-blank": "error",
"react/jsx-no-undef": "error",
"react/jsx-pascal-case": [
"error",
{
"allowAllCaps": true,
"ignore": []
}
],
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
"react/no-danger-with-children": "error",
"react/no-deprecated": "error",
"react/no-direct-mutation-state": "error",
"react/no-is-mounted": "error",
"react/no-typos": "error",
"react/react-in-jsx-scope": "off",
"react/require-render-return": "error",
"react/style-prop-object": "error",
"react-hooks/rules-of-hooks": "error",
// "@typescript-eslint/non-nullable-type-assertion-style": "error",
"@typescript-eslint/prefer-as-const": "error",
"@typescript-eslint/no-redeclare": [
"error",
{ "builtinGlobals": false, "ignoreDeclarationMerge": true }
]
}
}
+1 -1
View File
@@ -16,7 +16,7 @@
"typescript",
"typescriptreact"
],
"eslint.useFlatConfig": false,
"eslint.useFlatConfig": true,
// 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",
+1 -1
View File
@@ -23,7 +23,7 @@
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint": "9.37.0",
"eslint-config-next": "canary",
"tailwindcss": "4.1.13",
"typescript": "^5"
+1 -1
View File
@@ -22,7 +22,7 @@ If you get a warning by alex, follow the instructions to correct the language.
We recommend installing the [ESLint plugin for VS Code](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint).
You can find the enabled rules in the [ESLint config](../../.eslintrc.json).
You can find the enabled rules in the [ESLint config](../../eslint.config.mjs).
## Prettier
+27
View File
@@ -0,0 +1,27 @@
import { defineConfig } from 'eslint/config'
import baseConfig from './eslint.config.mjs'
export default defineConfig([
{
extends: [baseConfig],
},
{
files: ['**/*.ts', '**/*.tsx'],
// This override adds type-checked rules.
// Linting with type-checked rules is very slow and needs a lot of memory,
// so we exclude non-essential files.
ignores: ['examples/**/*', 'test/**/*', '**/*.d.ts', 'turbopack/**/*'],
languageOptions: {
parserOptions: {
project: true,
},
},
// These rules are added on top of the rules that are declared in
// the base config for the matching files.
rules: {
// TODO: enable in follow-up PR
'@typescript-eslint/no-floating-promises': 'off',
'@typescript-eslint/switch-exhaustiveness-check': 'error',
},
},
])
+554
View File
@@ -0,0 +1,554 @@
import { defineConfig } from 'eslint/config'
import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import jest from 'eslint-plugin-jest'
import _import from 'eslint-plugin-import'
import jsdoc from 'eslint-plugin-jsdoc'
import { fixupPluginRules } from '@eslint/compat'
import globals from 'globals'
import babelParser from '@babel/eslint-parser'
import tseslint from 'typescript-eslint'
import nextEslintPluginInternal from '@next/eslint-plugin-internal'
import mdxParser from 'eslint-mdx'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import js from '@eslint/js'
import { FlatCompat } from '@eslint/eslintrc'
import eslintignore from './.config/eslintignore.mjs'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
})
// This is the default eslint config that is used by IDEs. It does not use
// computation-heavy type-checked rules to ensure maximum responsiveness while
// writing code. In addition, there is .eslintrc.cli.json that does use
// type-checked rules in addition to the rules defined here, and it is used
// when running `pnpm lint-eslint` locally or in CI.
export default defineConfig([
eslintignore,
{
files: ['**/*.{js,jsx,mjs,ts,tsx,mts,mdx}'],
linterOptions: {
reportUnusedDisableDirectives: 'error',
},
plugins: {
'@typescript-eslint': tseslint.plugin,
react,
'react-hooks': reactHooks,
jest,
import: fixupPluginRules(_import),
jsdoc,
},
languageOptions: {
globals: {
...globals.browser,
...globals.commonjs,
...globals.node,
...globals.jest,
},
parser: babelParser,
ecmaVersion: 2020,
sourceType: 'module',
parserOptions: {
requireConfigFile: false,
ecmaFeatures: {
jsx: true,
},
babelOptions: {
presets: ['next/babel'],
caller: {
supportsTopLevelAwait: true,
},
},
},
},
settings: {
react: {
version: 'detect',
},
'import/internal-regex': '^next/',
},
rules: {
'array-callback-return': 'error',
'default-case': [
'error',
{
commentPattern: '^no default$',
},
],
'dot-location': ['error', 'property'],
eqeqeq: ['error', 'smart'],
'new-parens': 'error',
'no-array-constructor': 'error',
'no-caller': 'error',
'no-cond-assign': ['error', 'except-parens'],
'no-const-assign': 'error',
'no-control-regex': 'error',
'no-delete-var': 'error',
'no-dupe-args': 'error',
'no-dupe-class-members': 'error',
'no-dupe-keys': 'error',
'no-duplicate-case': 'error',
'no-empty-character-class': 'error',
'no-empty-pattern': 'error',
'no-eval': 'error',
'no-ex-assign': 'error',
'no-extend-native': 'error',
'no-extra-bind': 'error',
'no-extra-label': 'error',
'no-fallthrough': 'error',
'no-func-assign': 'error',
'no-implied-eval': 'error',
'no-invalid-regexp': 'error',
'no-iterator': 'error',
'no-label-var': 'error',
'no-labels': [
'error',
{
allowLoop: true,
allowSwitch: false,
},
],
'no-lone-blocks': 'error',
'no-loop-func': 'error',
'no-mixed-operators': [
'error',
{
groups: [
['&', '|', '^', '~', '<<', '>>', '>>>'],
['==', '!=', '===', '!==', '>', '>=', '<', '<='],
['&&', '||'],
['in', 'instanceof'],
],
allowSamePrecedence: false,
},
],
'no-multi-str': 'error',
'no-native-reassign': 'error',
'no-negated-in-lhs': 'error',
'no-new-func': 'error',
'no-new-object': 'error',
'no-new-symbol': 'error',
'no-new-wrappers': 'error',
'no-obj-calls': 'error',
'no-octal': 'error',
'no-octal-escape': 'error',
'no-regex-spaces': 'error',
'no-restricted-imports': [
'error',
{
patterns: [
{
group: ['*/next-devtools/dev-overlay*'],
message:
'Use `next/dist/compiled/next-devtools` (`src/next-devtools/dev-overlay/entrypoint.ts`) instead. Prefer `src/next-devtools/shared/` for shared utils.',
},
],
},
],
'no-restricted-syntax': [
'error',
'WithStatement',
{
message: 'substr() is deprecated, use slice() or substring() instead',
selector: "MemberExpression > Identifier[name='substr']",
},
{
selector:
"BinaryExpression[left.object.name='workUnitStore'][left.property.name='type'][operator=/^(?:===|!==)$/]",
message:
'Use an exhaustive switch on `workUnitStore.type` (with a `never`-based default) instead of using if statements or ternaries.',
},
{
selector:
"BinaryExpression[left.type='ChainExpression'][left.expression.object.name='workUnitStore'][left.expression.property.name='type'][operator=/^(?:===|!==)$/]",
message:
'Use an exhaustive switch on `workUnitStore.type` (with a `never`-based default) instead of using if statements or ternaries.',
},
],
'no-script-url': 'error',
'no-self-assign': 'error',
'no-self-compare': 'error',
'no-sequences': 'error',
'no-shadow-restricted-names': 'error',
'no-sparse-arrays': 'error',
'no-template-curly-in-string': 'error',
'no-this-before-super': 'error',
'no-throw-literal': 'error',
'no-undef': 'error',
'no-unexpected-multiline': 'error',
'no-unreachable': 'error',
'no-unused-expressions': [
'error',
{
allowShortCircuit: true,
allowTernary: true,
allowTaggedTemplates: true,
},
],
'no-unused-labels': 'error',
'no-unused-vars': [
'error',
{
args: 'none',
caughtErrors: 'none',
ignoreRestSiblings: true,
},
],
'no-use-before-define': 'off',
'no-useless-computed-key': 'error',
'no-useless-concat': 'error',
'no-useless-constructor': 'error',
'no-useless-escape': 'error',
'no-useless-rename': [
'error',
{
ignoreDestructuring: false,
ignoreImport: false,
ignoreExport: false,
},
],
'no-with': 'error',
'no-whitespace-before-property': 'error',
'react-hooks/exhaustive-deps': 'error',
'require-yield': 'error',
'rest-spread-spacing': ['error', 'never'],
strict: ['error', 'never'],
'unicode-bom': ['error', 'never'],
'use-isnan': 'error',
'valid-typeof': 'error',
'getter-return': 'error',
'react/forbid-foreign-prop-types': [
'error',
{
allowInPropTypes: true,
},
],
'react/jsx-no-comment-textnodes': 'error',
'react/jsx-no-duplicate-props': 'error',
'react/jsx-no-target-blank': 'error',
'react/jsx-no-undef': 'error',
'react/jsx-pascal-case': [
'error',
{
allowAllCaps: true,
ignore: [],
},
],
'react/jsx-uses-react': 'error',
'react/jsx-uses-vars': 'error',
'react/no-danger-with-children': 'error',
'react/no-deprecated': 'error',
'react/no-direct-mutation-state': 'error',
'react/no-is-mounted': 'error',
'react/no-typos': 'error',
'react/react-in-jsx-scope': 'off',
'react/require-render-return': 'error',
'react/style-prop-object': 'error',
'react-hooks/rules-of-hooks': 'error',
'@typescript-eslint/prefer-as-const': 'error',
'@typescript-eslint/no-redeclare': [
'error',
{
builtinGlobals: false,
ignoreDeclarationMerge: true,
},
],
},
},
{
files: [
'test/**/*.js',
'test/**/*.ts',
'test/**/*.tsx',
'**/*.test.ts',
'**/*.test.tsx',
],
ignores: ['test/tmp/**'],
extends: compat.extends('plugin:jest/recommended'),
rules: {
'jest/expect-expect': 'off',
'jest/no-disabled-tests': 'off',
'jest/no-conditional-expect': 'off',
'jest/valid-title': 'off',
'jest/no-interpolation-in-snapshots': 'off',
'jest/no-export': 'off',
'jest/no-standalone-expect': [
'error',
{
additionalTestBlockFunctions: ['retry', 'itCI', 'itHeaded'],
},
],
},
},
{
files: ['**/__tests__/**'],
languageOptions: {
globals: {
...globals.jest,
},
},
},
{
files: ['**/*.ts', '**/*.tsx', '**/*.mts'],
extends: [tseslint.configs.recommended, tseslint.configs.stylistic],
languageOptions: {
ecmaVersion: 2020,
sourceType: 'module',
parserOptions: {
warnOnUnsupportedTypeScriptVersion: false,
},
},
rules: {
'@typescript-eslint/array-type': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/ban-tslint-comment': 'off',
'@typescript-eslint/no-empty-object-type': 'off',
'@typescript-eslint/no-restricted-types': 'off',
'@typescript-eslint/no-unsafe-function-type': 'off',
'@typescript-eslint/no-wrapper-object-types': 'off',
'@typescript-eslint/class-literal-property-style': 'off',
'@typescript-eslint/consistent-generic-constructors': 'off',
'@typescript-eslint/consistent-indexed-object-style': 'off',
'@typescript-eslint/consistent-type-definitions': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-shadow': 'off',
'@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',
'@typescript-eslint/no-this-alias': 'off',
'@typescript-eslint/triple-slash-reference': 'off',
'no-var': 'off',
'prefer-const': 'off',
'prefer-rest-params': 'off',
'prefer-spread': 'off',
'no-unused-expressions': 'off',
'@typescript-eslint/no-unused-expressions': [
'error',
{
allowShortCircuit: true,
allowTernary: true,
allowTaggedTemplates: true,
},
],
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{
args: 'none',
ignoreRestSiblings: true,
argsIgnorePattern: '^_',
caughtErrors: 'none',
caughtErrorsIgnorePattern: '^_',
destructuredArrayIgnorePattern: '^_',
varsIgnorePattern: '^_',
},
],
'no-use-before-define': 'off',
'no-useless-constructor': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/no-useless-constructor': 'error',
'@typescript-eslint/prefer-literal-enum-member': 'error',
},
},
{
files: ['packages/**/*.ts', 'packages/**/*.tsx'],
plugins: {
'@next/internal': nextEslintPluginInternal,
},
rules: {
'@next/internal/typechecked-require': 'error',
'jsdoc/no-types': 'error',
'jsdoc/no-undefined-types': 'error',
},
},
{
files: ['examples/**/*'],
linterOptions: {
reportUnusedDisableDirectives: 'off',
},
rules: {
'@typescript-eslint/no-use-before-define': [
'error',
{
functions: true,
classes: true,
variables: true,
enums: true,
typedefs: true,
},
],
'import/no-anonymous-default-export': [
'error',
{
allowArrowFunction: false,
allowAnonymousClass: false,
allowAnonymousFunction: false,
allowArray: true,
allowCallExpression: true,
allowLiteral: true,
allowObject: true,
},
],
},
},
{
files: ['packages/**'],
ignores: [
'packages/next/taskfile*.js',
'packages/next/next-devtools.webpack-config.js',
'packages/next/next-runtime.webpack-config.js',
],
rules: {
'no-shadow': [
'error',
{
builtinGlobals: false,
},
],
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: false,
},
],
},
},
{
files: ['packages/**/*.tsx', 'packages/**/*.ts'],
rules: {
'no-shadow': 'off',
'@typescript-eslint/no-shadow': [
'error',
{
builtinGlobals: false,
},
],
'@typescript-eslint/no-unused-vars': [
'error',
{
args: 'all',
argsIgnorePattern: '^_',
caughtErrors: 'none',
ignoreRestSiblings: true,
varsIgnorePattern: '^_',
},
],
},
},
{
files: [
'packages/eslint-plugin-next/**/*.js',
'test/unit/eslint-plugin-next/**/*.test.ts',
],
extends: compat.extends('plugin:eslint-plugin/recommended'),
languageOptions: {
ecmaVersion: 5,
sourceType: 'script',
},
rules: {
'eslint-plugin/prefer-replace-text': 'error',
'eslint-plugin/report-message-format': [
'error',
'.+\\. See: https://nextjs.org/docs/messages/[a-z\\-]+$',
],
'eslint-plugin/require-meta-docs-description': [
'error',
{
pattern: '.+',
},
],
'eslint-plugin/require-meta-docs-url': 'error',
},
},
{
files: ['packages/**/*.tsx', 'packages/**/*.ts'],
rules: {
'@typescript-eslint/consistent-type-imports': [
'error',
{
disallowTypeAnnotations: false,
},
],
'@typescript-eslint/no-import-type-side-effects': 'error',
},
},
{
files: ['**/*.mdx'],
extends: compat.extends('plugin:mdx/recommended'),
languageOptions: {
parser: mdxParser,
},
rules: {
'react/jsx-no-undef': 'off',
},
},
{
files: [
'packages/next/src/next-devtools/dev-overlay/**/*.tsx',
'packages/next/src/next-devtools/dev-overlay/**/*.ts',
],
extends: [reactHooks.configs.flat['recommended']],
rules: {
'react-hooks/exhaustive-deps': 'error',
},
},
{
// auto-generated file
files: [
'packages/next/src/build/swc/generated-native.d.ts',
'packages/next/src/build/swc/generated-wasm.d.ts',
'rspack/crates/binding/index.d.ts',
],
linterOptions: {
reportUnusedDisableDirectives: 'off',
},
},
{
files: ['turbopack/crates/turbopack-tests/tests/**/*'],
rules: {
'no-console': 'off',
},
},
])
+1 -1
View File
@@ -1,7 +1,7 @@
module.exports = {
'*.{js,jsx,mjs,ts,tsx,mts,mdx}': [
'prettier --with-node-modules --ignore-path .prettierignore --write',
'cross-env ESLINT_USE_FLAT_CONFIG=false eslint --config .eslintrc.json --no-eslintrc --fix',
'eslint --config eslint.config.mjs --fix',
],
'*.{json,md,css,html,yml,yaml,scss}': [
'prettier --with-node-modules --ignore-path .prettierignore --write',
+7 -4
View File
@@ -67,7 +67,7 @@
"git-clean": "git clean -d -x -e node_modules -e packages -f",
"typescript": "tsc --noEmit",
"lint-typescript": "turbo run typescript",
"lint-eslint": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint --ext js,jsx,mjs,ts,tsx,mts,mdx --config .eslintrc.cli.json --no-eslintrc",
"lint-eslint": "eslint --config eslint.cli.config.mjs",
"lint-ast-grep": "ast-grep scan",
"lint-no-typescript": "run-p prettier-check \"lint-eslint .\" lint-language",
"types-and-precompiled": "run-p \"lint-typescript --log-order=stream\" check-compiler-fixtures types:test-lib && pnpm check-precompiled",
@@ -127,6 +127,9 @@
"@edge-runtime/jest-environment": "4.0.0",
"@emotion/cache": "11.11.0",
"@emotion/react": "11.11.1",
"@eslint/compat": "1.4.0",
"@eslint/eslintrc": "^3",
"@eslint/js": "9.37.0",
"@fullhuman/postcss-purgecss": "1.3.0",
"@jest/expect-utils": "29.7.0",
"@mdx-js/loader": "2.2.1",
@@ -168,8 +171,6 @@
"@types/relay-runtime": "14.1.13",
"@types/string-hash": "1.1.1",
"@types/trusted-types": "2.0.3",
"@typescript-eslint/eslint-plugin": "^8.36.0",
"@typescript-eslint/parser": "^8.36.0",
"@vercel/devlow-bench": "workspace:*",
"@vercel/kv": "3.0.0",
"@vercel/og": "0.7.2",
@@ -190,7 +191,7 @@
"dd-trace": "4.12.0",
"es5-ext": "0.10.53",
"escape-string-regexp": "2.0.0",
"eslint": "9.12.0",
"eslint": "9.37.0",
"eslint-config-next": "workspace:*",
"eslint-formatter-codeframe": "7.32.1",
"eslint-plugin-eslint-plugin": "5.2.1",
@@ -214,6 +215,7 @@
"get-port": "5.1.1",
"get-port-please": "3.1.1",
"glob": "7.1.6",
"globals": "16.4.0",
"gzip-size": "5.1.1",
"html-validator": "5.1.18",
"http-proxy": "1.18.1",
@@ -294,6 +296,7 @@
"tsx": "4.19.2",
"turbo": "2.5.5",
"typescript": "5.9.2",
"typescript-eslint": "8.46.0",
"unfetch": "4.2.0",
"wait-port": "0.2.2",
"webpack": "5.98.0",
+2 -2
View File
@@ -12,9 +12,9 @@
"directory": "packages/eslint-plugin-internal"
},
"peerDependencies": {
"eslint": "9.12.0"
"eslint": "9.37.0"
},
"devDependencies": {
"eslint": "9.12.0"
"eslint": "9.37.0"
}
}
+1 -1
View File
@@ -17,7 +17,7 @@
},
"devDependencies": {
"@types/eslint": "9.6.1",
"eslint": "9.12.0"
"eslint": "9.37.0"
},
"scripts": {
"dev": "pnpm build",
+3 -3
View File
@@ -37,9 +37,9 @@ const config: StorybookConfig = {
},
},
}),
webpackFinal: async (config) => {
webpackFinal: async (webpackConfig) => {
// Find and override CSS rule to use the devtool style injection
const cssRule = config.module?.rules?.find((rule) => {
const cssRule = webpackConfig.module?.rules?.find((rule) => {
if (typeof rule !== 'object' || !rule) return false
if ('test' in rule && rule.test instanceof RegExp) {
return rule.test.test('.css')
@@ -77,7 +77,7 @@ const config: StorybookConfig = {
}
}
return config
return webpackConfig
},
}
File diff suppressed because one or more lines are too long
+1171 -663
View File
File diff suppressed because it is too large Load Diff
@@ -1,5 +0,0 @@
{
"rules": {
"no-console": "off"
}
}