Skip to content

Commit

Permalink
Update: Option for object literals in arrow-body-style (fixes #5936)
Browse files Browse the repository at this point in the history
  • Loading branch information
alberto committed Jun 9, 2016
1 parent 977cdd5 commit 2b0f22a
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 12 deletions.
26 changes: 24 additions & 2 deletions docs/rules/arrow-body-style.md
Expand Up @@ -8,13 +8,13 @@ This rule can enforce or disallow the use of braces around arrow function body.

## Options

The rule takes one option, a string, which can be:
The rule takes one or two options. The first is a string, which can be:

* `"always"` enforces braces around the function body
* `"as-needed"` enforces no braces where they can be omitted (default)
* `"never"` enforces no braces around the function body (constrains arrow functions to the role of returning an expression)

### "always"
The second one is an object for more fine-grained configuration when the first option is `"as-needed"`. Currently, the only available option is `requireReturnForObjectLiteral`, a boolean property. It's `false` by default. If set to `true`, it requires braces and an explicit return for object literals.

```json
"arrow-body-style": ["error", "always"]
Expand Down Expand Up @@ -84,6 +84,28 @@ let foo = () => { /* do nothing */ };
let foo = () => {
// do nothing.
};
let foo = () => ({ bar: 0 });
```

#### requireReturnForObjectLiteral

When the rule is set to `"as-needed", { requireReturnForObjectLiteral: true }` the following patterns are considered problems:

```js
/*eslint arrow-body-style: ["error", "as-needed", { requireReturnForObjectLiteral: true }]*/
/*eslint-env es6*/
let foo = () => ({});
let foo = () => ({ bar: 0 });
```

The following patterns are not considered problems:

```js
/*eslint arrow-body-style: ["error", "as-needed", { requireReturnForObjectLiteral: true }]*/
/*eslint-env es6*/

let foo = () => {};
let foo = () => { return { bar: 0 }; };
```

### "never"
Expand Down
51 changes: 42 additions & 9 deletions lib/rules/arrow-body-style.js
Expand Up @@ -16,17 +16,45 @@ module.exports = {
recommended: false
},

schema: [
{
enum: ["always", "as-needed", "never"]
}
]
schema: {
anyOf: [
{
type: "array",
items: [
{
enum: ["always", "never"]
}
],
minItems: 0,
maxItems: 1
},
{
type: "array",
items: [
{
enum: ["as-needed"]
},
{
type: "object",
properties: {
requireReturnForObjectLiteral: {type: "boolean"}
},
additionalProperties: false
}
],
minItems: 0,
maxItems: 2
}
]
}
},

