diff --git a/packages/babel-generator/src/generators/types.js b/packages/babel-generator/src/generators/types.js index aed1c3f35c..6ca86a74e1 100644 --- a/packages/babel-generator/src/generators/types.js +++ b/packages/babel-generator/src/generators/types.js @@ -4,6 +4,16 @@ import * as t from "babel-types"; export function Identifier(node: Object) { + // FIXME: We hang variance off Identifer to support Flow's def-site variance. + // This is a terrible hack, but changing type annotations to use a new, + // dedicated node would be a breaking change. This should be cleaned up in + // the next major. + if (node.variance === "plus") { + this.push("+"); + } else if (node.variance === "minus") { + this.push("-"); + } + this.push(node.name); } diff --git a/packages/babel-generator/test/fixtures/flow/def-site-variance/actual.js b/packages/babel-generator/test/fixtures/flow/def-site-variance/actual.js new file mode 100644 index 0000000000..f046505722 --- /dev/null +++ b/packages/babel-generator/test/fixtures/flow/def-site-variance/actual.js @@ -0,0 +1,3 @@ +class C<+T, -U> {} +function f<+T, -U>() {} +type T<+T, -U> = {}; diff --git a/packages/babel-generator/test/fixtures/flow/def-site-variance/expected.js b/packages/babel-generator/test/fixtures/flow/def-site-variance/expected.js new file mode 100644 index 0000000000..f046505722 --- /dev/null +++ b/packages/babel-generator/test/fixtures/flow/def-site-variance/expected.js @@ -0,0 +1,3 @@ +class C<+T, -U> {} +function f<+T, -U>() {} +type T<+T, -U> = {}; diff --git a/packages/babel-plugin-transform-flow-comments/test/fixtures/flow-comments/def-site-variance/actual.js b/packages/babel-plugin-transform-flow-comments/test/fixtures/flow-comments/def-site-variance/actual.js new file mode 100644 index 0000000000..f046505722 --- /dev/null +++ b/packages/babel-plugin-transform-flow-comments/test/fixtures/flow-comments/def-site-variance/actual.js @@ -0,0 +1,3 @@ +class C<+T, -U> {} +function f<+T, -U>() {} +type T<+T, -U> = {}; diff --git a/packages/babel-plugin-transform-flow-comments/test/fixtures/flow-comments/def-site-variance/expected.js b/packages/babel-plugin-transform-flow-comments/test/fixtures/flow-comments/def-site-variance/expected.js new file mode 100644 index 0000000000..195209568b --- /dev/null +++ b/packages/babel-plugin-transform-flow-comments/test/fixtures/flow-comments/def-site-variance/expected.js @@ -0,0 +1,3 @@ +class C /*:: <+T, -U>*/ {} +function f /*:: <+T, -U>*/() {} +/*:: type T<+T, -U> = {};*/ diff --git a/packages/babel-plugin-transform-flow-strip-types/test/fixtures/strip-types/def-site-variance/actual.js b/packages/babel-plugin-transform-flow-strip-types/test/fixtures/strip-types/def-site-variance/actual.js new file mode 100644 index 0000000000..f046505722 --- /dev/null +++ b/packages/babel-plugin-transform-flow-strip-types/test/fixtures/strip-types/def-site-variance/actual.js @@ -0,0 +1,3 @@ +class C<+T, -U> {} +function f<+T, -U>() {} +type T<+T, -U> = {}; diff --git a/packages/babel-plugin-transform-flow-strip-types/test/fixtures/strip-types/def-site-variance/expected.js b/packages/babel-plugin-transform-flow-strip-types/test/fixtures/strip-types/def-site-variance/expected.js new file mode 100644 index 0000000000..9eb99a782f --- /dev/null +++ b/packages/babel-plugin-transform-flow-strip-types/test/fixtures/strip-types/def-site-variance/expected.js @@ -0,0 +1,2 @@ +class C {} +function f() {} diff --git a/packages/babylon/src/plugins/flow.js b/packages/babylon/src/plugins/flow.js index f856955176..3ecaeb84e2 100644 --- a/packages/babylon/src/plugins/flow.js +++ b/packages/babylon/src/plugins/flow.js @@ -624,9 +624,23 @@ pp.flowParseTypeAnnotation = function () { }; pp.flowParseTypeAnnotatableIdentifier = function (requireTypeAnnotation, canBeOptionalParam) { + let variance; + if (this.match(tt.plusMin)) { + if (this.state.value === "+") { + variance = "plus"; + } else if (this.state.value === "-") { + variance = "minus"; + } + this.eat(tt.plusMin); + } + let ident = this.parseIdentifier(); let isOptionalParam = false; + if (variance) { + ident.variance = variance; + } + if (canBeOptionalParam && this.eat(tt.question)) { this.expect(tt.question); isOptionalParam = true; diff --git a/packages/babylon/test/fixtures/flow/def-site-variance/1/actual.js b/packages/babylon/test/fixtures/flow/def-site-variance/1/actual.js new file mode 100644 index 0000000000..5eb19f458a --- /dev/null +++ b/packages/babylon/test/fixtures/flow/def-site-variance/1/actual.js @@ -0,0 +1,3 @@ +class C<+T,-U> {} +function f<+T,-U>() {} +type T<+T,-U> = {} diff --git a/packages/babylon/test/fixtures/flow/def-site-variance/1/expected.json b/packages/babylon/test/fixtures/flow/def-site-variance/1/expected.json new file mode 100644 index 0000000000..b42edfb108 --- /dev/null +++ b/packages/babylon/test/fixtures/flow/def-site-variance/1/expected.json @@ -0,0 +1,336 @@ +{ + "type": "File", + "start": 0, + "end": 59, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 18 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 59, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 18 + } + }, + "sourceType": "module", + "body": [ + { + "type": "ClassDeclaration", + "start": 0, + "end": 17, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 17 + } + }, + "id": { + "type": "Identifier", + "start": 6, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + } + }, + "name": "C" + }, + "typeParameters": { + "type": "TypeParameterDeclaration", + "start": 7, + "end": 14, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 14 + } + }, + "params": [ + { + "type": "Identifier", + "start": 9, + "end": 10, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "name": "T", + "variance": "plus" + }, + { + "type": "Identifier", + "start": 12, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 13 + } + }, + "name": "U", + "variance": "minus" + } + ] + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 15, + "end": 17, + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 1, + "column": 17 + } + }, + "body": [] + } + }, + { + "type": "FunctionDeclaration", + "start": 18, + "end": 40, + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 22 + } + }, + "id": { + "type": "Identifier", + "start": 27, + "end": 28, + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 10 + } + }, + "name": "f" + }, + "generator": false, + "expression": false, + "async": false, + "typeParameters": { + "type": "TypeParameterDeclaration", + "start": 28, + "end": 35, + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 2, + "column": 17 + } + }, + "params": [ + { + "type": "Identifier", + "start": 30, + "end": 31, + "loc": { + "start": { + "line": 2, + "column": 12 + }, + "end": { + "line": 2, + "column": 13 + } + }, + "name": "T", + "variance": "plus" + }, + { + "type": "Identifier", + "start": 33, + "end": 34, + "loc": { + "start": { + "line": 2, + "column": 15 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "name": "U", + "variance": "minus" + } + ] + }, + "params": [], + "body": { + "type": "BlockStatement", + "start": 38, + "end": 40, + "loc": { + "start": { + "line": 2, + "column": 20 + }, + "end": { + "line": 2, + "column": 22 + } + }, + "body": [], + "directives": [] + } + }, + { + "type": "TypeAlias", + "start": 41, + "end": 59, + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 18 + } + }, + "id": { + "type": "Identifier", + "start": 46, + "end": 47, + "loc": { + "start": { + "line": 3, + "column": 5 + }, + "end": { + "line": 3, + "column": 6 + } + }, + "name": "T" + }, + "typeParameters": { + "type": "TypeParameterDeclaration", + "start": 47, + "end": 54, + "loc": { + "start": { + "line": 3, + "column": 6 + }, + "end": { + "line": 3, + "column": 13 + } + }, + "params": [ + { + "type": "Identifier", + "start": 49, + "end": 50, + "loc": { + "start": { + "line": 3, + "column": 8 + }, + "end": { + "line": 3, + "column": 9 + } + }, + "name": "T", + "variance": "plus" + }, + { + "type": "Identifier", + "start": 52, + "end": 53, + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 3, + "column": 12 + } + }, + "name": "U", + "variance": "minus" + } + ] + }, + "right": { + "type": "ObjectTypeAnnotation", + "start": 57, + "end": 59, + "loc": { + "start": { + "line": 3, + "column": 16 + }, + "end": { + "line": 3, + "column": 18 + } + }, + "callProperties": [], + "properties": [], + "indexers": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file