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