diff --git a/lib/extractors/exported.js b/lib/extractors/exported.js index 8645c679a..7ede439cb 100644 --- a/lib/extractors/exported.js +++ b/lib/extractors/exported.js @@ -3,7 +3,8 @@ var traverse = require('babel-traverse').default, t = require('babel-types'), nodePath = require('path'), fs = require('fs'), - parseToAst = require('../parsers/parse_to_ast'); + parseToAst = require('../parsers/parse_to_ast'), + findTarget = require('../infer/finders').findTarget; /** * Iterate through the abstract syntax tree, finding ES6-style exports, @@ -52,14 +53,18 @@ function walkExported(ast, data, addComment) { var declaration = path.get('declaration'); if (t.isDeclaration(declaration)) { traverseExportedSubtree(declaration, data, addComments); + return path.skip(); } if (path.isExportDefaultDeclaration()) { if (declaration.isDeclaration()) { traverseExportedSubtree(declaration, data, addComments); - } else if (declaration.isIdentifier()) { + return path.skip(); + } + if (declaration.isIdentifier()) { var binding = declaration.scope.getBinding(declaration.node.name); traverseExportedSubtree(binding.path, data, addComments); + return path.skip(); } } @@ -92,6 +97,7 @@ function walkExported(ast, data, addComment) { traverseExportedSubtree(bindingPath, specData, addComments, exported); }); + return path.skip(); } } }); @@ -110,12 +116,10 @@ function traverseExportedSubtree(path, data, addComments, overrideName) { } addComments(data, attachCommentPath, overrideName); - if (path.isVariableDeclaration()) { - // TODO: How does JSDoc handle multiple declarations? - path = path.get('declarations')[0].get('init'); - if (!path) { - return; - } + path = findTarget(path); + + if (t.isVariableDeclarator(path) && path.has('init')) { + path = path.get('init'); } if (path.isClass() || path.isObjectExpression()) { diff --git a/lib/infer/augments.js b/lib/infer/augments.js index 5ff13be9d..d1e64f7e5 100644 --- a/lib/infer/augments.js +++ b/lib/infer/augments.js @@ -1,7 +1,7 @@ 'use strict'; var shouldSkipInference = require('./should_skip_inference'), - finders = require('./finders'); + findClass = require('./finders').findClass; /** * Infers an `augments` tag from an ES6 class declaration @@ -15,12 +15,12 @@ function inferAugments() { return comment; } - var node = finders.findClass(comment.context.ast); + var path = findClass(comment.context.ast); - if (node && node.superClass) { + if (path && path.node.superClass) { comment.augments = [{ title: 'augments', - name: node.superClass.name + name: path.node.superClass.name }]; } diff --git a/lib/infer/finders.js b/lib/infer/finders.js index 394f24ce6..cef792d9f 100644 --- a/lib/infer/finders.js +++ b/lib/infer/finders.js @@ -1,3 +1,5 @@ +'use strict'; + var t = require('babel-types'); /** @@ -5,47 +7,44 @@ var t = require('babel-types'); * looking at the syntax tree closest to that comment. * * @param {Object} path abstract syntax tree path - * @returns {?Object} ast node, if one is found. + * @returns {?Object} ast path, if one is found. * @private */ function findTarget(path) { - if (!path) { return path; } - if (path.node) { - path = path.node; - } - - if (t.isExportNamedDeclaration(path) || t.isExportDefaultDeclaration(path)) { - path = path.declaration; + if (t.isExportDefaultDeclaration(path) || + t.isExportNamedDeclaration(path) && path.has('declaration')) { + path = path.get('declaration'); } // var x = init; if (t.isVariableDeclaration(path)) { - return path.declarations[0]; - } + path = path.get('declarations')[0]; // foo.x = TARGET - if (t.isExpressionStatement(path)) { - return path.expression.right; + } else if (t.isExpressionStatement(path)) { + path = path.get('expression').get('right'); } - return path; + 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} node abstract syntax tree node - * @returns {?Object} ast node, if one is found. + * @param {Object} path abstract syntax tree path + * @returns {?Object} ast path, if one is found. * @private */ -function findClass(node) { - var target = findTarget(node); - return (t.isClassDeclaration(target) || t.isClassExpression(target)) && target; +function findClass(path) { + var target = findTarget(path); + if (target && (target.isClassDeclaration() || target.isClassExpression())) { + return target; + } } module.exports.findTarget = findTarget; diff --git a/lib/infer/params.js b/lib/infer/params.js index 511a3a9b5..c8f9c931e 100644 --- a/lib/infer/params.js +++ b/lib/infer/params.js @@ -2,7 +2,7 @@ var shouldSkipInference = require('./should_skip_inference'), t = require('babel-types'), - finders = require('./finders'), + findTarget = require('./finders').findTarget, flowDoctrine = require('../flow_doctrine'); /** @@ -160,15 +160,15 @@ function paramToDoc(param, comment, i, prefix) { */ function inferParams() { return shouldSkipInference(function inferParams(comment) { - var node = finders.findTarget(comment.context.ast); + var path = findTarget(comment.context.ast); // In case of `/** */ var x = function () {}` findTarget returns // the declarator. - if (t.isVariableDeclarator(node)) { - node = node.init; + if (t.isVariableDeclarator(path)) { + path = path.get('init'); } - if (!t.isFunction(node)) { + if (!t.isFunction(path)) { return comment; } @@ -182,7 +182,7 @@ function inferParams() { var paramOrder = {}; var i = 0; - node.params + path.node.params .reduce(function (params, param, i) { return params.concat(paramToDoc(param, comment, i)); }, []) diff --git a/lib/infer/return.js b/lib/infer/return.js index e266880e4..d6bdcb01b 100644 --- a/lib/infer/return.js +++ b/lib/infer/return.js @@ -17,7 +17,8 @@ module.exports = function () { if (comment.returns) { return comment; } - var fn = finders.findTarget(comment.context.ast); + var path = finders.findTarget(comment.context.ast); + var fn = path && path.node; if (t.isFunction(fn) && fn.returnType && fn.returnType.typeAnnotation) { diff --git a/lib/infer/type.js b/lib/infer/type.js index d9b0004c1..74982cafe 100644 --- a/lib/infer/type.js +++ b/lib/infer/type.js @@ -1,6 +1,6 @@ 'use strict'; -var finders = require('./finders'), +var findTarget = require('./finders').findTarget, shouldSkipInference = require('./should_skip_inference'), flowDoctrine = require('../flow_doctrine'), t = require('babel-types'); @@ -24,11 +24,12 @@ module.exports = function () { return comment; } - var n = finders.findTarget(comment.context.ast); - if (!n) { + var path = findTarget(comment.context.ast); + if (!path) { return comment; } + var n = path.node; var type; switch (n.type) { case 'VariableDeclarator': diff --git a/test/fixture/document-exported.input.js b/test/fixture/document-exported.input.js index 3be25eee7..5e97a6d86 100644 --- a/test/fixture/document-exported.input.js +++ b/test/fixture/document-exported.input.js @@ -63,3 +63,17 @@ type T3 = string; export type {T2, T3 as T4}; export type {T5} from './document-exported/x.js'; + +export var f4 = function(x: X) {} + +var f5 = function(y: Y) {} +export {f5}; + +export var o1 = { + om1() {} +} + +var o2 = { + om2() {} +} +export {o2}; diff --git a/test/fixture/document-exported.output.json b/test/fixture/document-exported.output.json index 6b63135c5..2b0f875b6 100644 --- a/test/fixture/document-exported.output.json +++ b/test/fixture/document-exported.output.json @@ -1132,5 +1132,261 @@ } ], "namespace": "T4" + }, + { + "description": "", + "tags": [], + "loc": { + "start": { + "line": 67, + "column": 0 + }, + "end": { + "line": 67, + "column": 33 + } + }, + "context": { + "loc": { + "start": { + "line": 67, + "column": 0 + }, + "end": { + "line": 67, + "column": 33 + } + } + }, + "errors": [], + "name": "f4", + "kind": "function", + "params": [ + { + "title": "param", + "name": "x", + "lineNumber": 67, + "type": { + "type": "NameExpression", + "name": "X" + } + } + ], + "members": { + "instance": [], + "static": [] + }, + "path": [ + { + "name": "f4", + "kind": "function" + } + ], + "namespace": "f4" + }, + { + "description": "", + "tags": [], + "loc": { + "start": { + "line": 69, + "column": 4 + }, + "end": { + "line": 69, + "column": 26 + } + }, + "context": { + "loc": { + "start": { + "line": 69, + "column": 4 + }, + "end": { + "line": 69, + "column": 26 + } + } + }, + "errors": [], + "name": "f5", + "params": [ + { + "title": "param", + "name": "y", + "lineNumber": 69, + "type": { + "type": "NameExpression", + "name": "Y" + } + } + ], + "members": { + "instance": [], + "static": [] + }, + "path": [ + { + "name": "f5" + } + ], + "namespace": "f5" + }, + { + "description": "", + "tags": [], + "loc": { + "start": { + "line": 72, + "column": 0 + }, + "end": { + "line": 74, + "column": 1 + } + }, + "context": { + "loc": { + "start": { + "line": 72, + "column": 0 + }, + "end": { + "line": 74, + "column": 1 + } + } + }, + "errors": [], + "name": "o1", + "members": { + "instance": [], + "static": [] + }, + "path": [ + { + "name": "o1" + } + ], + "namespace": "o1" + }, + { + "description": "", + "tags": [], + "loc": { + "start": { + "line": 73, + "column": 2 + }, + "end": { + "line": 73, + "column": 10 + } + }, + "context": { + "loc": { + "start": { + "line": 73, + "column": 2 + }, + "end": { + "line": 73, + "column": 10 + } + } + }, + "errors": [], + "name": "om1", + "kind": "function", + "members": { + "instance": [], + "static": [] + }, + "path": [ + { + "name": "om1", + "kind": "function" + } + ], + "namespace": "om1" + }, + { + "description": "", + "tags": [], + "loc": { + "start": { + "line": 76, + "column": 4 + }, + "end": { + "line": 78, + "column": 1 + } + }, + "context": { + "loc": { + "start": { + "line": 76, + "column": 4 + }, + "end": { + "line": 78, + "column": 1 + } + } + }, + "errors": [], + "name": "o2", + "members": { + "instance": [], + "static": [] + }, + "path": [ + { + "name": "o2" + } + ], + "namespace": "o2" + }, + { + "description": "", + "tags": [], + "loc": { + "start": { + "line": 77, + "column": 2 + }, + "end": { + "line": 77, + "column": 10 + } + }, + "context": { + "loc": { + "start": { + "line": 77, + "column": 2 + }, + "end": { + "line": 77, + "column": 10 + } + } + }, + "errors": [], + "name": "om2", + "kind": "function", + "members": { + "instance": [], + "static": [] + }, + "path": [ + { + "name": "om2", + "kind": "function" + } + ], + "namespace": "om2" } ] \ No newline at end of file diff --git a/test/fixture/document-exported.output.md b/test/fixture/document-exported.output.md index b2681b6b7..cfd575c70 100644 --- a/test/fixture/document-exported.output.md +++ b/test/fixture/document-exported.output.md @@ -71,3 +71,23 @@ Returns **void** # T2 # T4 + +# f4 + +**Parameters** + +- `x` **X** + +# f5 + +**Parameters** + +- `y` **Y** + +# o1 + +# om1 + +# o2 + +# om2 diff --git a/test/fixture/document-exported.output.md.json b/test/fixture/document-exported.output.md.json index 2934d22bd..5bd9b84cf 100644 --- a/test/fixture/document-exported.output.md.json +++ b/test/fixture/document-exported.output.md.json @@ -502,6 +502,158 @@ "value": "T4" } ] + }, + { + "depth": 1, + "type": "heading", + "children": [ + { + "type": "text", + "value": "f4" + } + ] + }, + { + "type": "strong", + "children": [ + { + "type": "text", + "value": "Parameters" + } + ] + }, + { + "ordered": false, + "type": "list", + "children": [ + { + "type": "listItem", + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "inlineCode", + "value": "x" + }, + { + "type": "text", + "value": " " + }, + { + "type": "strong", + "children": [ + { + "type": "text", + "value": "X" + } + ] + }, + { + "type": "text", + "value": " " + } + ] + } + ] + } + ] + }, + { + "depth": 1, + "type": "heading", + "children": [ + { + "type": "text", + "value": "f5" + } + ] + }, + { + "type": "strong", + "children": [ + { + "type": "text", + "value": "Parameters" + } + ] + }, + { + "ordered": false, + "type": "list", + "children": [ + { + "type": "listItem", + "children": [ + { + "type": "paragraph", + "children": [ + { + "type": "inlineCode", + "value": "y" + }, + { + "type": "text", + "value": " " + }, + { + "type": "strong", + "children": [ + { + "type": "text", + "value": "Y" + } + ] + }, + { + "type": "text", + "value": " " + } + ] + } + ] + } + ] + }, + { + "depth": 1, + "type": "heading", + "children": [ + { + "type": "text", + "value": "o1" + } + ] + }, + { + "depth": 1, + "type": "heading", + "children": [ + { + "type": "text", + "value": "om1" + } + ] + }, + { + "depth": 1, + "type": "heading", + "children": [ + { + "type": "text", + "value": "o2" + } + ] + }, + { + "depth": 1, + "type": "heading", + "children": [ + { + "type": "text", + "value": "om2" + } + ] } ] } \ No newline at end of file