From 2b0f22abd2b13a8c7a91b86e1549c6586cd68901 Mon Sep 17 00:00:00 2001 From: alberto Date: Wed, 25 May 2016 19:05:15 +0200 Subject: [PATCH] Update: Option for object literals in `arrow-body-style` (fixes #5936) --- docs/rules/arrow-body-style.md | 26 ++++++++++++-- lib/rules/arrow-body-style.js | 51 ++++++++++++++++++++++----- tests/lib/rules/arrow-body-style.js | 53 ++++++++++++++++++++++++++++- 3 files changed, 118 insertions(+), 12 deletions(-) diff --git a/docs/rules/arrow-body-style.md b/docs/rules/arrow-body-style.md index 502a48f6307..a22c3b6fcca 100644 --- a/docs/rules/arrow-body-style.md +++ b/docs/rules/arrow-body-style.md @@ -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"] @@ -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" diff --git a/lib/rules/arrow-body-style.js b/lib/rules/arrow-body-style.js index 1b2d1996a67..13486fa74bc 100644 --- a/lib/rules/arrow-body-style.js +++ b/lib/rules/arrow-body-style.js @@ -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 @@ -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, @@ -59,7 +92,7 @@ module.exports = { } } } else { - if (always) { + if (always || (asNeeded && requireReturnForObjectLiteral && arrowBody.type === "ObjectExpression")) { context.report({ node: node, loc: arrowBody.loc.start, diff --git a/tests/lib/rules/arrow-body-style.js b/tests/lib/rules/arrow-body-style.js index a441c751fda..55592b048cd 100644 --- a/tests/lib/rules/arrow-body-style.js +++ b/tests/lib/rules/arrow-body-style.js @@ -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: [ { @@ -75,6 +86,14 @@ 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 }, @@ -82,6 +101,38 @@ ruleTester.run("arrow-body-style", rule, { 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." } + ] } ] });