From f5f7b50e179b79aa4ae29ceabbfb9455c54da52c Mon Sep 17 00:00:00 2001 From: Henry Zhu Date: Sat, 15 Aug 2015 21:05:46 -0400 Subject: [PATCH] Merge pull request babel/eslint-plugin-babel#9 from babel/arrow-parens Add support for async functions in arrow-parens --- eslint/babel-eslint-plugin/README.md | 2 + eslint/babel-eslint-plugin/package.json | 4 +- .../babel-eslint-plugin/rules/arrow-parens.js | 53 ++++++ .../babel-eslint-plugin/tests/arrow-parens.js | 177 ++++++++++++++++++ 4 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 eslint/babel-eslint-plugin/rules/arrow-parens.js create mode 100644 eslint/babel-eslint-plugin/tests/arrow-parens.js diff --git a/eslint/babel-eslint-plugin/README.md b/eslint/babel-eslint-plugin/README.md index c76c666ca3..3d28839d67 100644 --- a/eslint/babel-eslint-plugin/README.md +++ b/eslint/babel-eslint-plugin/README.md @@ -27,6 +27,7 @@ Finally enable all the rules you like to use (remember to disable the originals "babel/new-cap": 1, "babel/object-curly-spacing": 1, "babel/object-shorthand": 1, + "babel/arrow-parens": 1 } } ``` @@ -38,3 +39,4 @@ Each rule cooresponds to a core eslint rule, and has the same options. - `babel/new-cap`: Ignores capitalized decorators (`@Decorator`) - `babel/object-curly-spacing`: doesn't complain about `export x from "mod";` or `export * as x from "mod";` - `babel/object-shorthand`: doesn't fail when using object spread (`...obj`) +- `babel/arrow-parens`: Handles async functions correctly \ No newline at end of file diff --git a/eslint/babel-eslint-plugin/package.json b/eslint/babel-eslint-plugin/package.json index 5acdaaa6a2..dacdf7518a 100644 --- a/eslint/babel-eslint-plugin/package.json +++ b/eslint/babel-eslint-plugin/package.json @@ -27,8 +27,8 @@ "eslint": ">=1.0.0" }, "devDependencies": { - "babel-eslint": "^4.0.5", - "eslint": "^1.0.0", + "babel-eslint": "^4.0.7", + "eslint": "^1.1.0", "is-my-json-valid": "^2.12.0", "mocha": "^2.2.5", "phantomjs": "^1.9.17" diff --git a/eslint/babel-eslint-plugin/rules/arrow-parens.js b/eslint/babel-eslint-plugin/rules/arrow-parens.js new file mode 100644 index 0000000000..b3ee3a7652 --- /dev/null +++ b/eslint/babel-eslint-plugin/rules/arrow-parens.js @@ -0,0 +1,53 @@ +/** + * @fileoverview Rule to require parens in arrow function arguments. + * @author Jxck + * @copyright 2015 Jxck. All rights reserved. + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +module.exports = function(context) { + var message = "Expected parentheses around arrow function argument."; + var asNeededMessage = "Unexpected parentheses around single function argument"; + var asNeeded = context.options[0] === "as-needed"; + + /** + * Determines whether a arrow function argument end with `)` + * @param {ASTNode} node The arrow function node. + * @returns {void} + */ + function parens(node) { + var token = context.getFirstToken(node); + if (node.async) token = context.getTokenAfter(token); + + // as-needed: x => x + if (asNeeded && node.params.length === 1 && node.params[0].type === "Identifier") { + if (token.type === "Punctuator" && token.value === "(") { + context.report(node, asNeededMessage); + } + return; + } + + if (token.type === "Identifier") { + var after = context.getTokenAfter(token); + + // (x) => x + if (after.value !== ")") { + context.report(node, message); + } + } + } + + return { + "ArrowFunctionExpression": parens + }; +}; + +module.exports.schema = [ + { + "enum": ["always", "as-needed"] + } +]; \ No newline at end of file diff --git a/eslint/babel-eslint-plugin/tests/arrow-parens.js b/eslint/babel-eslint-plugin/tests/arrow-parens.js new file mode 100644 index 0000000000..74a03f62c5 --- /dev/null +++ b/eslint/babel-eslint-plugin/tests/arrow-parens.js @@ -0,0 +1,177 @@ +/* eslint-disable */ + +/** + * @fileoverview Tests for arrow-parens + * @author Jxck + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var rule = require("../rules/arrow-parens"), + RuleTester = require('eslint').RuleTester; + +function ok(code, args){ + return { code: code, options: args, parser: 'babel-eslint' } +} + +function err(code, errors, args){ + var e = ok(code, args) + e.errors = errors + return e +} + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ +var ruleTester = new RuleTester(); + +var valid = [ + { code: "() => {}", ecmaFeatures: { arrowFunctions: true } }, + { code: "(a) => {}", ecmaFeatures: { arrowFunctions: true } }, + { code: "(a) => a", ecmaFeatures: { arrowFunctions: true } }, + { code: "(a) => {\n}", ecmaFeatures: { arrowFunctions: true } }, + { code: "a.then((foo) => {});", ecmaFeatures: { arrowFunctions: true } }, + { code: "a.then((foo) => { if (true) {}; });", ecmaFeatures: { arrowFunctions: true } }, + + // // as-needed + { code: "() => {}", options: ["as-needed"], ecmaFeatures: { arrowFunctions: true } }, + { code: "a => {}", options: ["as-needed"], ecmaFeatures: { arrowFunctions: true } }, + { code: "a => a", options: ["as-needed"], ecmaFeatures: { arrowFunctions: true } }, + { code: "([a, b]) => {}", options: ["as-needed"], ecmaFeatures: { arrowFunctions: true, destructuring: true } }, + { code: "({ a, b }) => {}", options: ["as-needed"], ecmaFeatures: { arrowFunctions: true, destructuring: true } }, + { code: "(a = 10) => {}", options: ["as-needed"], ecmaFeatures: { arrowFunctions: true, destructuring: true, defaultParams: true } }, + { code: "(...a) => a[0]", options: ["as-needed"], ecmaFeatures: { arrowFunctions: true, restParams: true } }, + { code: "(a, b) => {}", options: ["as-needed"], ecmaFeatures: { arrowFunctions: true } }, + + // async + ok("async () => {}"), + ok("async (a) => {}"), + ok("async (a) => a"), + ok("async (a) => {\n}"), + ok("a.then(async (foo) => {});"), + ok("a.then((foo) => { if (true) {}; })"), + + ok("async () => {}", ["as-needed"]), + ok("async a => {}", ["as-needed"]), + ok("async a => a", ["as-needed"]), + ok("async ([a, b]) => {}", ["as-needed"]), + ok("async ({ a, b }) => {}", ["as-needed"]), + ok("async (a = 10) => {}", ["as-needed"]), + ok("async (...a) => a[0]", ["as-needed"]), + ok("async (a, b) => {}", ["as-needed"]), + +]; + +var message = message; +var asNeededMessage = asNeededMessage; +var type = type; + +var invalid = [ + { + code: "a => {}", + ecmaFeatures: { arrowFunctions: true }, + errors: [{ + line: 1, + column: 1, + message: message, + type: type + }] + }, + { + code: "a => a", + ecmaFeatures: { arrowFunctions: true }, + errors: [{ + line: 1, + column: 1, + message: message, + type: type + }] + }, + { + code: "a => {\n}", + ecmaFeatures: { arrowFunctions: true }, + errors: [{ + line: 1, + column: 1, + message: message, + type: type + }] + }, + { + code: "a.then(foo => {});", + ecmaFeatures: { arrowFunctions: true }, + errors: [{ + line: 1, + column: 8, + message: message, + type: type + }] + }, + { + code: "a.then(foo => a);", + ecmaFeatures: { arrowFunctions: true }, + errors: [{ + line: 1, + column: 8, + message: message, + type: type + }] + }, + { + code: "a(foo => { if (true) {}; });", + ecmaFeatures: { arrowFunctions: true }, + errors: [{ + line: 1, + column: 3, + message: message, + type: type + }] + }, + + // as-needed + { + code: "(a) => a", + options: ["as-needed"], + ecmaFeatures: { arrowFunctions: true }, + errors: [{ + line: 1, + column: 1, + message: asNeededMessage, + type: type + }] + }, + { + code: "(b) => b", + options: ["as-needed"], + ecmaFeatures: { arrowFunctions: true }, + errors: [{ + line: 1, + column: 1, + message: asNeededMessage, + type: type + }] + }, + + // async + err('async a => {}', [ + { message: 'Expected parentheses around arrow function argument.' }, + ]), + + err('async a => a', [ + { message: 'Expected parentheses around arrow function argument.' }, + ]), + + err('async (a) => a', [ + { message: 'Unexpected parentheses around single function argument' }, + ], + ["as-needed"]) +]; + +ruleTester.run("arrow-parens", rule, { + valid: valid, + invalid: invalid +}); \ No newline at end of file