parseJsDoc.js 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import doctrine from 'doctrine';
  2. function getType(tagType) {
  3. if (!tagType) {
  4. return null;
  5. }
  6. switch (tagType.type) {
  7. case 'NameExpression':
  8. // {a}
  9. return { name: tagType.name };
  10. case 'UnionType':
  11. // {a|b}
  12. return {
  13. name: 'union',
  14. elements: tagType.elements
  15. .map((element) => getType(element))
  16. .filter(Boolean),
  17. };
  18. case 'AllLiteral':
  19. // {*}
  20. return { name: 'mixed' };
  21. case 'TypeApplication':
  22. // {Array<string>} or {string[]}
  23. return {
  24. name: 'name' in tagType.expression ? tagType.expression.name : '',
  25. elements: tagType.applications
  26. .map((element) => getType(element))
  27. .filter(Boolean),
  28. };
  29. case 'ArrayType':
  30. // {[number, string]}
  31. return {
  32. name: 'tuple',
  33. elements: tagType.elements
  34. .map((element) => getType(element))
  35. .filter(Boolean),
  36. };
  37. default: {
  38. const typeName = 'name' in tagType && tagType.name
  39. ? tagType.name
  40. : 'expression' in tagType &&
  41. tagType.expression &&
  42. 'name' in tagType.expression
  43. ? tagType.expression.name
  44. : null;
  45. if (typeName) {
  46. return { name: typeName };
  47. }
  48. else {
  49. return null;
  50. }
  51. }
  52. }
  53. }
  54. function getOptional(tag) {
  55. return !!(tag.type && tag.type.type && tag.type.type === 'OptionalType');
  56. }
  57. // Add jsdoc @return description.
  58. function getReturnsJsDoc(jsDoc) {
  59. const returnTag = jsDoc.tags.find((tag) => tag.title === 'return' || tag.title === 'returns');
  60. if (returnTag) {
  61. return {
  62. description: returnTag.description,
  63. type: getType(returnTag.type),
  64. };
  65. }
  66. return null;
  67. }
  68. // Add jsdoc @param descriptions.
  69. function getParamsJsDoc(jsDoc) {
  70. if (!jsDoc.tags) {
  71. return [];
  72. }
  73. return jsDoc.tags
  74. .filter((tag) => tag.title === 'param')
  75. .map((tag) => {
  76. return {
  77. name: tag.name || '',
  78. description: tag.description,
  79. type: getType(tag.type),
  80. optional: getOptional(tag),
  81. };
  82. });
  83. }
  84. export default function parseJsDoc(docblock) {
  85. const jsDoc = doctrine.parse(docblock);
  86. return {
  87. description: jsDoc.description || null,
  88. params: getParamsJsDoc(jsDoc),
  89. returns: getReturnsJsDoc(jsDoc),
  90. };
  91. }