Skip to content
This repository has been archived by the owner on Jul 6, 2019. It is now read-only.

Commit

Permalink
feat(node): add --node-arg support to pass flags to node for script b…
Browse files Browse the repository at this point in the history
…inaries (#77)

* feat(node): add ability to inspect binaries when detected to be node scripts

Fixes: #68

* test: add tests for -n and --node-arg parsing

* feat(node-arg): allow space-separated arg strings
  • Loading branch information
zkat committed Jul 12, 2017
1 parent bc60ea7 commit 65665bd
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 5 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ If a full specifier is included, or if `--package` is used, npx will always use

* `-q, --quiet` - Suppressed any output from npx itself (progress bars, error messages, install reports). Subcommand output itself will not be silenced.

* `-n, --node-arg` - Extra node argument to supply to node when binary is a node script. You can supply this option multiple times to add more arguments.

* `-v, --version` - Show the current npx version.

## EXAMPLES
Expand Down Expand Up @@ -89,6 +91,13 @@ $ npx -p lolcatjs -p cowsay -c \
|| ||
```

### Run node binary with --inspect

```
$ npx --node-arg=--inspect cowsay
Debugger listening on ws://127.0.0.1:9229/....
```

## SHELL AUTO FALLBACK

You can configure `npx` to run as your default fallback command when you type something in the command line with an `@` but the command is not found. This includes installing packages that were not found in the local prefix either.
Expand Down
28 changes: 25 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,8 @@ function installPackages (specs, prefix, opts) {
module.exports._execCommand = execCommand
function execCommand (_existing, argv) {
return findNodeScript(_existing, argv).then(existing => {
const Module = require('module')
if (existing && Module.runMain && !argv.shell && existing !== process.argv[1]) {
if (existing && !argv.nodeArg && !argv.shell && existing !== process.argv[1]) {
const Module = require('module')
// let it take over the process. This means we can skip node startup!
if (!argv.noYargs) {
// blow away built-up yargs crud
Expand All @@ -245,8 +245,30 @@ function execCommand (_existing, argv) {
existing // node script path. `runMain()` will set this as the new main
].concat(argv.cmdOpts) // options for the cmd itself
Module.runMain() // ✨MAGIC✨. Sorry-not-sorry
} else if (!existing && argv.nodeArg && argv.nodeArg.length) {
throw new Error(Y()`ERROR: --node-arg/-n can only be used on packages with node scripts.`)
} else {
return child.runCommand(existing, argv).catch(err => {
let cmd = existing
let opts = argv
if (existing && argv.nodeArg && argv.nodeArg.length) {
// If we know we're running a run script and we got a --node-arg,
// we need to fudge things a bit to get them working right.
let nargs = argv.nodeArg
if (typeof nargs === 'string') {
nargs = [nargs]
}
// It's valid for a single arg to be a string of multiple
// space-separated node args.
// Example: `$ npx -n '--inspect --harmony --debug' ...`
nargs = nargs.reduce((acc, arg) => {
return acc.concat(arg.split(/\s+/))
}, [])
cmd = process.argv[0]
opts = Object.assign({}, argv, {
cmdOpts: nargs.concat([existing], argv.cmdOpts || [])
})
}
return child.runCommand(cmd, opts).catch(err => {
if (err.isOperational && err.exitCode) {
// At this point, we want to treat errors from the child as if
// we were just running the command. That means no extra msg logging
Expand Down
3 changes: 2 additions & 1 deletion locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@
"shell": "shell",
"package": "package",
"npx: installed %s in %ss": "npx: installed %s in %ss",
"Suppress output from npx itself. Subcommands will not be affected.": "Suppress output from npx itself. Subcommands will not be affected."
"Suppress output from npx itself. Subcommands will not be affected.": "Suppress output from npx itself. Subcommands will not be affected.",
"Extra node argument when calling a node binary.": "Extra node argument when calling a node binary."
}
11 changes: 10 additions & 1 deletion parse-args.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,16 @@ function parseArgs (argv, defaultNpm) {
if (opt === '--') {
hasDashDash = true
break
} else if (opt === '--node-arg' || opt === '-n') {
argv[i] = `${opt}=${argv[i + 1]}`
argv.splice(i + 1, 1)
} else if (opt[0] === '-') {
if (
// --no-install needs to be special-cased because we're abusing
// yargs a bit in order to get the --help text right.
opt !== '--no-install' &&
!bools.has(opt.replace(/^--?(no-)?/i, ''))
!bools.has(opt.replace(/^--?(no-)?/i, '')) &&
opt.indexOf('=') === -1
) {
i++
}
Expand Down Expand Up @@ -214,6 +218,11 @@ function yargsParser (argv, defaultNpm) {
type: 'string',
default: defaultNpm || 'npm'
})
.option('node-arg', {
alias: 'n',
type: 'string',
describe: Y()`Extra node argument when calling a node binary.`
})
.version(() => require('./package.json').version)
.alias('version', 'v')
.help()
Expand Down
45 changes: 45 additions & 0 deletions test/parse-args.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,48 @@ test('treats directory-type commands specially', t => {
t.equal(parsed.cmdHadVersion, false)
t.done()
})

test('-n and --node-arg special parsing rules', t => {
const command = 'command'
t.like(
mockParse('-n=--foo', command),
{command, nodeArg: '--foo'}
)
t.like(
mockParse('-n', '--foo', command),
{command, nodeArg: '--foo'}
)
t.like(
mockParse('--node-arg=--foo', command),
{command, nodeArg: '--foo'}
)
t.like(
mockParse('--node-arg', '--foo', command),
{command, nodeArg: '--foo'}
)
t.like(
mockParse('-n', '--foo', '-n', '--bar', '-n', 'baz', command),
{command, nodeArg: ['--foo', '--bar', 'baz']}
)
t.like(
mockParse('--node-arg', '--foo', '--node-arg', '--bar', '--node-arg', 'baz', command),
{command, nodeArg: ['--foo', '--bar', 'baz']}
)
t.like(
mockParse('-n', '--foo', '--node-arg', '--bar', '-n=baz', command),
{command, nodeArg: ['--foo', '--bar', 'baz']}
)
t.like(
mockParse('-n', '-n', command),
{command, nodeArg: '-n'}
)
t.like(
mockParse('--node-arg', '--node-arg', command),
{command, nodeArg: '--node-arg'}
)
t.like(
mockParse(command, '--node-arg', 'blah'),
{command, nodeArg: undefined, cmdOpts: ['--node-arg', 'blah']}
)
t.done()
})

0 comments on commit 65665bd

Please sign in to comment.