Skip to content

Commit e0cf0d8

Browse files
bpmutternzakassnitin315sam3kmoniuch
authored
docs: Custom rule & plugin tutorial (#17024)
* Start copy edits * checkpoint * docs update * docs update * Add intro * Copy edits * remove old draft of tutorial * Fix take ii * update tutorial * Apply suggestions from code review Co-authored-by: Nicholas C. Zakas <nicholas@humanwhocodes.com> * update src code names * rename tutorial * update code examples to match updated code * additional fixes * implement additional NZ feedback * Apply suggestions from code review Co-authored-by: Nitin Kumar <snitin315@gmail.com> Co-authored-by: Samuel Roldan <sroldan24@gmail.com> Co-authored-by: moniuch <moniuch@gmail.com> * draft tutorial changes * copy edits * fix lint err * Apply suggestions from code review Co-authored-by: Nitin Kumar <snitin315@gmail.com> * add file overviews * copy edits on step 8 intro * Apply suggestions from code review Co-authored-by: Nicholas C. Zakas <nicholas@humanwhocodes.com> * implement NZ feedback * Apply suggestions from code review Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com> * Apply suggestions from code review Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com> * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review * update rule name to "enforce-foo-bar" * Apply suggestions from code review * implement MD feedback * Apply suggestions from code review Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com> * implement MD feedback * copy edit * Apply suggestions from code review Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com> * move tutorial to _examples dir * undo big change * Fix broken example * Apply suggestions from code review Co-authored-by: Nitin Kumar <snitin315@gmail.com> --------- Co-authored-by: Nicholas C. Zakas <nicholas@humanwhocodes.com> Co-authored-by: Nitin Kumar <snitin315@gmail.com> Co-authored-by: Samuel Roldan <sroldan24@gmail.com> Co-authored-by: moniuch <moniuch@gmail.com> Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
1 parent 8e51ea9 commit e0cf0d8

11 files changed

Lines changed: 652 additions & 2 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* @fileoverview Rule to enforce that `const foo` is assigned "bar".
3+
* @author Ben Perlmutter
4+
*/
5+
6+
"use strict";
7+
8+
// The enforce-foo-bar rule definition
9+
module.exports = {
10+
meta: {
11+
type: "problem",
12+
docs: {
13+
description: "Enforce that a variable named `foo` can only be assigned a value of 'bar'."
14+
},
15+
fixable: "code",
16+
schema: []
17+
},
18+
create(context) {
19+
return {
20+
21+
// Performs action in the function on every variable declarator
22+
VariableDeclarator(node) {
23+
24+
// Check if a `const` variable declaration
25+
if (node.parent.kind === "const") {
26+
27+
// Check if variable name is `foo`
28+
if (node.id.type === "Identifier" && node.id.name === "foo") {
29+
30+
// Check if value of variable is "bar"
31+
if (node.init && node.init.type === "Literal" && node.init.value !== "bar") {
32+
33+
/*
34+
* Report error to ESLint. Error message uses
35+
* a message placeholder to include the incorrect value
36+
* in the error message.
37+
* Also includes a `fix(fixer)` function that replaces
38+
* any values assigned to `const foo` with "bar".
39+
*/
40+
context.report({
41+
node,
42+
message: 'Value other than "bar" assigned to `const foo`. Unexpected value: {{ notBar }}.',
43+
data: {
44+
notBar: node.init.value
45+
},
46+
fix(fixer) {
47+
return fixer.replaceText(node.init, '"bar"');
48+
}
49+
});
50+
}
51+
}
52+
}
53+
}
54+
};
55+
}
56+
};
57+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* @fileoverview Tests for enforce-foo-bar.js rule.
3+
* @author Ben Perlmutter
4+
*/
5+
"use strict";
6+
7+
const {RuleTester} = require("eslint");
8+
const fooBarRule = require("./enforce-foo-bar");
9+
10+
const ruleTester = new RuleTester({
11+
// Must use at least ecmaVersion 2015 because
12+
// that's when `const` variable were introduced.
13+
parserOptions: { ecmaVersion: 2015 }
14+
});
15+
16+
// Throws error if the tests in ruleTester.run() do not pass
17+
ruleTester.run(
18+
"enforce-foo-bar", // rule name
19+
fooBarRule, // rule code
20+
{ // checks
21+
// 'valid' checks cases that should pass
22+
valid: [{
23+
code: "const foo = 'bar';",
24+
}],
25+
// 'invalid' checks cases that should not pass
26+
invalid: [{
27+
code: "const foo = 'baz';",
28+
output: 'const foo = "bar";',
29+
errors: 1,
30+
}],
31+
}
32+
);
33+
34+
console.log("All tests passed!");
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* @fileoverview Example an ESLint plugin with a custom rule.
3+
* @author Ben Perlmutter
4+
*/
5+
"use strict";
6+
7+
const fooBarRule = require("./enforce-foo-bar");
8+
const plugin = { rules: { "enforce-foo-bar": fooBarRule } };
9+
module.exports = plugin;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* @fileoverview Example ESLint config file that uses the custom rule from this tutorial.
3+
* @author Ben Perlmutter
4+
*/
5+
"use strict";
6+
7+
// Import the ESLint plugin
8+
const eslintPluginExample = require("./eslint-plugin-example");
9+
10+
module.exports = [
11+
{
12+
files: ["**/*.js"],
13+
languageOptions: {
14+
sourceType: "commonjs",
15+
ecmaVersion: "latest",
16+
},
17+
// Using the eslint-plugin-example plugin defined locally
18+
plugins: {"example": eslintPluginExample},
19+
rules: {
20+
"example/enforce-foo-bar": "error",
21+
},
22+
}
23+
]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* @fileoverview Example of a file that will fail the custom rule in this tutorial.
3+
* @author Ben Perlmutter
4+
*/
5+
"use strict";
6+
7+
/* eslint-disable no-unused-vars -- Disable other rule causing problem for this file */
8+
9+
// To see the error in the terminal, run the following command:
10+
// npx eslint example.js
11+
12+
// To fix the error, run the following command:
13+
// npx eslint example.js --fix
14+
15+
function correctFooBar() {
16+
const foo = "bar";
17+
}
18+
19+
function incorrectFoo(){
20+
const foo = "baz"; // Problem!
21+
}
22+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "eslint-plugin-example",
3+
"version": "1.0.0",
4+
"description": "ESLint plugin for enforce-foo-bar rule.",
5+
"main": "eslint-plugin-example.js",
6+
"keywords": [
7+
"eslint",
8+
"eslintplugin",
9+
"eslint-plugin"
10+
],
11+
"peerDependencies": {
12+
"eslint": ">=8.0.0"
13+
},
14+
"scripts": {
15+
"test": "node enforce-foo-bar.test.js"
16+
},
17+
"author": "",
18+
"license": "ISC",
19+
"devDependencies": {
20+
"eslint": "^8.36.0"
21+
}
22+
}

docs/src/extend/custom-processors.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ eleventyNavigation:
44
key: custom processors
55
parent: create plugins
66
title: Custom Processors
7-
order: 2
7+
order: 3
88

99
---
1010

0 commit comments

Comments
 (0)