From 36d74fec3d5af1a45f4fc0c2c6cb2bfe685c7fbe 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 | 44 ++++++++++++++++++++---- tests/lib/rules/arrow-body-style.js | 53 ++++++++++++++++++++++++++++- 3 files changed, 114 insertions(+), 9 deletions(-) diff --git a/docs/rules/arrow-body-style.md b/docs/rules/arrow-body-style.md index 25f3b5129b8..094cb328d6f 100644 --- a/docs/rules/arrow-body-style.md +++ b/docs/rules/arrow-body-style.md @@ -8,12 +8,12 @@ This rule can enforce 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) -### "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"] @@ -83,4 +83,26 @@ 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 }; }; ``` diff --git a/lib/rules/arrow-body-style.js b/lib/rules/arrow-body-style.js index 79fde90f805..d4b78aff476 100644 --- a/lib/rules/arrow-body-style.js +++ b/lib/rules/arrow-body-style.js @@ -16,16 +16,43 @@ module.exports = { recommended: false }, - schema: [ - { - enum: ["always", "as-needed"] - } - ] + schema: { + anyOf: [ + { + type: "array", + items: [ + { + enum: ["always"] + } + ], + 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 requireReturnForObjectLiteral = context.options[1] && context.options[1].requireReturnForObjectLiteral; /** * Determines whether a arrow function body needs braces @@ -42,6 +69,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, @@ -50,7 +82,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 fc19dfe081c..8b89073e2a0 100644 --- a/tests/lib/rules/arrow-body-style.js +++ b/tests/lib/rules/arrow-body-style.js @@ -26,11 +26,22 @@ 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 = () => { return bar(); };", parserOptions: { ecmaVersion: 6 }, options: ["always"] }, + { 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: [ { @@ -64,6 +75,46 @@ ruleTester.run("arrow-body-style", rule, { errors: [ { 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 = () => { 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." } + ] } ] });