deprecate.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. const fetch = require('npm-registry-fetch')
  2. const otplease = require('./utils/otplease.js')
  3. const npa = require('npm-package-arg')
  4. const semver = require('semver')
  5. const getIdentity = require('./utils/get-identity.js')
  6. const libaccess = require('libnpmaccess')
  7. const BaseCommand = require('./base-command.js')
  8. class Deprecate extends BaseCommand {
  9. static get description () {
  10. return 'Deprecate a version of a package'
  11. }
  12. /* istanbul ignore next - see test/lib/load-all-commands.js */
  13. static get name () {
  14. return 'deprecate'
  15. }
  16. /* istanbul ignore next - see test/lib/load-all-commands.js */
  17. static get usage () {
  18. return ['<pkg>[@<version>] <message>']
  19. }
  20. /* istanbul ignore next - see test/lib/load-all-commands.js */
  21. static get params () {
  22. return [
  23. 'registry',
  24. 'otp',
  25. ]
  26. }
  27. async completion (opts) {
  28. if (opts.conf.argv.remain.length > 1)
  29. return []
  30. const username = await getIdentity(this.npm, this.npm.flatOptions)
  31. const packages = await libaccess.lsPackages(username, this.npm.flatOptions)
  32. return Object.keys(packages)
  33. .filter((name) =>
  34. packages[name] === 'write' &&
  35. (opts.conf.argv.remain.length === 0 ||
  36. name.startsWith(opts.conf.argv.remain[0])))
  37. }
  38. exec (args, cb) {
  39. this.deprecate(args)
  40. .then(() => cb())
  41. .catch(err => cb(err.code === 'EUSAGE' ? err.message : err))
  42. }
  43. async deprecate ([pkg, msg]) {
  44. // msg == null because '' is a valid value, it indicates undeprecate
  45. if (!pkg || msg == null)
  46. throw this.usageError()
  47. // fetch the data and make sure it exists.
  48. const p = npa(pkg)
  49. // npa makes the default spec "latest", but for deprecation
  50. // "*" is the appropriate default.
  51. const spec = p.rawSpec === '' ? '*' : p.fetchSpec
  52. if (semver.validRange(spec, true) === null)
  53. throw new Error(`invalid version range: ${spec}`)
  54. const uri = '/' + p.escapedName
  55. const packument = await fetch.json(uri, {
  56. ...this.npm.flatOptions,
  57. spec: p,
  58. query: { write: true },
  59. })
  60. Object.keys(packument.versions)
  61. .filter(v => semver.satisfies(v, spec, { includePrerelease: true }))
  62. .forEach(v => {
  63. packument.versions[v].deprecated = msg
  64. })
  65. return otplease(this.npm.flatOptions, opts => fetch(uri, {
  66. ...opts,
  67. spec: p,
  68. method: 'PUT',
  69. body: packument,
  70. ignoreBody: true,
  71. }))
  72. }
  73. }
  74. module.exports = Deprecate