diff --git a/docs/rules/arrow-body-style.md b/docs/rules/arrow-body-style.md index 8c35d6a7feaa..b4c2ad6a5cf7 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 parameter is `allowObjectLiteralBody`, which indicates if object literals should be declared using braces, thus requiring an explicit return. ```json "arrow-body-style": ["error", "always"] @@ -50,6 +50,8 @@ When the rule is set to `"as-needed"` the following patterns are considered prob let foo = () => { return 0; }; + +let foo = () => { return { bar: 0 }; } ``` The following patterns are not considered problems: @@ -69,4 +71,26 @@ let foo = () => { /* do nothing */ }; let foo = () => { // do nothing. }; +let foo = () => ({ bar: 0 }); +``` + +#### allowObjectLiteralBody + +When the rule is set to `"as-needed", { allowObjectLiteralBody: true }` the following patterns are considered problems: + +```js +/*eslint arrow-body-style: ["error", "as-needed", { allowObjectLiteralBody: 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", { allowObjectLiteralBody: 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 79fde90f805d..9c262cbd8c42 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: { + allowObjectLiteralBody: {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 allowObjectLiteralBody = context.options[1] && context.options[1].allowObjectLiteralBody === true; /** * Determines whether a arrow function body needs braces @@ -42,6 +69,11 @@ module.exports = { return; } + if (asNeeded && allowObjectLiteralBody && 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 && allowObjectLiteralBody && 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 fc19dfe081ce..b9b9e724ecf8 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", {allowObjectLiteralBody: true }] }, + { code: "var foo = () => 0;", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {allowObjectLiteralBody: true }] }, + { code: "var addToB = (a) => { b = b + a };", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {allowObjectLiteralBody: true }] }, + { code: "var foo = () => { /* do nothing */ };", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {allowObjectLiteralBody: true }] }, + { code: "var foo = () => {\n /* do nothing */ \n};", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {allowObjectLiteralBody: true }] }, + { code: "var foo = (retv, name) => {\nretv[name] = true;\nreturn retv;\n};", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {allowObjectLiteralBody: true }] }, + { code: "var foo = () => bar();", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {allowObjectLiteralBody: true }] }, + { code: "var foo = () => { bar(); };", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {allowObjectLiteralBody: true }] }, + { code: "var addToB = (a) => { b = b + a };", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {allowObjectLiteralBody: true }] }, + { code: "var foo = () => { return { bar: 0 }; };", parserOptions: { ecmaVersion: 6 }, options: ["as-needed", {allowObjectLiteralBody: 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", {allowObjectLiteralBody: 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", {allowObjectLiteralBody: true }], + errors: [ + { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." } + ] + }, + { + code: "var foo = () => ({});", + parserOptions: { ecmaVersion: 6 }, + options: ["as-needed", {allowObjectLiteralBody: 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", {allowObjectLiteralBody: true }], + errors: [ + { line: 1, column: 18, type: "ArrowFunctionExpression", message: "Expected block statement surrounding arrow body." } + ] } ] });