Skip to content

Commit 2d49baa

Browse files
moar eslint updates and bugfixes
1 parent a008d01 commit 2d49baa

File tree

5 files changed

+122
-28
lines changed

5 files changed

+122
-28
lines changed

packages/next/cli/next-lint.ts

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,65 @@ import { resolve, join } from 'path'
55
import chalk from 'chalk'
66

77
import { cliCommand } from '../bin/next'
8+
import { ESLINT_DEFAULT_DIRS } from '../lib/constants'
89
import { runLintCheck } from '../lib/eslint/runLintCheck'
910
import { printAndExit } from '../server/lib/utils'
1011

12+
const eslintOptions = (args: arg.Spec) => ({
13+
overrideConfigFile: args['--config'] || null,
14+
extensions: args['--ext'] ?? ['.js', '.jsx', '.ts', '.tsx'],
15+
resolvePluginsRelativeTo: args['--resolve-plugins-relative-to'] || null,
16+
rulePaths: args['--rulesdir'] ?? [],
17+
fix: args['--fix'] ?? false,
18+
fixTypes: args['--fix-type'] ?? null,
19+
ignorePath: args['--ignore-path'] || null,
20+
ignore: !Boolean(args['--no-ignore']),
21+
allowInlineConfig: !Boolean(args['--no-inline-config']),
22+
reportUnusedDisableDirectives:
23+
args['--report-unused-disable-directives'] || null,
24+
cache: args['--cache'] ?? false,
25+
cacheLocation: args['--cache-location'] || '.eslintcache',
26+
cacheStrategy: args['--cache-strategy'] || 'metadata',
27+
errorOnUnmatchedPattern: !Boolean(args['--no-error-on-unmatched-pattern']),
28+
})
29+
1130
const nextLint: cliCommand = (argv) => {
1231
const validArgs: arg.Spec = {
1332
// Types
1433
'--help': Boolean,
34+
'--base-dir': String,
1535
'--dir': [String],
1636

1737
// Aliases
1838
'-h': '--help',
39+
'-b': '--base-dir',
1940
'-d': '--dir',
2041
}
2142

43+
const validEslintArgs: arg.Spec = {
44+
// Types
45+
'--config': String,
46+
'--ext': [String],
47+
'--resolve-plugins-relative-to': String,
48+
'--rulesdir': [String],
49+
'--fix': Boolean,
50+
'--fix-type': [String],
51+
'--ignore-path': String,
52+
'--no-ignore': Boolean,
53+
'--no-inline-config': Boolean,
54+
'--report-unused-disable-directives': String,
55+
'--cache': Boolean,
56+
'--cache-location': String,
57+
'--cache-strategy': String,
58+
'--no-error-on-unmatched-pattern': Boolean,
59+
60+
// Aliases
61+
'-c': '--config',
62+
}
63+
2264
let args: arg.Result<arg.Spec>
2365
try {
24-
args = arg(validArgs, { argv })
66+
args = arg({ ...validArgs, ...validEslintArgs }, { argv })
2567
} catch (error) {
2668
if (error.code === 'ARG_UNKNOWN_OPTION') {
2769
return printAndExit(error.message, 1)
@@ -37,14 +79,41 @@ const nextLint: cliCommand = (argv) => {
3779
3880
Usage
3981
$ next lint <baseDir> [options]
40-
82+
4183
<baseDir> represents the directory of the Next.js application.
4284
If no directory is provided, the current directory will be used.
4385
4486
Options
45-
-h - list this help
46-
-d - set directory, or directories, to run ESLint (defaults to only 'pages')
47-
`,
87+
Basic configuration:
88+
-h, --help List this help
89+
-d, --dir Array Set directory, or directories, to run ESLint - default: 'pages', 'components', and 'lib'
90+
-c, --config path::String Use this configuration file, overriding all other config options
91+
--ext [String] Specify JavaScript file extensions - default: .js, .jsx, .ts, .tsx
92+
--resolve-plugins-relative-to path::String A folder where plugins should be resolved from, CWD by default
93+
94+
Specifying rules:
95+
--rulesdir [path::String] Use additional rules from this directory
96+
97+
Fixing problems:
98+
--fix Automatically fix problems
99+
--fix-type Array Specify the types of fixes to apply (problem, suggestion, layout)
100+
101+
Ignoring files:
102+
--ignore-path path::String Specify path of ignore file
103+
--no-ignore Disable use of ignore files and patterns
104+
105+
Inline configuration comments:
106+
--no-inline-config Prevent comments from changing config or rules
107+
--report-unused-disable-directives Adds reported errors for unused eslint-disable directives ("error" | "warn" | "off")
108+
109+
Caching:
110+
--cache Only check changed files - default: false
111+
--cache-location path::String Path to the cache file or directory - default: .eslintcache
112+
--cache-strategy String Strategy to use for detecting changed files - either: metadata or content - default: metadata
113+
114+
Miscellaneous:
115+
--no-error-on-unmatched-pattern Prevent errors when pattern is unmatched - default: false
116+
`,
48117
0
49118
)
50119
}
@@ -57,7 +126,7 @@ const nextLint: cliCommand = (argv) => {
57126
}
58127

59128
const dirs: string[] = args['--dir']
60-
const lintDirs = (dirs ?? ['pages', 'components', 'lib']).reduce(
129+
const lintDirs = (dirs ?? ESLINT_DEFAULT_DIRS).reduce(
61130
(res: string[], d: string) => {
62131
const currDir = join(baseDir, d)
63132
if (!existsSync(currDir)) return res
@@ -67,7 +136,7 @@ const nextLint: cliCommand = (argv) => {
67136
[]
68137
)
69138

70-
runLintCheck(baseDir, lintDirs)
139+
runLintCheck(baseDir, lintDirs, false, eslintOptions(args))
71140
.then((results) => {
72141
if (results) {
73142
console.log(results)

packages/next/lib/constants.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,12 @@ export const GSSP_COMPONENT_MEMBER_ERROR = `can not be attached to a page's comp
4848
export const NON_STANDARD_NODE_ENV = `You are using a non-standard "NODE_ENV" value in your environment. This creates inconsistencies in the project and is strongly advised against. Read more: https://nextjs.org/docs/messages/non-standard-node-env`
4949

5050
export const SSG_FALLBACK_EXPORT_ERROR = `Pages with \`fallback\` enabled in \`getStaticPaths\` can not be exported. See more info here: https://nextjs.org/docs/messages/ssg-fallback-true-export`
51+
52+
export const ESLINT_DEFAULT_DIRS = [
53+
'pages',
54+
'components',
55+
'lib',
56+
'src/pages',
57+
'src/components',
58+
'src/lib',
59+
]

packages/next/lib/eslint/runLintCheck.ts

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { promises as fs } from 'fs'
22
import chalk from 'chalk'
3+
import path from 'path'
34

45
import findUp from 'next/dist/compiled/find-up'
56
import semver from 'next/dist/compiled/semver'
67
import * as CommentJson from 'next/dist/compiled/comment-json'
78

89
import { formatResults } from './customFormatter'
910
import { writeDefaultConfig } from './writeDefaultConfig'
10-
import { findPagesDir } from '../find-pages-dir'
11+
import { existsSync, findPagesDir } from '../find-pages-dir'
1112
import { CompileError } from '../compile-error'
1213
import {
1314
hasNecessaryDependencies,
@@ -21,16 +22,13 @@ type Config = {
2122
rules: { [key: string]: Array<number | string> }
2223
}
2324

24-
const linteableFiles = (dir: string) => {
25-
return `${dir}/**/*.{${['jsx', 'js', 'ts', 'tsx'].join(',')}}`
26-
}
27-
2825
async function lint(
2926
deps: NecessaryDependencies,
3027
baseDir: string,
3128
lintDirs: string[],
3229
eslintrcFile: string | null,
33-
pkgJsonPath: string | null
30+
pkgJsonPath: string | null,
31+
eslintOptions: any = null
3432
): Promise<string | null> {
3533
// Load ESLint after we're sure it exists:
3634
const mod = await import(deps.resolved)
@@ -41,23 +39,23 @@ async function lint(
4139
const eslintVersion: string | undefined = mod?.CLIEngine?.version
4240

4341
if (!eslintVersion || semver.lt(eslintVersion, '7.0.0')) {
44-
Log.error(
45-
`Your project has an older version of ESLint installed${
46-
eslintVersion ? ' (' + eslintVersion + ')' : ''
47-
}. Please upgrade to ESLint version 7 or later`
48-
)
49-
return null
42+
return `${chalk.red(
43+
'error'
44+
)} - Your project has an older version of ESLint installed${
45+
eslintVersion ? ' (' + eslintVersion + ')' : ''
46+
}. Please upgrade to ESLint version 7 or later`
5047
}
5148

52-
Log.error(
53-
`ESLint class not found. Please upgrade to ESLint version 7 or later`
54-
)
55-
return null
49+
return `${chalk.red(
50+
'error'
51+
)} - ESLint class not found. Please upgrade to ESLint version 7 or later`
5652
}
5753

5854
let options: any = {
5955
useEslintrc: true,
6056
baseConfig: {},
57+
extensions: ['.js', '.jsx', '.ts', '.tsx'],
58+
...eslintOptions,
6159
}
6260
let eslint = new ESLint(options)
6361

@@ -101,18 +99,21 @@ async function lint(
10199
eslint = new ESLint(options)
102100
}
103101
}
102+
const results = await eslint.lintFiles(lintDirs)
103+
if (options.fix) await ESLint.outputFixes(results)
104104

105-
const results = await eslint.lintFiles(lintDirs.map(linteableFiles))
106105
if (ESLint.getErrorResults(results)?.length > 0) {
107106
throw new CompileError(await formatResults(baseDir, results))
108107
}
108+
109109
return results?.length > 0 ? formatResults(baseDir, results) : null
110110
}
111111

112112
export async function runLintCheck(
113113
baseDir: string,
114114
lintDirs: string[],
115-
lintDuringBuild: boolean = false
115+
lintDuringBuild: boolean = false,
116+
eslintOptions: any = null
116117
): Promise<string | null> {
117118
try {
118119
// Find user's .eslintrc file
@@ -158,10 +159,23 @@ export async function runLintCheck(
158159
)
159160

160161
// Write default ESLint config if none is present
161-
await writeDefaultConfig(eslintrcFile, pkgJsonPath, packageJsonConfig)
162+
// Check for /pages and src/pages is to make sure this happens in Next.js folder
163+
if (
164+
existsSync(path.join(baseDir, 'pages')) ||
165+
existsSync(path.join(baseDir, 'src/pages'))
166+
) {
167+
await writeDefaultConfig(eslintrcFile, pkgJsonPath, packageJsonConfig)
168+
}
162169

163170
// Run ESLint
164-
return await lint(deps, baseDir, lintDirs, eslintrcFile, pkgJsonPath)
171+
return await lint(
172+
deps,
173+
baseDir,
174+
lintDirs,
175+
eslintrcFile,
176+
pkgJsonPath,
177+
eslintOptions
178+
)
165179
} catch (err) {
166180
throw err
167181
}

packages/next/lib/verifyAndLint.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import chalk from 'chalk'
22
import { Worker } from 'jest-worker'
33
import { existsSync } from 'fs'
44
import { join } from 'path'
5+
import { ESLINT_DEFAULT_DIRS } from './constants'
56

67
export async function verifyAndLint(
78
dir: string,
@@ -20,7 +21,7 @@ export async function verifyAndLint(
2021
lintWorkers.getStdout().pipe(process.stdout)
2122
lintWorkers.getStderr().pipe(process.stderr)
2223

23-
const lintDirs = (configLintDirs ?? ['pages', 'components', 'lib']).reduce(
24+
const lintDirs = (configLintDirs ?? ESLINT_DEFAULT_DIRS).reduce(
2425
(res: string[], d: string) => {
2526
const currDir = join(dir, d)
2627
if (!existsSync(currDir)) return res
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2+
"root": true,
23
"extends": "next"
34
}

0 commit comments

Comments
 (0)