Skip to content

Commit 75642c6

Browse files
committed
deps: @npmcli/promise-spawn@7.0.0
1 parent dbb18f4 commit 75642c6

File tree

22 files changed

+1080
-35
lines changed

22 files changed

+1080
-35
lines changed

DEPENDENCIES.md

-2
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ graph LR;
115115
npm-->npm-profile;
116116
npm-->npm-registry-fetch;
117117
npm-->npm-user-validate;
118-
npm-->npmcli-agent["@npmcli/agent"];
119118
npm-->npmcli-arborist["@npmcli/arborist"];
120119
npm-->npmcli-config["@npmcli/config"];
121120
npm-->npmcli-docs["@npmcli/docs"];
@@ -541,7 +540,6 @@ graph LR;
541540
npm-->npm-profile;
542541
npm-->npm-registry-fetch;
543542
npm-->npm-user-validate;
544-
npm-->npmcli-agent["@npmcli/agent"];
545543
npm-->npmcli-arborist["@npmcli/arborist"];
546544
npm-->npmcli-config["@npmcli/config"];
547545
npm-->npmcli-docs["@npmcli/docs"];

node_modules/.gitignore

+12-3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
!/@npmcli/git
3131
!/@npmcli/git/node_modules/
3232
/@npmcli/git/node_modules/*
33+
!/@npmcli/git/node_modules/@npmcli/
34+
/@npmcli/git/node_modules/@npmcli/*
35+
!/@npmcli/git/node_modules/@npmcli/promise-spawn
3336
!/@npmcli/git/node_modules/which
3437
!/@npmcli/installed-package-contents
3538
!/@npmcli/map-workspaces
@@ -38,13 +41,13 @@
3841
!/@npmcli/node-gyp
3942
!/@npmcli/package-json
4043
!/@npmcli/promise-spawn
41-
!/@npmcli/promise-spawn/node_modules/
42-
/@npmcli/promise-spawn/node_modules/*
43-
!/@npmcli/promise-spawn/node_modules/which
4444
!/@npmcli/query
4545
!/@npmcli/run-script
4646
!/@npmcli/run-script/node_modules/
4747
/@npmcli/run-script/node_modules/*
48+
!/@npmcli/run-script/node_modules/@npmcli/
49+
/@npmcli/run-script/node_modules/@npmcli/*
50+
!/@npmcli/run-script/node_modules/@npmcli/promise-spawn
4851
!/@npmcli/run-script/node_modules/which
4952
!/@pkgjs/
5053
/@pkgjs/*
@@ -226,6 +229,12 @@
226229
!/once
227230
!/p-map
228231
!/pacote
232+
!/pacote/node_modules/
233+
/pacote/node_modules/*
234+
!/pacote/node_modules/@npmcli/
235+
/pacote/node_modules/@npmcli/*
236+
!/pacote/node_modules/@npmcli/promise-spawn
237+
!/pacote/node_modules/which
229238
!/parse-conflict-json
230239
!/path-is-absolute
231240
!/path-key
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
The ISC License
2+
3+
Copyright (c) npm, Inc.
4+
5+
Permission to use, copy, modify, and/or distribute this software for any
6+
purpose with or without fee is hereby granted, provided that the above
7+
copyright notice and this permission notice appear in all copies.
8+
9+
THE SOFTWARE IS PROVIDED "AS IS" AND THE NPM DISCLAIMS ALL WARRANTIES WITH
10+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
11+
FITNESS. IN NO EVENT SHALL THE NPM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
12+
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
13+
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14+
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15+
SOFTWARE.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
'use strict'
2+
3+
// eslint-disable-next-line max-len
4+
// this code adapted from: https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
5+
const cmd = (input, doubleEscape) => {
6+
if (!input.length) {
7+
return '""'
8+
}
9+
10+
let result
11+
if (!/[ \t\n\v"]/.test(input)) {
12+
result = input
13+
} else {
14+
result = '"'
15+
for (let i = 0; i <= input.length; ++i) {
16+
let slashCount = 0
17+
while (input[i] === '\\') {
18+
++i
19+
++slashCount
20+
}
21+
22+
if (i === input.length) {
23+
result += '\\'.repeat(slashCount * 2)
24+
break
25+
}
26+
27+
if (input[i] === '"') {
28+
result += '\\'.repeat(slashCount * 2 + 1)
29+
result += input[i]
30+
} else {
31+
result += '\\'.repeat(slashCount)
32+
result += input[i]
33+
}
34+
}
35+
result += '"'
36+
}
37+
38+
// and finally, prefix shell meta chars with a ^
39+
result = result.replace(/[ !%^&()<>|"]/g, '^$&')
40+
if (doubleEscape) {
41+
result = result.replace(/[ !%^&()<>|"]/g, '^$&')
42+
}
43+
44+
return result
45+
}
46+
47+
const sh = (input) => {
48+
if (!input.length) {
49+
return `''`
50+
}
51+
52+
if (!/[\t\n\r "#$&'()*;<>?\\`|~]/.test(input)) {
53+
return input
54+
}
55+
56+
// replace single quotes with '\'' and wrap the whole result in a fresh set of quotes
57+
const result = `'${input.replace(/'/g, `'\\''`)}'`
58+
// if the input string already had single quotes around it, clean those up
59+
.replace(/^(?:'')+(?!$)/, '')
60+
.replace(/\\'''/g, `\\'`)
61+
62+
return result
63+
}
64+
65+
module.exports = {
66+
cmd,
67+
sh,
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
'use strict'
2+
3+
const { spawn } = require('child_process')
4+
const os = require('os')
5+
const which = require('which')
6+
7+
const escape = require('./escape.js')
8+
9+
// 'extra' object is for decorating the error a bit more
10+
const promiseSpawn = (cmd, args, opts = {}, extra = {}) => {
11+
if (opts.shell) {
12+
return spawnWithShell(cmd, args, opts, extra)
13+
}
14+
15+
let proc
16+
17+
const p = new Promise((res, rej) => {
18+
proc = spawn(cmd, args, opts)
19+
20+
const stdout = []
21+
const stderr = []
22+
23+
const reject = er => rej(Object.assign(er, {
24+
cmd,
25+
args,
26+
...stdioResult(stdout, stderr, opts),
27+
...extra,
28+
}))
29+
30+
proc.on('error', reject)
31+
32+
if (proc.stdout) {
33+
proc.stdout.on('data', c => stdout.push(c)).on('error', reject)
34+
proc.stdout.on('error', er => reject(er))
35+
}
36+
37+
if (proc.stderr) {
38+
proc.stderr.on('data', c => stderr.push(c)).on('error', reject)
39+
proc.stderr.on('error', er => reject(er))
40+
}
41+
42+
proc.on('close', (code, signal) => {
43+
const result = {
44+
cmd,
45+
args,
46+
code,
47+
signal,
48+
...stdioResult(stdout, stderr, opts),
49+
...extra,
50+
}
51+
52+
if (code || signal) {
53+
rej(Object.assign(new Error('command failed'), result))
54+
} else {
55+
res(result)
56+
}
57+
})
58+
})
59+
60+
p.stdin = proc.stdin
61+
p.process = proc
62+
return p
63+
}
64+
65+
const spawnWithShell = (cmd, args, opts, extra) => {
66+
let command = opts.shell
67+
// if shell is set to true, we use a platform default. we can't let the core
68+
// spawn method decide this for us because we need to know what shell is in use
69+
// ahead of time so that we can escape arguments properly. we don't need coverage here.
70+
if (command === true) {
71+
// istanbul ignore next
72+
command = process.platform === 'win32' ? process.env.ComSpec : 'sh'
73+
}
74+
75+
const options = { ...opts, shell: false }
76+
const realArgs = []
77+
let script = cmd
78+
79+
// first, determine if we're in windows because if we are we need to know if we're
80+
// running an .exe or a .cmd/.bat since the latter requires extra escaping
81+
const isCmd = /(?:^|\\)cmd(?:\.exe)?$/i.test(command)
82+
if (isCmd) {
83+
let doubleEscape = false
84+
85+
// find the actual command we're running
86+
let initialCmd = ''
87+
let insideQuotes = false
88+
for (let i = 0; i < cmd.length; ++i) {
89+
const char = cmd.charAt(i)
90+
if (char === ' ' && !insideQuotes) {
91+
break
92+
}
93+
94+
initialCmd += char
95+
if (char === '"' || char === "'") {
96+
insideQuotes = !insideQuotes
97+
}
98+
}
99+
100+
let pathToInitial
101+
try {
102+
pathToInitial = which.sync(initialCmd, {
103+
path: (options.env && options.env.PATH) || process.env.PATH,
104+
pathext: (options.env && options.env.PATHEXT) || process.env.PATHEXT,
105+
}).toLowerCase()
106+
} catch (err) {
107+
pathToInitial = initialCmd.toLowerCase()
108+
}
109+
110+
doubleEscape = pathToInitial.endsWith('.cmd') || pathToInitial.endsWith('.bat')
111+
for (const arg of args) {
112+
script += ` ${escape.cmd(arg, doubleEscape)}`
113+
}
114+
realArgs.push('/d', '/s', '/c', script)
115+
options.windowsVerbatimArguments = true
116+
} else {
117+
for (const arg of args) {
118+
script += ` ${escape.sh(arg)}`
119+
}
120+
realArgs.push('-c', script)
121+
}
122+
123+
return promiseSpawn(command, realArgs, options, extra)
124+
}
125+
126+
// open a file with the default application as defined by the user's OS
127+
const open = (_args, opts = {}, extra = {}) => {
128+
const options = { ...opts, shell: true }
129+
const args = [].concat(_args)
130+
131+
let platform = process.platform
132+
// process.platform === 'linux' may actually indicate WSL, if that's the case
133+
// we want to treat things as win32 anyway so the host can open the argument
134+
if (platform === 'linux' && os.release().toLowerCase().includes('microsoft')) {
135+
platform = 'win32'
136+
}
137+
138+
let command = options.command
139+
if (!command) {
140+
if (platform === 'win32') {
141+
// spawnWithShell does not do the additional os.release() check, so we
142+
// have to force the shell here to make sure we treat WSL as windows.
143+
options.shell = process.env.ComSpec
144+
// also, the start command accepts a title so to make sure that we don't
145+
// accidentally interpret the first arg as the title, we stick an empty
146+
// string immediately after the start command
147+
command = 'start ""'
148+
} else if (platform === 'darwin') {
149+
command = 'open'
150+
} else {
151+
command = 'xdg-open'
152+
}
153+
}
154+
155+
return spawnWithShell(command, args, options, extra)
156+
}
157+
promiseSpawn.open = open
158+
159+
const isPipe = (stdio = 'pipe', fd) => {
160+
if (stdio === 'pipe' || stdio === null) {
161+
return true
162+
}
163+
164+
if (Array.isArray(stdio)) {
165+
return isPipe(stdio[fd], fd)
166+
}
167+
168+
return false
169+
}
170+
171+
const stdioResult = (stdout, stderr, { stdioString = true, stdio }) => {
172+
const result = {
173+
stdout: null,
174+
stderr: null,
175+
}
176+
177+
// stdio is [stdin, stdout, stderr]
178+
if (isPipe(stdio, 1)) {
179+
result.stdout = Buffer.concat(stdout)
180+
if (stdioString) {
181+
result.stdout = result.stdout.toString().trim()
182+
}
183+
}
184+
185+
if (isPipe(stdio, 2)) {
186+
result.stderr = Buffer.concat(stderr)
187+
if (stdioString) {
188+
result.stderr = result.stderr.toString().trim()
189+
}
190+
}
191+
192+
return result
193+
}
194+
195+
module.exports = promiseSpawn
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{
2+
"name": "@npmcli/promise-spawn",
3+
"version": "6.0.2",
4+
"files": [
5+
"bin/",
6+
"lib/"
7+
],
8+
"main": "./lib/index.js",
9+
"description": "spawn processes the way the npm cli likes to do",
10+
"repository": {
11+
"type": "git",
12+
"url": "https://github.com/npm/promise-spawn.git"
13+
},
14+
"author": "GitHub Inc.",
15+
"license": "ISC",
16+
"scripts": {
17+
"test": "tap",
18+
"snap": "tap",
19+
"lint": "eslint \"**/*.js\"",
20+
"lintfix": "npm run lint -- --fix",
21+
"posttest": "npm run lint",
22+
"postsnap": "npm run lintfix --",
23+
"postlint": "template-oss-check",
24+
"template-oss-apply": "template-oss-apply --force"
25+
},
26+
"tap": {
27+
"check-coverage": true,
28+
"nyc-arg": [
29+
"--exclude",
30+
"tap-snapshots/**"
31+
]
32+
},
33+
"devDependencies": {
34+
"@npmcli/eslint-config": "^4.0.0",
35+
"@npmcli/template-oss": "4.11.0",
36+
"minipass": "^4.0.0",
37+
"spawk": "^1.7.1",
38+
"tap": "^16.0.1"
39+
},
40+
"engines": {
41+
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
42+
},
43+
"templateOSS": {
44+
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
45+
"version": "4.11.0"
46+
},
47+
"dependencies": {
48+
"which": "^3.0.0"
49+
}
50+
}

0 commit comments

Comments
 (0)