rsnext/packages/eslint-plugin-next/lib/rules/no-html-link-for-pages.js

118 lines
3 KiB
JavaScript
Raw Normal View History

Add rootDir setting to eslint-plugin-next (#27918) ## Introduction This PR enables setting a `rootDir` for a Next.js project, and follows the same pattern used by [`@typescript-eslint/parser`](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#parseroptionsproject). ## Details Previously, users had to pass paths to the rule itself. ```js module.exports = { rules: { "@next/next/no-html-link-for-pages": [ "error", // This could be a string, or array of strings. "/packages/my-app/pages", ], }, }; ``` With this PR, this has been simplified (the previous implementation still works as expected). ```js module.exports = { settings: { next: { rootDir: "/packages/my-app", }, }, rules: { "@next/next/no-html-link-for-pages": "error", }, }; ``` Further, this rule allows the use of globs, again aligning with `@typescript-eslint/parser`. ```js module.exports = { settings: { next: { // Globs rootDir: "/packages/*", rootDir: "/packages/{app-a,app-b}", // Arrays rootDir: ["/app-a", "/app-b"], // Arrays with globs rootDir: ["/main-app", "/other-apps/*"], }, }; ``` This enables users to either provide per-workspace configuration with overrides, or to use globs for situations like monorepos where the apps share a domain (micro-frontends). This doesn't solve, but improves https://github.com/vercel/next.js/issues/26330. ## Feature - [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [x] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [x] Make sure the linting passes
2021-08-11 12:37:55 +02:00
// @ts-check
const path = require('path')
const fs = require('fs')
Add rootDir setting to eslint-plugin-next (#27918) ## Introduction This PR enables setting a `rootDir` for a Next.js project, and follows the same pattern used by [`@typescript-eslint/parser`](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#parseroptionsproject). ## Details Previously, users had to pass paths to the rule itself. ```js module.exports = { rules: { "@next/next/no-html-link-for-pages": [ "error", // This could be a string, or array of strings. "/packages/my-app/pages", ], }, }; ``` With this PR, this has been simplified (the previous implementation still works as expected). ```js module.exports = { settings: { next: { rootDir: "/packages/my-app", }, }, rules: { "@next/next/no-html-link-for-pages": "error", }, }; ``` Further, this rule allows the use of globs, again aligning with `@typescript-eslint/parser`. ```js module.exports = { settings: { next: { // Globs rootDir: "/packages/*", rootDir: "/packages/{app-a,app-b}", // Arrays rootDir: ["/app-a", "/app-b"], // Arrays with globs rootDir: ["/main-app", "/other-apps/*"], }, }; ``` This enables users to either provide per-workspace configuration with overrides, or to use globs for situations like monorepos where the apps share a domain (micro-frontends). This doesn't solve, but improves https://github.com/vercel/next.js/issues/26330. ## Feature - [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [x] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [x] Make sure the linting passes
2021-08-11 12:37:55 +02:00
const getRootDir = require('../utils/get-root-dirs')
Adds ESLint with default rule-set (#23702) 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
2021-04-30 13:09:07 +02:00
const {
getUrlFromPagesDirectories,
Adds ESLint with default rule-set (#23702) 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
2021-04-30 13:09:07 +02:00
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`
)
})
// Cache for fs.existsSync lookup.
// Prevent multiple blocking IO requests that have already been calculated.
const fsExistsSyncCache = {}
module.exports = {
meta: {
docs: {
Add rootDir setting to eslint-plugin-next (#27918) ## Introduction This PR enables setting a `rootDir` for a Next.js project, and follows the same pattern used by [`@typescript-eslint/parser`](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#parseroptionsproject). ## Details Previously, users had to pass paths to the rule itself. ```js module.exports = { rules: { "@next/next/no-html-link-for-pages": [ "error", // This could be a string, or array of strings. "/packages/my-app/pages", ], }, }; ``` With this PR, this has been simplified (the previous implementation still works as expected). ```js module.exports = { settings: { next: { rootDir: "/packages/my-app", }, }, rules: { "@next/next/no-html-link-for-pages": "error", }, }; ``` Further, this rule allows the use of globs, again aligning with `@typescript-eslint/parser`. ```js module.exports = { settings: { next: { // Globs rootDir: "/packages/*", rootDir: "/packages/{app-a,app-b}", // Arrays rootDir: ["/app-a", "/app-b"], // Arrays with globs rootDir: ["/main-app", "/other-apps/*"], }, }; ``` This enables users to either provide per-workspace configuration with overrides, or to use globs for situations like monorepos where the apps share a domain (micro-frontends). This doesn't solve, but improves https://github.com/vercel/next.js/issues/26330. ## Feature - [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [x] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [x] Make sure the linting passes
2021-08-11 12:37:55 +02:00
description: 'Prohibit full page refresh for Next.js pages',
category: 'HTML',
recommended: true,
},
fixable: null, // or "code" or "whitespace"
schema: [
{
oneOf: [
{
type: 'string',
},
{
type: 'array',
uniqueItems: true,
items: {
type: 'string',
},
},
],
},
],
},
Add rootDir setting to eslint-plugin-next (#27918) ## Introduction This PR enables setting a `rootDir` for a Next.js project, and follows the same pattern used by [`@typescript-eslint/parser`](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#parseroptionsproject). ## Details Previously, users had to pass paths to the rule itself. ```js module.exports = { rules: { "@next/next/no-html-link-for-pages": [ "error", // This could be a string, or array of strings. "/packages/my-app/pages", ], }, }; ``` With this PR, this has been simplified (the previous implementation still works as expected). ```js module.exports = { settings: { next: { rootDir: "/packages/my-app", }, }, rules: { "@next/next/no-html-link-for-pages": "error", }, }; ``` Further, this rule allows the use of globs, again aligning with `@typescript-eslint/parser`. ```js module.exports = { settings: { next: { // Globs rootDir: "/packages/*", rootDir: "/packages/{app-a,app-b}", // Arrays rootDir: ["/app-a", "/app-b"], // Arrays with globs rootDir: ["/main-app", "/other-apps/*"], }, }; ``` This enables users to either provide per-workspace configuration with overrides, or to use globs for situations like monorepos where the apps share a domain (micro-frontends). This doesn't solve, but improves https://github.com/vercel/next.js/issues/26330. ## Feature - [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [x] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [x] Make sure the linting passes
2021-08-11 12:37:55 +02:00
/**
* Creates an ESLint rule listener.
*
* @param {import('eslint').Rule.RuleContext} context - ESLint rule context
* @returns {import('eslint').Rule.RuleListener} An ESLint rule listener
*/
create: function (context) {
Add rootDir setting to eslint-plugin-next (#27918) ## Introduction This PR enables setting a `rootDir` for a Next.js project, and follows the same pattern used by [`@typescript-eslint/parser`](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#parseroptionsproject). ## Details Previously, users had to pass paths to the rule itself. ```js module.exports = { rules: { "@next/next/no-html-link-for-pages": [ "error", // This could be a string, or array of strings. "/packages/my-app/pages", ], }, }; ``` With this PR, this has been simplified (the previous implementation still works as expected). ```js module.exports = { settings: { next: { rootDir: "/packages/my-app", }, }, rules: { "@next/next/no-html-link-for-pages": "error", }, }; ``` Further, this rule allows the use of globs, again aligning with `@typescript-eslint/parser`. ```js module.exports = { settings: { next: { // Globs rootDir: "/packages/*", rootDir: "/packages/{app-a,app-b}", // Arrays rootDir: ["/app-a", "/app-b"], // Arrays with globs rootDir: ["/main-app", "/other-apps/*"], }, }; ``` This enables users to either provide per-workspace configuration with overrides, or to use globs for situations like monorepos where the apps share a domain (micro-frontends). This doesn't solve, but improves https://github.com/vercel/next.js/issues/26330. ## Feature - [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [x] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [x] Make sure the linting passes
2021-08-11 12:37:55 +02:00
/** @type {(string|string[])[]} */
const ruleOptions = context.options
const [customPagesDirectory] = ruleOptions
const rootDirs = getRootDir(context)
const pagesDirs = (
customPagesDirectory
? [customPagesDirectory]
: rootDirs.map((dir) => [
path.join(dir, 'pages'),
path.join(dir, 'src', 'pages'),
])
Add rootDir setting to eslint-plugin-next (#27918) ## Introduction This PR enables setting a `rootDir` for a Next.js project, and follows the same pattern used by [`@typescript-eslint/parser`](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#parseroptionsproject). ## Details Previously, users had to pass paths to the rule itself. ```js module.exports = { rules: { "@next/next/no-html-link-for-pages": [ "error", // This could be a string, or array of strings. "/packages/my-app/pages", ], }, }; ``` With this PR, this has been simplified (the previous implementation still works as expected). ```js module.exports = { settings: { next: { rootDir: "/packages/my-app", }, }, rules: { "@next/next/no-html-link-for-pages": "error", }, }; ``` Further, this rule allows the use of globs, again aligning with `@typescript-eslint/parser`. ```js module.exports = { settings: { next: { // Globs rootDir: "/packages/*", rootDir: "/packages/{app-a,app-b}", // Arrays rootDir: ["/app-a", "/app-b"], // Arrays with globs rootDir: ["/main-app", "/other-apps/*"], }, }; ``` This enables users to either provide per-workspace configuration with overrides, or to use globs for situations like monorepos where the apps share a domain (micro-frontends). This doesn't solve, but improves https://github.com/vercel/next.js/issues/26330. ## Feature - [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [x] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [x] Make sure the linting passes
2021-08-11 12:37:55 +02:00
).flat()
const foundPagesDirs = pagesDirs.filter((dir) => {
if (fsExistsSyncCache[dir] === undefined) {
fsExistsSyncCache[dir] = fs.existsSync(dir)
}
return fsExistsSyncCache[dir]
})
if (foundPagesDirs.length === 0) {
Adds ESLint with default rule-set (#23702) 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
2021-04-30 13:09:07 +02:00
pagesDirWarning(pagesDirs)
return {}
}
const urls = getUrlFromPagesDirectories('/', foundPagesDirs)
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,
Adds ESLint with default rule-set (#23702) 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
2021-04-30 13:09:07 +02:00
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.`,
})
}
})
},
}
},
}