rebuild.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. const { resolve } = require('path')
  2. const Arborist = require('@npmcli/arborist')
  3. const npa = require('npm-package-arg')
  4. const semver = require('semver')
  5. const completion = require('./utils/completion/installed-deep.js')
  6. const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js')
  7. class Rebuild extends ArboristWorkspaceCmd {
  8. /* istanbul ignore next - see test/lib/load-all-commands.js */
  9. static get description () {
  10. return 'Rebuild a package'
  11. }
  12. /* istanbul ignore next - see test/lib/load-all-commands.js */
  13. static get name () {
  14. return 'rebuild'
  15. }
  16. /* istanbul ignore next - see test/lib/load-all-commands.js */
  17. static get params () {
  18. return [
  19. 'global',
  20. 'bin-links',
  21. 'ignore-scripts',
  22. ...super.params,
  23. ]
  24. }
  25. /* istanbul ignore next - see test/lib/load-all-commands.js */
  26. static get usage () {
  27. return ['[[<@scope>/]<name>[@<version>] ...]']
  28. }
  29. /* istanbul ignore next - see test/lib/load-all-commands.js */
  30. async completion (opts) {
  31. return completion(this.npm, opts)
  32. }
  33. exec (args, cb) {
  34. this.rebuild(args).then(() => cb()).catch(cb)
  35. }
  36. async rebuild (args) {
  37. const globalTop = resolve(this.npm.globalDir, '..')
  38. const where = this.npm.config.get('global') ? globalTop : this.npm.prefix
  39. const arb = new Arborist({
  40. ...this.npm.flatOptions,
  41. path: where,
  42. // TODO when extending ReifyCmd
  43. // workspaces: this.workspaceNames,
  44. })
  45. if (args.length) {
  46. // get the set of nodes matching the name that we want rebuilt
  47. const tree = await arb.loadActual()
  48. const specs = args.map(arg => {
  49. const spec = npa(arg)
  50. if (spec.type === 'tag' && spec.rawSpec === '')
  51. return spec
  52. if (spec.type !== 'range' && spec.type !== 'version' && spec.type !== 'directory')
  53. throw new Error('`npm rebuild` only supports SemVer version/range specifiers')
  54. return spec
  55. })
  56. const nodes = tree.inventory.filter(node => this.isNode(specs, node))
  57. await arb.rebuild({ nodes })
  58. } else
  59. await arb.rebuild()
  60. this.npm.output('rebuilt dependencies successfully')
  61. }
  62. isNode (specs, node) {
  63. return specs.some(spec => {
  64. if (spec.type === 'directory')
  65. return node.path === spec.fetchSpec
  66. if (spec.name !== node.name)
  67. return false
  68. if (spec.rawSpec === '' || spec.rawSpec === '*')
  69. return true
  70. const { version } = node.package
  71. // TODO: add tests for a package with missing version
  72. return semver.satisfies(version, spec.fetchSpec)
  73. })
  74. }
  75. }
  76. module.exports = Rebuild