diff --git a/packages/babylon/src/plugins/flow.js b/packages/babylon/src/plugins/flow.js index 88fa2df1a1..f930f5b881 100644 --- a/packages/babylon/src/plugins/flow.js +++ b/packages/babylon/src/plugins/flow.js @@ -505,7 +505,18 @@ export default (superClass: Class): Class => // Type annotations - flowParseTypeParameter(): N.TypeParameter { + flowParseTypeParameter( + allowDefault?: boolean = true, + requireDefault?: boolean = false, + ): N.TypeParameter { + if (!allowDefault && requireDefault) { + throw new Error( + "Cannot disallow a default value (`allowDefault`) while also requiring it (`requireDefault`).", + ); + } + + const nodeStart = this.state.start; + const node = this.startNode(); const variance = this.flowParseVariance(); @@ -516,14 +527,28 @@ export default (superClass: Class): Class => node.bound = ident.typeAnnotation; if (this.match(tt.eq)) { - this.eat(tt.eq); - node.default = this.flowParseType(); + if (allowDefault) { + this.eat(tt.eq); + node.default = this.flowParseType(); + } else { + this.unexpected(); + } + } else { + if (requireDefault) { + this.unexpected( + nodeStart, + // eslint-disable-next-line max-len + "Type parameter declaration needs a default, since a preceding type parameter declaration has a default.", + ); + } } return this.finishNode(node, "TypeParameter"); } - flowParseTypeParameterDeclaration(): N.TypeParameterDeclaration { + flowParseTypeParameterDeclaration( + allowDefault?: boolean = true, + ): N.TypeParameterDeclaration { const oldInType = this.state.inType; const node = this.startNode(); node.params = []; @@ -537,8 +562,20 @@ export default (superClass: Class): Class => this.unexpected(); } + let defaultRequired = false; + do { - node.params.push(this.flowParseTypeParameter()); + const typeParameter = this.flowParseTypeParameter( + allowDefault, + defaultRequired, + ); + + node.params.push(typeParameter); + + if (typeParameter.default) { + defaultRequired = true; + } + if (!this.isRelational(">")) { this.expect(tt.comma); } @@ -607,7 +644,9 @@ export default (superClass: Class): Class => node.typeParameters = null; if (this.isRelational("<")) { - node.typeParameters = this.flowParseTypeParameterDeclaration(); + node.typeParameters = this.flowParseTypeParameterDeclaration( + /* allowDefault */ false, + ); } this.expect(tt.parenL); @@ -668,16 +707,15 @@ export default (superClass: Class): Class => while (!this.match(endDelim)) { let isStatic = false; const node = this.startNode(); - const lookahead = this.lookahead(); - if ( - allowStatic && - this.isContextual("static") && + if (allowStatic && this.isContextual("static")) { + const lookahead = this.lookahead(); + // static is a valid identifier name - (lookahead.type !== tt.colon && lookahead.type !== tt.question) - ) { - this.next(); - isStatic = true; + if (lookahead.type !== tt.colon && lookahead.type !== tt.question) { + this.next(); + isStatic = true; + } } const variance = this.flowParseVariance(); @@ -999,7 +1037,9 @@ export default (superClass: Class): Class => case tt.relational: if (this.state.value === "<") { - node.typeParameters = this.flowParseTypeParameterDeclaration(); + node.typeParameters = this.flowParseTypeParameterDeclaration( + /* allowDefault */ false, + ); this.expect(tt.parenL); tmp = this.flowParseFunctionTypeParams(); node.params = tmp.params; @@ -1777,7 +1817,9 @@ export default (superClass: Class): Class => } delete (method: $FlowFixMe).variance; if (this.isRelational("<")) { - method.typeParameters = this.flowParseTypeParameterDeclaration(); + method.typeParameters = this.flowParseTypeParameterDeclaration( + /* allowDefault */ false, + ); } super.pushClassMethod( @@ -1858,7 +1900,9 @@ export default (superClass: Class): Class => // method shorthand if (this.isRelational("<")) { - typeParameters = this.flowParseTypeParameterDeclaration(); + typeParameters = this.flowParseTypeParameterDeclaration( + /* allowDefault */ false, + ); if (!this.match(tt.parenL)) this.unexpected(); } @@ -2057,7 +2101,9 @@ export default (superClass: Class): Class => // $FlowFixMe const kind = node.kind; if (kind !== "get" && kind !== "set" && this.isRelational("<")) { - node.typeParameters = this.flowParseTypeParameterDeclaration(); + node.typeParameters = this.flowParseTypeParameterDeclaration( + /* allowDefault */ false, + ); } super.parseFunctionParams(node); } diff --git a/packages/babylon/src/types.js b/packages/babylon/src/types.js index f6557ed942..ee9bd93631 100644 --- a/packages/babylon/src/types.js +++ b/packages/babylon/src/types.js @@ -856,6 +856,7 @@ export type TypeParameterBase = NodeBase & { export type TypeParameter = TypeParameterBase & { type: "TypeParameter", + default?: TypeAnnotation, }; export type TsTypeParameter = TypeParameterBase & { diff --git a/packages/babylon/test/fixtures/flow/type-annotations/function-param-reserved/output.json b/packages/babylon/test/fixtures/flow/type-annotations/function-param-reserved/output.json deleted file mode 100644 index 016fc254c0..0000000000 --- a/packages/babylon/test/fixtures/flow/type-annotations/function-param-reserved/output.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "type": "File", - "start": 0, - "end": 0, - "loc": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 1, - "column": 0 - } - }, - "program": { - "type": "Program", - "start": 0, - "end": 0, - "loc": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 1, - "column": 0 - } - }, - "sourceType": "module", - "body": [], - "directives": [] - } -} \ No newline at end of file diff --git a/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-1/input.js b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-1/input.js new file mode 100644 index 0000000000..e85753f1bf --- /dev/null +++ b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-1/input.js @@ -0,0 +1,3 @@ +(class A { + foo() {} +}); diff --git a/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-1/options.json b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-1/options.json new file mode 100644 index 0000000000..ef2b7c682f --- /dev/null +++ b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-1/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token (2:8)" +} diff --git a/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-2/input.js b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-2/input.js new file mode 100644 index 0000000000..088051643f --- /dev/null +++ b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-2/input.js @@ -0,0 +1 @@ +({ foo() {} }); diff --git a/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-2/options.json b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-2/options.json new file mode 100644 index 0000000000..2a28555f76 --- /dev/null +++ b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-2/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token (1:9)" +} diff --git a/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-3/input.js b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-3/input.js new file mode 100644 index 0000000000..742685c460 --- /dev/null +++ b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-3/input.js @@ -0,0 +1 @@ +declare class A { foo(): void } diff --git a/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-3/options.json b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-3/options.json new file mode 100644 index 0000000000..fa579aa831 --- /dev/null +++ b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-3/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token (1:24)" +} diff --git a/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-4/input.js b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-4/input.js new file mode 100644 index 0000000000..a35315333a --- /dev/null +++ b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-4/input.js @@ -0,0 +1,3 @@ +class A { + foo() {} +} diff --git a/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-4/options.json b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-4/options.json new file mode 100644 index 0000000000..ef2b7c682f --- /dev/null +++ b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-4/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token (2:8)" +} diff --git a/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-5/input.js b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-5/input.js new file mode 100644 index 0000000000..3223246d39 --- /dev/null +++ b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-5/input.js @@ -0,0 +1 @@ +function foo() {} diff --git a/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-5/options.json b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-5/options.json new file mode 100644 index 0000000000..98d7123790 --- /dev/null +++ b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-invalid-5/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token (1:15)" +} diff --git a/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-missing/input.js b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-missing/input.js new file mode 100644 index 0000000000..2096695c1b --- /dev/null +++ b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-missing/input.js @@ -0,0 +1 @@ +type A = T; diff --git a/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-missing/options.json b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-missing/options.json new file mode 100644 index 0000000000..022607b817 --- /dev/null +++ b/packages/babylon/test/fixtures/flow/type-parameter-declaration/default-missing/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Type parameter declaration needs a default, since a preceding type parameter declaration has a default. (1:28)" +} diff --git a/scripts/tests/flow/flow_tests_whitelist.txt b/scripts/tests/flow/flow_tests_whitelist.txt index dbf6781ff4..1475a7fa18 100644 --- a/scripts/tests/flow/flow_tests_whitelist.txt +++ b/scripts/tests/flow/flow_tests_whitelist.txt @@ -28,12 +28,6 @@ types/annotations/migrated_0001.js types/annotations_in_comments_invalid/migrated_0003.js types/annotations/void_is_reserved_param.js types/member/reserved_words.js -types/parameter_defaults/migrated_0023.js -types/parameter_defaults/migrated_0026.js -types/parameter_defaults/migrated_0028.js -types/parameter_defaults/migrated_0029.js -types/parameter_defaults/migrated_0030.js -types/parameter_defaults/migrated_0031.js types/parameter_defaults/migrated_0032.js types/typecasts_invalid/migrated_0001.js class_method_kinds/polymorphic_getter.js