From 4a53d74a85be28882173c1d34cbf504cc7c43b17 Mon Sep 17 00:00:00 2001 From: morozRed Date: Tue, 20 Nov 2018 12:28:32 +0100 Subject: [PATCH 1/4] handle disordered rest parameter in function expressions --- packages/babel-parser/src/parser/expression.js | 13 ++++++++++++- packages/babel-parser/src/parser/lval.js | 14 +++++++++++++- .../fixtures/core/uncategorised/396/options.json | 2 +- .../test/fixtures/core/uncategorised/555/input.js | 6 ++++++ .../fixtures/core/uncategorised/555/options.json | 4 ++++ .../invalid-rest-in-params/input.js | 5 +++++ .../invalid-rest-in-params/options.json | 4 ++++ .../fixtures/es2015/uncategorised/277/options.json | 2 +- .../fixtures/es2015/uncategorised/283/options.json | 2 +- .../arrow-with-multiple-rest/options.json | 2 +- .../invalid-syntax/migrated_0258/options.json | 2 +- 11 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 packages/babel-parser/test/fixtures/core/uncategorised/555/input.js create mode 100644 packages/babel-parser/test/fixtures/core/uncategorised/555/options.json create mode 100644 packages/babel-parser/test/fixtures/es2015/arrow-functions/invalid-rest-in-params/input.js create mode 100644 packages/babel-parser/test/fixtures/es2015/arrow-functions/invalid-rest-in-params/options.json diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 84e8975e0140..b4b54ed6a2b3 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -141,7 +141,7 @@ export default class ExpressionParser extends LValParser { if (this.match(tt.parenL) || this.match(tt.name) || this.match(tt._yield)) { this.state.potentialArrowAt = this.state.start; } - + let left = this.parseMaybeConditional( noIn, refShorthandDefaultPos, @@ -1120,6 +1120,17 @@ export default class ExpressionParser extends LValParser { ); } + if ( + this.match(tt.comma) && + (this.lookahead().type === tt.name || + this.lookahead().type === tt.ellipsis) + ) { + this.raise( + this.state.start, + "Rest parameter must be last formal parameter", + ); + } + break; } else { exprList.push( diff --git a/packages/babel-parser/src/parser/lval.js b/packages/babel-parser/src/parser/lval.js index b9e023cbd3d2..7d86c281521c 100644 --- a/packages/babel-parser/src/parser/lval.js +++ b/packages/babel-parser/src/parser/lval.js @@ -258,7 +258,19 @@ export default class LValParser extends NodeUtils { break; } else if (this.match(tt.ellipsis)) { elts.push(this.parseAssignableListItemTypes(this.parseRest())); - this.expect(close); + if ( + this.state.inFunction && + this.state.inParameters && + (this.lookahead().type === tt.name || + this.lookahead().type === tt.ellipsis) + ) { + this.raise( + this.state.start, + "Rest parameter must be last formal parameter", + ); + } else { + this.expect(close); + } break; } else { const decorators = []; diff --git a/packages/babel-parser/test/fixtures/core/uncategorised/396/options.json b/packages/babel-parser/test/fixtures/core/uncategorised/396/options.json index 570ef651fb67..b8808d8a689a 100644 --- a/packages/babel-parser/test/fixtures/core/uncategorised/396/options.json +++ b/packages/babel-parser/test/fixtures/core/uncategorised/396/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \")\" (1:18)" + "throws": "Rest parameter must be last formal parameter (1:18)" } diff --git a/packages/babel-parser/test/fixtures/core/uncategorised/555/input.js b/packages/babel-parser/test/fixtures/core/uncategorised/555/input.js new file mode 100644 index 000000000000..2c262ab21189 --- /dev/null +++ b/packages/babel-parser/test/fixtures/core/uncategorised/555/input.js @@ -0,0 +1,6 @@ +function foo ( + first, + ...second, + third, +) { +}; diff --git a/packages/babel-parser/test/fixtures/core/uncategorised/555/options.json b/packages/babel-parser/test/fixtures/core/uncategorised/555/options.json new file mode 100644 index 000000000000..162e897221a5 --- /dev/null +++ b/packages/babel-parser/test/fixtures/core/uncategorised/555/options.json @@ -0,0 +1,4 @@ +{ + "throws": "Rest parameter must be last formal parameter (3:13)" + } + \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/arrow-functions/invalid-rest-in-params/input.js b/packages/babel-parser/test/fixtures/es2015/arrow-functions/invalid-rest-in-params/input.js new file mode 100644 index 000000000000..c13825de4f0a --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/arrow-functions/invalid-rest-in-params/input.js @@ -0,0 +1,5 @@ +( + first, + ...second, + third +) => {}; diff --git a/packages/babel-parser/test/fixtures/es2015/arrow-functions/invalid-rest-in-params/options.json b/packages/babel-parser/test/fixtures/es2015/arrow-functions/invalid-rest-in-params/options.json new file mode 100644 index 000000000000..1bff860e7bc3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/arrow-functions/invalid-rest-in-params/options.json @@ -0,0 +1,4 @@ +{ + "throws": "Rest parameter must be last formal parameter (3:13)" +} + \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/uncategorised/277/options.json b/packages/babel-parser/test/fixtures/es2015/uncategorised/277/options.json index 570ef651fb67..b8808d8a689a 100644 --- a/packages/babel-parser/test/fixtures/es2015/uncategorised/277/options.json +++ b/packages/babel-parser/test/fixtures/es2015/uncategorised/277/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \")\" (1:18)" + "throws": "Rest parameter must be last formal parameter (1:18)" } diff --git a/packages/babel-parser/test/fixtures/es2015/uncategorised/283/options.json b/packages/babel-parser/test/fixtures/es2015/uncategorised/283/options.json index 2da83bcd6f69..263bbbb08029 100644 --- a/packages/babel-parser/test/fixtures/es2015/uncategorised/283/options.json +++ b/packages/babel-parser/test/fixtures/es2015/uncategorised/283/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \")\" (1:5)" + "throws": "Rest parameter must be last formal parameter (1:5)" } diff --git a/packages/babel-parser/test/fixtures/esprima/es2015-arrow-function/arrow-with-multiple-rest/options.json b/packages/babel-parser/test/fixtures/esprima/es2015-arrow-function/arrow-with-multiple-rest/options.json index 2da83bcd6f69..263bbbb08029 100644 --- a/packages/babel-parser/test/fixtures/esprima/es2015-arrow-function/arrow-with-multiple-rest/options.json +++ b/packages/babel-parser/test/fixtures/esprima/es2015-arrow-function/arrow-with-multiple-rest/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \")\" (1:5)" + "throws": "Rest parameter must be last formal parameter (1:5)" } diff --git a/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0258/options.json b/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0258/options.json index 570ef651fb67..b8808d8a689a 100644 --- a/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0258/options.json +++ b/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0258/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \")\" (1:18)" + "throws": "Rest parameter must be last formal parameter (1:18)" } From e494c12cd58c6390d19aef862de96ef8c553ad55 Mon Sep 17 00:00:00 2001 From: morozRed Date: Tue, 20 Nov 2018 13:01:29 +0100 Subject: [PATCH 2/4] remove spaces [lint] --- packages/babel-parser/src/parser/expression.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index b4b54ed6a2b3..c11a464bed67 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -141,7 +141,7 @@ export default class ExpressionParser extends LValParser { if (this.match(tt.parenL) || this.match(tt.name) || this.match(tt._yield)) { this.state.potentialArrowAt = this.state.start; } - + let left = this.parseMaybeConditional( noIn, refShorthandDefaultPos, From 4f68c210285e75fb515e209410ea16bc2b590d6a Mon Sep 17 00:00:00 2001 From: Grigory Moroz Date: Tue, 20 Nov 2018 19:45:20 +0100 Subject: [PATCH 3/4] polish function parameters validation --- .../babel-parser/src/parser/expression.js | 23 ++++++------------- packages/babel-parser/src/parser/lval.js | 13 ++++++----- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index c11a464bed67..7d92c3c28161 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -1113,22 +1113,13 @@ export default class ExpressionParser extends LValParser { ), ); - if (this.match(tt.comma) && this.lookahead().type === tt.parenR) { - this.raise( - this.state.start, - "A trailing comma is not permitted after the rest element", - ); - } - - if ( - this.match(tt.comma) && - (this.lookahead().type === tt.name || - this.lookahead().type === tt.ellipsis) - ) { - this.raise( - this.state.start, - "Rest parameter must be last formal parameter", - ); + if (this.match(tt.comma)) { + const nextTokenType = this.lookahead().type; + const errorMessage = + nextTokenType === tt.parenR + ? "A trailing comma is not permitted after the rest element" + : "Rest parameter must be last formal parameter"; + this.raise(this.state.start, errorMessage); } break; diff --git a/packages/babel-parser/src/parser/lval.js b/packages/babel-parser/src/parser/lval.js index 7d86c281521c..e6c9065afdb2 100644 --- a/packages/babel-parser/src/parser/lval.js +++ b/packages/babel-parser/src/parser/lval.js @@ -261,13 +261,14 @@ export default class LValParser extends NodeUtils { if ( this.state.inFunction && this.state.inParameters && - (this.lookahead().type === tt.name || - this.lookahead().type === tt.ellipsis) + this.match(tt.comma) ) { - this.raise( - this.state.start, - "Rest parameter must be last formal parameter", - ); + const nextTokenType = this.lookahead().type; + const errorMessage = + nextTokenType === tt.parenR + ? "A trailing comma is not permitted after the rest element" + : "Rest parameter must be last formal parameter"; + this.raise(this.state.start, errorMessage); } else { this.expect(close); } From d1f38b3617a2ca6ec54e7264d37db6ef178c7a54 Mon Sep 17 00:00:00 2001 From: Grigory Moroz Date: Wed, 21 Nov 2018 00:02:41 +0100 Subject: [PATCH 4/4] add test with arrow function and comma after rest parameter [babel-parser] --- .../es2015/arrow-functions/comma-after-rest-param/input.js | 1 + .../es2015/arrow-functions/comma-after-rest-param/options.json | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 packages/babel-parser/test/fixtures/es2015/arrow-functions/comma-after-rest-param/input.js create mode 100644 packages/babel-parser/test/fixtures/es2015/arrow-functions/comma-after-rest-param/options.json diff --git a/packages/babel-parser/test/fixtures/es2015/arrow-functions/comma-after-rest-param/input.js b/packages/babel-parser/test/fixtures/es2015/arrow-functions/comma-after-rest-param/input.js new file mode 100644 index 000000000000..d06c522c05b3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/arrow-functions/comma-after-rest-param/input.js @@ -0,0 +1 @@ +(...rest,) => {} diff --git a/packages/babel-parser/test/fixtures/es2015/arrow-functions/comma-after-rest-param/options.json b/packages/babel-parser/test/fixtures/es2015/arrow-functions/comma-after-rest-param/options.json new file mode 100644 index 000000000000..ba0229eff23d --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/arrow-functions/comma-after-rest-param/options.json @@ -0,0 +1,3 @@ +{ + "throws": "A trailing comma is not permitted after the rest element (1:8)" +} \ No newline at end of file