generate-api-docs.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. #!/usr/bin/env node
  2. const {writeFileSync} = require('fs')
  3. const {join: pathJoin} = require('path')
  4. const debug = require('debug')('octokit:rest')
  5. const upperFirst = require('lodash/upperFirst')
  6. const ROUTES = require('./routes-for-api-docs.json')
  7. debug('Converting routes to functions')
  8. const apiDocs = Object.keys(ROUTES)
  9. .map(namespaceName => prepareNamespace(ROUTES[namespaceName], namespaceName))
  10. .join('\n\n\n')
  11. function prepareNamespace (namespace, namespaceName) {
  12. return [toSectionComment(namespaceName)]
  13. .concat(
  14. Object.keys(namespace).map(apiName => prepareApi(namespace[apiName], apiName, namespaceName))
  15. ).join('\n\n\n')
  16. }
  17. function prepareApi (api, apiName, namespaceName) {
  18. return toApiComment(namespaceName, apiName, api)
  19. }
  20. function toSectionComment (namespaceName) {
  21. return `
  22. /**,
  23. * ${upperFirst(namespaceName)}
  24. * @namespace ${upperFirst(namespaceName)}
  25. */`
  26. }
  27. function toApiComment (namespaceName, apiName, api) {
  28. if (!api.method) {
  29. throw new Error(
  30. `No HTTP method specified for ${namespaceName}.${apiName} in routes.json`
  31. )
  32. }
  33. const method = api['method'].toUpperCase()
  34. const params = api['params']
  35. const descriptionWithLinkToV3Docs = [
  36. api.description,
  37. `<a href="${api.documentationUrl}">REST API doc</a>`
  38. ].filter(Boolean).join(' ')
  39. const commentLines = [
  40. '/**',
  41. ` * @api {${method}} ${api.path} ${apiName}`,
  42. ` * @apiName ${apiName}`,
  43. ` * @apiDescription ${descriptionWithLinkToV3Docs}`,
  44. ` * @apiGroup ${upperFirst(namespaceName)}`,
  45. ' *'
  46. ].concat(
  47. params.map(toApiParamComment)
  48. )
  49. const paramsString = params.map(param => param.name).join(', ')
  50. return commentLines.concat([
  51. ' * @apiExample {js} async/await',
  52. ` * const result = await octokit.${namespaceName}.${apiName}({${paramsString}})`,
  53. ' * @apiExample {js} Promise',
  54. ` * octokit.${namespaceName}.${apiName}({${paramsString}}).then(result => {})`,
  55. ' * @apiExample {js} Callback',
  56. ` * octokit.${namespaceName}.${apiName}({${paramsString}}, (error, result) => {})`
  57. ]).join('\n') + '\n */'
  58. }
  59. function toApiParamComment (paramInfo) {
  60. const paramRequired = paramInfo['required']
  61. const paramDescription = paramInfo['description'] || ''
  62. const paramDefaultVal = paramInfo['default']
  63. const paramType = paramInfo['type']
  64. .toLowerCase()
  65. // https://github.com/octokit/rest.js/issues/721
  66. .replace('string | object', 'object')
  67. let paramLabel = paramInfo.name
  68. // add default value if there is one
  69. if (typeof paramDefaultVal !== 'undefined') {
  70. paramLabel += `="${String(paramDefaultVal).replace(/[<>]/g, '')}"`
  71. }
  72. // show param as either required or optional
  73. if (!paramRequired) {
  74. paramLabel = `[${paramLabel}]`
  75. }
  76. let allowedValues = ''
  77. if (paramInfo['enum']) {
  78. allowedValues = `=${paramInfo['enum'].join(',')}`
  79. }
  80. return ` * @apiParam {${paramType}${allowedValues}} ${paramLabel.replace(/\./g, ':').replace(/\[\]/g, '')} ${paramDescription}`
  81. }
  82. // function sortByRequired (api, paramA, paramB) {
  83. // const paramInfoA = api[paramA]
  84. // const paramInfoB = api[paramB]
  85. //
  86. // const aIsRequired = paramInfoA['required']
  87. // const bIsRequired = paramInfoB['required']
  88. //
  89. // if (aIsRequired && !bIsRequired) return -1
  90. // if (!aIsRequired && bIsRequired) return 1
  91. // return 0
  92. // }
  93. writeFileSync(
  94. pathJoin(__dirname, '..', 'doc', 'apidoc.js'),
  95. apiDocs.trim() + '\n'
  96. )