Skip to content

Commit

Permalink
Add support for pnpm (bcomnes#117)
Browse files Browse the repository at this point in the history
  • Loading branch information
kinland committed Sep 29, 2023
1 parent fe72148 commit 3df3708
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 7 deletions.
39 changes: 34 additions & 5 deletions lib/run-task.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// Requirements
// ------------------------------------------------------------------------------

const fs = require('fs')
const path = require('path')
const parseArgs = require('shell-quote').parse
const createHeader = require('./create-header')
Expand Down Expand Up @@ -128,6 +129,9 @@ function cleanTaskArg (arg) {
* An array of options which are inserted before the task name.
* @param {object} options.labelState - A state object for printing labels.
* @param {boolean} options.printName - The flag to print task names before running each task.
* @param {object} options.packageInfo - A package.json's information.
* @param {object} options.packageInfo.body - A package.json's JSON object.
* @param {string} options.packageInfo.path - A package.json's file path.
* @returns {Promise}
* A promise object which becomes fullfilled when the npm-script is completed.
* This promise object has an extra method: `abort()`.
Expand Down Expand Up @@ -156,12 +160,37 @@ module.exports = function runTask (task, options) {
}

// Execute.
const npmPath = options.npmPath || path.basename(process.env.npm_execpath).startsWith('npx') // eslint-disable-line no-process-env
? path.join(path.dirname(process.env.npm_execpath), path.basename(process.env.npm_execpath).replace('npx', 'npm')) // eslint-disable-line no-process-env
: process.env.npm_execpath // eslint-disable-line no-process-env
const npmPathIsJs = typeof npmPath === 'string' && /\.m?js/.test(path.extname(npmPath))
const execPath = (npmPathIsJs ? process.execPath : npmPath || 'npm')
let npmPath = options.npmPath
if (!npmPath && process.env.npm_execpath) {
const basename = path.basename(process.env.npm_execpath)
let newBasename = basename
if (basename.startsWith('npx')) {
newBasename = basename.replace('npx', 'npm') // eslint-disable-line no-process-env
} else if (basename.startsWith('pnpx')) {
newBasename = basename.replace('pnpx', 'pnpm') // eslint-disable-line no-process-env
}

npmPath = newBasename === basename
? path.join(path.dirname(process.env.npm_execpath), newBasename)
: process.env.npm_execpath // eslint-disable-line no-process-env
}

const npmPathIsJs = typeof npmPath === 'string' && /\.(c|m)?js/.test(path.extname(npmPath))
let execPath = (npmPathIsJs ? process.execPath : npmPath || 'npm')

if (!npmPath && !process.env.npm_execpath) {
// When a script is being run via pnpm, npmPath and npm_execpath will be null or undefined
// Attempt to figure out whether we're running via pnpm
const projectRoot = path.dirname(options.packageInfo.path)
const hasPnpmLockfile = fs.existsSync(path.join(projectRoot, 'pnpm-lock.yaml'))
const { status: pnpmFound, output } = spawn.sync('which', 'pnpm', { silent: true })
if (hasPnpmLockfile && __dirname.split(path.delimiter).includes('.pnpm') && pnpmFound) {
execPath = output
}
}

const isYarn = process.env.npm_config_user_agent && process.env.npm_config_user_agent.startsWith('yarn') // eslint-disable-line no-process-env

const spawnArgs = ['run']

if (npmPathIsJs) {
Expand Down
18 changes: 17 additions & 1 deletion lib/spawn-posix.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,25 @@ function kill () {
* @returns {ChildProcess} A ChildProcess instance of new process.
* @private
*/
module.exports = function spawn (command, args, options) {
function spawn (command, args, options) {
const child = crossSpawn(command, args, options)
child.kill = kill

return child
}

/**
* Launches a new process synchronously with the given command.
* This is almost same as `child_process.spawnSync`.
*
* This returns a `SpawnSyncReturns` object.
*
* @param {string} command - The command to run.
* @param {string[]} args - List of string arguments.
* @param {object} options - Options.
* @returns {SpawnSyncReturns} A ChildProcess instance of new process.
* @private
*/
spawn.sync = crossSpawn.sync

module.exports = spawn
18 changes: 17 additions & 1 deletion lib/spawn-win32.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,25 @@ function kill () {
* @returns {ChildProcess} A ChildProcess instance of new process.
* @private
*/
module.exports = function spawn (command, args, options) {
function spawn (command, args, options) {
const child = crossSpawn(command, args, options)
child.kill = kill

return child
}

/**
* Launches a new process synchronously with the given command.
* This is almost same as `child_process.spawnSync`.
*
* This returns a `SpawnSyncReturns` object.
*
* @param {string} command - The command to run.
* @param {string[]} args - List of string arguments.
* @param {object} options - Options.
* @returns {SpawnSyncReturns} A ChildProcess instance of new process.
* @private
*/
spawn.sync = crossSpawn.sync

module.exports = spawn

0 comments on commit 3df3708

Please sign in to comment.