pack.js 2.8 KB

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