Skip to content

Commit 70cc7d0

Browse files
committed
Infer Flow type aliases into typedefs. Fixes #227
Given the `type` tag introduced with Flow, this can infer a typedef statement, as well as infer its potentially nested properties and their types. This also includes * Refactor of Markdown AST generation that fixes #228 * Refactor of nest.js to handle multi-level nesting
1 parent 88bc96d commit 70cc7d0

File tree

99 files changed

+2059
-2206
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+2059
-2206
lines changed

index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ var sort = require('./lib/sort'),
1313
inferName = require('./lib/infer/name'),
1414
inferKind = require('./lib/infer/kind'),
1515
inferParams = require('./lib/infer/params'),
16+
inferProperties = require('./lib/infer/properties'),
1617
inferMembership = require('./lib/infer/membership'),
1718
inferReturn = require('./lib/infer/return'),
1819
lint = require('./lib/lint');
@@ -96,6 +97,7 @@ module.exports = function (indexes, options, callback) {
9697
inferName(),
9798
inferKind(),
9899
inferParams(),
100+
inferProperties(),
99101
inferReturn(),
100102
inferMembership(),
101103
nest,

lib/flow_doctrine.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
var namedTypes = {
22
'NumberTypeAnnotation': 'number',
33
'BooleanTypeAnnotation': 'boolean',
4+
'ObjectTypeAnnotation': 'Object',
45
'StringTypeAnnotation': 'string'
56
};
67

lib/infer/kind.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ module.exports = function () {
4141
this.abort();
4242
}
4343
},
44-
44+
visitTypeAlias: function () {
45+
comment.kind = 'typedef';
46+
this.abort();
47+
},
4548
visitVariableDeclaration: function (path) {
4649
if (path.value.kind === 'const') {
4750
comment.kind = 'constant';

lib/infer/properties.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
'use strict';
2+
3+
var types = require('ast-types'),
4+
flowDoctrine = require('../flow_doctrine');
5+
6+
7+
/**
8+
* Infers param tags by reading function parameter names
9+
*
10+
* @name inferParams
11+
* @param {Object} comment parsed comment
12+
* @returns {Object} comment with parameters
13+
*/
14+
module.exports = function () {
15+
16+
function prefixedName(name, prefix) {
17+
if (prefix.length) {
18+
return prefix.join('.') + '.' + name;
19+
}
20+
return name;
21+
}
22+
23+
function propertyToDoc(property, prefix) {
24+
var newProperty = {
25+
title: 'property',
26+
name: prefixedName(property.key.name, prefix),
27+
lineNumber: property.loc.start.line,
28+
type: flowDoctrine(property.value)
29+
};
30+
return newProperty;
31+
}
32+
33+
return function inferProperties(comment) {
34+
35+
36+
// Ensure that explicitly specified properties are not overridden
37+
// by inferred properties
38+
var explicitProperties = (comment.properties || []).reduce(function (memo, property) {
39+
memo[property.name] = true;
40+
return memo;
41+
}, {});
42+
43+
function inferProperties(value, prefix) {
44+
if (value.type === 'ObjectTypeAnnotation') {
45+
value.properties.forEach(function (property) {
46+
if (explicitProperties[prefixedName(property.key.name, prefix)] === undefined) {
47+
if (!comment.properties) {
48+
comment.properties = [];
49+
}
50+
comment.properties = comment.properties.concat(propertyToDoc(property, prefix));
51+
// Nested type parameters
52+
if (property.value.type === 'ObjectTypeAnnotation') {
53+
inferProperties(property.value, prefix.concat(property.key.name));
54+
}
55+
}
56+
});
57+
}
58+
}
59+
60+
types.visit(comment.context.ast, {
61+
visitTypeAlias: function (path) {
62+
inferProperties(path.value.right, []);
63+
this.abort();
64+
}
65+
});
66+
67+
return comment;
68+
};
69+
};

lib/nest.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ function nestTag(comment, tagName, target) {
1010

1111
comment[target].forEach(function (tag) {
1212
index[tag.name] = tag;
13-
var parts = tag.name.split(/(\[\])?\./);
13+
var parts = tag.name.split(/(\[\])?\./)
14+
.filter(function (part) {
15+
return part && part !== '[]';
16+
});
1417
if (parts.length > 1) {
15-
var parent = index[parts[0]];
18+
var parent = index[parts.slice(0, -1).join('.')];
1619
if (parent === undefined) {
1720
comment.errors.push({
1821
message: '@' + tagName + ' ' + tag.name + '\'s parent ' + parts[0] + ' not found',

lib/output/markdown_ast.js

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,17 @@ function commentsToAST(comments, opts, callback) {
3131
u('inlineCode', param.name),
3232
u('text', ' '),
3333
!!param.type && u('strong', [u('text', formatType(param.type))]),
34-
u('text', ' '),
35-
mdast.parse(formatInlineTags(param.description)),
34+
u('text', ' ')
35+
].concat(mdast.parse(formatInlineTags(param.description)).children)
36+
.concat([
3637
!!param.default && u('paragraph', [
3738
u('text', ' (optional, default '),
3839
u('inlineCode', param.default),
3940
u('text', ')')
40-
]),
41-
param.properties && paramList(param.properties)
42-
].filter(Boolean))
43-
]);
41+
])
42+
]).filter(Boolean))
43+
].concat(param.properties && paramList(param.properties))
44+
.filter(Boolean));
4445
}));
4546
}
4647

