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
JoshuaKGoldberg and eps1lon committed Jun 27, 2024
1 parent 689e4b8 commit 72a6408
Show file tree
Hide file tree
Showing 16 changed files with 289 additions and 57 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": "15.0.0-canary.46",
"@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 @@ -79,26 +79,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 @@ -356,10 +359,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
95 changes: 83 additions & 12 deletions pnpm-lock.yaml

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

Loading

0 comments on commit 72a6408

Please sign in to comment.