create: function(context) {
var always = context.options[0] === "always";
var asNeeded = !context.options[0] || context.options[0] === "as-needed";
var never = context.options[0] === "never";
var options = context.options;
var always = options[0] === "always";
var asNeeded = !options[0] || options[0] === "as-needed";
var never = options[0] === "never";
var requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral;

/**
* Determines whether a arrow function body needs braces
Expand All @@ -50,6 +78,11 @@ module.exports = {
return;
}

if (asNeeded && requireReturnForObjectLiteral && blockBody[0].type === "ReturnStatement" &&
blockBody[0].argument.type === "ObjectExpression") {
return;
}

if (asNeeded && blockBody[0].type === "ReturnStatement") {
context.report({
node: node,
Expand All @@ -59,7 +92,7 @@ module.exports = {
}
}
} else {
if (always) {
if (always || (asNeeded && requireReturnForObjectLiteral && arrowBody.type === "ObjectExpression")) {
context.report({
node: node,
loc: arrowBody.loc.start,
Expand Down
53 changes: 52 additions & 1 deletion tests/lib/rules/arrow-body-style.js
Expand Up @@ -26,13 +26,24 @@ ruleTester.run("arrow-body-style", rule, {
{ code: "var foo = () => {\n /* do nothing */ \n};", parserOptions: { ecmaVersion: 6 } },
{ code: "var foo = (retv, name) => {\nretv[name] = true;\nreturn retv;\n};", parserOptions: { ecmaVersion: 6 } },
{ code: "var foo = () => ({});", parserOptions: { ecmaVersion: 6 } },
{ code: "var foo = () => bar();", parserOptions: { ecmaVersion: 6 } },
{ code: "var foo = () => { bar(); };", parserOptions: { ecmaVersion: 6 } },
{ code: "var foo = () => { b = a };", parserOptions: { ecmaVersion: 6 } },
{ code: "var foo = () => { bar: 1 };", parserOptions: { ecmaVersion: 6 } },
{ code: "var foo = () => { return 0; };", parserOptions: { ecmaVersion: 6 }, options: ["always"] },
{ code: "var foo = () => { return bar(); };", parserOptions: { ecmaVersion: 6 }, options: ["always"] },
{ code: "var foo = () => 0;", parserOptions: { ecmaVersion: 6 }, options: ["never"] },
{ code: "var foo = () => ({ foo: 0 });", parserOptions: { ecmaVersion: 6 }, options: ["never"] }
{ code: "var foo = () => ({ foo: 0 });", parserOptions: { ecmaVersion: 6 }, options: ["never"] },
{ code: "var foo = () => {};", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {requireReturnForObjectLiteral: true }] },
{ code: "var foo = () => 0;", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {requireReturnForObjectLiteral: true }] },
{ code: "var addToB = (a) => { b = b + a };", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {requireReturnForObjectLiteral: true }] },
{ code: "var foo = () => { /* do nothing */ };", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {requireReturnForObjectLiteral: true }] },
{ code: "var foo = () => {\n /* do nothing */ \n};", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {requireReturnForObjectLiteral: true }] },
{ code: "var foo = (retv, name) => {\nretv[name] = true;\nreturn retv;\n};", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {requireReturnForObjectLiteral: true }] },
{ code: "var foo = () => bar();", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {requireReturnForObjectLiteral: true }] },
{ code: "var foo = () => { bar(); };", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {requireReturnForObjectLiteral: true }] },
{ code: "var addToB = (a) => { b = b + a };", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {requireReturnForObjectLiteral: true }] },
{ code: "var foo = () => { return { bar: 0 }; };", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {requireReturnForObjectLiteral: true }] }
],
invalid: [
{
Expand Down Expand Up @@ -75,13 +86,53 @@ ruleTester.run("arrow-body-style", rule, {
{ line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
]
},
{
code: "var foo = () => { return { bar: 0 }; };",
parserOptions: { ecmaVersion: 6 },
options: ["as-needed"],
errors: [
{ line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
]
},
{
code: "var foo = (retv, name) => {\nretv[name] = true;\nreturn retv;\n};",
parserOptions: { ecmaVersion: 6 },
options: ["never"],
errors: [
{ line: 1, column: 27, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
]
},
{
code: "var foo = () => { return 0; };",
parserOptions: { ecmaVersion: 6 },
options: ["as-needed", {requireReturnForObjectLiteral: true }],
errors: [
{ line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
]
},
{
code: "var foo = () => { return bar(); };",
parserOptions: { ecmaVersion: 6 },
options: ["as-needed", {requireReturnForObjectLiteral: true }],
errors: [
{ line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
]
},
{
code: "var foo = () => ({});",
parserOptions: { ecmaVersion: 6 },
options: ["as-needed", {requireReturnForObjectLiteral: true }],
errors: [
{ line: 1, column: 18, type: "ArrowFunctionExpression", message: "Expected block statement surrounding arrow body." }
]
},
{
code: "var foo = () => ({ bar: 0 });",
parserOptions: { ecmaVersion: 6 },
options: ["as-needed", {requireReturnForObjectLiteral: true }],
errors: [
{ line: 1, column: 18, type: "ArrowFunctionExpression", message: "Expected block statement surrounding arrow body." }
]
}
]
});

0 comments on commit 2b0f22a

Please sign in to comment.