• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1const pacote = require('pacote')
2const libpack = require('libnpmpack')
3const npa = require('npm-package-arg')
4const log = require('../utils/log-shim')
5const { getContents, logTar } = require('../utils/tar.js')
6const BaseCommand = require('../base-command.js')
7
8class Pack extends BaseCommand {
9  static description = 'Create a tarball from a package'
10  static name = 'pack'
11  static params = [
12    'dry-run',
13    'json',
14    'pack-destination',
15    'workspace',
16    'workspaces',
17    'include-workspace-root',
18  ]
19
20  static usage = ['<package-spec>']
21  static workspaces = true
22  static ignoreImplicitWorkspace = false
23
24  async exec (args) {
25    if (args.length === 0) {
26      args = ['.']
27    }
28
29    const unicode = this.npm.config.get('unicode')
30    const json = this.npm.config.get('json')
31
32    // Get the manifests and filenames first so we can bail early on manifest
33    // errors before making any tarballs
34    const manifests = []
35    for (const arg of args) {
36      const spec = npa(arg)
37      const manifest = await pacote.manifest(spec, this.npm.flatOptions)
38      if (!manifest._id) {
39        throw new Error('Invalid package, must have name and version')
40      }
41      manifests.push({ arg, manifest })
42    }
43
44    // Load tarball names up for printing afterward to isolate from the
45    // noise generated during packing
46    const tarballs = []
47    for (const { arg, manifest } of manifests) {
48      const tarballData = await libpack(arg, {
49        ...this.npm.flatOptions,
50        prefix: this.npm.localPrefix,
51        workspaces: this.workspacePaths,
52      })
53      const pkgContents = await getContents(manifest, tarballData)
54      tarballs.push(pkgContents)
55    }
56
57    if (json) {
58      this.npm.output(JSON.stringify(tarballs, null, 2))
59      return
60    }
61
62    for (const tar of tarballs) {
63      logTar(tar, { unicode })
64      this.npm.output(tar.filename.replace(/^@/, '').replace(/\//, '-'))
65    }
66  }
67
68  async execWorkspaces (args) {
69    // If they either ask for nothing, or explicitly include '.' in the args,
70    // we effectively translate that into each workspace requested
71
72    const useWorkspaces = args.length === 0 || args.includes('.')
73
74    if (!useWorkspaces) {
75      log.warn('Ignoring workspaces for specified package(s)')
76      return this.exec(args)
77    }
78
79    await this.setWorkspaces()
80    return this.exec([...this.workspacePaths, ...args.filter(a => a !== '.')])
81  }
82}
83module.exports = Pack
84