11cb0ef41Sopenharmony_ciconst { resolve } = require('path') 21cb0ef41Sopenharmony_ciconst libexec = require('libnpmexec') 31cb0ef41Sopenharmony_ciconst BaseCommand = require('../base-command.js') 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ciclass Exec extends BaseCommand { 61cb0ef41Sopenharmony_ci static description = 'Run a command from a local or remote npm package' 71cb0ef41Sopenharmony_ci static params = [ 81cb0ef41Sopenharmony_ci 'package', 91cb0ef41Sopenharmony_ci 'call', 101cb0ef41Sopenharmony_ci 'workspace', 111cb0ef41Sopenharmony_ci 'workspaces', 121cb0ef41Sopenharmony_ci 'include-workspace-root', 131cb0ef41Sopenharmony_ci ] 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ci static name = 'exec' 161cb0ef41Sopenharmony_ci static usage = [ 171cb0ef41Sopenharmony_ci '-- <pkg>[@<version>] [args...]', 181cb0ef41Sopenharmony_ci '--package=<pkg>[@<version>] -- <cmd> [args...]', 191cb0ef41Sopenharmony_ci '-c \'<cmd> [args...]\'', 201cb0ef41Sopenharmony_ci '--package=foo -c \'<cmd> [args...]\'', 211cb0ef41Sopenharmony_ci ] 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ci static workspaces = true 241cb0ef41Sopenharmony_ci static ignoreImplicitWorkspace = false 251cb0ef41Sopenharmony_ci static isShellout = true 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ci async exec (args) { 281cb0ef41Sopenharmony_ci return this.callExec(args) 291cb0ef41Sopenharmony_ci } 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ci async execWorkspaces (args) { 321cb0ef41Sopenharmony_ci await this.setWorkspaces() 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ci for (const [name, path] of this.workspaces) { 351cb0ef41Sopenharmony_ci const locationMsg = 361cb0ef41Sopenharmony_ci `in workspace ${this.npm.chalk.green(name)} at location:\n${this.npm.chalk.dim(path)}` 371cb0ef41Sopenharmony_ci await this.callExec(args, { name, locationMsg, runPath: path }) 381cb0ef41Sopenharmony_ci } 391cb0ef41Sopenharmony_ci } 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci async callExec (args, { name, locationMsg, runPath } = {}) { 421cb0ef41Sopenharmony_ci // This is where libnpmexec will look for locally installed packages at the project level 431cb0ef41Sopenharmony_ci const localPrefix = this.npm.localPrefix 441cb0ef41Sopenharmony_ci // This is where libnpmexec will look for locally installed packages at the workspace level 451cb0ef41Sopenharmony_ci let localBin = this.npm.localBin 461cb0ef41Sopenharmony_ci let path = localPrefix 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ci // This is where libnpmexec will actually run the scripts from 491cb0ef41Sopenharmony_ci if (!runPath) { 501cb0ef41Sopenharmony_ci runPath = process.cwd() 511cb0ef41Sopenharmony_ci } else { 521cb0ef41Sopenharmony_ci // We have to consider if the workspace has its own separate versions 531cb0ef41Sopenharmony_ci // libnpmexec will walk up to localDir after looking here 541cb0ef41Sopenharmony_ci localBin = resolve(this.npm.localDir, name, 'node_modules', '.bin') 551cb0ef41Sopenharmony_ci // We also need to look for `bin` entries in the workspace package.json 561cb0ef41Sopenharmony_ci // libnpmexec will NOT look in the project root for the bin entry 571cb0ef41Sopenharmony_ci path = runPath 581cb0ef41Sopenharmony_ci } 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ci const call = this.npm.config.get('call') 611cb0ef41Sopenharmony_ci let globalPath 621cb0ef41Sopenharmony_ci const { 631cb0ef41Sopenharmony_ci flatOptions, 641cb0ef41Sopenharmony_ci globalBin, 651cb0ef41Sopenharmony_ci globalDir, 661cb0ef41Sopenharmony_ci chalk, 671cb0ef41Sopenharmony_ci } = this.npm 681cb0ef41Sopenharmony_ci const output = this.npm.output.bind(this.npm) 691cb0ef41Sopenharmony_ci const scriptShell = this.npm.config.get('script-shell') || undefined 701cb0ef41Sopenharmony_ci const packages = this.npm.config.get('package') 711cb0ef41Sopenharmony_ci const yes = this.npm.config.get('yes') 721cb0ef41Sopenharmony_ci // --prefix sets both of these to the same thing, meaning the global prefix 731cb0ef41Sopenharmony_ci // is invalid (i.e. no lib/node_modules). This is not a trivial thing to 741cb0ef41Sopenharmony_ci // untangle and fix so we work around it here. 751cb0ef41Sopenharmony_ci if (this.npm.localPrefix !== this.npm.globalPrefix) { 761cb0ef41Sopenharmony_ci globalPath = resolve(globalDir, '..') 771cb0ef41Sopenharmony_ci } 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci if (call && args.length) { 801cb0ef41Sopenharmony_ci throw this.usageError() 811cb0ef41Sopenharmony_ci } 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci return libexec({ 841cb0ef41Sopenharmony_ci ...flatOptions, 851cb0ef41Sopenharmony_ci // we explicitly set packageLockOnly to false because if it's true 861cb0ef41Sopenharmony_ci // when we try to install a missing package, we won't actually install it 871cb0ef41Sopenharmony_ci packageLockOnly: false, 881cb0ef41Sopenharmony_ci // copy args so they dont get mutated 891cb0ef41Sopenharmony_ci args: [...args], 901cb0ef41Sopenharmony_ci call, 911cb0ef41Sopenharmony_ci chalk, 921cb0ef41Sopenharmony_ci globalBin, 931cb0ef41Sopenharmony_ci globalPath, 941cb0ef41Sopenharmony_ci localBin, 951cb0ef41Sopenharmony_ci locationMsg, 961cb0ef41Sopenharmony_ci output, 971cb0ef41Sopenharmony_ci packages, 981cb0ef41Sopenharmony_ci path, 991cb0ef41Sopenharmony_ci runPath, 1001cb0ef41Sopenharmony_ci scriptShell, 1011cb0ef41Sopenharmony_ci yes, 1021cb0ef41Sopenharmony_ci }) 1031cb0ef41Sopenharmony_ci } 1041cb0ef41Sopenharmony_ci} 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_cimodule.exports = Exec 107