repo.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. const log = require('npmlog')
  2. const pacote = require('pacote')
  3. const { URL } = require('url')
  4. const hostedFromMani = require('./utils/hosted-git-info-from-manifest.js')
  5. const openUrl = require('./utils/open-url.js')
  6. const BaseCommand = require('./base-command.js')
  7. class Repo extends BaseCommand {
  8. /* istanbul ignore next - see test/lib/load-all-commands.js */
  9. static get description () {
  10. return 'Open package repository page in the browser'
  11. }
  12. /* istanbul ignore next - see test/lib/load-all-commands.js */
  13. static get name () {
  14. return 'repo'
  15. }
  16. /* istanbul ignore next - see test/lib/load-all-commands.js */
  17. static get params () {
  18. return ['browser', 'workspace', 'workspaces', 'include-workspace-root']
  19. }
  20. /* istanbul ignore next - see test/lib/load-all-commands.js */
  21. static get usage () {
  22. return ['[<pkgname> [<pkgname> ...]]']
  23. }
  24. exec (args, cb) {
  25. this.repo(args).then(() => cb()).catch(cb)
  26. }
  27. execWorkspaces (args, filters, cb) {
  28. this.repoWorkspaces(args, filters).then(() => cb()).catch(cb)
  29. }
  30. async repo (args) {
  31. if (!args || !args.length)
  32. args = ['.']
  33. await Promise.all(args.map(pkg => this.get(pkg)))
  34. }
  35. async repoWorkspaces (args, filters) {
  36. await this.setWorkspaces(filters)
  37. return this.repo(this.workspacePaths)
  38. }
  39. async get (pkg) {
  40. // XXX It is very odd that `where` is how pacote knows to look anywhere
  41. // other than the cwd.
  42. const opts = {
  43. ...this.npm.flatOptions,
  44. where: this.npm.localPrefix,
  45. fullMetadata: true,
  46. }
  47. const mani = await pacote.manifest(pkg, opts)
  48. const r = mani.repository
  49. const rurl = !r ? null
  50. : typeof r === 'string' ? r
  51. : typeof r === 'object' && typeof r.url === 'string' ? r.url
  52. : null
  53. if (!rurl) {
  54. throw Object.assign(new Error('no repository'), {
  55. pkgid: pkg,
  56. })
  57. }
  58. const info = hostedFromMani(mani)
  59. const url = info ?
  60. info.browse(mani.repository.directory) : unknownHostedUrl(rurl)
  61. if (!url) {
  62. throw Object.assign(new Error('no repository: could not get url'), {
  63. pkgid: pkg,
  64. })
  65. }
  66. log.silly('docs', 'url', url)
  67. await openUrl(this.npm, url, `${mani.name} repo available at the following URL`)
  68. }
  69. }
  70. module.exports = Repo
  71. const unknownHostedUrl = url => {
  72. try {
  73. const {
  74. protocol,
  75. hostname,
  76. pathname,
  77. } = new URL(url)
  78. /* istanbul ignore next - URL ctor should prevent this */
  79. if (!protocol || !hostname)
  80. return null
  81. const proto = /(git\+)http:$/.test(protocol) ? 'http:' : 'https:'
  82. const path = pathname.replace(/\.git$/, '')
  83. return `${proto}//${hostname}${path}`
  84. } catch (e) {
  85. return null
  86. }
  87. }