1 |
|
2 | 'use strict'
|
3 |
|
4 | module.exports = unpublish
|
5 |
|
6 | const BB = require('bluebird')
|
7 |
|
8 | const figgyPudding = require('figgy-pudding')
|
9 | const libaccess = require('libnpm/access')
|
10 | const libunpub = require('libnpm/unpublish')
|
11 | const log = require('npmlog')
|
12 | const npa = require('npm-package-arg')
|
13 | const npm = require('./npm.js')
|
14 | const npmConfig = require('./config/figgy-config.js')
|
15 | const npmFetch = require('npm-registry-fetch')
|
16 | const otplease = require('./utils/otplease.js')
|
17 | const output = require('./utils/output.js')
|
18 | const path = require('path')
|
19 | const readJson = BB.promisify(require('read-package-json'))
|
20 | const usage = require('./utils/usage.js')
|
21 | const whoami = BB.promisify(require('./whoami.js'))
|
22 |
|
23 | unpublish.usage = usage('npm unpublish [<@scope>/]<pkg>[@<version>]')
|
24 |
|
25 | function UsageError () {
|
26 | throw Object.assign(new Error(`Usage: ${unpublish.usage}`), {
|
27 | code: 'EUSAGE'
|
28 | })
|
29 | }
|
30 |
|
31 | const UnpublishConfig = figgyPudding({
|
32 | force: {},
|
33 | loglevel: {},
|
34 | silent: {}
|
35 | })
|
36 |
|
37 | unpublish.completion = function (cliOpts, cb) {
|
38 | if (cliOpts.conf.argv.remain.length >= 3) return cb()
|
39 |
|
40 | whoami([], true).then(username => {
|
41 | if (!username) { return [] }
|
42 | const opts = UnpublishConfig(npmConfig())
|
43 | return libaccess.lsPackages(username, opts).then(access => {
|
44 |
|
45 |
|
46 |
|
47 | let pkgs = Object.keys(access)
|
48 | if (!cliOpts.partialWord || !pkgs.length) { return pkgs }
|
49 | const pp = npa(cliOpts.partialWord).name
|
50 | pkgs = pkgs.filter(p => !p.indexOf(pp))
|
51 | if (pkgs.length > 1) return pkgs
|
52 | return npmFetch.json(npa(pkgs[0]).escapedName, opts).then(doc => {
|
53 | const vers = Object.keys(doc.versions)
|
54 | if (!vers.length) {
|
55 | return pkgs
|
56 | } else {
|
57 | return vers.map(v => `${pkgs[0]}@${v}`)
|
58 | }
|
59 | })
|
60 | })
|
61 | }).nodeify(cb)
|
62 | }
|
63 |
|
64 | function unpublish (args, cb) {
|
65 | if (args.length > 1) return cb(unpublish.usage)
|
66 |
|
67 | const spec = args.length && npa(args[0])
|
68 | const opts = UnpublishConfig(npmConfig())
|
69 | const version = spec.rawSpec
|
70 | BB.try(() => {
|
71 | log.silly('unpublish', 'args[0]', args[0])
|
72 | log.silly('unpublish', 'spec', spec)
|
73 | if (!version && !opts.force) {
|
74 | throw Object.assign(new Error(
|
75 | 'Refusing to delete entire project.\n' +
|
76 | 'Run with --force to do this.\n' +
|
77 | unpublish.usage
|
78 | ), {code: 'EUSAGE'})
|
79 | }
|
80 | if (!spec || path.resolve(spec.name) === npm.localPrefix) {
|
81 |
|
82 |
|
83 | const cwdJson = path.join(npm.localPrefix, 'package.json')
|
84 | return readJson(cwdJson).then(data => {
|
85 | log.verbose('unpublish', data)
|
86 | return otplease(opts, opts => {
|
87 | return libunpub(npa.resolve(data.name, data.version), opts.concat(data.publishConfig))
|
88 | })
|
89 | }, err => {
|
90 | if (err && err.code !== 'ENOENT' && err.code !== 'ENOTDIR') {
|
91 | throw err
|
92 | } else {
|
93 | UsageError()
|
94 | }
|
95 | })
|
96 | } else {
|
97 | return otplease(opts, opts => libunpub(spec, opts))
|
98 | }
|
99 | }).then(
|
100 | ret => {
|
101 | if (!opts.silent && opts.loglevel !== 'silent') {
|
102 | output(`- ${spec.name}${
|
103 | spec.type === 'version' ? `@${spec.rawSpec}` : ''
|
104 | }`)
|
105 | }
|
106 | cb(null, ret)
|
107 | },
|
108 | err => err.code === 'EUSAGE' ? cb(err.message) : cb(err)
|
109 | )
|
110 | }
|