@@ -65,10 +66,11 @@ function commentsToAST(comments, opts, callback) {
6566
u('paragraph', [
6667
u('inlineCode', property.name),
6768
u('text', ' '),
68-
u('text', [u('text', formatType(property.type))]),
69-
u('text', ' '),
70-
mdast.parse(formatInlineTags(property.description))
71-
]),
69+
u('strong', [u('text', formatType(property.type))]),
70+
u('text', ' ')
71+
]
72+
.concat(mdast.parse(formatInlineTags(property.description)).children)
73+
.filter(Boolean)),
7274
property.properties && propertyList(property.properties)
7375
].filter(Boolean))
7476
}));
@@ -86,14 +88,13 @@ function commentsToAST(comments, opts, callback) {
8688
return u('paragraph', [
8789
u('text', 'Returns '),
8890
u('strong', [u('text', formatType(returns.type))]),
89-
u('text', ' '),
90-
mdast.parse(formatInlineTags(returns.description))
91-
]);
91+
u('text', ' ')
92+
].concat(mdast.parse(formatInlineTags(returns.description)).children))
9293
});
9394
}
9495

9596
return [u('heading', { depth: depth }, [u('text', comment.name)])]
96-
.concat(mdast.parse(formatInlineTags(comment.description)).children[0])
97+
.concat(mdast.parse(formatInlineTags(comment.description)).children)
9798
.concat(paramSection(comment))
9899
.concat(propertySection(comment))
99100
.concat(examplesSection(comment))

test/fixture/class.output.custom.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ This is my class, a demo thing.
44

55
**Properties**
66

7-
- `howMany` how many things it contains
8-
7+
- `howMany` **number** how many things it contains
98

109
## getFoo
1110

@@ -15,13 +14,10 @@ Get the number 42
1514

1615
- `getIt` **boolean** whether to get the number
1716

18-
1917
Returns **number** forty-two
2018

21-
2219
## getUndefined
2320

2421
Get undefined
2522

2623
Returns **undefined** does not return anything.
27-

test/fixture/class.output.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ This is my class, a demo thing.
44

55
**Properties**
66

7-
- `howMany` how many things it contains
8-
7+
- `howMany` **number** how many things it contains
98

109
## getFoo
1110

@@ -15,13 +14,10 @@ Get the number 42
1514

1615
- `getIt` **boolean** whether to get the number
1716

