diff --git a/.eslintignore b/.eslintignore
index 37e0a229afb6..fa46bc2d129c 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -2,6 +2,7 @@ node_modules
**/.next/**
**/_next/**
**/dist/**
+e2e-tests/**
examples/with-typescript-eslint-jest/**
examples/with-kea/**
packages/next/bundles/webpack/packages/*.runtime.js
@@ -16,4 +17,5 @@ packages/next-codemod/**/*.js
packages/next-codemod/**/*.d.ts
packages/next-env/**/*.d.ts
test/integration/async-modules/**
+test/integration/eslint/**
test-timings.json
\ No newline at end of file
diff --git a/docs/api-reference/next.config.js/eslint-warnings-errors.md b/docs/api-reference/next.config.js/eslint-warnings-errors.md
new file mode 100644
index 000000000000..d13372413216
--- /dev/null
+++ b/docs/api-reference/next.config.js/eslint-warnings-errors.md
@@ -0,0 +1,70 @@
+---
+description: Learn how to opt-in and out of ESLint during development mode and production builds.
+---
+
+# ESLint Warnings and Errors
+
+## During builds
+
+Next.js fails your **production build** (`next build`) when ESLint errors are present in your
+project.
+
+If you'd like Next.js to dangerously produce production code even when your application has errors,
+you can disable ESLint running during the build process.
+
+> It's recommended to run ESLint as part of the production build process to ensure your application
+> is resilient against runtime issues.
+
+Open `next.config.js` and disable the `build` option in the `eslint` config:
+
+```js
+module.exports = {
+ eslint: {
+ // !! WARN !!
+ // Dangerously allow production builds to successfully complete even if
+ // your project has ESLint errors.
+ // !! WARN !!
+ build: false,
+ },
+}
+```
+
+## During development
+
+By default, Next.js does not run ESLint during **development** (`next dev`).
+
+If you would like Next.js to lint files separately in development mode, you can enable it in your
+configuration.
+
+> Enabling ESLint during development mode will slow down how fast pages are compiled. Until this is
+> optimized, we recommend that you [integrate ESLint in your code
+> editor](https://eslint.org/docs/user-guide/integrations#editors).
+
+Open `next.config.js` and enable the `dev` option in the `eslint` config:
+
+```js
+module.exports = {
+ eslint: {
+ // !! WARN !!
+ // This can slow down how long pages take to compile during development
+ // !! WARN !!
+ dev: true,
+ },
+}
+```
+
+## Related
+
+
+
+
diff --git a/docs/basic-features/eslint.md b/docs/basic-features/eslint.md
new file mode 100644
index 000000000000..019cc1d7c3e2
--- /dev/null
+++ b/docs/basic-features/eslint.md
@@ -0,0 +1,50 @@
+---
+description: Next.js uses ESLint to find and resolve issues affecting the user or developer
+experience.
+---
+
+# ESLint
+
+Next.js uses [ESLint](https://eslint.org/) to find and resolve issues affecting the user or
+developer experience. A minimal set of Next.js rules are provided by default, but can be extended by
+adding an `.eslintrc` file to your project.
+
+## Default configuration
+
+By default, Next.js provides a set of [recommended ESLint
+rules](https://github.com/vercel/next.js/blob/canary/packages/eslint-plugin-next/lib/index.js#L10-L18)
+that are automatically linted against as part of `next build`. If you would like to control which
+ESLint rules are checked during builds, you will need to add an `.eslintrc` file to the root of your
+project.
+
+Here's an example of an `.eslintrc.json` file:
+
+```json
+{
+ "extends": ["plugin:@next/next/recommended"],
+ "parser": "@babel/eslint-parser",
+ "parserOptions": {
+ "requireConfigFile": false,
+ "sourceType": "module",
+ "babelOptions": {
+ "presets": ["next/babel"]
+ }
+ }
+}
+```
+
+- Extending the original base of rules (`plugin:@next/next/recommended`) is highly recommended to
+ catch and fix significant Next.js issues in your application
+- Including `@babel/eslint-parser` with the `next/babel` preset ensures that all language features
+ supported by Next.js will also be supported by ESLint. Although `@babel/eslint-parser` can parse
+ TypeScript, consider using
+ [`@typescript-eslint/parser`](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser)
+ if you have TypeScript enabled in your application to check for type-specific linting rules.
+
+> If you add an `.eslintrc` file to your application and don't include
+> `plugin:@next/next/recommended`in the config, its rules will not be checked during development or
+> production builds. This is **not recommended**.
+
+If you want to enable ESLint to run during development, or disable it for production builds; refer
+to the documentation for [ESLint Warnings and
+Errors](/docs/api-reference/next.config.js/eslint-warnings-errors.md).
diff --git a/docs/manifest.json b/docs/manifest.json
index a9dcd38126b8..cd9010eb8bfc 100644
--- a/docs/manifest.json
+++ b/docs/manifest.json
@@ -33,6 +33,10 @@
"title": "Fast Refresh",
"path": "/docs/basic-features/fast-refresh.md"
},
+ {
+ "title": "ESLint",
+ "path": "/docs/basic-features/eslint.md"
+ },
{
"title": "TypeScript",
"path": "/docs/basic-features/typescript.md"
@@ -336,6 +340,10 @@
"title": "Configuring onDemandEntries",
"path": "/docs/api-reference/next.config.js/configuring-onDemandEntries.md"
},
+ {
+ "title": "ESLint Warnings and Errors",
+ "path": "/docs/api-reference/next.config.js/eslint-warnings-errors.md"
+ },
{
"title": "Ignoring TypeScript Errors",
"path": "/docs/api-reference/next.config.js/ignoring-typescript-errors.md"
diff --git a/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js b/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js
index 947850a6f5af..b816a418b860 100644
--- a/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js
+++ b/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js
@@ -1,10 +1,18 @@
const path = require('path')
const fs = require('fs')
-const { getUrlFromPagesDirectory, normalizeURL } = require('../utils/url')
+const {
+ getUrlFromPagesDirectory,
+ normalizeURL,
+ execOnce,
+} = require('../utils/url')
+
+const pagesDirWarning = execOnce((pagesDirs) => {
+ console.warn(
+ `Pages directory cannot be found at ${pagesDirs.join(' or ')}. ` +
+ `If using a custom path, please configure with the no-html-link-for-pages rule in your eslint config file`
+ )
+})
-//------------------------------------------------------------------------------
-// Rule Definition
-//------------------------------------------------------------------------------
module.exports = {
meta: {
docs: {
@@ -26,10 +34,8 @@ module.exports = {
]
const pagesDir = pagesDirs.find((dir) => fs.existsSync(dir))
if (!pagesDir) {
- throw new Error(
- `Pages directory cannot be found at ${pagesDirs.join(' or ')}. ` +
- `If using a custom path, please configure with the no-html-link-for-pages rule`
- )
+ pagesDirWarning(pagesDirs)
+ return {}
}
const urls = getUrlFromPagesDirectory('/', pagesDir)
diff --git a/packages/eslint-plugin-next/lib/utils/url.js b/packages/eslint-plugin-next/lib/utils/url.js
index 4b3999b10f45..ae1163b47ff1 100644
--- a/packages/eslint-plugin-next/lib/utils/url.js
+++ b/packages/eslint-plugin-next/lib/utils/url.js
@@ -76,7 +76,21 @@ function normalizeURL(url) {
return url
}
+function execOnce(fn) {
+ let used = false
+ let result
+
+ return (...args) => {
+ if (!used) {
+ used = true
+ result = fn(...args)
+ }
+ return result
+ }
+}
+
module.exports = {
getUrlFromPagesDirectory,
normalizeURL,
+ execOnce,
}
diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts
index 4faaaad434e9..e79555487d23 100644
--- a/packages/next/build/index.ts
+++ b/packages/next/build/index.ts
@@ -175,6 +175,41 @@ export default async function build(
telemetry.record(events)
)
+ if (config.eslint?.build) {
+ await nextBuildSpan
+ .traceChild('verify-and-lint')
+ .traceAsyncFn(async () => {
+ const lintWorkers = new Worker(
+ require.resolve('../lib/verifyAndLint'),
+ {
+ numWorkers: config.experimental.cpus,
+ enableWorkerThreads: config.experimental.workerThreads,
+ }
+ ) as Worker & {
+ verifyAndLint: typeof import('../lib/verifyAndLint').verifyAndLint
+ }
+
+ lintWorkers.getStdout().pipe(process.stdout)
+ lintWorkers.getStderr().pipe(process.stderr)
+
+ const lintResults = await lintWorkers.verifyAndLint(
+ dir,
+ pagesDir,
+ null
+ )
+
+ if (lintResults.hasErrors) {
+ console.error(chalk.red('Failed to compile.'))
+ console.error(lintResults.results)
+ process.exit(1)
+ } else if (lintResults.hasMessages) {
+ console.log(lintResults.results)
+ }
+
+ lintWorkers.end()
+ })
+ }
+
const ignoreTypeScriptErrors = Boolean(config.typescript?.ignoreBuildErrors)
await nextBuildSpan
.traceChild('verify-typescript-setup')
diff --git a/packages/next/lib/eslint/customFormatter.ts b/packages/next/lib/eslint/customFormatter.ts
new file mode 100644
index 000000000000..6fc55ef09b04
--- /dev/null
+++ b/packages/next/lib/eslint/customFormatter.ts
@@ -0,0 +1,68 @@
+import { ESLint, Linter } from 'eslint'
+
+import chalk from 'chalk'
+import path from 'path'
+
+export enum MessageSeverity {
+ Warning = 1,
+ Error = 2,
+}
+
+function formatMessage(
+ dir: string,
+ messages: Linter.LintMessage[],
+ filePath: string
+): string | void {
+ let fileName = path.posix.normalize(
+ path.relative(dir, filePath).replace(/\\/g, '/')
+ )
+
+ if (!fileName.startsWith('.')) {
+ fileName = './' + fileName
+ }
+
+ let output = '\n' + chalk.cyan(fileName)
+
+ for (let i = 0; i < messages.length; i++) {
+ const { message, severity, line, column, ruleId } = messages[i]
+
+ output = output + '\n'
+
+ if (line && column) {
+ output =
+ output +
+ chalk.yellow(line.toString()) +
+ ':' +
+ chalk.yellow(column.toString()) +
+ ' '
+ }
+
+ if (severity === MessageSeverity.Warning) {
+ output += chalk.yellow.bold('Warning') + ': '
+ } else {
+ output += chalk.red.bold('Error') + ': '
+ }
+
+ output += message
+
+ if (ruleId) {
+ output += ' ' + chalk.gray.bold(ruleId)
+ }
+ }
+
+ return output
+}
+
+export function formatResults(
+ baseDir: string,
+ results: ESLint.LintResult[]
+): string {
+ return (
+ results
+ .filter(({ messages }) => messages?.length)
+ .map(({ messages, filePath }) =>
+ formatMessage(baseDir, messages, filePath)
+ )
+ .join('\n') + '\n'
+ )
+}
diff --git a/packages/next/lib/verifyAndLint.ts b/packages/next/lib/verifyAndLint.ts
new file mode 100644
index 000000000000..997b77b94b10
--- /dev/null
+++ b/packages/next/lib/verifyAndLint.ts
@@ -0,0 +1,141 @@
+import { ESLint } from 'eslint'
+import { join } from 'path'
+
+import { formatResults } from './eslint/customFormatter'
+import { fileExists } from './file-exists'
+import * as log from '../build/output/log'
+
+import findUp from 'next/dist/compiled/find-up'
+
+type Config = {
+ plugins: string[]
+ rules: { [key: string]: Array }
+}
+
+export async function verifyAndLint(
+ baseDir: string,
+ pagesDir: string,
+ pagePath: string | null
+): Promise<{
+ results: string
+ hasErrors: boolean
+ hasMessages: boolean
+}> {
+ let options: ESLint.Options
+
+ let pathNotExists = Boolean(
+ pagePath && !(await fileExists(join(pagesDir, pagePath)))
+ )
+
+ if (pathNotExists)
+ return { results: '', hasErrors: false, hasMessages: false }
+
+ const eslintrcFile = await findUp(
+ [
+ '.eslintrc.js',
+ '.eslintrc.yaml',
+ '.eslintrc.yml',
+ '.eslintrc.json',
+ '.eslintrc',
+ ],
+ {
+ cwd: baseDir,
+ }
+ )
+
+ const pagesDirRules = ['@next/next/no-html-link-for-pages']
+ const pkgJsonPath = await findUp('package.json', { cwd: baseDir })
+ const { eslintConfig = null } = !!pkgJsonPath
+ ? await import(pkgJsonPath!)
+ : {}
+ let pluginIsEnabled = false
+
+ if (eslintrcFile) {
+ options = {
+ useEslintrc: true,
+ baseConfig: {},
+ }
+ } else {
+ if (!eslintConfig) {
+ console.log()
+ log.info(
+ 'No ESLint configuration was detected, but checks from the Next.js ESLint plugin were included automatically (see https://nextjs.org/docs/basic-features/eslint).'
+ )
+ pluginIsEnabled = true
+ }
+
+ options = {
+ baseConfig: eslintConfig ?? {
+ extends: ['plugin:@next/next/recommended'],
+ parser: require.resolve('@babel/eslint-parser'),
+ parserOptions: {
+ requireConfigFile: false,
+ sourceType: 'module',
+ babelOptions: {
+ presets: ['next/babel'],
+ },
+ },
+ },
+ useEslintrc: false,
+ }
+ }
+
+ let eslint = new ESLint(options)
+
+ // check both eslintrc and package.json config since
+ // eslint will load config from both
+ for (const configFile of [eslintrcFile, pkgJsonPath]) {
+ if (!configFile) continue
+
+ const completeConfig: Config = await eslint.calculateConfigForFile(
+ configFile
+ )
+
+ if (completeConfig.plugins?.includes('@next/next')) {
+ pluginIsEnabled = true
+ break
+ }
+ }
+
+ if (pluginIsEnabled) {
+ let updatedPagesDir = false
+
+ for (const rule of pagesDirRules) {
+ if (
+ !options.baseConfig!.rules?.[rule] &&
+ !options.baseConfig!.rules?.[
+ rule.replace('@next/next', '@next/babel-plugin-next')
+ ]
+ ) {
+ if (!options.baseConfig!.rules) {
+ options.baseConfig!.rules = {}
+ }
+ options.baseConfig!.rules[rule] = [1, pagesDir]
+ updatedPagesDir = true
+ }
+ }
+
+ if (updatedPagesDir) {
+ eslint = new ESLint(options)
+ }
+ } else {
+ console.log()
+ log.warn(
+ `The Next.js ESLint plugin was not detected in ${
+ eslintrcFile || pkgJsonPath
+ }. We recommend including it to prevent significant issues in your application (see https://nextjs.org/docs/basic-features/eslint).`
+ )
+ }
+
+ const results = await eslint.lintFiles([
+ pagePath ? join(pagesDir, pagePath) : `${pagesDir}/**/*.{js,tsx}`,
+ ])
+
+ const errors = ESLint.getErrorResults(results)
+
+ return {
+ results: formatResults(baseDir, results),
+ hasErrors: errors?.length > 0 && !pagePath,
+ hasMessages: results?.length > 0,
+ }
+}
diff --git a/packages/next/next-server/server/config-shared.ts b/packages/next/next-server/server/config-shared.ts
index a677d5db3a25..196973e5709b 100644
--- a/packages/next/next-server/server/config-shared.ts
+++ b/packages/next/next-server/server/config-shared.ts
@@ -89,6 +89,10 @@ export const defaultConfig: NextConfig = {
serverRuntimeConfig: {},
publicRuntimeConfig: {},
reactStrictMode: false,
+ eslint: {
+ dev: false,
+ build: true,
+ },
}
export function normalizeConfig(phase: string, config: any) {
diff --git a/packages/next/package.json b/packages/next/package.json
index c248c52fb4d8..e2fe18a11b8c 100644
--- a/packages/next/package.json
+++ b/packages/next/package.json
@@ -60,9 +60,12 @@
]
},
"dependencies": {
+ "@babel/core": "7.12.10",
"@babel/runtime": "7.12.5",
+ "@babel/eslint-parser": "7.13.4",
"@hapi/accept": "5.0.1",
"@next/env": "10.0.10-canary.7",
+ "@next/eslint-plugin-next": "10.0.10-canary.7",
"@next/polyfill-module": "10.0.10-canary.7",
"@next/react-dev-overlay": "10.0.10-canary.7",
"@next/react-refresh-utils": "10.0.10-canary.7",
@@ -79,6 +82,7 @@
"crypto-browserify": "3.12.0",
"cssnano-simple": "1.2.2",
"domain-browser": "4.19.0",
+ "eslint": "7.9.0",
"etag": "1.8.1",
"find-cache-dir": "3.3.1",
"get-orientation": "1.1.2",
@@ -130,7 +134,6 @@
"devDependencies": {
"@ampproject/toolbox-optimizer": "2.7.1-alpha.0",
"@babel/code-frame": "7.12.11",
- "@babel/core": "7.12.10",
"@babel/plugin-proposal-class-properties": "7.12.1",
"@babel/plugin-proposal-export-namespace-from": "7.12.1",
"@babel/plugin-proposal-numeric-separator": "7.12.7",
@@ -161,6 +164,7 @@
"@types/cookie": "0.3.3",
"@types/cross-spawn": "6.0.0",
"@types/debug": "4.1.5",
+ "@types/eslint": "7.2.5",
"@types/etag": "1.8.0",
"@types/fresh": "0.5.0",
"@types/json5": "0.0.30",
diff --git a/packages/next/server/hot-reloader.ts b/packages/next/server/hot-reloader.ts
index 15e33caa2a6c..1470bde405eb 100644
--- a/packages/next/server/hot-reloader.ts
+++ b/packages/next/server/hot-reloader.ts
@@ -512,6 +512,7 @@ export default class HotReloader {
this.onDemandEntries = onDemandEntryHandler(this.watcher, multiCompiler, {
pagesDir: this.pagesDir,
pageExtensions: this.config.pageExtensions,
+ eslint: this.config.eslint?.dev,
...(this.config.onDemandEntries as {
maxInactiveAge: number
pagesBufferLength: number
diff --git a/packages/next/server/on-demand-entry-handler.ts b/packages/next/server/on-demand-entry-handler.ts
index d6bef0477fe5..bd918494f257 100644
--- a/packages/next/server/on-demand-entry-handler.ts
+++ b/packages/next/server/on-demand-entry-handler.ts
@@ -4,6 +4,7 @@ import { join, posix } from 'path'
import { parse } from 'url'
import { webpack } from 'next/dist/compiled/webpack/webpack'
import * as Log from '../build/output/log'
+import { verifyAndLint } from '../lib/verifyAndLint'
import {
normalizePagePath,
normalizePathSep,
@@ -32,11 +33,13 @@ export default function onDemandEntryHandler(
{
pagesDir,
pageExtensions,
+ eslint,
maxInactiveAge,
pagesBufferLength,
}: {
pagesDir: string
pageExtensions: string[]
+ eslint: boolean
maxInactiveAge: number
pagesBufferLength: number
}
@@ -192,6 +195,15 @@ export default function onDemandEntryHandler(
}
}
+ // TODO: Move out of hot-reloader into a separate process
+ if (eslint) {
+ verifyAndLint(process.cwd(), pagesDir, pagePath).then(
+ ({ results, hasMessages }) => {
+ if (hasMessages) console.log(results)
+ }
+ )
+ }
+
Log.event(`build page: ${normalizedPage}`)
entries[normalizedPage] = {
diff --git a/test-pnp.sh b/test-pnp.sh
index 8b5fd93beb57..1bcc4a4016c7 100755
--- a/test-pnp.sh
+++ b/test-pnp.sh
@@ -29,6 +29,9 @@ do
cp -r "./examples/$testCase/." "./e2e-tests/$testCase"
cd "./e2e-tests/$testCase"
+ # Ensure builds do not fail due to lint errors
+ echo "module.exports = { eslint: { build: false } }" > next.config.js
+
touch yarn.lock
yarn set version berry
diff --git a/test/integration/dist-dir/test/index.test.js b/test/integration/dist-dir/test/index.test.js
index 8930f21ed046..d9202d8d8d52 100644
--- a/test/integration/dist-dir/test/index.test.js
+++ b/test/integration/dist-dir/test/index.test.js
@@ -47,7 +47,10 @@ describe('distDir', () => {
it('should throw error with invalid distDir', async () => {
const origNextConfig = await fs.readFile(nextConfig, 'utf8')
- await fs.writeFile(nextConfig, `module.exports = { distDir: '' }`)
+ await fs.writeFile(
+ nextConfig,
+ `module.exports = { distDir: '', eslint: { build: false } }`
+ )
const { stderr } = await nextBuild(appDir, [], { stderr: true })
await fs.writeFile(nextConfig, origNextConfig)
@@ -58,10 +61,12 @@ describe('distDir', () => {
it('should handle null/undefined distDir', async () => {
const origNextConfig = await fs.readFile(nextConfig, 'utf8')
- await fs.writeFile(nextConfig, `module.exports = { distDir: null }`)
+ await fs.writeFile(
+ nextConfig,
+ `module.exports = { distDir: null, eslint: { build: false } }`
+ )
const { stderr } = await nextBuild(appDir, [], { stderr: true })
await fs.writeFile(nextConfig, origNextConfig)
-
expect(stderr.length).toBe(0)
})
})
diff --git a/test/integration/eslint/custom-eslint-config/.eslintrc.json b/test/integration/eslint/custom-eslint-config/.eslintrc.json
new file mode 100644
index 000000000000..f0dc21af7d53
--- /dev/null
+++ b/test/integration/eslint/custom-eslint-config/.eslintrc.json
@@ -0,0 +1,16 @@
+{
+ "extends": ["plugin:@next/next/recommended"],
+ "rules": {
+ "@next/next/no-sync-scripts": "off",
+ "@next/next/no-css-tags": "warn",
+ "@next/next/no-html-link-for-pages": ["error", "./"]
+ },
+ "parserOptions": {
+ "ecmaVersion": 2018,
+ "sourceType": "module",
+ "ecmaFeatures": {
+ "jsx": true,
+ "modules": true
+ }
+ }
+}
diff --git a/test/integration/eslint/custom-eslint-config/pages/index.js b/test/integration/eslint/custom-eslint-config/pages/index.js
new file mode 100644
index 000000000000..64a516a0323a
--- /dev/null
+++ b/test/integration/eslint/custom-eslint-config/pages/index.js
@@ -0,0 +1,13 @@
+import { Head } from 'next/document'
+
+export default class Test extends Head {
+ render() {
+ return (
+
+
Hello title
+
+
+
+ )
+ }
+}
diff --git a/test/integration/eslint/custom-next-config/.eslintrc.json b/test/integration/eslint/custom-next-config/.eslintrc.json
new file mode 100644
index 000000000000..444bf63d9ee1
--- /dev/null
+++ b/test/integration/eslint/custom-next-config/.eslintrc.json
@@ -0,0 +1,14 @@
+{
+ "extends": ["plugin:@next/next/recommended"],
+ "rules": {
+ "@next/next/no-html-link-for-pages": ["error", "./"]
+ },
+ "parserOptions": {
+ "ecmaVersion": 2018,
+ "sourceType": "module",
+ "ecmaFeatures": {
+ "jsx": true,
+ "modules": true
+ }
+ }
+}
diff --git a/test/integration/eslint/custom-next-config/next.config.js b/test/integration/eslint/custom-next-config/next.config.js
new file mode 100644
index 000000000000..d1567e6d0576
--- /dev/null
+++ b/test/integration/eslint/custom-next-config/next.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ eslint: {
+ dev: true,
+ build: false,
+ },
+}
diff --git a/test/integration/eslint/custom-next-config/pages/index.js b/test/integration/eslint/custom-next-config/pages/index.js
new file mode 100644
index 000000000000..64a516a0323a
--- /dev/null
+++ b/test/integration/eslint/custom-next-config/pages/index.js
@@ -0,0 +1,13 @@
+import { Head } from 'next/document'
+
+export default class Test extends Head {
+ render() {
+ return (
+
+
Hello title
+
+
+
+ )
+ }
+}
diff --git a/test/integration/eslint/pkg-json-eslint-config/package.json b/test/integration/eslint/pkg-json-eslint-config/package.json
new file mode 100644
index 000000000000..4d09b24ceb47
--- /dev/null
+++ b/test/integration/eslint/pkg-json-eslint-config/package.json
@@ -0,0 +1,36 @@
+{
+ "name": "hello-world",
+ "version": "1.0.0",
+ "scripts": {
+ "dev": "next",
+ "build": "next build",
+ "start": "next start"
+ },
+ "dependencies": {
+ "next": "latest",
+ "react": "^16.13.1",
+ "react-dom": "^16.13.1"
+ },
+ "license": "MIT",
+ "eslintConfig": {
+ "extends": [
+ "plugin:@next/next/recommended"
+ ],
+ "rules": {
+ "@next/next/no-sync-scripts": "off",
+ "@next/next/no-css-tags": "warn",
+ "@next/next/no-html-link-for-pages": [
+ "error",
+ "./"
+ ]
+ },
+ "parserOptions": {
+ "ecmaVersion": 2018,
+ "sourceType": "module",
+ "ecmaFeatures": {
+ "jsx": true,
+ "modules": true
+ }
+ }
+ }
+}
diff --git a/test/integration/eslint/pkg-json-eslint-config/pages/index.js b/test/integration/eslint/pkg-json-eslint-config/pages/index.js
new file mode 100644
index 000000000000..64a516a0323a
--- /dev/null
+++ b/test/integration/eslint/pkg-json-eslint-config/pages/index.js
@@ -0,0 +1,13 @@
+import { Head } from 'next/document'
+
+export default class Test extends Head {
+ render() {
+ return (
+
+
Hello title
+
+
+
+ )
+ }
+}
diff --git a/test/integration/eslint/test/custom-eslint-config.test.js b/test/integration/eslint/test/custom-eslint-config.test.js
new file mode 100644
index 000000000000..bcfce446a5f5
--- /dev/null
+++ b/test/integration/eslint/test/custom-eslint-config.test.js
@@ -0,0 +1,37 @@
+import { join } from 'path'
+import { nextBuild } from 'next-test-utils'
+import { remove } from 'fs-extra'
+
+jest.setTimeout(1000 * 60 * 2)
+
+const appDir = join(__dirname, '../custom-eslint-config')
+
+describe('ESLint', () => {
+ let stdout
+ let code
+
+ beforeAll(async () => {
+ await remove(join(appDir, '.next'))
+ ;({ code, stdout } = await nextBuild(appDir, [], {
+ stdout: true,
+ }))
+ })
+
+ it('should show warnings and errors based on custom eslint config', async () => {
+ expect(code).toBe(0)
+ expect(stdout).not.toContain(
+ 'No ESLint configuration was detected, but checks from the Next.js ESLint plugin were included automatically'
+ )
+ expect(stdout).toContain('./pages/index.js')
+ expect(stdout).not.toContain(
+ "8:9 Warning: A synchronous script tag can impact your webpage's performance @next/next/no-sync-scripts"
+ )
+ expect(stdout).toContain(
+ '9:9 Warning: In order to use external stylesheets use @import in the root stylesheet compiled with NextJS. This ensures proper priority to CSS when loading a webpage. @next/next/no-css-tags'
+ )
+ expect(stdout).toContain(
+ '9:9 Warning: Stylesheet does not have an associated preload tag. This could potentially impact First paint. @next/next/missing-preload'
+ )
+ expect(stdout).toContain('Compiled successfully')
+ })
+})
diff --git a/test/integration/eslint/test/custom-next-config.test.js b/test/integration/eslint/test/custom-next-config.test.js
new file mode 100644
index 000000000000..7daf4689de0a
--- /dev/null
+++ b/test/integration/eslint/test/custom-next-config.test.js
@@ -0,0 +1,55 @@
+import { join } from 'path'
+import {
+ launchApp,
+ renderViaHTTP,
+ killApp,
+ findPort,
+ nextBuild,
+} from 'next-test-utils'
+
+jest.setTimeout(1000 * 60 * 2)
+
+const appDir = join(__dirname, '../custom-next-config')
+
+describe('ESLint', () => {
+ it('should show messages in dev mode as specified in next config', async () => {
+ let stdout
+
+ const appPort = await findPort()
+ const app = await launchApp(appDir, appPort, {
+ onStdout(msg) {
+ stdout += msg || ''
+ },
+ })
+ await renderViaHTTP(appPort, '/')
+ await killApp(app)
+ expect(stdout).toContain('pages/index.js')
+ expect(stdout).toContain(
+ "8:9 Warning: A synchronous script tag can impact your webpage's performance @next/next/no-sync-scripts"
+ )
+ expect(stdout).toContain(
+ '9:9 Warning: In order to use external stylesheets use @import in the root stylesheet compiled with NextJS. This ensures proper priority to CSS when loading a webpage. @next/next/no-css-tags'
+ )
+ expect(stdout).toContain(
+ '9:9 Warning: Stylesheet does not have an associated preload tag. This could potentially impact First paint. @next/next/missing-preload'
+ )
+ })
+
+ it('should not show messages in build mode as specified in next config', async () => {
+ const { code, stdout } = await nextBuild(appDir, [], {
+ stdout: true,
+ })
+ expect(code).toBe(0)
+ expect(stdout).not.toContain('pages/index.js')
+ expect(stdout).not.toContain(
+ "8:9 Warning: A synchronous script tag can impact your webpage's performance @next/next/no-sync-scripts"
+ )
+ expect(stdout).not.toContain(
+ '9:9 Warning: In order to use external stylesheets use @import in the root stylesheet compiled with NextJS. This ensures proper priority to CSS when loading a webpage. @next/next/no-css-tags'
+ )
+ expect(stdout).not.toContain(
+ '9:9 Warning: Stylesheet does not have an associated preload tag. This could potentially impact First paint. @next/next/missing-preload'
+ )
+ expect(stdout).toContain('Compiled successfully')
+ })
+})
diff --git a/test/integration/eslint/test/pkg-json-eslint-config.test.js b/test/integration/eslint/test/pkg-json-eslint-config.test.js
new file mode 100644
index 000000000000..ac0069ee7b74
--- /dev/null
+++ b/test/integration/eslint/test/pkg-json-eslint-config.test.js
@@ -0,0 +1,44 @@
+import { join } from 'path'
+import { nextBuild } from 'next-test-utils'
+import { remove } from 'fs-extra'
+
+jest.setTimeout(1000 * 60 * 2)
+
+const appDir = join(__dirname, '../pkg-json-eslint-config')
+
+describe('ESLint', () => {
+ let code
+ let output
+
+ beforeAll(async () => {
+ await remove(join(appDir, '.next'))
+ let stderr
+ let stdout
+ ;({ code, stdout, stderr } = await nextBuild(appDir, [], {
+ stdout: true,
+ stderr: true,
+ }))
+ output = stderr + stdout
+ })
+
+ it('should show warnings and errors based on eslint config in package.json', async () => {
+ expect(code).toBe(0)
+ expect(output).not.toContain(
+ 'The Next.js ESLint plugin was not detected in'
+ )
+ expect(output).not.toContain(
+ 'No ESLint configuration was detected, but checks from the Next.js ESLint plugin were included automatically'
+ )
+ expect(output).toContain('./pages/index.js')
+ expect(output).not.toContain(
+ "8:9 Warning: A synchronous script tag can impact your webpage's performance @next/next/no-sync-scripts"
+ )
+ expect(output).toContain(
+ '9:9 Warning: In order to use external stylesheets use @import in the root stylesheet compiled with NextJS. This ensures proper priority to CSS when loading a webpage. @next/next/no-css-tags'
+ )
+ expect(output).toContain(
+ '9:9 Warning: Stylesheet does not have an associated preload tag. This could potentially impact First paint. @next/next/missing-preload'
+ )
+ expect(output).toContain('Compiled successfully')
+ })
+})
diff --git a/test/integration/index-index/pages/index/index.js b/test/integration/index-index/pages/index/index.js
index 626b31302558..6a83652f5ecf 100644
--- a/test/integration/index-index/pages/index/index.js
+++ b/test/integration/index-index/pages/index/index.js
@@ -1,3 +1,3 @@
export default function Index() {
- return index > index
+ return index > index
}
diff --git a/test/integration/index-index/pages/index/index/index.js b/test/integration/index-index/pages/index/index/index.js
index 639914d7c4bb..5dfa7851c114 100644
--- a/test/integration/index-index/pages/index/index/index.js
+++ b/test/integration/index-index/pages/index/index/index.js
@@ -1,3 +1,3 @@
export default function Index() {
- return index > index > index
+ return index > index > index
}
diff --git a/test/integration/index-index/pages/index/project/index.js b/test/integration/index-index/pages/index/project/index.js
index b6b50016bf4e..87892a403390 100644
--- a/test/integration/index-index/pages/index/project/index.js
+++ b/test/integration/index-index/pages/index/project/index.js
@@ -1,3 +1,3 @@
export default function Index() {
- return index > project
+ return index > project
}
diff --git a/test/integration/index-index/pages/index/user.js b/test/integration/index-index/pages/index/user.js
index b317488aaebf..398520816d1d 100644
--- a/test/integration/index-index/pages/index/user.js
+++ b/test/integration/index-index/pages/index/user.js
@@ -1,3 +1,3 @@
export default function Index() {
- return index > user
+ return index > user
}
diff --git a/test/integration/production-build-dir/next.config.js b/test/integration/production-build-dir/next.config.js
new file mode 100644
index 000000000000..397e034c301b
--- /dev/null
+++ b/test/integration/production-build-dir/next.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+ eslint: {
+ build: false,
+ },
+}
diff --git a/test/integration/production/pages/error-in-ssr-render.js b/test/integration/production/pages/error-in-ssr-render.js
index 863abf80fb1d..c2477a38db1c 100644
--- a/test/integration/production/pages/error-in-ssr-render.js
+++ b/test/integration/production/pages/error-in-ssr-render.js
@@ -1,10 +1,11 @@
+/* eslint-disable */
+
import React from 'react'
export default class ErrorInRenderPage extends React.Component {
static async getInitialProps() {
return {}
}
- // eslint-disable-next-line react/require-render-return
render() {
throw new Error('An Expected error occured')
}
diff --git a/test/integration/tsconfig-verifier/pages/index.tsx b/test/integration/tsconfig-verifier/pages/index.tsx
index f8dc264a3716..47bd85b976b0 100644
--- a/test/integration/tsconfig-verifier/pages/index.tsx
+++ b/test/integration/tsconfig-verifier/pages/index.tsx
@@ -1,6 +1,6 @@
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
+/* eslint-disable */
+
const blah: boolean = false
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
const blah2 = import('../value').then((r) => r.default)
export default () => Hello TypeScript
diff --git a/test/integration/webpack-require-hook/next.config.js b/test/integration/webpack-require-hook/next.config.js
index 01cbcf62c6cf..588fbfd05bb5 100644
--- a/test/integration/webpack-require-hook/next.config.js
+++ b/test/integration/webpack-require-hook/next.config.js
@@ -11,4 +11,7 @@ module.exports = {
throw new Error('Webpack require hook not applying')
return config
},
+ eslint: {
+ build: false,
+ },
}
diff --git a/yarn.lock b/yarn.lock
index 464133effdf5..5062f49526fa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -93,6 +93,15 @@
semver "^5.4.1"
source-map "^0.5.0"
+"@babel/eslint-parser@7.13.4":
+ version "7.13.4"
+ resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.13.4.tgz#dd9df3c70f44d2fb5a6519e8e10ca06c67dca43a"
+ integrity sha512-WfFEd89SzqmtYox8crTLJuEXyJolZY6Uu6iJpJmw4aMu50zHbYnxzxwuVkCt2cWygw+gLkUPTtAuox7eSnrL8g==
+ dependencies:
+ eslint-scope "5.1.0"
+ eslint-visitor-keys "^1.3.0"
+ semver "7.0.0"
+
"@babel/generator@^7.12.10", "@babel/generator@^7.12.11":
version "7.12.11"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.11.tgz#98a7df7b8c358c9a37ab07a24056853016aba3af"
@@ -1162,6 +1171,22 @@
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
+"@eslint/eslintrc@^0.1.3":
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.1.3.tgz#7d1a2b2358552cc04834c0979bd4275362e37085"
+ integrity sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==
+ dependencies:
+ ajv "^6.12.4"
+ debug "^4.1.1"
+ espree "^7.3.0"
+ globals "^12.1.0"
+ ignore "^4.0.6"
+ import-fresh "^3.2.1"
+ js-yaml "^3.13.1"
+ lodash "^4.17.19"
+ minimatch "^3.0.4"
+ strip-json-comments "^3.1.1"
+
"@firebase/analytics-types@0.3.1":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.3.1.tgz#3c5f5d71129c88295e17e914e34b391ffda1723c"
@@ -2925,6 +2950,14 @@
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
+"@types/eslint@7.2.5":
+ version "7.2.5"
+ resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.5.tgz#92172ecf490c2fce4b076739693d75f30376d610"
+ integrity sha512-Dc6ar9x16BdaR3NSxSF7T4IjL9gxxViJq8RmFd+2UAyA+K6ck2W+gUwfgpG/y9TPyUuBL35109bbULpEynvltA==
+ dependencies:
+ "@types/estree" "*"
+ "@types/json-schema" "*"
+
"@types/estree@*":
version "0.0.45"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884"
@@ -3034,6 +3067,11 @@
dependencies:
"@types/jest-diff" "*"
+"@types/json-schema@*":
+ version "7.0.7"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
+ integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
+
"@types/json-schema@^7.0.3", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6":
version "7.0.6"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
@@ -3568,6 +3606,11 @@ acorn-jsx@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.1.0.tgz#294adb71b57398b0680015f0a38c563ee1db5384"
+acorn-jsx@^5.3.1:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b"
+ integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==
+
acorn-walk@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.1.1.tgz#345f0dffad5c735e7373d2fec9a1023e6a44b83e"
@@ -3585,6 +3628,11 @@ acorn@^7.1.0, acorn@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf"
+acorn@^7.4.0:
+ version "7.4.1"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
+ integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
+
acorn@^8.0.4:
version "8.0.4"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.0.4.tgz#7a3ae4191466a6984eee0fe3407a4f3aa9db8354"
@@ -3681,6 +3729,11 @@ anser@1.4.9:
version "1.4.9"
resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.9.tgz#1f85423a5dcf8da4631a341665ff675b96845760"
+ansi-colors@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
+ integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
+
ansi-escapes@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
@@ -5624,7 +5677,7 @@ cross-spawn@^5.0.1:
shebang-command "^1.2.0"
which "^1.2.9"
-cross-spawn@^7.0.0, cross-spawn@^7.0.3:
+cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@@ -6064,7 +6117,7 @@ deep-extend@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
-deep-is@~0.1.3:
+deep-is@^0.1.3, deep-is@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
@@ -6468,6 +6521,13 @@ enhanced-resolve@^4.3.0:
memory-fs "^0.5.0"
tapable "^1.0.0"
+enquirer@^2.3.5:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
+ integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
+ dependencies:
+ ansi-colors "^4.1.1"
+
entities@^1.1.1, entities@~1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
@@ -6707,6 +6767,14 @@ eslint-plugin-react@7.19.0:
string.prototype.matchall "^4.0.2"
xregexp "^4.3.0"
+eslint-scope@5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5"
+ integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==
+ dependencies:
+ esrecurse "^4.1.0"
+ estraverse "^4.1.1"
+
eslint-scope@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848"
@@ -6722,6 +6790,14 @@ eslint-scope@^5.0.0:
esrecurse "^4.1.0"
estraverse "^4.1.1"
+eslint-scope@^5.1.0:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
+ integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
+ dependencies:
+ esrecurse "^4.3.0"
+ estraverse "^4.1.1"
+
eslint-utils@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f"
@@ -6734,10 +6810,22 @@ eslint-utils@^2.0.0:
dependencies:
eslint-visitor-keys "^1.1.0"
+eslint-utils@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
+ integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
+ dependencies:
+ eslint-visitor-keys "^1.1.0"
+
eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
+eslint-visitor-keys@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
+ integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
+
eslint@6.8.0:
version "6.8.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb"
@@ -6780,6 +6868,49 @@ eslint@6.8.0:
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
+eslint@7.9.0:
+ version "7.9.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.9.0.tgz#522aeccc5c3a19017cf0cb46ebfd660a79acf337"
+ integrity sha512-V6QyhX21+uXp4T+3nrNfI3hQNBDa/P8ga7LoQOenwrlEFXrEnUEE+ok1dMtaS3b6rmLXhT1TkTIsG75HMLbknA==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ "@eslint/eslintrc" "^0.1.3"
+ ajv "^6.10.0"
+ chalk "^4.0.0"
+ cross-spawn "^7.0.2"
+ debug "^4.0.1"
+ doctrine "^3.0.0"
+ enquirer "^2.3.5"
+ eslint-scope "^5.1.0"
+ eslint-utils "^2.1.0"
+ eslint-visitor-keys "^1.3.0"
+ espree "^7.3.0"
+ esquery "^1.2.0"
+ esutils "^2.0.2"
+ file-entry-cache "^5.0.1"
+ functional-red-black-tree "^1.0.1"
+ glob-parent "^5.0.0"
+ globals "^12.1.0"
+ ignore "^4.0.6"
+ import-fresh "^3.0.0"
+ imurmurhash "^0.1.4"
+ is-glob "^4.0.0"
+ js-yaml "^3.13.1"
+ json-stable-stringify-without-jsonify "^1.0.1"
+ levn "^0.4.1"
+ lodash "^4.17.19"
+ minimatch "^3.0.4"
+ natural-compare "^1.4.0"
+ optionator "^0.9.1"
+ progress "^2.0.0"
+ regexpp "^3.1.0"
+ semver "^7.2.1"
+ strip-ansi "^6.0.0"
+ strip-json-comments "^3.1.0"
+ table "^5.2.3"
+ text-table "^0.2.0"
+ v8-compile-cache "^2.0.3"
+
espree@^6.1.2:
version "6.1.2"
resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.2.tgz#6c272650932b4f91c3714e5e7b5f5e2ecf47262d"
@@ -6788,6 +6919,15 @@ espree@^6.1.2:
acorn-jsx "^5.1.0"
eslint-visitor-keys "^1.1.0"
+espree@^7.3.0:
+ version "7.3.1"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6"
+ integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==
+ dependencies:
+ acorn "^7.4.0"
+ acorn-jsx "^5.3.1"
+ eslint-visitor-keys "^1.3.0"
+
esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
@@ -6798,17 +6938,31 @@ esquery@^1.0.1:
dependencies:
estraverse "^4.0.0"
+esquery@^1.2.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57"
+ integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==
+ dependencies:
+ estraverse "^5.1.0"
+
esrecurse@^4.1.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
dependencies:
estraverse "^4.1.0"
+esrecurse@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+ integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
+ dependencies:
+ estraverse "^5.2.0"
+
estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1:
version "4.3.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
-estraverse@^5.2.0:
+estraverse@^5.1.0, estraverse@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
@@ -7116,7 +7270,7 @@ fast-json-stable-stringify@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
-fast-levenshtein@~2.0.6:
+fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
@@ -9858,6 +10012,14 @@ levn@^0.3.0, levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
+levn@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
+ integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
+ dependencies:
+ prelude-ls "^1.2.1"
+ type-check "~0.4.0"
+
libnpmaccess@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-4.0.1.tgz#17e842e03bef759854adf6eb6c2ede32e782639f"
@@ -11484,6 +11646,18 @@ optionator@^0.8.1, optionator@^0.8.3:
type-check "~0.3.2"
word-wrap "~1.2.3"
+optionator@^0.9.1:
+ version "0.9.1"
+ resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
+ integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
+ dependencies:
+ deep-is "^0.1.3"
+ fast-levenshtein "^2.0.6"
+ levn "^0.4.1"
+ prelude-ls "^1.2.1"
+ type-check "^0.4.0"
+ word-wrap "^1.2.3"
+
ora@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ora/-/ora-2.0.0.tgz#8ec3a37fa7bffb54a3a0c188a1f6798e7e1827cd"
@@ -12826,6 +13000,11 @@ pre-commit@1.2.2:
spawn-sync "^1.0.15"
which "1.2.x"
+prelude-ls@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
+ integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
+
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@@ -13499,6 +13678,11 @@ regexpp@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.0.0.tgz#dd63982ee3300e67b41c1956f850aa680d9d330e"
+regexpp@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
+ integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
+
regexpu-core@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b"
@@ -14146,7 +14330,7 @@ semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
-semver@^7.0.0, semver@^7.1.1, semver@^7.1.3, semver@^7.3.2, semver@^7.3.4:
+semver@^7.0.0, semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4:
version "7.3.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
@@ -14900,6 +15084,11 @@ strip-json-comments@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7"
+strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+ integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
+
strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
@@ -15535,6 +15724,13 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+type-check@^0.4.0, type-check@~0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
+ integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
+ dependencies:
+ prelude-ls "^1.2.1"
+
type-check@~0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
@@ -16240,7 +16436,7 @@ wide-align@^1.1.0:
dependencies:
string-width "^1.0.2 || 2"
-word-wrap@~1.2.3:
+word-wrap@^1.2.3, word-wrap@~1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"