deprecate.js 2.4 KB

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