Skip to content

Commit e2915dc

Browse files
authored
feat(core): Support Flow interface declarations
* Add support for interface declarations * Support exported interfaces/type aliases * Update test fixtures * Add interface type, fix test * Fix comment style and typo
1 parent 5fe1859 commit e2915dc

File tree

9 files changed

+364
-34
lines changed

9 files changed

+364
-34
lines changed

declarations/comment.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ declare type Kind = 'class' |
9898
'mixin' |
9999
'module' |
100100
'namespace' |
101-
'typedef';
101+
'typedef' |
102+
'interface';
102103

103104
declare type Comment = {
104105
errors: Array<CommentError>,

lib/infer/augments.js

+32-13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/* @flow */
44

55
var generate = require('babel-generator').default,
6-
findClass = require('./finders').findClass;
6+
findTarget = require('./finders').findTarget;
77

88
/**
99
* Infers an `augments` tag from an ES6 class declaration
@@ -16,18 +16,37 @@ function inferAugments(comment/*: Comment */) {
1616
return comment;
1717
}
1818

19-
var path = findClass(comment.context.ast);
20-
21-
/*
22-
* A superclass can be a single name, like React,
23-
* or a MemberExpression like React.Component,
24-
* so we generate code from the AST rather than assuming
25-
* we can access a name like `path.node.superClass.name`
26-
*/
27-
if (path && path.node.superClass) {
28-
comment.augments.push({
29-
title: 'augments',
30-
name: generate(path.node.superClass).code
19+
var path = findTarget(comment.context.ast);
20+
21+
if (!path) {
22+
return comment;
23+
}
24+
25+
if (path.isClass()) {
26+
/*
27+
* A superclass can be a single name, like React,
28+
* or a MemberExpression like React.Component,
29+
* so we generate code from the AST rather than assuming
30+
* we can access a name like `path.node.superClass.name`
31+
*/
32+
if (path.node.superClass) {
33+
comment.augments.push({
34+
title: 'augments',
35+
name: generate(path.node.superClass).code
36+
});
37+
}
38+
} else if (path.isInterfaceDeclaration()) {
39+
/*
40+
* extends is an array of interface identifiers or
41+
* qualified type identifiers, so we generate code
42+
* from the AST rather than assuming we can acces
43+
* a name.
44+
*/
45+
path.node.extends.forEach(node => {
46+
comment.augments.push({
47+
title: 'extends',
48+
name: generate(node).code
49+
});
3150
});
3251
}
3352

lib/infer/finders.js

-16
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,4 @@ function findTarget(path/*: Object */) {
3838
return path.node && path;
3939
}
4040

41-
/**
42-
* Try to find a JavaScript class that this comment refers to,
43-
* whether an expression in an assignment, or a declaration.
44-
*
45-
* @param {Object} path abstract syntax tree path
46-
* @returns {?Object} ast path, if one is found.
47-
* @private
48-
*/
49-
function findClass(path/*: Object*/) {
50-
var target = findTarget(path);
51-
if (target && (target.isClassDeclaration() || target.isClassExpression())) {
52-
return target;
53-
}
54-
}
55-
5641
module.exports.findTarget = findTarget;
57-
module.exports.findClass = findClass;

lib/infer/kind.js

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ function inferKind(comment/*: Comment*/) {
3232
}
3333
} else if (t.isTypeAlias(node)) {
3434
comment.kind = 'typedef';
35+
} else if (t.isInterfaceDeclaration(node)) {
36+
comment.kind = 'interface';
3537
} else if (t.isVariableDeclaration(node)) {
3638
if (node.kind === 'const') {
3739
comment.kind = 'constant';

lib/infer/properties.js

+10-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
'use strict';
33
/* @flow */
44

5-
var t = require('babel-types'),
6-
flowDoctrine = require('../flow_doctrine');
5+
var flowDoctrine = require('../flow_doctrine'),
6+
findTarget = require('./finders').findTarget;
77

88
function prefixedName(name, prefix) {
99
if (prefix.length) {
@@ -56,8 +56,14 @@ function inferProperties(comment/*: Comment */)/*: Comment */ {
5656
}
5757
}
5858

59-
if (t.isTypeAlias(comment.context.ast)) {
60-
inferProperties(comment.context.ast.node.right, []);
59+
var path = findTarget(comment.context.ast);
60+
61+
if (path) {
62+
if (path.isTypeAlias()) {
63+
inferProperties(path.node.right, []);
64+
} else if (path.isInterfaceDeclaration()) {
65+
inferProperties(path.node.body, []);
66+
}
6167
}
6268

6369
return comment;

test/fixture/interface.input.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* This is my interface.
3+
*/
4+
interface Foo extends Bar, Baz {
5+
prop1: number;
6+
prop2: string;
7+
}

test/fixture/interface.output.json

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
[
2+
{
3+
"description": {
4+
"type": "root",
5+
"children": [
6+
{
7+
"type": "paragraph",
8+
"children": [
9+
{
10+
"type": "text",
11+
"value": "This is my interface.",
12+
"position": {
13+
"start": {
14+
"line": 1,
15+
"column": 1,
16+
"offset": 0
17+
},
18+
"end": {
19+
"line": 1,
20+
"column": 22,
21+
"offset": 21
22+
},
23+
"indent": []
24+
}
25+
}
26+
],
27+
"position": {
28+
"start": {
29+
"line": 1,
30+
"column": 1,
31+
"offset": 0
32+
},
33+
"end": {
34+
"line": 1,
35+
"column": 22,
36+
"offset": 21
37+
},
38+
"indent": []
39+
}
40+
}
41+
],
42+
"position": {
43+
"start": {
44+
"line": 1,
45+
"column": 1,
46+
"offset": 0
47+
},
48+
"end": {
49+
"line": 1,
50+
"column": 22,
51+
"offset": 21
52+
}
53+
}
54+
},
55+
"tags": [],
56+
"loc": {
57+
"start": {
58+
"line": 1,
59+
"column": 0
60+
},
61+
"end": {
62+
"line": 3,
63+
"column": 3
64+
}
65+
},
66+
"context": {
67+
"loc": {
68+
"start": {
69+
"line": 4,
70+
"column": 0
71+
},
72+
"end": {
73+
"line": 7,
74+
"column": 1
75+
}
76+
}
77+
},
78+
"augments": [
79+
{
80+
"title": "extends",
81+
"name": "Bar"
82+
},
83+
{
84+
"title": "extends",
85+
"name": "Baz"
86+
}
87+
],
88+
"errors": [],
89+
"examples": [],
90+
"params": [],
91+
"properties": [
92+
{
93+
"title": "property",
94+
"name": "prop1",
95+
"lineNumber": 5,
96+
"type": {
97+
"type": "NameExpression",
98+
"name": "number"
99+
}
100+
},
101+
{
102+
"title": "property",
103+
"name": "prop2",
104+
"lineNumber": 6,
105+
"type": {
106+
"type": "NameExpression",
107+
"name": "string"
108+
}
109+
}
110+
],
111+
"returns": [],
112+
"sees": [],
113+
"throws": [],
114+
"todos": [],
115+
"name": "Foo",
116+
"kind": "interface",
117+
"members": {
118+
"global": [],
119+
"inner": [],
120+
"instance": [],
121+
"events": [],
122+
"static": []
123+
},
124+
"path": [
125+
{
126+
"name": "Foo",
127+
"kind": "interface"
128+
}
129+
],
130+
"namespace": "Foo"
131+
}
132+
]

test/fixture/interface.output.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
2+
3+
### Table of Contents
4+
5+
- [Foo](#foo)
6+
7+
## Foo
8+
9+
**Extends Bar, Baz**
10+
11+
This is my interface.
12+
13+
**Properties**
14+
15+
- `prop1` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)**
16+
- `prop2` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)**

0 commit comments

Comments
 (0)