Skip to content

Commit

Permalink
feat: enable @typescript-eslint/recommended in create-next-app --type…
Browse files Browse the repository at this point in the history
…script (#52845)

Co-authored-by: eps1lon <sebastian.silbermann@vercel.com>
  • Loading branch information
2 people authored and lubieowoce committed Sep 2, 2024
1 parent 442807b commit c021c2f
Show file tree
Hide file tree
Showing 16 changed files with 296 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,19 @@ The `next/core-web-vitals` rule set is enabled when `next lint` is run for the f

> The `next/core-web-vitals` entry point is automatically included for new applications built with [Create Next App](/docs/app/api-reference/create-next-app).
### TypeScript

In addition to the Next.js ESLint rules, `create-next-app --typescript` will also add TypeScript-specific lint rules with `next/typescript` to your config:

```json filename=".eslintrc.json"
{
"extends": ["next/core-web-vitals", "next/typescript"]
}
```

Those rules are based on [`plugin:@typescript-eslint/recommended`](https://typescript-eslint.io/linting/configs#recommended).
See [typescript-eslint > Configs](https://typescript-eslint.io/linting/configs) for more details.

## Usage With Other Tools

### Prettier
Expand Down
4 changes: 2 additions & 2 deletions examples/with-temporal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
"@types/node-fetch": "^3.0.3",
"@types/react": "^17.0.2",
"@types/react-dom": "^17.0.1",
"@typescript-eslint/eslint-plugin": "^5.3.0",
"@typescript-eslint/parser": "^5.3.0",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.1.0",
"cross-env": "^7.0.3",
"nodemon": "^2.0.12",
"ts-node": "^10.2.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/create-next-app/templates/app-tw/ts/eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"extends": "next/core-web-vitals"
"extends": ["next/core-web-vitals", "next/typescript"]
}
2 changes: 1 addition & 1 deletion packages/create-next-app/templates/app/ts/eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"extends": "next/core-web-vitals"
"extends": ["next/core-web-vitals", "next/typescript"]
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"extends": "next/core-web-vitals"
"extends": ["next/core-web-vitals", "next/typescript"]
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"extends": "next/core-web-vitals"
"extends": ["next/core-web-vitals", "next/typescript"]
}
15 changes: 6 additions & 9 deletions packages/eslint-config-next/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ sortedPaths.push(...keptPaths)

const hookPropertyMap = new Map(
[
['eslint-plugin-import', 'eslint-plugin-import'],
['eslint-plugin-react', 'eslint-plugin-react'],
['eslint-plugin-jsx-a11y', 'eslint-plugin-jsx-a11y'],
].map(([request, replacement]) => [
'@typescript-eslint/eslint-plugin',
'eslint-plugin-import',
'eslint-plugin-react',
'eslint-plugin-jsx-a11y',
].map((request) => [
request,
require.resolve(replacement, { paths: sortedPaths }),
require.resolve(request, { paths: sortedPaths }),
])
)

Expand Down Expand Up @@ -96,10 +97,6 @@ module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
warnOnUnsupportedTypeScriptVersion: true,
},
},
],
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-config-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"dependencies": {
"@next/eslint-plugin-next": "14.2.7",
"@rushstack/eslint-patch": "^1.3.3",
"@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0",
"@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0",
"eslint-import-resolver-node": "^0.3.6",
"eslint-import-resolver-typescript": "^3.5.2",
Expand Down
3 changes: 3 additions & 0 deletions packages/eslint-config-next/typescript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
extends: ['plugin:@typescript-eslint/recommended'],
}
20 changes: 0 additions & 20 deletions packages/next/src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,26 +78,6 @@ export const SSG_FALLBACK_EXPORT_ERROR = `Pages with \`fallback\` enabled in \`g

export const ESLINT_DEFAULT_DIRS = ['app', 'pages', 'components', 'lib', 'src']

export const ESLINT_PROMPT_VALUES = [
{
title: 'Strict',
recommended: true,
config: {
extends: 'next/core-web-vitals',
},
},
{
title: 'Base',
config: {
extends: 'next',
},
},
{
title: 'Cancel',
config: null,
},
]

export const SERVER_RUNTIME: Record<string, ServerRuntime> = {
edge: 'edge',
experimentalEdge: 'experimental-edge',
Expand Down
32 changes: 32 additions & 0 deletions packages/next/src/lib/eslint/getESLintPromptValues.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import findUp from 'next/dist/compiled/find-up'

export const getESLintStrictValue = async (cwd: string) => {
const tsConfigLocation = await findUp('tsconfig.json', { cwd })
const hasTSConfig = tsConfigLocation !== undefined

return {
title: 'Strict',
recommended: true,
config: {
extends: hasTSConfig
? ['next/core-web-vitals', 'next/typescript']
: 'next/core-web-vitals',
},
}
}

export const getESLintPromptValues = async (cwd: string) => {
return [
await getESLintStrictValue(cwd),
{
title: 'Base',
config: {
extends: 'next',
},
},
{
title: 'Cancel',
config: null,
},
]
}
15 changes: 8 additions & 7 deletions packages/next/src/lib/eslint/runLintCheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { writeDefaultConfig } from './writeDefaultConfig'
import { hasEslintConfiguration } from './hasEslintConfiguration'
import { writeOutputFile } from './writeOutputFile'

import { ESLINT_PROMPT_VALUES } from '../constants'
import { findPagesDir } from '../find-pages-dir'
import { installDependencies } from '../install-dependencies'
import { hasNecessaryDependencies } from '../has-necessary-dependencies'
Expand All @@ -21,6 +20,10 @@ import * as Log from '../../build/output/log'
import type { EventLintCheckCompleted } from '../../telemetry/events/build'
import isError, { getProperError } from '../is-error'
import { getPkgManager } from '../helpers/get-pkg-manager'
import {
getESLintStrictValue,
getESLintPromptValues,
} from './getESLintPromptValues'

type Config = {
plugins: string[]
Expand All @@ -44,7 +47,7 @@ const requiredPackages = [
},
]

async function cliPrompt(): Promise<{ config?: any }> {
async function cliPrompt(cwd: string): Promise<{ config?: any }> {
console.log(
bold(
`${cyan(
Expand All @@ -58,7 +61,7 @@ async function cliPrompt(): Promise<{ config?: any }> {
await Promise.resolve(require('next/dist/compiled/cli-select'))
).default
const { value } = await cliSelect({
values: ESLINT_PROMPT_VALUES,
values: await getESLintPromptValues(cwd),
valueRenderer: (
{
title,
Expand Down Expand Up @@ -355,10 +358,8 @@ export async function runLintCheck(
} else {
// Ask user what config they would like to start with for first time "next lint" setup
const { config: selectedConfig } = strict
? ESLINT_PROMPT_VALUES.find(
(opt: { title: string }) => opt.title === 'Strict'
)!
: await cliPrompt()
? await getESLintStrictValue(baseDir)
: await cliPrompt(baseDir)

if (selectedConfig == null) {
// Show a warning if no option is selected in prompt
Expand Down
100 changes: 90 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions test/integration/eslint/test/next-lint.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ describe('Next Lint', () => {
'We created the .eslintrc.json file for you and included your selected configuration'
)
expect(eslintrcJson).toMatchObject({ extends: 'next/core-web-vitals' })
})

test('creates .eslintrc.json file with a default app router configuration', async () => {
// App Router
const { stdout: appStdout, eslintrcJson: appEslintrcJson } =
await nextLintTemp(null, true)
Expand Down
Loading

0 comments on commit c021c2f

Please sign in to comment.