Skip to content

Commit

Permalink
Breaking: check unnamed default export in func-names (fixes #12194) (#…
Browse files Browse the repository at this point in the history
…12195)

* Breaking: check unnamed default export in func-names (fixes #12194)

* docs: add that default export functions are checked

* Revert "docs: add that default export functions are checked"

This reverts commit 036ce53.

* docs: add a note that export default functions needs name
  • Loading branch information
golopot committed Feb 17, 2020
1 parent 77df505 commit 6423e11
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 31 deletions.
10 changes: 10 additions & 0 deletions docs/rules/func-names.md
Expand Up @@ -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:
Expand All @@ -45,6 +47,8 @@ const cat = {
(function() {
// ...
}())

export default function() {}
```

Examples of **correct** code for this rule with the default `"always"` option:
Expand All @@ -61,6 +65,8 @@ const cat = {
(function bar() {
// ...
}())

export default function foo() {}
```

### as-needed
Expand All @@ -77,6 +83,8 @@ Foo.prototype.bar = function() {};
(function() {
// ...
}())

export default function() {}
```

Examples of **correct** code for this rule with the `"as-needed"` option:
Expand All @@ -93,6 +101,8 @@ const cat = {
(function bar() {
// ...
}())

export default function foo() {}
```

### never
Expand Down
53 changes: 30 additions & 23 deletions lib/rules/func-names.js
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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
};
}
};
65 changes: 57 additions & 8 deletions tests/lib/rules/func-names.js
Expand Up @@ -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"],
Expand Down Expand Up @@ -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() {});",
Expand Down Expand Up @@ -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 *() {});",
Expand Down

0 comments on commit 6423e11

Please sign in to comment.