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