Skip to content

Commit daa6039

Browse files
committed
Fix: Only consider functions with a single argument as function-style rules
1 parent 1bd45d9 commit daa6039

File tree

4 files changed

+72
-41
lines changed

4 files changed

+72
-41
lines changed

lib/utils.js

+17-4
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,19 @@ function hasObjectReturn (node) {
121121
return foundMatch;
122122
}
123123

124+
/**
125+
* Determine if the given node is likely to be a function-style rule.
126+
* @param {*} node
127+
* @returns {boolean}
128+
*/
129+
function isFunctionRule (node) {
130+
return (
131+
isNormalFunctionExpression(node) && // Is a function definition.
132+
node.params.length === 1 && // The function has a single `context` argument.
133+
hasObjectReturn(node) // Returns an object containing the visitor functions.
134+
);
135+
}
136+
124137
/**
125138
* Helper for `getRuleInfo`. Handles ESM and TypeScript rules.
126139
*/
@@ -133,8 +146,8 @@ function getRuleExportsESM (ast) {
133146
if (node.type === 'ObjectExpression') {
134147
// Check `export default { create() {}, meta: {} }`
135148
return collectInterestingProperties(node.properties, INTERESTING_RULE_KEYS);
136-
} else if (isNormalFunctionExpression(node) && hasObjectReturn(node)) {
137-
// Check `export default function() { return { ... }; }`
149+
} else if (isFunctionRule(node)) {
150+
// Check `export default function(context) { return { ... }; }`
138151
return { create: node, meta: null, isNewStyle: false };
139152
} else if (
140153
node.type === 'CallExpression' &&
@@ -175,8 +188,8 @@ function getRuleExportsCJS (ast) {
175188
node.left.property.type === 'Identifier' && node.left.property.name === 'exports'
176189
) {
177190
exportsVarOverridden = true;
178-
if (isNormalFunctionExpression(node.right) && hasObjectReturn(node.right)) {
179-
// Check `module.exports = function () { return {}; }`
191+
if (isFunctionRule(node.right)) {
192+
// Check `module.exports = function (context) { return { ... }; }`
180193

181194
exportsIsFunction = true;
182195
return { create: node.right, meta: null, isNewStyle: false };

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,14 @@ ruleTester.run('prefer-object-rule', rule, {
132132
errors: [{ messageId: 'preferObject', line: 2, column: 24 }],
133133
},
134134
{
135-
code: 'export default function create() { return {}; };',
136-
output: 'export default {create() { return {}; }};',
135+
code: 'export default function create(context) { return {}; };',
136+
output: 'export default {create(context) { return {}; }};',
137137
parserOptions: { sourceType: 'module' },
138138
errors: [{ messageId: 'preferObject', line: 1, column: 16 }],
139139
},
140140
{
141-
code: 'export default () => { return {}; };',
142-
output: 'export default {create: () => { return {}; }};',
141+
code: 'export default (context) => { return {}; };',
142+
output: 'export default {create: (context) => { return {}; }};',
143143
parserOptions: { sourceType: 'module' },
144144
errors: [{ messageId: 'preferObject', line: 1, column: 16 }],
145145
},

tests/lib/rules/require-meta-docs-url.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ tester.run('require-meta-docs-url', rule, {
125125
invalid: [
126126
{
127127
code: `
128-
module.exports = function() { return {}; }
128+
module.exports = function(context) { return {}; }
129129
`,
130130
output: null,
131131
errors: [{ messageId: 'missing', type: 'FunctionExpression' }],
@@ -310,7 +310,7 @@ tester.run('require-meta-docs-url', rule, {
310310
// -------------------------------------------------------------------------
311311
{
312312
code: `
313-
module.exports = function() { return {}; }
313+
module.exports = function(context) { return {}; }
314314
`,
315315
output: null,
316316
options: [{
@@ -492,7 +492,7 @@ tester.run('require-meta-docs-url', rule, {
492492
{
493493
filename: 'test.js',
494494
code: `
495-
module.exports = function() { return {}; }
495+
module.exports = function(context) { return {}; }
496496
`,
497497
output: null,
498498
options: [{

tests/lib/utils.js

+48-30
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ describe('utils', () => {
1616
'',
1717
'module.exports;',
1818
'module.exports = foo;',
19-
'module.boop = function() { return {};};',
20-
'exports = function() { return {};};',
21-
'module.exports = function* () { return {}; };',
22-
'module.exports = async function () { return {};};',
19+
'module.boop = function(context) { return {};};',
20+
'exports = function(context) { return {};};',
21+
'module.exports = function* (context) { return {}; };',
22+
'module.exports = async function (context) { return {};};',
2323
'module.exports = {};',
2424
'module.exports = { meta: {} }',
2525
'module.exports = { create: {} }',
@@ -28,14 +28,18 @@ describe('utils', () => {
2828
'module.exports = { create: async function foo() {} }',
2929

3030
// Function-style rule but missing object return.
31-
'module.exports = () => { }',
32-
'module.exports = () => { return; }',
33-
'module.exports = () => { return 123; }',
34-
'module.exports = () => { return FOO; }',
35-
'module.exports = function foo() { }',
36-
'module.exports = () => { }',
37-
'exports.meta = {}; module.exports = () => { }',
38-
'module.exports = () => { }; module.exports.meta = {};',
31+
'module.exports = (context) => { }',
32+
'module.exports = (context) => { return; }',
33+
'module.exports = (context) => { return 123; }',
34+
'module.exports = (context) => { return FOO; }',
35+
'module.exports = function foo(context) { }',
36+
'module.exports = (context) => { }',
37+
'exports.meta = {}; module.exports = (context) => { }',
38+
'module.exports = (context) => { }; module.exports.meta = {};',
39+
40+
// Function-style rule but missing context parameter.
41+
'module.exports = () => { return {}; }',
42+
'module.exports = (foo, bar) => { return {}; }',
3943

4044
// Correct TypeScript helper structure but we don't support CJS for TypeScript rules:
4145
'module.exports = createESLintRule({ create() {}, meta: {} });',
@@ -57,13 +61,17 @@ describe('utils', () => {
5761
'const foo = {}; export default foo',
5862

5963
// Exports function but not default export.
60-
'export function foo () { return {}; }',
64+
'export function foo (context) { return {}; }',
6165

6266
// Exports function but no object return inside function.
63-
'export default function () { }',
64-
'export default function () { return; }',
65-
'export default function () { return 123; }',
66-
'export default function () { return FOO; }',
67+
'export default function (context) { }',
68+
'export default function (context) { return; }',
69+
'export default function (context) { return 123; }',
70+
'export default function (context) { return FOO; }',
71+
72+
// Function-style rule but missing context parameter.
73+
'export default function () { return {}; }',
74+
'export default function (foo, bar) { return {}; }',
6775

6876
// Incorrect TypeScript helper structure:
6977
'export default foo()({ create() {}, meta: {} });',
@@ -185,7 +193,7 @@ describe('utils', () => {
185193
meta: { type: 'ObjectExpression' },
186194
isNewStyle: true,
187195
},
188-
'module.exports.create = function foo() {}; module.exports.meta = {}': {
196+
'module.exports.create = function foo(context) {}; module.exports.meta = {}': {
189197
create: { type: 'FunctionExpression', id: { name: 'foo' } },
190198
meta: { type: 'ObjectExpression' },
191199
isNewStyle: true,
@@ -220,32 +228,42 @@ describe('utils', () => {
220228
meta: { type: 'ObjectExpression' },
221229
isNewStyle: true,
222230
},
223-
'module.exports = { create: () => { } }; exports.meta = {};': {
231+
'module.exports = { create: (context) => { } }; exports.meta = {};': {
224232
create: { type: 'ArrowFunctionExpression' },
225233
meta: null,
226234
isNewStyle: true,
227235
},
228-
'module.exports = function foo() { return {}; }': {
236+
'module.exports = function foo(context) { return {}; }': {
237+
create: { type: 'FunctionExpression', id: { name: 'foo' } },
238+
meta: null,
239+
isNewStyle: false,
240+
},
241+
'module.exports = function foo(slightlyDifferentContextName) { return {}; }': {
242+
create: { type: 'FunctionExpression', id: { name: 'foo' } },
243+
meta: null,
244+
isNewStyle: false,
245+
},
246+
'module.exports = function foo({ report }) { return {}; }': {
229247
create: { type: 'FunctionExpression', id: { name: 'foo' } },
230248
meta: null,
231249
isNewStyle: false,
232250
},
233-
'module.exports = () => { return {}; }': {
251+
'module.exports = (context) => { return {}; }': {
234252
create: { type: 'ArrowFunctionExpression' },
235253
meta: null,
236254
isNewStyle: false,
237255
},
238-
'module.exports = () => { if (foo) { return {}; } }': {
256+
'module.exports = (context) => { if (foo) { return {}; } }': {
239257
create: { type: 'ArrowFunctionExpression' },
240258
meta: null,
241259
isNewStyle: false,
242260
},
243-
'exports.meta = {}; module.exports = () => { return {}; }': {
261+
'exports.meta = {}; module.exports = (context) => { return {}; }': {
244262
create: { type: 'ArrowFunctionExpression' },
245263
meta: null,
246264
isNewStyle: false,
247265
},
248-
'module.exports = () => { return {}; }; module.exports.meta = {};': {
266+
'module.exports = (context) => { return {}; }; module.exports.meta = {};': {
249267
create: { type: 'ArrowFunctionExpression' },
250268
meta: null,
251269
isNewStyle: false,
@@ -279,17 +297,17 @@ describe('utils', () => {
279297
},
280298

281299
// ESM (function style)
282-
'export default function () { return {}; }': {
300+
'export default function (context) { return {}; }': {
283301
create: { type: 'FunctionDeclaration' },
284302
meta: null,
285303
isNewStyle: false,
286304
},
287-
'export default function () { if (foo) { return {}; } }': {
305+
'export default function (context) { if (foo) { return {}; } }': {
288306
create: { type: 'FunctionDeclaration' },
289307
meta: null,
290308
isNewStyle: false,
291309
},
292-
'export default () => { return {}; }': {
310+
'export default (context) => { return {}; }': {
293311
create: { type: 'ArrowFunctionExpression' },
294312
meta: null,
295313
isNewStyle: false,
@@ -315,7 +333,7 @@ describe('utils', () => {
315333
{ ignoreEval: true, ecmaVersion: 6, sourceType: 'module' },
316334
]) {
317335
const ast = espree.parse(`
318-
const create = () => {};
336+
const create = (context) => {};
319337
const meta = {};
320338
module.exports = { create, meta };
321339
`, { ecmaVersion: 6 });
@@ -338,7 +356,7 @@ describe('utils', () => {
338356
describe('the file has newer syntax', () => {
339357
const CASES = [
340358
{
341-
source: 'module.exports = function() { class Foo { @someDecorator() someProp }; return {}; };',
359+
source: 'module.exports = function(context) { class Foo { @someDecorator() someProp }; return {}; };',
342360
options: { sourceType: 'script' },
343361
expected: {
344362
create: { type: 'FunctionExpression' },
@@ -347,7 +365,7 @@ describe('utils', () => {
347365
},
348366
},
349367
{
350-
source: 'export default function() { class Foo { @someDecorator() someProp }; return {}; };',
368+
source: 'export default function(context) { class Foo { @someDecorator() someProp }; return {}; };',
351369
options: { sourceType: 'module' },
352370
expected: {
353371
create: { type: 'FunctionDeclaration' },

0 commit comments

Comments
 (0)