diff --git a/packages/babylon/src/parser/expression.js b/packages/babylon/src/parser/expression.js index 1712baf40f..9785d854b7 100644 --- a/packages/babylon/src/parser/expression.js +++ b/packages/babylon/src/parser/expression.js @@ -1383,17 +1383,24 @@ export default class ExpressionParser extends LValParser { } // get methods aren't allowed to have any parameters - // set methods must have exactly 1 parameter - checkGetterSetterParamCount(method: N.ObjectMethod | N.ClassMethod): void { + // set methods must have exactly 1 parameter which is not a rest parameter + checkGetterSetterParams(method: N.ObjectMethod | N.ClassMethod): void { const paramCount = method.kind === "get" ? 0 : 1; + const start = method.start; if (method.params.length !== paramCount) { - const start = method.start; if (method.kind === "get") { - this.raise(start, "getter should have no params"); + this.raise(start, "getter must not have any formal parameters"); } else { - this.raise(start, "setter should have exactly one param"); + this.raise(start, "setter must have exactly one formal parameter"); } } + + if (method.kind === "set" && method.params[0].type === "RestElement") { + this.raise( + start, + "setter function argument must not be a rest parameter", + ); + } } parseObjectMethod( @@ -1426,7 +1433,7 @@ export default class ExpressionParser extends LValParser { /* isConstructor */ false, "ObjectMethod", ); - this.checkGetterSetterParamCount(prop); + this.checkGetterSetterParams(prop); return prop; } } diff --git a/packages/babylon/src/parser/statement.js b/packages/babylon/src/parser/statement.js index cd8a9efbea..f8c102a37a 100644 --- a/packages/babylon/src/parser/statement.js +++ b/packages/babylon/src/parser/statement.js @@ -1161,7 +1161,7 @@ export default class StatementParser extends ExpressionParser { ); } - this.checkGetterSetterParamCount(publicMethod); + this.checkGetterSetterParams(publicMethod); } else if (this.isLineTerminator()) { // an uninitialized class property (due to ASI, since we don't otherwise recognize the next token) if (isPrivate) { diff --git a/packages/babylon/src/plugins/estree.js b/packages/babylon/src/plugins/estree.js index 81ed5a2010..091d4b35e8 100644 --- a/packages/babylon/src/plugins/estree.js +++ b/packages/babylon/src/plugins/estree.js @@ -82,17 +82,24 @@ export default (superClass: Class): Class => } } - checkGetterSetterParamCount(prop: N.ObjectMethod | N.ClassMethod): void { + checkGetterSetterParams(method: N.ObjectMethod | N.ClassMethod): void { + const prop = ((method: any): N.EstreeProperty | N.EstreeMethodDefinition); const paramCount = prop.kind === "get" ? 0 : 1; - // $FlowFixMe (prop.value present for ObjectMethod, but for ClassMethod should use prop.params?) + const start = prop.start; if (prop.value.params.length !== paramCount) { - const start = prop.start; if (prop.kind === "get") { - this.raise(start, "getter should have no params"); + this.raise(start, "getter must not have any formal parameters"); } else { - this.raise(start, "setter should have exactly one param"); + this.raise(start, "setter must have exactly one formal parameter"); } } + + if (prop.kind === "set" && prop.value.params[0].type === "RestElement") { + this.raise( + start, + "setter function argument must not be a rest parameter", + ); + } } checkLVal( diff --git a/packages/babylon/src/plugins/flow.js b/packages/babylon/src/plugins/flow.js index cce373f357..679d932fa5 100644 --- a/packages/babylon/src/plugins/flow.js +++ b/packages/babylon/src/plugins/flow.js @@ -763,7 +763,7 @@ export default (superClass: Class): Class => this.startNodeAt(node.start, node.loc.start), ); if (kind === "get" || kind === "set") { - this.flowCheckGetterSetterParamCount(node); + this.flowCheckGetterSetterParams(node); } } else { if (kind !== "init") this.unexpected(); @@ -783,20 +783,29 @@ export default (superClass: Class): Class => } } - // This is similar to checkGetterSetterParamCount, but as + // This is similar to checkGetterSetterParams, but as // babylon uses non estree properties we cannot reuse it here - flowCheckGetterSetterParamCount( + flowCheckGetterSetterParams( property: N.FlowObjectTypeProperty | N.FlowObjectTypeSpreadProperty, ): void { const paramCount = property.kind === "get" ? 0 : 1; - if (property.value.params.length !== paramCount) { - const start = property.start; + const start = property.start; + const length = + property.value.params.length + (property.value.rest ? 1 : 0); + if (length !== paramCount) { if (property.kind === "get") { - this.raise(start, "getter should have no params"); + this.raise(start, "getter must not have any formal parameters"); } else { - this.raise(start, "setter should have exactly one param"); + this.raise(start, "setter must have exactly one formal parameter"); } } + + if (property.kind === "set" && property.value.rest) { + this.raise( + start, + "setter function argument must not be a rest parameter", + ); + } } flowObjectTypeSemicolon(): void { diff --git a/packages/babylon/src/types.js b/packages/babylon/src/types.js index 7f7f46b646..41d457d7f1 100644 --- a/packages/babylon/src/types.js +++ b/packages/babylon/src/types.js @@ -941,6 +941,18 @@ export type EstreeProperty = NodeBase & { variance?: ?FlowVariance, }; +export type EstreeMethodDefinition = NodeBase & { + type: "MethodDefinition", + static: boolean, + key: Expression, + computed: boolean, + value: Expression, + decorators: $ReadOnlyArray, + kind?: "get" | "set" | "method", + + variance?: ?FlowVariance, +}; + // === === === === // TypeScript // === === === === diff --git a/packages/babylon/test/fixtures/es2015/class-methods/getter-signature/options.json b/packages/babylon/test/fixtures/es2015/class-methods/getter-signature/options.json index 9699409e82..e096100dcf 100644 --- a/packages/babylon/test/fixtures/es2015/class-methods/getter-signature/options.json +++ b/packages/babylon/test/fixtures/es2015/class-methods/getter-signature/options.json @@ -1,3 +1,3 @@ { - "throws": "getter should have no params (2:2)" + "throws": "getter must not have any formal parameters (2:2)" } \ No newline at end of file diff --git a/packages/babylon/test/fixtures/es2015/uncategorised/347/options.json b/packages/babylon/test/fixtures/es2015/uncategorised/347/options.json index 739bda889b..9a137564ee 100644 --- a/packages/babylon/test/fixtures/es2015/uncategorised/347/options.json +++ b/packages/babylon/test/fixtures/es2015/uncategorised/347/options.json @@ -1,3 +1,3 @@ { - "throws": "setter should have exactly one param (1:10)" + "throws": "setter must have exactly one formal parameter (1:10)" } diff --git a/packages/babylon/test/fixtures/esprima/rest-parameter/invalid-setter-rest/options.json b/packages/babylon/test/fixtures/esprima/rest-parameter/invalid-setter-rest/options.json new file mode 100644 index 0000000000..c397e398c8 --- /dev/null +++ b/packages/babylon/test/fixtures/esprima/rest-parameter/invalid-setter-rest/options.json @@ -0,0 +1,3 @@ +{ + "throws": "setter function argument must not be a rest parameter (1:6)" + } diff --git a/packages/babylon/test/fixtures/esprima/rest-parameter/invalid-setter-rest/output.json b/packages/babylon/test/fixtures/esprima/rest-parameter/invalid-setter-rest/output.json deleted file mode 100644 index 8d4bed2eb1..0000000000 --- a/packages/babylon/test/fixtures/esprima/rest-parameter/invalid-setter-rest/output.json +++ /dev/null @@ -1,188 +0,0 @@ -{ - "type": "File", - "start": 0, - "end": 22, - "loc": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 1, - "column": 22 - } - }, - "program": { - "type": "Program", - "start": 0, - "end": 22, - "loc": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 1, - "column": 22 - } - }, - "sourceType": "script", - "body": [ - { - "type": "ExpressionStatement", - "start": 0, - "end": 22, - "loc": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 1, - "column": 22 - } - }, - "expression": { - "type": "AssignmentExpression", - "start": 0, - "end": 22, - "loc": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 1, - "column": 22 - } - }, - "operator": "=", - "left": { - "type": "Identifier", - "start": 0, - "end": 1, - "loc": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 1, - "column": 1 - }, - "identifierName": "x" - }, - "name": "x" - }, - "right": { - "type": "ObjectExpression", - "start": 4, - "end": 22, - "loc": { - "start": { - "line": 1, - "column": 4 - }, - "end": { - "line": 1, - "column": 22 - } - }, - "properties": [ - { - "type": "ObjectMethod", - "start": 6, - "end": 20, - "loc": { - "start": { - "line": 1, - "column": 6 - }, - "end": { - "line": 1, - "column": 20 - } - }, - "method": false, - "key": { - "type": "Identifier", - "start": 10, - "end": 11, - "loc": { - "start": { - "line": 1, - "column": 10 - }, - "end": { - "line": 1, - "column": 11 - }, - "identifierName": "f" - }, - "name": "f" - }, - "computed": false, - "kind": "set", - "id": null, - "generator": false, - "async": false, - "params": [ - { - "type": "RestElement", - "start": 12, - "end": 16, - "loc": { - "start": { - "line": 1, - "column": 12 - }, - "end": { - "line": 1, - "column": 16 - } - }, - "argument": { - "type": "Identifier", - "start": 15, - "end": 16, - "loc": { - "start": { - "line": 1, - "column": 15 - }, - "end": { - "line": 1, - "column": 16 - }, - "identifierName": "y" - }, - "name": "y" - } - } - ], - "body": { - "type": "BlockStatement", - "start": 18, - "end": 20, - "loc": { - "start": { - "line": 1, - "column": 18 - }, - "end": { - "line": 1, - "column": 20 - } - }, - "body": [], - "directives": [] - } - } - ] - } - } - } - ], - "directives": [] - } -} \ No newline at end of file diff --git a/packages/babylon/test/fixtures/flow/object-types/invalid-getter-param-count-rest/input.js b/packages/babylon/test/fixtures/flow/object-types/invalid-getter-param-count-rest/input.js new file mode 100644 index 0000000000..a93bcb11c2 --- /dev/null +++ b/packages/babylon/test/fixtures/flow/object-types/invalid-getter-param-count-rest/input.js @@ -0,0 +1,3 @@ +type B = { + get a(...foo): number; +} diff --git a/packages/babylon/test/fixtures/flow/object-types/invalid-getter-param-count-rest/options.json b/packages/babylon/test/fixtures/flow/object-types/invalid-getter-param-count-rest/options.json new file mode 100644 index 0000000000..65bc24a66f --- /dev/null +++ b/packages/babylon/test/fixtures/flow/object-types/invalid-getter-param-count-rest/options.json @@ -0,0 +1,3 @@ +{ + "throws": "getter must not have any formal parameters (2:2)" +} diff --git a/packages/babylon/test/fixtures/flow/object-types/invalid-getter-param-count/options.json b/packages/babylon/test/fixtures/flow/object-types/invalid-getter-param-count/options.json index 8694117aee..65bc24a66f 100644 --- a/packages/babylon/test/fixtures/flow/object-types/invalid-getter-param-count/options.json +++ b/packages/babylon/test/fixtures/flow/object-types/invalid-getter-param-count/options.json @@ -1,3 +1,3 @@ { - "throws": "getter should have no params (2:2)" + "throws": "getter must not have any formal parameters (2:2)" } diff --git a/packages/babylon/test/fixtures/flow/object-types/invalid-setter-param-count/options.json b/packages/babylon/test/fixtures/flow/object-types/invalid-setter-param-count/options.json index 8ea95ab888..6a15677822 100644 --- a/packages/babylon/test/fixtures/flow/object-types/invalid-setter-param-count/options.json +++ b/packages/babylon/test/fixtures/flow/object-types/invalid-setter-param-count/options.json @@ -1,3 +1,3 @@ { - "throws": "setter should have exactly one param (2:2)" + "throws": "setter must have exactly one formal parameter (2:2)" } diff --git a/packages/babylon/test/fixtures/flow/object-types/invalid-setter-param-type/input.js b/packages/babylon/test/fixtures/flow/object-types/invalid-setter-param-type/input.js new file mode 100644 index 0000000000..169d54941f --- /dev/null +++ b/packages/babylon/test/fixtures/flow/object-types/invalid-setter-param-type/input.js @@ -0,0 +1,3 @@ +type B = { + set a(...w): void; +} diff --git a/packages/babylon/test/fixtures/flow/object-types/invalid-setter-param-type/options.json b/packages/babylon/test/fixtures/flow/object-types/invalid-setter-param-type/options.json new file mode 100644 index 0000000000..15ce6a4c5a --- /dev/null +++ b/packages/babylon/test/fixtures/flow/object-types/invalid-setter-param-type/options.json @@ -0,0 +1,3 @@ +{ + "throws": "setter function argument must not be a rest parameter (2:2)" +}