Skip to content

Commit

Permalink
docs: detect and fix broken links (#16837)
Browse files Browse the repository at this point in the history
* docs: detect and fix broken links

* ci: build website before running lint:links

* chore: update lint:links script

* ci: refactor job

* ci: increase memory

* ci: fix

* chore: use custom script

* chore: fix script for windows

* chore: fix script for windows

* chore: update script

* ci: remove unwanted changes

* chore: fix script

* chore: remove unwanted changes

* docs: fix links
  • Loading branch information
snitin315 committed Feb 28, 2023
1 parent 92c1943 commit b09a512
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 9 deletions.
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:",
"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);
})();

0 comments on commit b09a512

Please sign in to comment.