From 6baa36cdc50b677af9927a9e2e5004e6944c9ba6 Mon Sep 17 00:00:00 2001 From: Sam Goldman Date: Fri, 18 May 2018 14:11:27 +0100 Subject: [PATCH] Support Flow's inline interface syntax (#7973) * Support Flow's inline interface syntax * Fix babel-generator --- .../babel-generator/src/generators/flow.js | 12 + .../fixtures/flow/interface-types/input.js | 3 + .../fixtures/flow/interface-types/output.js | 9 + packages/babel-types/src/definitions/flow.js | 9 + packages/babylon/src/plugins/flow.js | 20 ++ .../flow/interface-types/basic/input.js | 1 + .../flow/interface-types/basic/output.json | 156 ++++++++++++ .../interface-types/extends-multiple/input.js | 1 + .../extends-multiple/output.json | 223 ++++++++++++++++++ .../flow/interface-types/extends/input.js | 1 + .../flow/interface-types/extends/output.json | 190 +++++++++++++++ 11 files changed, 625 insertions(+) create mode 100644 packages/babel-generator/test/fixtures/flow/interface-types/input.js create mode 100644 packages/babel-generator/test/fixtures/flow/interface-types/output.js create mode 100644 packages/babylon/test/fixtures/flow/interface-types/basic/input.js create mode 100644 packages/babylon/test/fixtures/flow/interface-types/basic/output.json create mode 100644 packages/babylon/test/fixtures/flow/interface-types/extends-multiple/input.js create mode 100644 packages/babylon/test/fixtures/flow/interface-types/extends-multiple/output.json create mode 100644 packages/babylon/test/fixtures/flow/interface-types/extends/input.js create mode 100644 packages/babylon/test/fixtures/flow/interface-types/extends/output.json diff --git a/packages/babel-generator/src/generators/flow.js b/packages/babel-generator/src/generators/flow.js index b37a8dab95..9bf5fd2fd7 100644 --- a/packages/babel-generator/src/generators/flow.js +++ b/packages/babel-generator/src/generators/flow.js @@ -262,6 +262,18 @@ function andSeparator() { this.space(); } +export function InterfaceTypeAnnotation(node: Object) { + this.word("interface"); + if (node.extends && node.extends.length) { + this.space(); + this.word("extends"); + this.space(); + this.printList(node.extends, node); + } + this.space(); + this.print(node.body, node); +} + export function IntersectionTypeAnnotation(node: Object) { this.printJoin(node.types, node, { separator: andSeparator }); } diff --git a/packages/babel-generator/test/fixtures/flow/interface-types/input.js b/packages/babel-generator/test/fixtures/flow/interface-types/input.js new file mode 100644 index 0000000000..e475f614c9 --- /dev/null +++ b/packages/babel-generator/test/fixtures/flow/interface-types/input.js @@ -0,0 +1,3 @@ +type A = interface { p: string }; +type B = interface extends X { p: string }; +type C = interface extends X, Y { p: string }; diff --git a/packages/babel-generator/test/fixtures/flow/interface-types/output.js b/packages/babel-generator/test/fixtures/flow/interface-types/output.js new file mode 100644 index 0000000000..6fa9a97f7a --- /dev/null +++ b/packages/babel-generator/test/fixtures/flow/interface-types/output.js @@ -0,0 +1,9 @@ +type A = interface { + p: string +}; +type B = interface extends X { + p: string +}; +type C = interface extends X, Y { + p: string +}; \ No newline at end of file diff --git a/packages/babel-types/src/definitions/flow.js b/packages/babel-types/src/definitions/flow.js index 28506179e4..622fff3997 100644 --- a/packages/babel-types/src/definitions/flow.js +++ b/packages/babel-types/src/definitions/flow.js @@ -211,6 +211,15 @@ defineType("InterfaceExtends", { defineInterfaceishType("InterfaceDeclaration"); +defineType("InterfaceTypeAnnotation", { + visitor: ["extends", "body"], + aliases: ["Flow", "FlowType"], + fields: { + extends: validateOptional(arrayOfType("InterfaceExtends")), + body: validateType("ObjectTypeAnnotation"), + }, +}); + defineType("IntersectionTypeAnnotation", { visitor: ["types"], aliases: ["Flow", "FlowType"], diff --git a/packages/babylon/src/plugins/flow.js b/packages/babylon/src/plugins/flow.js index 87a738e464..221435cd02 100644 --- a/packages/babylon/src/plugins/flow.js +++ b/packages/babylon/src/plugins/flow.js @@ -641,6 +641,22 @@ export default (superClass: Class): Class => return this.finishNode(node, "TypeParameterInstantiation"); } + flowParseInterfaceType(): N.FlowInterfaceType { + const node = this.startNode(); + this.expectContextual("interface"); + + node.extends = []; + if (this.eat(tt._extends)) { + do { + node.extends.push(this.flowParseInterfaceExtends()); + } while (this.eat(tt.comma)); + } + + node.body = this.flowParseObjectType(true, false, false); + + return this.finishNode(node, "InterfaceTypeAnnotation"); + } + flowParseObjectPropertyKey(): N.Expression { return this.match(tt.num) || this.match(tt.string) ? this.parseExprAtom() @@ -1087,6 +1103,10 @@ export default (superClass: Class): Class => switch (this.state.type) { case tt.name: + if (this.isContextual("interface")) { + return this.flowParseInterfaceType(); + } + return this.flowIdentToTypeAnnotation( startPos, startLoc, diff --git a/packages/babylon/test/fixtures/flow/interface-types/basic/input.js b/packages/babylon/test/fixtures/flow/interface-types/basic/input.js new file mode 100644 index 0000000000..c192a85ff2 --- /dev/null +++ b/packages/babylon/test/fixtures/flow/interface-types/basic/input.js @@ -0,0 +1 @@ +type T = interface { p: string } diff --git a/packages/babylon/test/fixtures/flow/interface-types/basic/output.json b/packages/babylon/test/fixtures/flow/interface-types/basic/output.json new file mode 100644 index 0000000000..899492f04b --- /dev/null +++ b/packages/babylon/test/fixtures/flow/interface-types/basic/output.json @@ -0,0 +1,156 @@ +{ + "type": "File", + "start": 0, + "end": 32, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 32 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 32, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 32 + } + }, + "sourceType": "module", + "body": [ + { + "type": "TypeAlias", + "start": 0, + "end": 32, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 32 + } + }, + "id": { + "type": "Identifier", + "start": 5, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + }, + "identifierName": "T" + }, + "name": "T" + }, + "typeParameters": null, + "right": { + "type": "InterfaceTypeAnnotation", + "start": 9, + "end": 32, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 32 + } + }, + "extends": [], + "body": { + "type": "ObjectTypeAnnotation", + "start": 19, + "end": 32, + "loc": { + "start": { + "line": 1, + "column": 19 + }, + "end": { + "line": 1, + "column": 32 + } + }, + "callProperties": [], + "properties": [ + { + "type": "ObjectTypeProperty", + "start": 21, + "end": 30, + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 30 + } + }, + "key": { + "type": "Identifier", + "start": 21, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 22 + }, + "identifierName": "p" + }, + "name": "p" + }, + "static": false, + "kind": "init", + "method": false, + "value": { + "type": "StringTypeAnnotation", + "start": 24, + "end": 30, + "loc": { + "start": { + "line": 1, + "column": 24 + }, + "end": { + "line": 1, + "column": 30 + } + } + }, + "variance": null, + "optional": false + } + ], + "indexers": [], + "internalSlots": [], + "exact": false + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babylon/test/fixtures/flow/interface-types/extends-multiple/input.js b/packages/babylon/test/fixtures/flow/interface-types/extends-multiple/input.js new file mode 100644 index 0000000000..829a999d88 --- /dev/null +++ b/packages/babylon/test/fixtures/flow/interface-types/extends-multiple/input.js @@ -0,0 +1 @@ +type T = interface extends X, Y { p: string } diff --git a/packages/babylon/test/fixtures/flow/interface-types/extends-multiple/output.json b/packages/babylon/test/fixtures/flow/interface-types/extends-multiple/output.json new file mode 100644 index 0000000000..cc68e03c6b --- /dev/null +++ b/packages/babylon/test/fixtures/flow/interface-types/extends-multiple/output.json @@ -0,0 +1,223 @@ +{ + "type": "File", + "start": 0, + "end": 45, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 45 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 45, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 45 + } + }, + "sourceType": "module", + "body": [ + { + "type": "TypeAlias", + "start": 0, + "end": 45, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 45 + } + }, + "id": { + "type": "Identifier", + "start": 5, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + }, + "identifierName": "T" + }, + "name": "T" + }, + "typeParameters": null, + "right": { + "type": "InterfaceTypeAnnotation", + "start": 9, + "end": 45, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 45 + } + }, + "extends": [ + { + "type": "InterfaceExtends", + "start": 27, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 27 + }, + "end": { + "line": 1, + "column": 28 + } + }, + "id": { + "type": "Identifier", + "start": 27, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 27 + }, + "end": { + "line": 1, + "column": 28 + }, + "identifierName": "X" + }, + "name": "X" + }, + "typeParameters": null + }, + { + "type": "InterfaceExtends", + "start": 30, + "end": 31, + "loc": { + "start": { + "line": 1, + "column": 30 + }, + "end": { + "line": 1, + "column": 31 + } + }, + "id": { + "type": "Identifier", + "start": 30, + "end": 31, + "loc": { + "start": { + "line": 1, + "column": 30 + }, + "end": { + "line": 1, + "column": 31 + }, + "identifierName": "Y" + }, + "name": "Y" + }, + "typeParameters": null + } + ], + "body": { + "type": "ObjectTypeAnnotation", + "start": 32, + "end": 45, + "loc": { + "start": { + "line": 1, + "column": 32 + }, + "end": { + "line": 1, + "column": 45 + } + }, + "callProperties": [], + "properties": [ + { + "type": "ObjectTypeProperty", + "start": 34, + "end": 43, + "loc": { + "start": { + "line": 1, + "column": 34 + }, + "end": { + "line": 1, + "column": 43 + } + }, + "key": { + "type": "Identifier", + "start": 34, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 34 + }, + "end": { + "line": 1, + "column": 35 + }, + "identifierName": "p" + }, + "name": "p" + }, + "static": false, + "kind": "init", + "method": false, + "value": { + "type": "StringTypeAnnotation", + "start": 37, + "end": 43, + "loc": { + "start": { + "line": 1, + "column": 37 + }, + "end": { + "line": 1, + "column": 43 + } + } + }, + "variance": null, + "optional": false + } + ], + "indexers": [], + "internalSlots": [], + "exact": false + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babylon/test/fixtures/flow/interface-types/extends/input.js b/packages/babylon/test/fixtures/flow/interface-types/extends/input.js new file mode 100644 index 0000000000..31c4c29efc --- /dev/null +++ b/packages/babylon/test/fixtures/flow/interface-types/extends/input.js @@ -0,0 +1 @@ +type T = interface extends X { p: string } diff --git a/packages/babylon/test/fixtures/flow/interface-types/extends/output.json b/packages/babylon/test/fixtures/flow/interface-types/extends/output.json new file mode 100644 index 0000000000..a43a1b4118 --- /dev/null +++ b/packages/babylon/test/fixtures/flow/interface-types/extends/output.json @@ -0,0 +1,190 @@ +{ + "type": "File", + "start": 0, + "end": 42, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 42 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 42, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 42 + } + }, + "sourceType": "module", + "body": [ + { + "type": "TypeAlias", + "start": 0, + "end": 42, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 42 + } + }, + "id": { + "type": "Identifier", + "start": 5, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + }, + "identifierName": "T" + }, + "name": "T" + }, + "typeParameters": null, + "right": { + "type": "InterfaceTypeAnnotation", + "start": 9, + "end": 42, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 42 + } + }, + "extends": [ + { + "type": "InterfaceExtends", + "start": 27, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 27 + }, + "end": { + "line": 1, + "column": 28 + } + }, + "id": { + "type": "Identifier", + "start": 27, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 27 + }, + "end": { + "line": 1, + "column": 28 + }, + "identifierName": "X" + }, + "name": "X" + }, + "typeParameters": null + } + ], + "body": { + "type": "ObjectTypeAnnotation", + "start": 29, + "end": 42, + "loc": { + "start": { + "line": 1, + "column": 29 + }, + "end": { + "line": 1, + "column": 42 + } + }, + "callProperties": [], + "properties": [ + { + "type": "ObjectTypeProperty", + "start": 31, + "end": 40, + "loc": { + "start": { + "line": 1, + "column": 31 + }, + "end": { + "line": 1, + "column": 40 + } + }, + "key": { + "type": "Identifier", + "start": 31, + "end": 32, + "loc": { + "start": { + "line": 1, + "column": 31 + }, + "end": { + "line": 1, + "column": 32 + }, + "identifierName": "p" + }, + "name": "p" + }, + "static": false, + "kind": "init", + "method": false, + "value": { + "type": "StringTypeAnnotation", + "start": 34, + "end": 40, + "loc": { + "start": { + "line": 1, + "column": 34 + }, + "end": { + "line": 1, + "column": 40 + } + } + }, + "variance": null, + "optional": false + } + ], + "indexers": [], + "internalSlots": [], + "exact": false + } + } + } + ], + "directives": [] + } +} \ No newline at end of file