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 foregroundScripts: this.npm.config.isDefault('foreground-scripts') 51 ? true 52 : this.npm.config.get('foreground-scripts'), 53 prefix: this.npm.localPrefix, 54 workspaces: this.workspacePaths, 55 }) 56 const pkgContents = await getContents(manifest, tarballData) 57 tarballs.push(pkgContents) 58 } 59 60 if (json) { 61 this.npm.output(JSON.stringify(tarballs, null, 2)) 62 return 63 } 64 65 for (const tar of tarballs) { 66 logTar(tar, { unicode }) 67 this.npm.output(tar.filename.replace(/^@/, '').replace(/\//, '-')) 68 } 69 } 70 71 async execWorkspaces (args) { 72 // If they either ask for nothing, or explicitly include '.' in the args, 73 // we effectively translate that into each workspace requested 74 75 const useWorkspaces = args.length === 0 || args.includes('.') 76 77 if (!useWorkspaces) { 78 log.warn('Ignoring workspaces for specified package(s)') 79 return this.exec(args) 80 } 81 82 await this.setWorkspaces() 83 return this.exec([...this.workspacePaths, ...args.filter(a => a !== '.')]) 84 } 85} 86module.exports = Pack 87