Skip to content

Commit 8fda55a

Browse files
authoredNov 19, 2024··
feat: Add suggestions to require-meta-docs-recommended rule (#500)
* Add suggestions to `require-meta-docs-recommended` rule * Update docs
1 parent e9c75eb commit 8fda55a

File tree

4 files changed

+175
-9
lines changed

4 files changed

+175
-9
lines changed
 

‎README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ module.exports = [
9898
| [prefer-replace-text](docs/rules/prefer-replace-text.md) | require using `replaceText()` instead of `replaceTextRange()` | | | | |
9999
| [report-message-format](docs/rules/report-message-format.md) | enforce a consistent format for rule report messages | | | | |
100100
| [require-meta-docs-description](docs/rules/require-meta-docs-description.md) | require rules to implement a `meta.docs.description` property with the correct format | | | | |
101-
| [require-meta-docs-recommended](docs/rules/require-meta-docs-recommended.md) | require rules to implement a `meta.docs.recommended` property | | | | |
101+
| [require-meta-docs-recommended](docs/rules/require-meta-docs-recommended.md) | require rules to implement a `meta.docs.recommended` property | | | 💡 | |
102102
| [require-meta-docs-url](docs/rules/require-meta-docs-url.md) | require rules to implement a `meta.docs.url` property | | 🔧 | | |
103103
| [require-meta-fixable](docs/rules/require-meta-fixable.md) | require rules to implement a `meta.fixable` property || | | |
104104
| [require-meta-has-suggestions](docs/rules/require-meta-has-suggestions.md) | require suggestable rules to implement a `meta.hasSuggestions` property || 🔧 | | |

‎docs/rules/require-meta-docs-recommended.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Require rules to implement a `meta.docs.recommended` property (`eslint-plugin/require-meta-docs-recommended`)
22

3+
💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
4+
35
<!-- end auto-generated rule header -->
46

57
Utilizing `meta.docs.recommended` makes it clear from each rule implementation whether a rule is part of the `recommended` config. Some plugins also have scripting for conveniently generating their config based on this flag.

‎lib/rules/require-meta-docs-recommended.js

+48
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,24 @@
33
const { getStaticValue } = require('@eslint-community/eslint-utils');
44
const utils = require('../utils');
55

6+
/**
7+
* @param {import('eslint').Rule.RuleFixer} fixer
8+
* @param {import('estree').ObjectExpression} objectNode
9+
* @param {boolean} recommendedValue
10+
*/
11+
function insertRecommendedProperty(fixer, objectNode, recommendedValue) {
12+
if (objectNode.properties.length === 0) {
13+
return fixer.replaceText(
14+
objectNode,
15+
`{ recommended: ${recommendedValue} }`,
16+
);
17+
}
18+
return fixer.insertTextAfter(
19+
objectNode.properties.at(-1),
20+
`, recommended: ${recommendedValue}`,
21+
);
22+
}
23+
624
/** @type {import('eslint').Rule.RuleModule} */
725
module.exports = {
826
meta: {
@@ -15,6 +33,7 @@ module.exports = {
1533
url: 'https://github.com/eslint-community/eslint-plugin-eslint-plugin/tree/HEAD/docs/rules/require-meta-docs-recommended.md',
1634
},
1735
fixable: null,
36+
hasSuggestions: true,
1837
schema: [
1938
{
2039
type: 'object',
@@ -31,6 +50,8 @@ module.exports = {
3150
messages: {
3251
incorrect: '`meta.docs.recommended` is required to be a boolean.',
3352
missing: '`meta.docs.recommended` is required.',
53+
setRecommendedTrue: 'Set `meta.docs.recommended` to `true`.',
54+
setRecommendedFalse: 'Set `meta.docs.recommended` to `false`.',
3455
},
3556
},
3657

@@ -49,9 +70,26 @@ module.exports = {
4970
} = utils.getMetaDocsProperty('recommended', ruleInfo, scopeManager);
5071

5172
if (!descriptionNode) {
73+
const suggestions =
74+
docsNode?.value?.type === 'ObjectExpression'
75+
? [
76+
{
77+
messageId: 'setRecommendedTrue',
78+
fix: (fixer) =>
79+
insertRecommendedProperty(fixer, docsNode.value, true),
80+
},
81+
{
82+
messageId: 'setRecommendedFalse',
83+
fix: (fixer) =>
84+
insertRecommendedProperty(fixer, docsNode.value, false),
85+
},
86+
]
87+
: [];
88+
5289
context.report({
5390
node: docsNode || metaNode || ruleInfo.create,
5491
messageId: 'missing',
92+
suggest: suggestions,
5593
});
5694
return {};
5795
}
@@ -68,6 +106,16 @@ module.exports = {
68106
context.report({
69107
node: descriptionNode.value,
70108
messageId: 'incorrect',
109+
suggest: [
110+
{
111+
messageId: 'setRecommendedTrue',
112+
fix: (fixer) => fixer.replaceText(descriptionNode.value, 'true'),
113+
},
114+
{
115+
messageId: 'setRecommendedFalse',
116+
fix: (fixer) => fixer.replaceText(descriptionNode.value, 'false'),
117+
},
118+
],
71119
});
72120
return {};
73121
}

‎tests/lib/rules/require-meta-docs-recommended.js

+124-8
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ ruleTester.run('require-meta-docs-recommended', rule, {
9090
{
9191
code: 'module.exports = { create(context) {} };',
9292
output: null,
93-
errors: [{ messageId: 'missing', type: 'FunctionExpression' }],
93+
errors: [
94+
{ messageId: 'missing', type: 'FunctionExpression', suggestions: [] },
95+
],
9496
},
9597
{
9698
code: `
@@ -100,7 +102,13 @@ ruleTester.run('require-meta-docs-recommended', rule, {
100102
};
101103
`,
102104
output: null,
103-
errors: [{ messageId: 'missing', type: 'ObjectExpression' }],
105+
errors: [
106+
{
107+
messageId: 'missing',
108+
type: 'ObjectExpression',
109+
suggestions: [],
110+
},
111+
],
104112
},
105113
{
106114
code: `
@@ -110,7 +118,32 @@ ruleTester.run('require-meta-docs-recommended', rule, {
110118
};
111119
`,
112120
output: null,
113-
errors: [{ messageId: 'missing', type: 'Property' }],
121+
errors: [
122+
{
123+
messageId: 'missing',
124+
type: 'Property',
125+
suggestions: [
126+
{
127+
messageId: 'setRecommendedTrue',
128+
output: `
129+
module.exports = {
130+
meta: { docs: { recommended: true } },
131+
create(context) {}
132+
};
133+
`,
134+
},
135+
{
136+
messageId: 'setRecommendedFalse',
137+
output: `
138+
module.exports = {
139+
meta: { docs: { recommended: false } },
140+
create(context) {}
141+
};
142+
`,
143+
},
144+
],
145+
},
146+
],
114147
},
115148
{
116149
code: `
@@ -120,7 +153,32 @@ ruleTester.run('require-meta-docs-recommended', rule, {
120153
};
121154
`,
122155
output: null,
123-
errors: [{ messageId: 'incorrect', type: 'Identifier' }],
156+
errors: [
157+
{
158+
messageId: 'incorrect',
159+
type: 'Identifier',
160+
suggestions: [
161+
{
162+
messageId: 'setRecommendedTrue',
163+
output: `
164+
module.exports = {
165+
meta: { docs: { recommended: true } },
166+
create(context) {}
167+
};
168+
`,
169+
},
170+
{
171+
messageId: 'setRecommendedFalse',
172+
output: `
173+
module.exports = {
174+
meta: { docs: { recommended: false } },
175+
create(context) {}
176+
};
177+
`,
178+
},
179+
],
180+
},
181+
],
124182
},
125183
{
126184
code: `
@@ -130,7 +188,32 @@ ruleTester.run('require-meta-docs-recommended', rule, {
130188
};
131189
`,
132190
output: null,
133-
errors: [{ messageId: 'incorrect', type: 'Literal' }],
191+
errors: [
192+
{
193+
messageId: 'incorrect',
194+
type: 'Literal',
195+
suggestions: [
196+
{
197+
messageId: 'setRecommendedTrue',
198+
output: `
199+
module.exports = {
200+
meta: { docs: { recommended: true } },
201+
create(context) {}
202+
};
203+
`,
204+
},
205+
{
206+
messageId: 'setRecommendedFalse',
207+
output: `
208+
module.exports = {
209+
meta: { docs: { recommended: false } },
210+
create(context) {}
211+
};
212+
`,
213+
},
214+
],
215+
},
216+
],
134217
},
135218
{
136219
code: `
@@ -142,13 +225,44 @@ ruleTester.run('require-meta-docs-recommended', rule, {
142225
};
143226
`,
144227
output: null,
145-
errors: [{ messageId: 'missing', type: 'Property' }],
228+
errors: [
229+
{
230+
messageId: 'missing',
231+
type: 'Property',
232+
suggestions: [
233+
{
234+
messageId: 'setRecommendedTrue',
235+
output: `
236+
const extraDocs = { };
237+
const extraMeta = { docs: { ...extraDocs, recommended: true } };
238+
module.exports = {
239+
meta: { ...extraMeta },
240+
create(context) {}
241+
};
242+
`,
243+
},
244+
{
245+
messageId: 'setRecommendedFalse',
246+
output: `
247+
const extraDocs = { };
248+
const extraMeta = { docs: { ...extraDocs, recommended: false } };
249+
module.exports = {
250+
meta: { ...extraMeta },
251+
create(context) {}
252+
};
253+
`,
254+
},
255+
],
256+
},
257+
],
146258
},
147259
{
148260
code: 'module.exports = { create(context) {} };',
149261
output: null,
150262
options: [{ allowNonBoolean: true }],
151-
errors: [{ messageId: 'missing', type: 'FunctionExpression' }],
263+
errors: [
264+
{ messageId: 'missing', type: 'FunctionExpression', suggestions: [] },
265+
],
152266
},
153267
],
154268
});
@@ -178,7 +292,9 @@ ruleTesterTypeScript.run('require-meta-docs-recommended (TypeScript)', rule, {
178292
});
179293
`,
180294
output: null,
181-
errors: [{ messageId: 'missing', type: 'ObjectExpression' }],
295+
errors: [
296+
{ messageId: 'missing', type: 'ObjectExpression', suggestions: [] },
297+
],
182298
},
183299
],
184300
});

0 commit comments

Comments
 (0)
Please sign in to comment.