From 4716a61416b41eee7193bbd8224f9e7a5227d0ac Mon Sep 17 00:00:00 2001 From: Erik Arvidsson Date: Wed, 14 Sep 2016 20:04:53 -0700 Subject: [PATCH] Infer optional record fields in object types This is done with Doctrine's OptionalType, which Doctrine is only using for parameter types as of now. Towards #512 --- lib/flow_doctrine.js | 13 +- lib/infer/properties.js | 9 +- .../optional-record-field-type.input.js | 5 + .../optional-record-field-type.output.json | 89 +++++++++++++ .../optional-record-field-type.output.md | 8 ++ .../optional-record-field-type.output.md.json | 118 ++++++++++++++++++ 6 files changed, 240 insertions(+), 2 deletions(-) create mode 100644 test/fixture/optional-record-field-type.input.js create mode 100644 test/fixture/optional-record-field-type.output.json create mode 100644 test/fixture/optional-record-field-type.output.md create mode 100644 test/fixture/optional-record-field-type.output.md.json diff --git a/lib/flow_doctrine.js b/lib/flow_doctrine.js index 923dd4547..6300be392 100644 --- a/lib/flow_doctrine.js +++ b/lib/flow_doctrine.js @@ -1,3 +1,5 @@ +'use strict'; + var namedTypes = { 'NumberTypeAnnotation': 'number', 'BooleanTypeAnnotation': 'boolean', @@ -18,10 +20,19 @@ var literalTypes = { }; function propertyToField(property) { + var type = flowDoctrine(property.value); + if (property.optional) { + // Doctrine does not support optional fields but it does have something called optional types + // (which makes no sense, but let's play along). + type = { + type: 'OptionalType', + expression: type + }; + } return { type: 'FieldType', key: property.key.name, - value: flowDoctrine(property.value) + value: type }; } diff --git a/lib/infer/properties.js b/lib/infer/properties.js index b53212b47..a5c16f72a 100644 --- a/lib/infer/properties.js +++ b/lib/infer/properties.js @@ -21,11 +21,18 @@ function inferProperties() { } function propertyToDoc(property, prefix) { + var type = flowDoctrine(property.value); + if (property.optional) { + type = { + type: 'OptionalType', + expression: type + }; + } var newProperty = { title: 'property', name: prefixedName(property.key.name, prefix), lineNumber: property.loc.start.line, - type: flowDoctrine(property.value) + type: type }; return newProperty; } diff --git a/test/fixture/optional-record-field-type.input.js b/test/fixture/optional-record-field-type.input.js new file mode 100644 index 000000000..cc1893e21 --- /dev/null +++ b/test/fixture/optional-record-field-type.input.js @@ -0,0 +1,5 @@ +/** */ +type Record = { + opt?: number, + req: string, +}; diff --git a/test/fixture/optional-record-field-type.output.json b/test/fixture/optional-record-field-type.output.json new file mode 100644 index 000000000..7f75271c2 --- /dev/null +++ b/test/fixture/optional-record-field-type.output.json @@ -0,0 +1,89 @@ +[ + { + "description": "", + "tags": [], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "context": { + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 5, + "column": 2 + } + } + }, + "errors": [], + "name": "Record", + "kind": "typedef", + "properties": [ + { + "title": "property", + "name": "opt", + "lineNumber": 3, + "type": { + "type": "OptionalType", + "expression": { + "type": "NameExpression", + "name": "number" + } + } + }, + { + "title": "property", + "name": "req", + "lineNumber": 4, + "type": { + "type": "NameExpression", + "name": "string" + } + } + ], + "type": { + "type": "RecordType", + "fields": [ + { + "type": "FieldType", + "key": "opt", + "value": { + "type": "OptionalType", + "expression": { + "type": "NameExpression", + "name": "number" + } + } + }, + { + "type": "FieldType", + "key": "req", + "value": { + "type": "NameExpression", + "name": "string" + } + } + ] + }, + "members": { + "instance": [], + "static": [] + }, + "path": [ + { + "name": "Record", + "kind": "typedef" + } + ], + "namespace": "Record" + } +] \ No newline at end of file diff --git a/test/fixture/optional-record-field-type.output.md b/test/fixture/optional-record-field-type.output.md new file mode 100644 index 000000000..da72f3c22 --- /dev/null +++ b/test/fixture/optional-record-field-type.output.md @@ -0,0 +1,8 @@ + + +# Record + +**Properties** + +- `opt` **\[[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** +- `req` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** diff --git a/test/fixture/optional-record-field-type.output.md.json b/test/fixture/optional-record-field-type.output.md.json new file mode 100644 index 000000000..167b8a1f4 --- /dev/null +++ b/test/fixture/optional-record-field-type.output.md.json @@ -0,0 +1,118 @@ +{ + "type": "root", + "children": [ + { + "type": "html", + "value": "" + }, + { + "depth": 1, + "type": "heading", + "children": [ + { + "type": "text", + "value": "Record" + } + ] + }, + { + "type": "strong", + "children": [ + { + "type": "text", + "value": "Properties" + } + ] + }, + { + "ordered": false, + "type": "list", + "children": [ + { + "type": "listItem", + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "inlineCode", + "value": "opt" + }, + { + "type": "text", + "value": " " + }, + { + "type": "strong", + "children": [ + { + "type": "text", + "value": "[" + }, + { + "href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number", + "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number", + "type": "link", + "children": [ + { + "type": "text", + "value": "number" + } + ] + }, + { + "type": "text", + "value": "]" + } + ] + }, + { + "type": "text", + "value": " " + } + ] + } + ] + }, + { + "type": "listItem", + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "inlineCode", + "value": "req" + }, + { + "type": "text", + "value": " " + }, + { + "type": "strong", + "children": [ + { + "href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String", + "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String", + "type": "link", + "children": [ + { + "type": "text", + "value": "string" + } + ] + } + ] + }, + { + "type": "text", + "value": " " + } + ] + } + ] + } + ] + } + ] +} \ No newline at end of file