Skip to content

Commit 3df3708

Browse files
committedSep 29, 2023
Add support for pnpm (#117)
1 parent fe72148 commit 3df3708

File tree

3 files changed

+68
-7
lines changed

3 files changed

+68
-7
lines changed
 

‎lib/run-task.js

+34-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
// Requirements
1111
// ------------------------------------------------------------------------------
1212

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

158162
// Execute.
159-
const npmPath = options.npmPath || path.basename(process.env.npm_execpath).startsWith('npx') // eslint-disable-line no-process-env
160-
? path.join(path.dirname(process.env.npm_execpath), path.basename(process.env.npm_execpath).replace('npx', 'npm')) // eslint-disable-line no-process-env
161-
: process.env.npm_execpath // eslint-disable-line no-process-env
162-
const npmPathIsJs = typeof npmPath === 'string' && /\.m?js/.test(path.extname(npmPath))
163-
const execPath = (npmPathIsJs ? process.execPath : npmPath || 'npm')
163+
let npmPath = options.npmPath
164+
if (!npmPath && process.env.npm_execpath) {
165+
const basename = path.basename(process.env.npm_execpath)
166+
let newBasename = basename
167+
if (basename.startsWith('npx')) {
168+
newBasename = basename.replace('npx', 'npm') // eslint-disable-line no-process-env
169+
} else if (basename.startsWith('pnpx')) {
170+
newBasename = basename.replace('pnpx', 'pnpm') // eslint-disable-line no-process-env
171+
}
172+
173+
npmPath = newBasename === basename
174+
? path.join(path.dirname(process.env.npm_execpath), newBasename)
175+
: process.env.npm_execpath // eslint-disable-line no-process-env
176+
}
177+
178+
const npmPathIsJs = typeof npmPath === 'string' && /\.(c|m)?js/.test(path.extname(npmPath))
179+
let execPath = (npmPathIsJs ? process.execPath : npmPath || 'npm')
180+
181+
if (!npmPath && !process.env.npm_execpath) {
182+
// When a script is being run via pnpm, npmPath and npm_execpath will be null or undefined
183+
// Attempt to figure out whether we're running via pnpm
184+
const projectRoot = path.dirname(options.packageInfo.path)
185+
const hasPnpmLockfile = fs.existsSync(path.join(projectRoot, 'pnpm-lock.yaml'))
186+
const { status: pnpmFound, output } = spawn.sync('which', 'pnpm', { silent: true })
187+
if (hasPnpmLockfile && __dirname.split(path.delimiter).includes('.pnpm') && pnpmFound) {
188+
execPath = output
189+
}
190+
}
191+
164192
const isYarn = process.env.npm_config_user_agent && process.env.npm_config_user_agent.startsWith('yarn') // eslint-disable-line no-process-env
193+
165194
const spawnArgs = ['run']
166195

167196
if (npmPathIsJs) {

‎lib/spawn-posix.js

+17-1
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,25 @@ function kill () {
5555
* @returns {ChildProcess} A ChildProcess instance of new process.
5656
* @private
5757
*/
58-
module.exports = function spawn (command, args, options) {
58+
function spawn (command, args, options) {
5959
const child = crossSpawn(command, args, options)
6060
child.kill = kill
6161

6262
return child
6363
}
64+
65+
/**
66+
* Launches a new process synchronously with the given command.
67+
* This is almost same as `child_process.spawnSync`.
68+
*
69+
* This returns a `SpawnSyncReturns` object.
70+
*
71+
* @param {string} command - The command to run.
72+
* @param {string[]} args - List of string arguments.
73+
* @param {object} options - Options.
74+
* @returns {SpawnSyncReturns} A ChildProcess instance of new process.
75+
* @private
76+
*/
77+
spawn.sync = crossSpawn.sync
78+
79+
module.exports = spawn

‎lib/spawn-win32.js

+17-1
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,25 @@ function kill () {
4242
* @returns {ChildProcess} A ChildProcess instance of new process.
4343
* @private
4444
*/
45-
module.exports = function spawn (command, args, options) {
45+
function spawn (command, args, options) {
4646
const child = crossSpawn(command, args, options)
4747
child.kill = kill
4848

4949
return child
5050
}
51+
52+
/**
53+
* Launches a new process synchronously with the given command.
54+
* This is almost same as `child_process.spawnSync`.
55+
*
56+
* This returns a `SpawnSyncReturns` object.
57+
*
58+
* @param {string} command - The command to run.
59+
* @param {string[]} args - List of string arguments.
60+
* @param {object} options - Options.
61+
* @returns {SpawnSyncReturns} A ChildProcess instance of new process.
62+
* @private
63+
*/
64+
spawn.sync = crossSpawn.sync
65+
66+
module.exports = spawn

0 commit comments

Comments
 (0)
Please sign in to comment.