1#!/usr/bin/env node
2
3const run = conf => {
4  const pacote = require('../')
5  switch (conf._[0]) {
6    case 'resolve':
7    case 'manifest':
8    case 'packument':
9      if (conf._[0] === 'resolve' && conf.long) {
10        return pacote.manifest(conf._[1], conf).then(mani => ({
11          resolved: mani._resolved,
12          integrity: mani._integrity,
13          from: mani._from,
14        }))
15      }
16      return pacote[conf._[0]](conf._[1], conf)
17
18    case 'tarball':
19      if (!conf._[2] || conf._[2] === '-') {
20        return pacote.tarball.stream(conf._[1], stream => {
21          stream.pipe(
22            conf.testStdout ||
23            /* istanbul ignore next */
24            process.stdout
25          )
26          // make sure it resolves something falsey
27          return stream.promise().then(() => {
28            return false
29          })
30        }, conf)
31      } else {
32        return pacote.tarball.file(conf._[1], conf._[2], conf)
33      }
34
35    case 'extract':
36      return pacote.extract(conf._[1], conf._[2], conf)
37
38    default: /* istanbul ignore next */ {
39      throw new Error(`bad command: ${conf._[0]}`)
40    }
41  }
42}
43
44const version = require('../package.json').version
45const usage = () =>
46`Pacote - The JavaScript Package Handler, v${version}
47
48Usage:
49
50  pacote resolve <spec>
51    Resolve a specifier and output the fully resolved target
52    Returns integrity and from if '--long' flag is set.
53
54  pacote manifest <spec>
55    Fetch a manifest and print to stdout
56
57  pacote packument <spec>
58    Fetch a full packument and print to stdout
59
60  pacote tarball <spec> [<filename>]
61    Fetch a package tarball and save to <filename>
62    If <filename> is missing or '-', the tarball will be streamed to stdout.
63
64  pacote extract <spec> <folder>
65    Extract a package to the destination folder.
66
67Configuration values all match the names of configs passed to npm, or
68options passed to Pacote.  Additional flags for this executable:
69
70  --long     Print an object from 'resolve', including integrity and spec.
71  --json     Print result objects as JSON rather than node's default.
72             (This is the default if stdout is not a TTY.)
73  --help -h  Print this helpful text.
74
75For example '--cache=/path/to/folder' will use that folder as the cache.
76`
77
78const shouldJSON = (conf, result) =>
79  conf.json ||
80  !process.stdout.isTTY &&
81  conf.json === undefined &&
82  result &&
83  typeof result === 'object'
84
85const pretty = (conf, result) =>
86  shouldJSON(conf, result) ? JSON.stringify(result, 0, 2) : result
87
88let addedLogListener = false
89const main = args => {
90  const conf = parse(args)
91  if (conf.help || conf.h) {
92    return console.log(usage())
93  }
94
95  if (!addedLogListener) {
96    process.on('log', console.error)
97    addedLogListener = true
98  }
99
100  try {
101    return run(conf)
102      .then(result => result && console.log(pretty(conf, result)))
103      .catch(er => {
104        console.error(er)
105        process.exit(1)
106      })
107  } catch (er) {
108    console.error(er.message)
109    console.error(usage())
110  }
111}
112
113const parseArg = arg => {
114  const split = arg.slice(2).split('=')
115  const k = split.shift()
116  const v = split.join('=')
117  const no = /^no-/.test(k) && !v
118  const key = (no ? k.slice(3) : k)
119    .replace(/^tag$/, 'defaultTag')
120    .replace(/-([a-z])/g, (_, c) => c.toUpperCase())
121  const value = v ? v.replace(/^~/, process.env.HOME) : !no
122  return { key, value }
123}
124
125const parse = args => {
126  const conf = {
127    _: [],
128    cache: process.env.HOME + '/.npm/_cacache',
129  }
130  let dashdash = false
131  args.forEach(arg => {
132    if (dashdash) {
133      conf._.push(arg)
134    } else if (arg === '--') {
135      dashdash = true
136    } else if (arg === '-h') {
137      conf.help = true
138    } else if (/^--/.test(arg)) {
139      const { key, value } = parseArg(arg)
140      conf[key] = value
141    } else {
142      conf._.push(arg)
143    }
144  })
145  return conf
146}
147
148if (module === require.main) {
149  main(process.argv.slice(2))
150} else {
151  module.exports = {
152    main,
153    run,
154    usage,
155    parseArg,
156    parse,
157  }
158}
159