Skip to content

Commit 5239d69

Browse files
committed
Fix: Reduce false positives by only detecting ESM function-style rules when function returns an object
1 parent f8a642a commit 5239d69

File tree

3 files changed

+38
-6
lines changed

3 files changed

+38
-6
lines changed

lib/utils.js

+20-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
const { getStaticValue } = require('eslint-utils');
4+
const estraverse = require('estraverse');
45

56
/**
67
* Determines whether a node is a 'normal' (i.e. non-async, non-generator) function expression.
@@ -102,6 +103,23 @@ function collectInterestingProperties (properties, interestingKeys) {
102103
}, {});
103104
}
104105

106+
/**
107+
* Check if there is a return statement that returns an object somewhere inside the given node.
108+
* @param {Node} node
109+
* @returns {boolean}
110+
*/
111+
function hasObjectReturn (node) {
112+
let foundMatch = false;
113+
estraverse.traverse(node, {
114+
enter (child) {
115+
if (child.type === 'ReturnStatement' && child.argument && child.argument.type === 'ObjectExpression') {
116+
foundMatch = true;
117+
}
118+
},
119+
});
120+
return foundMatch;
121+
}
122+
105123
/**
106124
* Helper for `getRuleInfo`. Handles ESM and TypeScript rules.
107125
*/
@@ -114,8 +132,8 @@ function getRuleExportsESM (ast) {
114132
if (node.type === 'ObjectExpression') {
115133
// Check `export default { create() {}, meta: {} }`
116134
return collectInterestingProperties(node.properties, INTERESTING_RULE_KEYS);
117-
} else if (isNormalFunctionExpression(node)) {
118-
// Check `export default function() {}`
135+
} else if (isNormalFunctionExpression(node) && hasObjectReturn(node)) {
136+
// Check `export default function() { return { ... }; }`
119137
return { create: node, meta: null, isNewStyle: false };
120138
} else if (
121139
node.type === 'CallExpression' &&

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
},
3131
"homepage": "https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin#readme",
3232
"dependencies": {
33-
"eslint-utils": "^3.0.0"
33+
"eslint-utils": "^3.0.0",
34+
"estraverse": "^5.2.0"
3435
},
3536
"nyc": {
3637
"branches": 98,
@@ -51,7 +52,6 @@
5152
"eslint-plugin-unicorn": "^37.0.0",
5253
"eslint-scope": "^6.0.0",
5354
"espree": "^9.0.0",
54-
"estraverse": "^5.0.0",
5555
"lodash": "^4.17.2",
5656
"markdownlint-cli": "^0.28.1",
5757
"mocha": "^9.1.2",

tests/lib/utils.js

+16-2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ describe('utils', () => {
4646
'export default { foo: {} }',
4747
'const foo = {}; export default foo',
4848

49+
// Exports function but not default export.
50+
'export function foo () { return {}; }',
51+
52+
// Exports function but no object return inside function.
53+
'export default function () { }',
54+
'export default function () { return; }',
55+
'export default function () { return 123; }',
56+
'export default function () { return FOO; }',
57+
4958
// Incorrect TypeScript helper structure:
5059
'export default foo()({ create() {}, meta: {} });',
5160
'export default foo().bar({ create() {}, meta: {} });',
@@ -255,12 +264,17 @@ describe('utils', () => {
255264
},
256265

257266
// ESM (function style)
258-
'export default function () {}': {
267+
'export default function () { return {}; }': {
268+
create: { type: 'FunctionDeclaration' },
269+
meta: null,
270+
isNewStyle: false,
271+
},
272+
'export default function () { if (foo) { return {}; } }': {
259273
create: { type: 'FunctionDeclaration' },
260274
meta: null,
261275
isNewStyle: false,
262276
},
263-
'export default () => {}': {
277+
'export default () => { return {}; }': {
264278
create: { type: 'ArrowFunctionExpression' },
265279
meta: null,
266280
isNewStyle: false,

0 commit comments

Comments
 (0)