18-
1917
Returns **number** forty-two
2018

21-
2219
## getUndefined
2320

2421
Get undefined
2522

2623
Returns **undefined** does not return anything.
27-

test/fixture/class.output.md.json

Lines changed: 21 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
"value": " "
7171
},
7272
{
73-
"type": "text",
73+
"type": "strong",
7474
"children": [
7575
{
7676
"type": "text",
@@ -83,27 +83,11 @@
8383
"value": " "
8484
},
8585
{
86-
"type": "root",
86+
"type": "paragraph",
8787
"children": [
8888
{
89-
"type": "paragraph",
90-
"children": [
91-
{
92-
"type": "text",
93-
"value": "how many things it contains",
94-
"position": {
95-
"start": {
96-
"line": 1,
97-
"column": 1
98-
},
99-
"end": {
100-
"line": 1,
101-
"column": 28
102-
},
103-
"indent": []
104-
}
105-
}
106-
],
89+
"type": "text",
90+
"value": "how many things it contains",
10791
"position": {
10892
"start": {
10993
"line": 1,
@@ -125,7 +109,8 @@
125109
"end": {
126110
"line": 1,
127111
"column": 28
128-
}
112+
},
113+
"indent": []
129114
}
130115
}
131116
]
@@ -216,27 +201,11 @@
216201
"value": " "
217202
},
218203
{
219-
"type": "root",
204+
"type": "paragraph",
220205
"children": [
221206
{
222-
"type": "paragraph",
223-
"children": [
224-
{
225-
"type": "text",
226-
"value": "whether to get the number",
227-
"position": {
228-
"start": {
229-
"line": 1,
230-
"column": 1
231-
},
232-
"end": {
233-
"line": 1,
234-
"column": 26
235-
},
236-
"indent": []
237-
}
238-
}
239-
],
207+
"type": "text",
208+
"value": "whether to get the number",
240209
"position": {
241210
"start": {
242211
"line": 1,
@@ -258,7 +227,8 @@
258227
"end": {
259228
"line": 1,
260229
"column": 26
261-
}
230+
},
231+
"indent": []
262232
}
263233
}
264234
]
@@ -288,27 +258,11 @@
288258
"value": " "
289259
},
290260
{
291-
"type": "root",
261+
"type": "paragraph",
292262
"children": [
293263
{
294-
"type": "paragraph",
295-
"children": [
296-
{
297-
"type": "text",
298-
"value": "forty-two",
299-
"position": {
300-
"start": {
301-
"line": 1,
302-
"column": 1
303-
},
304-
"end": {
305-
"line": 1,
306-
"column": 10
307-
},
308-
"indent": []
309-
}
310-
}
311-
],
264+
"type": "text",
265+
"value": "forty-two",
312266
"position": {
313267
"start": {
314268
"line": 1,
@@ -330,7 +284,8 @@
330284
"end": {
331285
"line": 1,
332286
"column": 10
333-
}
287+
},
288+
"indent": []
334289
}
335290
}
336291
]
@@ -397,27 +352,11 @@
397352
"value": " "
398353
},
399354
{
400-
"type": "root",
355+
"type": "paragraph",
401356
"children": [
402357
{
403-
"type": "paragraph",
404-
"children": [
405-
{
406-
"type": "text",
407-
"value": "does not return anything.",
408-
"position": {
409-
"start": {
410-
"line": 1,
411-
"column": 1
412-
},
413-
"end": {
414-
"line": 1,
415-
"column": 26
416-
},
417-
"indent": []
418-
}
419-
}
420-
],
358+
"type": "text",
359+
"value": "does not return anything.",
421360
"position": {
422361
"start": {
423362
"line": 1,
@@ -439,7 +378,8 @@
439378
"end": {
440379
"line": 1,
441380
"column": 26
442-
}
381+
},
382+
"indent": []
443383
}
444384
}
445385
]

0 commit comments

Comments
 (0)