From af7ab71486ad42fc0471ea92693ac53360517a90 Mon Sep 17 00:00:00 2001 From: Sam Goldman Date: Thu, 17 May 2018 18:01:03 +0100 Subject: [PATCH] Allow flow internal slot properties to be optional (#7959) See https://github.com/facebook/flow/commit/23d1b1c5f21d45d5d8c61e4acc26f3f158254f21 --- .../babel-generator/src/generators/flow.js | 1 + .../test/fixtures/flow/internal-slot/input.js | 1 + .../fixtures/flow/internal-slot/output.js | 5 +- packages/babel-types/src/definitions/flow.js | 3 +- packages/babylon/src/plugins/flow.js | 4 + .../interface-method/output.json | 1 + .../internal-slot/object-method/output.json | 1 + .../internal-slot/object-optional/input.js | 1 + .../internal-slot/object-optional/output.json | 156 ++++++++++++++++++ 9 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 packages/babylon/test/fixtures/flow/internal-slot/object-optional/input.js create mode 100644 packages/babylon/test/fixtures/flow/internal-slot/object-optional/output.json diff --git a/packages/babel-generator/src/generators/flow.js b/packages/babel-generator/src/generators/flow.js index 2aa5acb939..b37a8dab95 100644 --- a/packages/babel-generator/src/generators/flow.js +++ b/packages/babel-generator/src/generators/flow.js @@ -424,6 +424,7 @@ export function ObjectTypeInternalSlot(node: Object) { this.print(node.id, node); this.token("]"); this.token("]"); + if (node.optional) this.token("?"); if (!node.method) { this.token(":"); this.space(); diff --git a/packages/babel-generator/test/fixtures/flow/internal-slot/input.js b/packages/babel-generator/test/fixtures/flow/internal-slot/input.js index e26a0046be..7888fc6cb4 100644 --- a/packages/babel-generator/test/fixtures/flow/internal-slot/input.js +++ b/packages/babel-generator/test/fixtures/flow/internal-slot/input.js @@ -4,3 +4,4 @@ interface T { [[foo]]: X } interface T { [[foo]](): X } type T = { [[foo]]: X } type T = { [[foo]](): X } +type T = { [[foo]]?: X } diff --git a/packages/babel-generator/test/fixtures/flow/internal-slot/output.js b/packages/babel-generator/test/fixtures/flow/internal-slot/output.js index 61a87ea113..a8c375a2c4 100644 --- a/packages/babel-generator/test/fixtures/flow/internal-slot/output.js +++ b/packages/babel-generator/test/fixtures/flow/internal-slot/output.js @@ -15,4 +15,7 @@ type T = { }; type T = { [[foo]]() => X -}; \ No newline at end of file +}; +type T = { + [[foo]]?: X +}; diff --git a/packages/babel-types/src/definitions/flow.js b/packages/babel-types/src/definitions/flow.js index caf33c2c9e..28506179e4 100644 --- a/packages/babel-types/src/definitions/flow.js +++ b/packages/babel-types/src/definitions/flow.js @@ -272,11 +272,12 @@ defineType("ObjectTypeAnnotation", { }); defineType("ObjectTypeInternalSlot", { - visitor: ["id", "value", "static", "method"], + visitor: ["id", "value", "optional", "static", "method"], aliases: ["Flow", "UserWhitespacable"], fields: { id: validateType("Identifier"), value: validateType("FlowType"), + optional: validate(assertValueType("boolean")), static: validate(assertValueType("boolean")), method: validate(assertValueType("boolean")), }, diff --git a/packages/babylon/src/plugins/flow.js b/packages/babylon/src/plugins/flow.js index ddc81e9484..7dba4ca5e0 100644 --- a/packages/babylon/src/plugins/flow.js +++ b/packages/babylon/src/plugins/flow.js @@ -647,11 +647,15 @@ export default (superClass: Class): Class => this.expect(tt.bracketR); if (this.isRelational("<") || this.match(tt.parenL)) { node.method = true; + node.optional = false; node.value = this.flowParseObjectTypeMethodish( this.startNodeAt(node.start, node.loc.start), ); } else { node.method = false; + if (this.eat(tt.question)) { + node.optional = true; + } node.value = this.flowParseTypeInitialiser(); } return this.finishNode(node, "ObjectTypeInternalSlot"); diff --git a/packages/babylon/test/fixtures/flow/internal-slot/interface-method/output.json b/packages/babylon/test/fixtures/flow/internal-slot/interface-method/output.json index 83ec869b9a..27b7d05a11 100644 --- a/packages/babylon/test/fixtures/flow/internal-slot/interface-method/output.json +++ b/packages/babylon/test/fixtures/flow/internal-slot/interface-method/output.json @@ -114,6 +114,7 @@ "name": "foo" }, "method": true, + "optional": false, "value": { "type": "FunctionTypeAnnotation", "start": 14, diff --git a/packages/babylon/test/fixtures/flow/internal-slot/object-method/output.json b/packages/babylon/test/fixtures/flow/internal-slot/object-method/output.json index a27cbbf6a2..3bbae52e07 100644 --- a/packages/babylon/test/fixtures/flow/internal-slot/object-method/output.json +++ b/packages/babylon/test/fixtures/flow/internal-slot/object-method/output.json @@ -111,6 +111,7 @@ "name": "foo" }, "method": true, + "optional": false, "value": { "type": "FunctionTypeAnnotation", "start": 11, diff --git a/packages/babylon/test/fixtures/flow/internal-slot/object-optional/input.js b/packages/babylon/test/fixtures/flow/internal-slot/object-optional/input.js new file mode 100644 index 0000000000..a3361be9ee --- /dev/null +++ b/packages/babylon/test/fixtures/flow/internal-slot/object-optional/input.js @@ -0,0 +1 @@ +type T = { [[foo]]?: X } diff --git a/packages/babylon/test/fixtures/flow/internal-slot/object-optional/output.json b/packages/babylon/test/fixtures/flow/internal-slot/object-optional/output.json new file mode 100644 index 0000000000..0e80d30f5d --- /dev/null +++ b/packages/babylon/test/fixtures/flow/internal-slot/object-optional/output.json @@ -0,0 +1,156 @@ +{ + "type": "File", + "start": 0, + "end": 24, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 24 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 24, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 24 + } + }, + "sourceType": "module", + "body": [ + { + "type": "TypeAlias", + "start": 0, + "end": 24, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 24 + } + }, + "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": "ObjectTypeAnnotation", + "start": 9, + "end": 24, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 24 + } + }, + "callProperties": [], + "properties": [], + "indexers": [], + "internalSlots": [ + { + "type": "ObjectTypeInternalSlot", + "start": 11, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 22 + } + }, + "static": false, + "id": { + "type": "Identifier", + "start": 13, + "end": 16, + "loc": { + "start": { + "line": 1, + "column": 13 + }, + "end": { + "line": 1, + "column": 16 + }, + "identifierName": "foo" + }, + "name": "foo" + }, + "method": false, + "optional": true, + "value": { + "type": "GenericTypeAnnotation", + "start": 21, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 22 + } + }, + "typeParameters": null, + "id": { + "type": "Identifier", + "start": 21, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 22 + }, + "identifierName": "X" + }, + "name": "X" + } + } + } + ], + "exact": false + } + } + ], + "directives": [] + } +} \ No newline at end of file