e783b0a2e8
This PR re-includes ESLint with some notable changes, namely a guided setup similar to how TypeScript is instantiated in a Next.js application. To add ESLint to a project, developers will have to create an `.eslintrc` file in the root of their project or add an empty `eslintConfig` object to their `package.json` file. ```js touch .eslintrc ``` Then running `next build` will show instructions to install the required packages needed: <img width="862" alt="Screen Shot 2021-04-19 at 7 38 27 PM" src="https://user-images.githubusercontent.com/12476932/115316182-dfd51b00-a146-11eb-830c-90bad20ed151.png"> Once installed and `next build` is run again, `.eslintrc` will be automatically configured to include the default config: ```json { "extends": "next" } ``` In addition to this change: - The feature is now under the experimental flag and requires opt-in. After testing and feedback, it will be switched to the top-level namespace and turned on by default. - A new ESLint shareable configuration package is included that can be extended in any application with `{ extends: 'next' }` - This default config extends recommended rule sets from [`eslint-plugin-react`](https://www.npmjs.com/package/eslint-plugin-react), [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks), and [`eslint-plugin-next`](https://www.npmjs.com/package/@next/eslint-plugin-next) - All rules in [`eslint-plugin-next`](https://www.npmjs.com/package/@next/eslint-plugin-next) have been modified to include actionable links that show more information to help resolve each issue
77 lines
2 KiB
JavaScript
77 lines
2 KiB
JavaScript
const path = require('path')
|
|
const fs = require('fs')
|
|
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`
|
|
)
|
|
})
|
|
|
|
module.exports = {
|
|
meta: {
|
|
docs: {
|
|
description: 'Prohibit full page refresh for nextjs pages',
|
|
category: 'HTML',
|
|
recommended: true,
|
|
},
|
|
fixable: null, // or "code" or "whitespace"
|
|
schema: ['pagesDirectory'],
|
|
},
|
|
|
|
create: function (context) {
|
|
const [customPagesDirectory] = context.options
|
|
const pagesDirs = customPagesDirectory
|
|
? [customPagesDirectory]
|
|
: [
|
|
path.join(context.getCwd(), 'pages'),
|
|
path.join(context.getCwd(), 'src', 'pages'),
|
|
]
|
|
const pagesDir = pagesDirs.find((dir) => fs.existsSync(dir))
|
|
if (!pagesDir) {
|
|
pagesDirWarning(pagesDirs)
|
|
return {}
|
|
}
|
|
|
|
const urls = getUrlFromPagesDirectory('/', pagesDir)
|
|
return {
|
|
JSXOpeningElement(node) {
|
|
if (node.name.name !== 'a') {
|
|
return
|
|
}
|
|
|
|
if (node.attributes.length === 0) {
|
|
return
|
|
}
|
|
|
|
const href = node.attributes.find(
|
|
(attr) => attr.type === 'JSXAttribute' && attr.name.name === 'href'
|
|
)
|
|
|
|
if (!href || href.value.type !== 'Literal') {
|
|
return
|
|
}
|
|
|
|
const hrefPath = normalizeURL(href.value.value)
|
|
// Outgoing links are ignored
|
|
if (/^(https?:\/\/|\/\/)/.test(hrefPath)) {
|
|
return
|
|
}
|
|
|
|
urls.forEach((url) => {
|
|
if (url.test(normalizeURL(hrefPath))) {
|
|
context.report({
|
|
node,
|
|
message: `Do not use the HTML <a> tag to navigate to ${hrefPath}. Use Link from 'next/link' instead. See: https://nextjs.org/docs/messages/no-html-link-for-pages.`,
|
|
})
|
|
}
|
|
})
|
|
},
|
|
}
|
|
},
|
|
}
|