Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: detect and fix broken links #16837

Merged
merged 14 commits into from Feb 28, 2023
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Expand Up @@ -33,6 +33,12 @@ jobs:
run: npm run lint:scss
- name: Lint Docs JS Files
run: node Makefile lintDocsJS
- name: Build Docs Website
working-directory: docs
run: npm run build
- name: Validate internal links
working-directory: docs
run: npm run lint:links

test_on_node:
name: Test
Expand Down
4 changes: 2 additions & 2 deletions conf/rule-type-list.json
Expand Up @@ -6,12 +6,12 @@
],
"deprecated": {
"name": "Deprecated",
"description": "These rules have been deprecated in accordance with the <a href=\"/docs/use/rule-deprecation\">deprecation policy</a>, and replaced by newer rules:",
"description": "These rules have been deprecated in accordance with the <a href=\"{{ '/use/rule-deprecation' | url }}\">deprecation policy</a>, and replaced by newer rules:",
"rules": []
},
"removed": {
"name": "Removed",
"description": "These rules from older versions of ESLint (before the <a href=\"/docs/use/rule-deprecation\">deprecation policy</a> existed) have been replaced by newer rules:",
"description": "These rules from older versions of ESLint (before the <a href=\"{{ '/use/rule-deprecation' | url }}\">deprecation policy</a> existed) have been replaced by newer rules:",
"rules": [
{ "removed": "generator-star", "replacedBy": ["generator-star-spacing"] },
{ "removed": "global-strict", "replacedBy": ["strict"] },
Expand Down
7 changes: 6 additions & 1 deletion docs/package.json
Expand Up @@ -19,6 +19,7 @@
"start": "npm-run-all build:sass build:postcss --parallel watch:*",
"build": "npm-run-all build:sass build:postcss build:eleventy images",
"lint:scss": "stylelint \"**/*.{scss,html}\"",
"lint:links": "cross-env NODE_OPTIONS=--max-old-space-size=4096 node tools/validate-links.js",
"lint:fix:scss": "npm run lint:scss -- --fix"
},
"devDependencies": {
Expand All @@ -27,15 +28,18 @@
"@11ty/eleventy-navigation": "^0.3.2",
"@11ty/eleventy-plugin-rss": "^1.1.1",
"@11ty/eleventy-plugin-syntaxhighlight": "^3.1.2",
"@munter/tap-render": "^0.2.0",
"@types/markdown-it": "^12.2.3",
"algoliasearch": "^4.12.1",
"autoprefixer": "^10.4.13",
"cross-env": "^7.0.3",
"cssnano": "^5.1.14",
"dom-parser": "^0.1.6",
"eleventy-plugin-nesting-toc": "^1.3.0",
"eleventy-plugin-page-assets": "^0.3.0",
"eleventy-plugin-reading-time": "^0.0.1",
"github-slugger": "^1.5.0",
"hyperlink": "^5.0.4",
"imagemin": "^8.0.1",
"imagemin-cli": "^7.0.0",
"js-yaml": "^3.14.1",
Expand All @@ -53,7 +57,8 @@
"stylelint": "^14.13.0",
"stylelint-config-html": "^1.1.0",
"stylelint-config-standard": "^29.0.0",
"stylelint-config-standard-scss": "^5.0.0"
"stylelint-config-standard-scss": "^5.0.0",
"tap-spot": "^1.1.2"
},
"engines": {
"node": ">=14.0.0"
Expand Down
4 changes: 2 additions & 2 deletions docs/src/_data/rules.json
Expand Up @@ -1893,7 +1893,7 @@
],
"deprecated": {
"name": "Deprecated",
"description": "These rules have been deprecated in accordance with the <a href=\"/docs/use/rule-deprecation\">deprecation policy</a>, and replaced by newer rules:",
"description": "These rules have been deprecated in accordance with the <a href=\"{{ '/use/rule-deprecation' | url }}\">deprecation policy</a>, and replaced by newer rules:",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is autogenerated during releases, so we should also update the template:

https://github.com/eslint/eslint/blob/main/conf/rule-type-list.json

Otherwise, next release will overwrite these changes. You can run node Makefile.js generateRuleIndexPage to verify.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the catch, fixed in 946173f

"rules": [
{
"name": "callback-return",
Expand Down Expand Up @@ -2009,7 +2009,7 @@
},
"removed": {
"name": "Removed",
"description": "These rules from older versions of ESLint (before the <a href=\"/docs/use/rule-deprecation\">deprecation policy</a> existed) have been replaced by newer rules:",
"description": "These rules from older versions of ESLint (before the <a href=\"{{ '/use/rule-deprecation' | url }}\">deprecation policy</a> existed) have been replaced by newer rules:",
"rules": [
{
"removed": "generator-star",
Expand Down
2 changes: 1 addition & 1 deletion docs/src/extend/custom-rules-deprecated.md
Expand Up @@ -37,7 +37,7 @@ module.exports.schema = []; // no options

## Rule Basics

`schema` (array) specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../use/configure/rules#configuring-rules)
`schema` (array) specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../use/configure/rules)

`create` (function) returns an object with methods that ESLint calls to "visit" nodes while traversing the abstract syntax tree (AST as defined by [ESTree](https://github.com/estree/estree)) of JavaScript code:

Expand Down
4 changes: 2 additions & 2 deletions docs/src/extend/custom-rules.md
Expand Up @@ -61,7 +61,7 @@ The source file for a rule exports an object with the following properties.

**Important:** the `hasSuggestions` property is mandatory for rules that provide suggestions. If this property isn't set to `true`, ESLint will throw an error whenever the rule attempts to produce a suggestion. Omit the `hasSuggestions` property if the rule does not provide suggestions.

* `schema` (array) specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../use/configure/rules#configuring-rules)
* `schema` (array) specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../use/configure/rules)

* `deprecated` (boolean) indicates whether the rule has been deprecated. You may omit the `deprecated` property if the rule has not been deprecated.

Expand Down Expand Up @@ -110,7 +110,7 @@ The `context` object contains additional functionality that is helpful for rules

* `parserOptions` - the parser options configured for this run (more details [here](../use/configure/language-options#specifying-parser-options)).
* `id` - the rule ID.
* `options` - an array of the [configured options](../use/configure/rules#configuring-rules) for this rule. This array does not include the rule severity. For more information, see [here](#contextoptions).
* `options` - an array of the [configured options](../use/configure/rules) for this rule. This array does not include the rule severity. For more information, see [here](#contextoptions).
* `settings` - the [shared settings](../use/configure/configuration-files#adding-shared-settings) from configuration.
* `parserPath` - the name of the `parser` from configuration.
* `parserServices` - an object containing parser-provided services for rules. The default parser does not provide any services. However, if a rule is intended to be used with a custom parser, it could use `parserServices` to access anything provided by that parser. (For example, a TypeScript parser could provide the ability to get the computed type of a given node.)
Expand Down
2 changes: 1 addition & 1 deletion docs/src/use/configure/index.md
Expand Up @@ -42,7 +42,7 @@ All of these options give you fine-grained control over how ESLint treats your c

[**Configure Rules**](rules)

* [Configuring Rules](./rules#configuring-rules)
* [Configuring Rules](./rules)
* [Disabling Rules](./rules#disabling-rules)

[**Configure Plugins**](plugins)
Expand Down
49 changes: 49 additions & 0 deletions docs/tools/validate-links.js
@@ -0,0 +1,49 @@
const path = require("path");
const TapRender = require("@munter/tap-render");
const spot = require("tap-spot");
const hyperlink = require("hyperlink");

const tapRenderInstance = new TapRender();

tapRenderInstance.pipe(spot()).pipe(process.stdout);

const skipPatterns = [
"https://",
"fragment-redirect",
"migrating-to",
"/blog",
"/play",
"/team",
"/donate",
"/docs/latest",
`src="null"`,
];

const skipFilter = (report) =>
Object.values(report).some((value) =>
skipPatterns.some((pattern) => String(value).includes(pattern))
);

(async () => {
try {
await hyperlink(
{
inputUrls: ["../_site/index.html"],
root: path.resolve(__dirname, "../_site"),
canonicalRoot: "https://eslint.org/docs/head/",
recursive: true,
internalOnly: true,
pretty: true,
concurrency: 25,
skipFilter,
},
tapRenderInstance
);
} catch (err) {
console.log(err.stack);
process.exit(1);
}
const results = tapRenderInstance.close();

process.exit(results.fail ? 1 : 0);
})();