diff --git a/docs/rules/consistent-function-scoping.md b/docs/rules/consistent-function-scoping.md index 45ab23fabe..3981a04317 100644 --- a/docs/rules/consistent-function-scoping.md +++ b/docs/rules/consistent-function-scoping.md @@ -71,3 +71,23 @@ function doFoo(FooComponent) { return Bar; }; ``` + +[Immediately invoked function expressions (IIFE)](https://en.wikipedia.org/wiki/Immediately_invoked_function_expression) are ignored: + +```js +(function () { + function doFoo(bar) { + return bar; + } +})(); +``` + +[Built-in Hooks in React](https://reactjs.org/docs/hooks-reference.html) are ignored: + +```js +useEffect(() => { + async function getItems() {} + + getItems(); +}, []) +``` diff --git a/rules/consistent-function-scoping.js b/rules/consistent-function-scoping.js index e68151d4be..864a430888 100644 --- a/rules/consistent-function-scoping.js +++ b/rules/consistent-function-scoping.js @@ -98,6 +98,15 @@ const isArrowFunctionWithThis = scope => scope.block.type === 'ArrowFunctionExpression' && (scope.thisFound || scope.childScopes.some(scope => isArrowFunctionWithThis(scope))); +const iifeFunctionTypes = new Set([ + 'FunctionExpression', + 'ArrowFunctionExpression' +]); +const isIife = node => node && + iifeFunctionTypes.has(node.type) && + node.parent && + node.parent.type === 'CallExpression'; + function checkNode(node, scopeManager) { const scope = scopeManager.acquire(node); @@ -126,7 +135,12 @@ function checkNode(node, scopeManager) { } const parentScope = scopeManager.acquire(parentNode); - if (!parentScope || parentScope.type === 'global' || isReactHook(parentScope)) { + if ( + !parentScope || + parentScope.type === 'global' || + isReactHook(parentScope) || + isIife(parentNode) + ) { return true; } diff --git a/test/consistent-function-scoping.js b/test/consistent-function-scoping.js index 043cc2e405..5cf0854945 100644 --- a/test/consistent-function-scoping.js +++ b/test/consistent-function-scoping.js @@ -226,6 +226,37 @@ ruleTester.run('consistent-function-scoping', rule, { function foo() {} }, []) `, + // IIEF + outdent` + (function() { + function bar() {} + })(); + `, + outdent` + (function() { + function bar() {} + }()); + `, + outdent` + !function() { + function bar() {} + }(); + `, + outdent` + (() => { + function bar() {} + })(); + `, + outdent` + (async function() { + function bar() {} + })(); + `, + outdent` + (async function * () { + function bar() {} + })(); + `, // #391 outdent` const enrichErrors = (packageName, cliArgs, f) => async (...args) => { @@ -472,6 +503,18 @@ ruleTester.run('consistent-function-scoping', rule, { }, []) `, errors: [createError({name: 'bar'})] + }, + // IIFE + { + code: outdent` + (function() { + function foo() { + function bar() { + } + } + })(); + `, + errors: [createError({name: 'bar'})] } ] });