| 15 | * @returns {Object} comment with type tag inferred |
| 16 | */ |
| 17 | export default function inferType(comment) { |
| 18 | if (comment.type) { |
| 19 | return comment; |
| 20 | } |
| 21 | |
| 22 | const ast = comment.context.ast; |
| 23 | const path = findTarget(ast); |
| 24 | if (!path) { |
| 25 | return comment; |
| 26 | } |
| 27 | |
| 28 | const n = path.node; |
| 29 | let type; |
| 30 | switch (n.type) { |
| 31 | case 'VariableDeclarator': |
| 32 | type = n.id.typeAnnotation; |
| 33 | if (!type && comment.kind === 'constant') { |
| 34 | type = constTypeMapping[n.init.type]; |
| 35 | } |
| 36 | break; |
| 37 | case 'ClassProperty': |
| 38 | case 'TSTypeAliasDeclaration': |
| 39 | case 'TSPropertySignature': |
| 40 | type = n.typeAnnotation; |
| 41 | break; |
| 42 | case 'ClassMethod': |
| 43 | case 'TSDeclareMethod': |
| 44 | if (n.kind === 'get') { |
| 45 | type = n.returnType; |
| 46 | } else if (n.kind === 'set' && n.params[0]) { |
| 47 | type = n.params[0].typeAnnotation; |
| 48 | } |
| 49 | break; |
| 50 | case 'TypeAlias': |
| 51 | type = n.right; |
| 52 | break; |
| 53 | case 'TSEnumMember': |
| 54 | if (n.initializer) { |
| 55 | if (constTypeMapping[n.initializer.type]) { |
| 56 | type = constTypeMapping[n.initializer.type]; |
| 57 | } |
| 58 | } else { |
| 59 | type = constTypeMapping.NumericLiteral; |
| 60 | } |
| 61 | break; |
| 62 | default: |
| 63 | if (ast.isObjectTypeProperty() && !ast.node.method) { |
| 64 | type = ast.node.value; |
| 65 | } |
| 66 | } |
| 67 | // Don't provide a `type` section when it's an ObjectTypeAnnotation, |
| 68 | // `properties` already exists and renders better. |
| 69 | if (type && type.type !== 'ObjectTypeAnnotation') { |
| 70 | comment.type = typeAnnotation(type); |
| 71 | } |
| 72 | return comment; |
| 73 | } |