From 18b29acfcc8fce0d6bfa1ac3c1f47eb02d48611f Mon Sep 17 00:00:00 2001 From: Chiawen Chen Date: Sat, 31 Aug 2019 17:27:34 +0800 Subject: [PATCH 1/4] Breaking: check unnamed default export in func-names (fixes #12194) --- docs/rules/func-names.md | 8 +++++ lib/rules/func-names.js | 53 +++++++++++++++------------- tests/lib/rules/func-names.js | 65 ++++++++++++++++++++++++++++++----- 3 files changed, 95 insertions(+), 31 deletions(-) diff --git a/docs/rules/func-names.md b/docs/rules/func-names.md index b051d9b9bef..ec6816a774a 100644 --- a/docs/rules/func-names.md +++ b/docs/rules/func-names.md @@ -45,6 +45,8 @@ const cat = { (function() { // ... }()) + +export default function() {} ``` Examples of **correct** code for this rule with the default `"always"` option: @@ -61,6 +63,8 @@ const cat = { (function bar() { // ... }()) + +export default function foo() {} ``` ### as-needed @@ -77,6 +81,8 @@ Foo.prototype.bar = function() {}; (function() { // ... }()) + +export default function() {} ``` Examples of **correct** code for this rule with the `"as-needed"` option: @@ -93,6 +99,8 @@ const cat = { (function bar() { // ... }()) + +export default function foo() {} ``` ### never diff --git a/lib/rules/func-names.js b/lib/rules/func-names.js index 1341d036308..4416dd35e6e 100644 --- a/lib/rules/func-names.js +++ b/lib/rules/func-names.js @@ -119,7 +119,6 @@ module.exports = { (parent.type === "VariableDeclarator" && parent.id.type === "Identifier" && parent.init === node) || (parent.type === "Property" && parent.value === node) || (parent.type === "AssignmentExpression" && parent.left.type === "Identifier" && parent.right === node) || - (parent.type === "ExportDefaultDeclaration" && parent.declaration === node) || (parent.type === "AssignmentPattern" && parent.right === node); } @@ -151,33 +150,41 @@ module.exports = { }); } - return { - "FunctionExpression:exit"(node) { + /** + * The listener for function nodes. + * @param {ASTNode} node function node + * @returns {void} + */ + function handleFunction(node) { - // Skip recursive functions. - const nameVar = context.getDeclaredVariables(node)[0]; + // Skip recursive functions. + const nameVar = context.getDeclaredVariables(node)[0]; - if (isFunctionName(nameVar) && nameVar.references.length > 0) { - return; - } + if (isFunctionName(nameVar) && nameVar.references.length > 0) { + return; + } - const hasName = Boolean(node.id && node.id.name); - const config = getConfigForNode(node); - - if (config === "never") { - if (hasName) { - reportUnexpectedNamedFunction(node); - } - } else if (config === "as-needed") { - if (!hasName && !hasInferredName(node)) { - reportUnexpectedUnnamedFunction(node); - } - } else { - if (!hasName && !isObjectOrClassMethod(node)) { - reportUnexpectedUnnamedFunction(node); - } + const hasName = Boolean(node.id && node.id.name); + const config = getConfigForNode(node); + + if (config === "never") { + if (hasName && node.type !== "FunctionDeclaration") { + reportUnexpectedNamedFunction(node); + } + } else if (config === "as-needed") { + if (!hasName && !hasInferredName(node)) { + reportUnexpectedUnnamedFunction(node); + } + } else { + if (!hasName && !isObjectOrClassMethod(node)) { + reportUnexpectedUnnamedFunction(node); } } + } + + return { + "FunctionExpression:exit": handleFunction, + "ExportDefaultDeclaration > FunctionDeclaration": handleFunction }; } }; diff --git a/tests/lib/rules/func-names.js b/tests/lib/rules/func-names.js index 1976d565c17..94a5e335118 100644 --- a/tests/lib/rules/func-names.js +++ b/tests/lib/rules/func-names.js @@ -64,14 +64,6 @@ ruleTester.run("func-names", rule, { code: "(foo = function(){});", options: ["as-needed"] }, - { - code: "export default (function(){});", - options: ["as-needed"], - parserOptions: { - ecmaVersion: 6, - sourceType: "module" - } - }, { code: "({foo = function(){}} = {});", options: ["as-needed"], @@ -127,6 +119,28 @@ ruleTester.run("func-names", rule, { parserOptions: { ecmaVersion: 6 } }, + // export default + { + code: "export default function foo() {}", + options: ["always"], + parserOptions: { sourceType: "module", ecmaVersion: 6 } + }, + { + code: "export default function foo() {}", + options: ["as-needed"], + parserOptions: { sourceType: "module", ecmaVersion: 6 } + }, + { + code: "export default function foo() {}", + options: ["never"], + parserOptions: { sourceType: "module", ecmaVersion: 6 } + }, + { + code: "export default function() {}", + options: ["never"], + parserOptions: { sourceType: "module", ecmaVersion: 6 } + }, + // generators { code: "var foo = bar(function *baz() {});", @@ -415,6 +429,41 @@ ruleTester.run("func-names", rule, { }] }, + // export default + { + code: "export default function() {}", + options: ["always"], + parserOptions: { sourceType: "module", ecmaVersion: 6 }, + errors: [{ + messageId: "unnamed", + type: "FunctionDeclaration", + column: 16, + endColumn: 24 + }] + }, + { + code: "export default function() {}", + options: ["as-needed"], + parserOptions: { sourceType: "module", ecmaVersion: 6 }, + errors: [{ + messageId: "unnamed", + type: "FunctionDeclaration", + column: 16, + endColumn: 24 + }] + }, + { + code: "export default (function(){});", + options: ["as-needed"], + parserOptions: { sourceType: "module", ecmaVersion: 6 }, + errors: [{ + messageId: "unnamed", + type: "FunctionExpression", + column: 17, + endColumn: 25 + }] + }, + // generators { code: "var foo = bar(function *() {});", From 036ce5335f65a34bcadd54e8b2457daaca964eb0 Mon Sep 17 00:00:00 2001 From: Chiawen Chen Date: Mon, 17 Feb 2020 08:41:27 +0800 Subject: [PATCH 2/4] docs: add that default export functions are checked --- docs/rules/func-names.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rules/func-names.md b/docs/rules/func-names.md index ec6816a774a..3d52b3dabe3 100644 --- a/docs/rules/func-names.md +++ b/docs/rules/func-names.md @@ -16,8 +16,8 @@ This rule can enforce or disallow the use of named function expressions. This rule has a string option: -* `"always"` (default) requires function expressions to have a name -* `"as-needed"` requires function expressions to have a name, if the name cannot be assigned automatically in an ES6 environment +* `"always"` (default) requires function expressions and default export functions to have a name +* `"as-needed"` requires function expressions and default export functions to have a name, if the name cannot be assigned automatically in an ES6 environment * `"never"` disallows named function expressions, except in recursive functions, where a name is needed This rule has an object option: From e03ba83411963307c1f1e769db16d4ad586e04e6 Mon Sep 17 00:00:00 2001 From: Chiawen Chen Date: Mon, 17 Feb 2020 10:10:34 +0800 Subject: [PATCH 3/4] Revert "docs: add that default export functions are checked" This reverts commit 036ce5335f65a34bcadd54e8b2457daaca964eb0. --- docs/rules/func-names.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rules/func-names.md b/docs/rules/func-names.md index 3d52b3dabe3..ec6816a774a 100644 --- a/docs/rules/func-names.md +++ b/docs/rules/func-names.md @@ -16,8 +16,8 @@ This rule can enforce or disallow the use of named function expressions. This rule has a string option: -* `"always"` (default) requires function expressions and default export functions to have a name -* `"as-needed"` requires function expressions and default export functions to have a name, if the name cannot be assigned automatically in an ES6 environment +* `"always"` (default) requires function expressions to have a name +* `"as-needed"` requires function expressions to have a name, if the name cannot be assigned automatically in an ES6 environment * `"never"` disallows named function expressions, except in recursive functions, where a name is needed This rule has an object option: From 2421ed9a865f78cf2254908e23adc27ec36a5406 Mon Sep 17 00:00:00 2001 From: Chiawen Chen Date: Mon, 17 Feb 2020 10:11:10 +0800 Subject: [PATCH 4/4] docs: add a note that export default functions needs name --- docs/rules/func-names.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/rules/func-names.md b/docs/rules/func-names.md index ec6816a774a..27b9cc20fcf 100644 --- a/docs/rules/func-names.md +++ b/docs/rules/func-names.md @@ -29,6 +29,8 @@ This rule has an object option: When a value for `generators` is not provided the behavior for generator functions falls back to the base option. +Please note that `"always"` and `"as-needed"` require function expressions and function declarations in `export default` declarations to have a name. + ### always Examples of **incorrect** code for this rule with the default `"always"` option: