Skip to content

Commit cd3467d

Browse files
Ethan Cohenbeefancohen
authored andcommitted
[new][dev] - Create script to easily scaffold new rules.
1 parent bd33c70 commit cd3467d

File tree

7 files changed

+864
-790
lines changed

7 files changed

+864
-790
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"lint": "eslint --config .eslintrc src tests",
2424
"lint:fix": "npm run lint -- --fix",
2525
"pretest": "npm run lint:fix",
26-
"test": "jest --coverage"
26+
"test": "jest --coverage",
27+
"create": "node ./scripts/create-rule"
2728
},
2829
"devDependencies": {
2930
"babel-cli": "^6.14.0",
@@ -37,6 +38,7 @@
3738
"eslint-config-airbnb-base": "^11.0.0",
3839
"eslint-plugin-import": "^2.2.0",
3940
"jest": "^18.1.0",
41+
"minimist": "^1.2.0",
4042
"rimraf": "^2.5.2",
4143
"to-ast": "^1.0.0"
4244
},

scripts/boilerplate/doc.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const docBoilerplateGenerator = name => `# ${name}
2+
3+
Write a useful explanation here!
4+
5+
#### References
6+
1.
7+
8+
## Rule details
9+
10+
This rule takes no arguments.
11+
12+
### Succeed
13+
\`\`\`jsx
14+
<div />
15+
\`\`\`
16+
17+
### Fail
18+
\`\`\`jsx
19+
20+
\`\`\`
21+
`;
22+
23+
module.exports = docBoilerplateGenerator;

scripts/boilerplate/rule.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const ruleBoilerplate = (author, description) => `/**
2+
* @fileoverview ${description}
3+
* @author ${author}
4+
*/
5+
6+
// ----------------------------------------------------------------------------
7+
// Rule Definition
8+
// ----------------------------------------------------------------------------
9+
10+
import { generateObjSchema } from '../util/schemas';
11+
12+
const errorMessage = '';
13+
14+
const schema = generateObjSchema();
15+
16+
module.exports = {
17+
meta: {
18+
docs: {},
19+
schema: [schema],
20+
},
21+
22+
create: context => ({
23+
JSXOpeningElement: (node) => {
24+
context.report({
25+
node,
26+
message: errorMessage,
27+
});
28+
},
29+
}),
30+
};
31+
`;
32+
33+
module.exports = ruleBoilerplate;

scripts/boilerplate/test.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const testBoilerplate = (name, author, description) => `/**
2+
* @fileoverview ${description}
3+
* @author ${author}
4+
*/
5+
6+
// -----------------------------------------------------------------------------
7+
// Requirements
8+
// -----------------------------------------------------------------------------
9+
10+
import { RuleTester } from 'eslint';
11+
import rule from '../../../src/rules/${name}';
12+
13+
const parserOptions = {
14+
ecmaVersion: 6,
15+
ecmaFeatures: {
16+
jsx: true,
17+
},
18+
};
19+
20+
// -----------------------------------------------------------------------------
21+
// Tests
22+
// -----------------------------------------------------------------------------
23+
24+
const ruleTester = new RuleTester();
25+
26+
const expectedError = {
27+
message: '',
28+
type: 'JSXOpeningElement',
29+
};
30+
31+
ruleTester.run('${name}', rule, {
32+
valid: [
33+
{ code: '<div />;', parserOptions },
34+
],
35+
invalid: [],
36+
});
37+
`;
38+
39+
module.exports = testBoilerplate;

scripts/create-rule.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const path = require('path');
2+
const fs = require('fs');
3+
const argv = require('minimist')(process.argv.slice(2)); // eslint-disable-line import/no-extraneous-dependencies
4+
const ruleBoilerplateGenerator = require('./boilerplate/rule');
5+
const testBoilerplateGenerator = require('./boilerplate/test');
6+
const docBoilerplateGenerator = require('./boilerplate/doc');
7+
8+
const ruleName = argv._[0];
9+
const author = argv.author || '$AUTHOR';
10+
const description = argv.description || '$DESCRIPTION';
11+
12+
const rulePath = path.resolve(`src/rules/${ruleName}.js`);
13+
const testPath = path.resolve(`__tests__/src/rules/${ruleName}-test.js`);
14+
const docsPath = path.resolve(`docs/rules/${ruleName}.md`);
15+
16+
// Validate
17+
if (!ruleName) {
18+
throw new Error('Rule name is required');
19+
} else if (fs.existsSync(rulePath)) {
20+
throw new Error('Rule already exists!');
21+
}
22+
23+
// Generate file boilerplate
24+
const ruleBoilerplate = ruleBoilerplateGenerator(author, description);
25+
const testBoilerplate = testBoilerplateGenerator(ruleName, author, description);
26+
const docBoilerplate = docBoilerplateGenerator(ruleName);
27+
28+
// Create new files
29+
fs.writeFileSync(rulePath, ruleBoilerplate);
30+
fs.writeFileSync(testPath, testBoilerplate);
31+
fs.writeFileSync(docsPath, docBoilerplate);

scripts/create-rule.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Rule Generator
2+
3+
```bash
4+
$ node scripts/create-rule.js rule-name --author="Your name" --description="Description of the rule"
5+
# OR with npm script alias
6+
$ npm run create -- rule-name --author="Your name" --description="Description of rule"
7+
```
8+
9+
This script will generate three files with basic boilerplate for the given rule:
10+
1. src/rules/${rule-name}.js
11+
2. \__tests__/src/rules/${rule-name}-test.js
12+
3. docs/rules/${rule-name}.md
13+
14+
If the rule already exists or is not specified in the correct format, an error will be thrown.
15+
16+
If we wanted to scaffold a rule for `no-marquee`, we could run:
17+
```bash
18+
$ node scripts/create-rule.js no-marquee --author="Ethan Cohen <@evcohen>" --description="Enforce <marquee> elements are not used."
19+
# OR
20+
$ npm run create -- no-marquee --author="Ethan Cohen <@evcohen>" --description="Enforce <marquee> elements are not used."
21+
```

0 commit comments

Comments
 (0)