Skip to content

Commit

Permalink
feat(core): Support Flow interface declarations
Browse files Browse the repository at this point in the history
* Add support for interface declarations

* Support exported interfaces/type aliases

* Update test fixtures

* Add interface type, fix test

* Fix comment style and typo
  • Loading branch information
tmcw authored Apr 10, 2017
1 parent 5fe1859 commit e2915dc
Show file tree
Hide file tree
Showing 9 changed files with 364 additions and 34 deletions.
3 changes: 2 additions & 1 deletion declarations/comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ declare type Kind = 'class' |
'mixin' |
'module' |
'namespace' |
'typedef';
'typedef' |
'interface';

declare type Comment = {
errors: Array<CommentError>,
Expand Down
45 changes: 32 additions & 13 deletions lib/infer/augments.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/* @flow */

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

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

var path = findClass(comment.context.ast);

/*
* A superclass can be a single name, like React,
* or a MemberExpression like React.Component,
* so we generate code from the AST rather than assuming
* we can access a name like `path.node.superClass.name`
*/
if (path && path.node.superClass) {
comment.augments.push({
title: 'augments',
name: generate(path.node.superClass).code
var path = findTarget(comment.context.ast);

if (!path) {
return comment;
}

if (path.isClass()) {
/*
* A superclass can be a single name, like React,
* or a MemberExpression like React.Component,
* so we generate code from the AST rather than assuming
* we can access a name like `path.node.superClass.name`
*/
if (path.node.superClass) {
comment.augments.push({
title: 'augments',
name: generate(path.node.superClass).code
});
}
} else if (path.isInterfaceDeclaration()) {
/*
* extends is an array of interface identifiers or
* qualified type identifiers, so we generate code
* from the AST rather than assuming we can acces
* a name.
*/
path.node.extends.forEach(node => {
comment.augments.push({
title: 'extends',
name: generate(node).code
});
});
}

Expand Down
16 changes: 0 additions & 16 deletions lib/infer/finders.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,4 @@ function findTarget(path/*: Object */) {
return path.node && path;
}

/**
* Try to find a JavaScript class that this comment refers to,
* whether an expression in an assignment, or a declaration.
*
* @param {Object} path abstract syntax tree path
* @returns {?Object} ast path, if one is found.
* @private
*/
function findClass(path/*: Object*/) {
var target = findTarget(path);
if (target && (target.isClassDeclaration() || target.isClassExpression())) {
return target;
}
}

module.exports.findTarget = findTarget;
module.exports.findClass = findClass;
2 changes: 2 additions & 0 deletions lib/infer/kind.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ function inferKind(comment/*: Comment*/) {
}
} else if (t.isTypeAlias(node)) {
comment.kind = 'typedef';
} else if (t.isInterfaceDeclaration(node)) {
comment.kind = 'interface';
} else if (t.isVariableDeclaration(node)) {
if (node.kind === 'const') {
comment.kind = 'constant';
Expand Down
14 changes: 10 additions & 4 deletions lib/infer/properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
'use strict';
/* @flow */

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

function prefixedName(name, prefix) {
if (prefix.length) {
Expand Down Expand Up @@ -56,8 +56,14 @@ function inferProperties(comment/*: Comment */)/*: Comment */ {
}
}

if (t.isTypeAlias(comment.context.ast)) {
inferProperties(comment.context.ast.node.right, []);
var path = findTarget(comment.context.ast);

if (path) {
if (path.isTypeAlias()) {
inferProperties(path.node.right, []);
} else if (path.isInterfaceDeclaration()) {
inferProperties(path.node.body, []);
}
}

return comment;
Expand Down
7 changes: 7 additions & 0 deletions test/fixture/interface.input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* This is my interface.
*/
interface Foo extends Bar, Baz {
prop1: number;
prop2: string;
}
132 changes: 132 additions & 0 deletions test/fixture/interface.output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
[
{
"description": {
"type": "root",
"children": [
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "This is my interface.",
"position": {
"start": {
"line": 1,
"column": 1,
"offset": 0
},
"end": {
"line": 1,
"column": 22,
"offset": 21
},
"indent": []
}
}
],
"position": {
"start": {
"line": 1,
"column": 1,
"offset": 0
},
"end": {
"line": 1,
"column": 22,
"offset": 21
},
"indent": []
}
}
],
"position": {
"start": {
"line": 1,
"column": 1,
"offset": 0
},
"end": {
"line": 1,
"column": 22,
"offset": 21
}
}
},
"tags": [],
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 3
}
},
"context": {
"loc": {
"start": {
"line": 4,
"column": 0
},
"end": {
"line": 7,
"column": 1
}
}
},
"augments": [
{
"title": "extends",
"name": "Bar"
},
{
"title": "extends",
"name": "Baz"
}
],
"errors": [],
"examples": [],
"params": [],
"properties": [
{
"title": "property",
"name": "prop1",
"lineNumber": 5,
"type": {
"type": "NameExpression",
"name": "number"
}
},
{
"title": "property",
"name": "prop2",
"lineNumber": 6,
"type": {
"type": "NameExpression",
"name": "string"
}
}
],
"returns": [],
"sees": [],
"throws": [],
"todos": [],
"name": "Foo",
"kind": "interface",
"members": {
"global": [],
"inner": [],
"instance": [],
"events": [],
"static": []
},
"path": [
{
"name": "Foo",
"kind": "interface"
}
],
"namespace": "Foo"
}
]
16 changes: 16 additions & 0 deletions test/fixture/interface.output.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->

### Table of Contents

- [Foo](#foo)

## Foo

**Extends Bar, Baz**

This is my interface.

**Properties**

- `prop1` **[number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)**
- `prop2` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)**
Loading

0 comments on commit e2915dc

Please sign in to comment.