Skip to content

Commit 7f625f4

Browse files
authored
New: Add rule prefer-object-rule (#101)
1 parent f50d3b8 commit 7f625f4

File tree

4 files changed

+233
-0
lines changed

4 files changed

+233
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ Name | ✔️ | 🛠 | Description
5858
[no-missing-placeholders](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/no-missing-placeholders.md) | ✔️ | | disallow missing placeholders in rule report messages
5959
[no-unused-placeholders](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/no-unused-placeholders.md) | ✔️ | | disallow unused placeholders in rule report messages
6060
[no-useless-token-range](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/no-useless-token-range.md) | ✔️ | 🛠 | disallow unnecessary calls to sourceCode.getFirstToken and sourceCode.getLastToken
61+
[prefer-object-rule](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/prefer-object-rule.md) | | 🛠 | disallow rule exports where the export is a function.
6162
[prefer-output-null](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/prefer-output-null.md) | | 🛠 | disallow invalid RuleTester test cases with the output the same as the code.
6263
[prefer-placeholders](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/prefer-placeholders.md) | | | disallow template literals as report messages
6364
[prefer-replace-text](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/prefer-replace-text.md) | | | require using replaceText instead of replaceTextRange.

docs/rules/prefer-object-rule.md

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Disallow rule exports where the export is a function. (prefer-object-rule)
2+
3+
(fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#fix) automatically fixes problems reported by this rule.
4+
5+
## Rule Details
6+
7+
The rule reports an error if it encounters a rule that's defined using the old style of just a `create` function.
8+
9+
Examples of **incorrect** code for this rule:
10+
11+
```js
12+
/* eslint eslint-plugin/prefer-object-rule: error */
13+
14+
module.exports = function (context) {
15+
return { Program() { context.report() } };
16+
};
17+
18+
module.exports = function create(context) {
19+
return { Program() { context.report() } };
20+
};
21+
22+
module.exports = (context) => {
23+
return { Program() { context.report() } };
24+
};
25+
```
26+
27+
Examples of **correct** code for this rule:
28+
29+
```js
30+
/* eslint eslint-plugin/prefer-object-rule: error */
31+
32+
module.exports = {
33+
create(context) {
34+
return { Program() { context.report() } };
35+
},
36+
};
37+
38+
module.exports = {
39+
create(context) {
40+
return { Program() { context.report() } };
41+
},
42+
};
43+
44+
module.exports = {
45+
create: (context) => {
46+
return { Program() { context.report() } };
47+
},
48+
};
49+
```

lib/rules/prefer-object-rule.js

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* @author Brad Zacher <https://github.com/bradzacher>
3+
*/
4+
5+
'use strict';
6+
7+
const utils = require('../utils');
8+
9+
// ------------------------------------------------------------------------------
10+
// Rule Definition
11+
// ------------------------------------------------------------------------------
12+
13+
module.exports = {
14+
meta: {
15+
docs: {
16+
description: 'disallow rule exports where the export is a function.',
17+
category: 'Rules',
18+
recommended: false,
19+
},
20+
messages: {
21+
preferObject: 'Rules should be declared using the object style.',
22+
},
23+
type: 'suggestion',
24+
fixable: 'code',
25+
schema: [],
26+
},
27+
28+
create (context) {
29+
// ----------------------------------------------------------------------
30+
// Public
31+
// ----------------------------------------------------------------------
32+
33+
const sourceCode = context.getSourceCode();
34+
const ruleInfo = utils.getRuleInfo(sourceCode.ast);
35+
36+
return {
37+
Program () {
38+
if (!ruleInfo || ruleInfo.isNewStyle) {
39+
return;
40+
}
41+
42+
context.report({
43+
node: ruleInfo.create,
44+
messageId: 'preferObject',
45+
*fix (fixer) {
46+
// note - we intentionally don't worry about formatting here, as otherwise we have
47+
// to indent the function correctly
48+
49+
if (ruleInfo.create.type === 'FunctionExpression') {
50+
const openParenToken = sourceCode.getFirstToken(
51+
ruleInfo.create,
52+
token => token.type === 'Punctuator' && token.value === '('
53+
);
54+
55+
if (!openParenToken) {
56+
// this shouldn't happen, but guarding against crashes just in case
57+
return null;
58+
}
59+
60+
yield fixer.replaceTextRange(
61+
[ruleInfo.create.range[0], openParenToken.range[0]],
62+
'{create'
63+
);
64+
yield fixer.insertTextAfter(ruleInfo.create, '}');
65+
} else if (ruleInfo.create.type === 'ArrowFunctionExpression') {
66+
yield fixer.insertTextBefore(ruleInfo.create, '{create: ');
67+
yield fixer.insertTextAfter(ruleInfo.create, '}');
68+
}
69+
},
70+
});
71+
},
72+
};
73+
},
74+
};

tests/lib/rules/prefer-object-rule.js

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* @author Brad Zacher <https://github.com/bradzacher>
3+
*/
4+
5+
'use strict';
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const rule = require('../../../lib/rules/prefer-object-rule');
12+
const RuleTester = require('eslint').RuleTester;
13+
14+
const ERROR = { messageId: 'preferObject', line: 2, column: 26 };
15+
16+
// ------------------------------------------------------------------------------
17+
// Tests
18+
// ------------------------------------------------------------------------------
19+
20+
const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
21+
ruleTester.run('prefer-object-rule', rule, {
22+
valid: [
23+
`
24+
module.exports = {
25+
create(context) {
26+
return { Program() { context.report() } };
27+
},
28+
};
29+
`,
30+
`
31+
module.exports = {
32+
create: (context) => {
33+
return { Program() { context.report() } };
34+
},
35+
};
36+
`,
37+
`
38+
module.exports.create = (context) => {
39+
return { Program() { context.report() } };
40+
};
41+
`,
42+
`
43+
module.exports.create = function (context) {
44+
return { Program() { context.report() } };
45+
};
46+
`,
47+
`
48+
module.exports.create = function create(context) {
49+
return { Program() { context.report() } };
50+
};
51+
`,
52+
`
53+
function create(context) {
54+
return { Program() { context.report() } };
55+
};
56+
module.exports.create = create;
57+
`,
58+
`
59+
const rule = {
60+
create(context) {
61+
return { Program() { context.report() } };
62+
},
63+
};
64+
module.exports = rule;
65+
`,
66+
],
67+
68+
invalid: [
69+
{
70+
code: `
71+
module.exports = function (context) {
72+
return { Program() { context.report() } };
73+
};
74+
`,
75+
output: `
76+
module.exports = {create(context) {
77+
return { Program() { context.report() } };
78+
}};
79+
`,
80+
errors: [ERROR],
81+
},
82+
{
83+
code: `
84+
module.exports = function create(context) {
85+
return { Program() { context.report() } };
86+
};
87+
`,
88+
output: `
89+
module.exports = {create(context) {
90+
return { Program() { context.report() } };
91+
}};
92+
`,
93+
errors: [ERROR],
94+
},
95+
{
96+
code: `
97+
module.exports = (context) => {
98+
return { Program() { context.report() } };
99+
};
100+
`,
101+
output: `
102+
module.exports = {create: (context) => {
103+
return { Program() { context.report() } };
104+
}};
105+
`,
106+
errors: [ERROR],
107+
},
108+
],
109+
});

0 commit comments

Comments
 (0)