Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
755c75a
fix(powershell): use Invoke-Expression to pass args
alexsch01 May 1, 2025
5981a1b
`$MyInvocation.Statement` is undefined in Windows PowerShell
alexsch01 May 1, 2025
d37f8f9
`windows-shims.js`: cover passing regular and named parameters to scr…
alexsch01 May 2, 2025
7a931ed
add tests for comma-separated values
alexsch01 May 2, 2025
6ac5541
remove test that doesn't work in command prompt
alexsch01 May 2, 2025
230fcd8
add npx tests
alexsch01 May 2, 2025
d18d75e
correct test
alexsch01 May 2, 2025
f3ff347
small change
alexsch01 May 3, 2025
ece490b
Update windows-shims.js
alexsch01 May 3, 2025
f446d38
Update windows-shims.js
alexsch01 May 3, 2025
a4077f5
make less strict
alexsch01 May 3, 2025
9f8bb56
oops
alexsch01 May 3, 2025
fee22f1
`npm.ps1` fix multiple commands
alexsch01 May 3, 2025
3a4bde2
`npx.ps1` fix multiple commands
alexsch01 May 3, 2025
16ee512
Update windows-shims.js
alexsch01 May 3, 2025
d8bd5a2
formatting change
alexsch01 May 3, 2025
58b9d55
fix typos
alexsch01 May 3, 2025
1526dfe
replace tests
alexsch01 May 3, 2025
860481e
Update windows-shims.js
alexsch01 May 3, 2025
50e77f7
Update windows-shims.js
alexsch01 May 3, 2025
c3f8c94
skip tests that can't pass with cygwin
alexsch01 May 4, 2025
77e5af2
more consistent
alexsch01 May 4, 2025
ce0bf2b
more consistent
alexsch01 May 4, 2025
bd2cd77
revert bad commits
alexsch01 May 4, 2025
cc9e57a
add back consistency commits, add check for Windows PowerShell but do…
alexsch01 May 4, 2025
1bfbd78
complete change
alexsch01 May 5, 2025
360b090
also for npx.ps1
alexsch01 May 5, 2025
668d40d
oop
alexsch01 May 5, 2025
72c9fdd
formatting
alexsch01 May 5, 2025
fb49f5b
remove normalize part
alexsch01 May 5, 2025
2d03217
check value of `$MyInvocation.OffsetInLine`
alexsch01 May 5, 2025
204a228
finally get it to pass
alexsch01 May 5, 2025
4befbeb
add `powershell.exe` test, have default case for PS1 scripts, revert …
alexsch01 May 5, 2025
8502ce0
Merge branch 'npm:latest' into latest
alexsch01 May 5, 2025
60161d2
make simpler
alexsch01 May 6, 2025
622f7fe
oops
alexsch01 May 6, 2025
09f002d
properly quote `$NODE_EXE` and `$NPM_CLI_JS`/`$NPX_CLI_JS` with Invok…
alexsch01 May 6, 2025
cd4eab7
use reflection to get the full powershell command
alexsch01 May 6, 2025
a128038
use `$MyInvocation.Statement` if exists already
alexsch01 May 6, 2025
d74a744
combine tests
alexsch01 May 6, 2025
8235520
fix test
alexsch01 May 6, 2025
59e56c0
make simpler
alexsch01 May 6, 2025
81f2426
single exit for ps1 bin files, single-quote test
alexsch01 May 7, 2025
7386bde
Merge branch 'npm:latest' into latest
alexsch01 May 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions bin/npm.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,29 @@ if (Test-Path $NPM_PREFIX_NPM_CLI_JS) {
$NPM_CLI_JS=$NPM_PREFIX_NPM_CLI_JS
}

# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & $NODE_EXE $NPM_CLI_JS $args
if ($MyInvocation.OffsetInLine -gt 0) {
if ($MyInvocation.Statement) {
$NPM_ARGS = $MyInvocation.Statement.Substring($MyInvocation.InvocationName.Length).Trim()
} else {
$NPM_OG_COMMAND = (
[System.Management.Automation.InvocationInfo].GetProperty('ScriptPosition', [System.Reflection.BindingFlags] 'Instance, NonPublic')
).GetValue($MyInvocation).Text
$NPM_ARGS = $NPM_OG_COMMAND.Substring($MyInvocation.InvocationName.Length).Trim()
}

# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | Invoke-Expression "& `"$NODE_EXE`" `"$NPM_CLI_JS`" $NPM_ARGS"
} else {
Invoke-Expression "& `"$NODE_EXE`" `"$NPM_CLI_JS`" $NPM_ARGS"
}
} else {
& $NODE_EXE $NPM_CLI_JS $args
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & $NODE_EXE $NPM_CLI_JS $args
} else {
& $NODE_EXE $NPM_CLI_JS $args
}
}

exit $LASTEXITCODE
26 changes: 22 additions & 4 deletions bin/npx.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,29 @@ if (Test-Path $NPM_PREFIX_NPX_CLI_JS) {
$NPX_CLI_JS=$NPM_PREFIX_NPX_CLI_JS
}

# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & $NODE_EXE $NPX_CLI_JS $args
if ($MyInvocation.OffsetInLine -gt 0) {
if ($MyInvocation.Statement) {
$NPX_ARGS = $MyInvocation.Statement.Substring($MyInvocation.InvocationName.Length).Trim()
} else {
$NPX_OG_COMMAND = (
[System.Management.Automation.InvocationInfo].GetProperty('ScriptPosition', [System.Reflection.BindingFlags] 'Instance, NonPublic')
).GetValue($MyInvocation).Text
$NPX_ARGS = $NPX_OG_COMMAND.Substring($MyInvocation.InvocationName.Length).Trim()
}

# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | Invoke-Expression "& `"$NODE_EXE`" `"$NPX_CLI_JS`" $NPX_ARGS"
} else {
Invoke-Expression "& `"$NODE_EXE`" `"$NPX_CLI_JS`" $NPX_ARGS"
}
} else {
& $NODE_EXE $NPX_CLI_JS $args
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & $NODE_EXE $NPX_CLI_JS $args
} else {
& $NODE_EXE $NPX_CLI_JS $args
}
}

exit $LASTEXITCODE
59 changes: 51 additions & 8 deletions test/bin/windows-shims.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ const BIN = join(ROOT, 'bin')
const SHIMS = readNonJsFiles(BIN)
const NODE_GYP = readNonJsFiles(join(BIN, 'node-gyp-bin'))
const SHIM_EXTS = [...new Set(Object.keys(SHIMS).map(p => extname(p)))]
const PACKAGE_NAME = 'test'
const PACKAGE_VERSION = '1.0.0'
const SCRIPT_NAME = 'args.js'

t.test('shim contents', t => {
// these scripts should be kept in sync so this tests the contents of each
Expand Down Expand Up @@ -99,6 +102,18 @@ t.test('run shims', t => {
},
},
},
// test script returning all command line arguments
[SCRIPT_NAME]: `#!/usr/bin/env node\n\nprocess.argv.slice(2).forEach((arg) => console.log(arg))`,
// package.json for the test script
'package.json': `
{
"name": "${PACKAGE_NAME}",
"version": "${PACKAGE_VERSION}",
"scripts": {
"test": "node ${SCRIPT_NAME}"
},
"bin": "${SCRIPT_NAME}"
}`,
})

// The removal of this fixture causes this test to fail when done with
Expand All @@ -112,6 +127,10 @@ t.test('run shims', t => {
// only cygwin *requires* the -l, but the others are ok with it
args.unshift('-l')
}
if (cmd.toLowerCase().endsWith('powershell.exe')) {
// Windows PowerShell requires escaping the double-quotes for this test
args = args.map(elem => elem.replaceAll('"', '\\"'))
}
const result = spawnSync(`"${cmd}"`, args, {
// don't hit the registry for the update check
env: { PATH: path, npm_config_update_notifier: 'false' },
Expand Down Expand Up @@ -162,6 +181,7 @@ t.test('run shims', t => {

const shells = Object.entries({
cmd: 'cmd',
powershell: 'powershell',
pwsh: 'pwsh',
git: join(ProgramFiles, 'Git', 'bin', 'bash.exe'),
'user git': join(ProgramFiles, 'Git', 'usr', 'bin', 'bash.exe'),
Expand Down Expand Up @@ -216,7 +236,7 @@ t.test('run shims', t => {
}
})

const matchCmd = (t, cmd, bin, match) => {
const matchCmd = (t, cmd, bin, match, params, expected) => {
const args = []
const opts = {}

Expand All @@ -227,25 +247,40 @@ t.test('run shims', t => {
case 'bash.exe':
args.push(bin)
break
case 'powershell.exe':
case 'pwsh.exe':
args.push(`${bin}.ps1`)
break
default:
throw new Error('unknown shell')
}

const isNpm = bin === 'npm'
const result = spawnPath(cmd, [...args, isNpm ? 'help' : '--version'], opts)
const result = spawnPath(cmd, [...args, ...params], opts)

// skip the first 3 lines of "npm test" to get the actual script output
if (params[0].startsWith('test')) {
result.stdout = result.stdout?.toString().split('\n').slice(3).join('\n').trim()
}

t.match(result, {
status: 0,
signal: null,
stderr: '',
stdout: isNpm ? `npm@${version} ${ROOT}` : version,
stdout: expected,
...match,
}, `${cmd} ${bin}`)
}, `${cmd} ${bin} ${params[0]}`)
}

// Array with command line parameters and expected output
const tests = [
{ bin: 'npm', params: ['help'], expected: `npm@${version} ${ROOT}` },
{ bin: 'npx', params: ['--version'], expected: version },
{ bin: 'npm', params: ['test'], expected: '' },
{ bin: 'npm', params: [`test -- hello -p1 world -p2 "hello world" -p3 'hello world' --q1=hello world --q2="hello world" --q3='hello world'`], expected: `hello\n-p1\nworld\n-p2\nhello world\n-p3\nhello world\n--q1=hello\nworld\n--q2=hello world\n--q3=hello world` },
{ bin: 'npm', params: ['test -- a=1,b=2,c=3'], expected: `a=1,b=2,c=3` },
{ bin: 'npx', params: ['. -- a=1,b=2,c=3'], expected: `a=1,b=2,c=3` },
]

// ensure that all tests are either run or skipped
t.plan(shells.length)

Expand All @@ -259,9 +294,17 @@ t.test('run shims', t => {
}
return t.end()
}
t.plan(2)
matchCmd(t, cmd, 'npm', match)
matchCmd(t, cmd, 'npx', match)
t.plan(tests.length)
for (const { bin, params, expected } of tests) {
if (name === 'cygwin bash' && (
(bin === 'npm' && params[0].startsWith('test')) ||
(bin === 'npx' && params[0].startsWith('.'))
)) {
t.skip("`cygwin bash` doesn't respect option `{ cwd: path }` when calling `spawnSync`")
} else {
matchCmd(t, cmd, bin, match, params, expected)
}
}
})
}
})