src/extractFunctionSpecFromDoc.js
import doctrine from 'doctrine'
export default function extractFunctionSpecFromDoc (doc) {
let description, name, title, summary, examples, params, _return
let parsed = doctrine.parse(doc, {
unwrap: true, // let doctrine remove the comment stuff
sloppy: true // allow optional parameters to be specified in brackets
})
description = parsed.description
for (let tag of parsed.tags) {
switch (tag.title) {
// Tags which always apply to the function as a whole
case 'name':
if (name) console.error('duplicate @name')
name = tag.name
break
case 'title':
if (title) console.error('duplicate @title')
title = tag.description
break
case 'summary':
if (summary) console.error('duplicate @summary')
summary = tag.description
break
case 'description':
if (description) console.error('duplicate @description')
description = tag.description
break
// Tags applied to indivdual methods
case 'param':
if (!tag.name) {
console.error('@param should have a name: expected format @param [type] <name> [description]')
} else {
let param = { name: tag.name }
if (tag.type) {
if (tag.type.type === 'RestType') {
param.type = _extractType(tag)
param.repeats = true
} else if (tag.type.type === 'NameExpression' && tag.type.name.substring(0, 3) === '___') {
param.type = tag.type.name.substring(3)
param.extends = true
} else {
param.type = _extractType(tag)
}
}
if (tag.description) param.description = tag.description
if (!params) params = new Map()
if (params.has(param.name)) {
console.error('duplicate @param for ' + param.name)
}
params.set(param.name, param)
}
break
case 'return':
if (!tag.type && !tag.description) {
console.error('@return is empty')
} else {
if (_return) {
console.error('duplicate @return')
}
_return = {}
if (tag.type) _return.type = _extractType(tag)
if (tag.description) _return.description = tag.description
}
break
case 'example':
let example = { usage: tag.description }
if (tag.caption) example.caption = tag.caption
if (!examples) examples = []
examples.push(example)
break
default:
//
}
}
return { name, title, description, summary, examples, params, _return }
}
// Extract the type specification for a `@param` or `@return` tag
function _extractType (tag) {
switch (tag.type.type) {
case 'AllLiteral':
return 'any'
case 'NameExpression':
return tag.type.name
case 'UnionType':
return tag.type.elements.map((element) => element.name).join('|')
case 'TypeApplication':
return tag.type.expression.name + '[' +
tag.type.applications.map((application) => application.name).join(',') + ']'
case 'OptionalType':
return tag.default ? tag.type.expression.name : 'null'
case 'RestType':
return tag.type.expression.name
default:
throw new Error('Unhandled type specification: ' + tag.type.type)
}
}