Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
@antora/run-command-helper
Advanced tools
Provides a helper function to run an external command uniformly across platforms with numerous options to control how stdio is handled.
A Node.js module that provides a helper function to run an external command consistently across platforms. This function is a Promise-based wrapper around the spawn function in Node.js. It’s goal is to eliminate the boilerplate code needed to use the spawn function correctly. Developed for use in Antora.
$ npm i @antora/run-command-helper
function runCommand (cmd[, args][, opts])
Runs the specified command. If the command exits with a zero status, the function will return an object containing information from the subprocess (e.g., exit status, stdout data, etc). If the command exits with a non-zero status, or the command fails to start, an Error is thrown.
cmd
<string> - The external command to run.
This parameter is required.args
<string[]> - List of string arguments to pass to command.
This parameter is optional.
If this parameter is not provided, the arguments list is parsed from the value of the cmd
argument (unless the parse
option is false
).
If any arguments are parsed from the value of the cmd
argument, this list of arguments gets appended to those.
Default: undefined
.opts
<Object> - Named parameters to control how the command is run.
All named parameters are optional.
Default: {}
.
cwd
<string> - The directory in which the subprocess will be run.
This value also controls the search path for the command if local (or any bare command on Windows, regardless).
Default: process.cwd()
.shell
<boolean> | <string> - Specifies whether to run the external command in a shell (uses '/bin/sh' on Unix and process.env.ComSpec on Windows).
If the shell
option is false
or not set, the command only has to be quoted if it’s being parsed.
Otherwise, the command and its arguments must be properly escaped for use in a shell, regardless of how they are specified.
In this case, the command and its arguments will also be subject to shell expansion as well.
On Unix, you can use a string value to specify the shell explicitly (e.g., ’/bin/bash') When using a shell, environment variable references in the form
$NAMEwill be resolved in the command and its arguments, even on Windows. **Default:**
false`.parse
<boolean> - Specifies whether the value of the cmd
argument should be parsed as a command string (meaning the list of arguments are extracted from the command).
If the value of the cmd
argument is parsed, then the base call must be properly quoted (e.g., it must be quoted if it contains spaces).
Default: false
if the args
parameter is specified, true
otherwise.local
<boolean> - Specifies whether to look for the command locally instead of on the PATH.
Setting this option to true
is equivalent to prepending ./
to the command.
This option is only relevant for a bare command (i.e., a command with no directory separators).
If the command (i.e., the base call) contains directory separators, the value true
is implied.
Default: false
.stdin
<string> | <Buffer> | <Stream.Readable> - Input to pass to the stdin of the process, if specified and not null, false, or undefined.
If an unknown value type is specified, it will be coerced to a string.
Default: undefined
.stdout
<string> - Specifies how to handle the stdout of the subprocess.
A value of ’print' will pass through the data to the stdout stream of the current process. A value of ’ignore'
will discard the stdout data.
A value of ’buffer'will cause the function to return the stdout data as a
Stringif the
encoding option is set and not ’buffer'
, otherwise a Buffer
.
All other values (such as false
) are the equivalent of ’ignore'. **Default:** ’buffer'
stderr
<string> - Specifies how to handle the stderr stream of the subprocess.
A value of ’print' will pass through the data to the stderr of the current process. A value of ’ignore'
will discard the stderr data.
A value of ’buffer' will append the stderr data to the end of the message of the Error if the subprocess fails, otherwise it’s ignored. A value of ’stdout
will redirect the stderr data to the stdout destination.
All other values (such as false
) are the equivalent of ’ignore'. **Default:** ’buffer'
encoding
<string> - The encoding used for all stdio outputs in the return value.
If set and not ’buffer', each stdio output buffer will be encoded to a string using the specified encoding. If the value of the
stdout option is ’buffer'
, the return value of the function will change from a Buffer
to a String
.
Note that this option does not impact the data type passed to the data event handler on the process.
Default: ’buffer'`stdout
option is set to buffer
, this object will be built on a copy of the stdout object for convenience.
stdout
<Buffer> | <null> - The stdout data as a Buffer
(or String
if the encoding
option is not buffer
) if the stdout
option is set to buffer
, otherwise null.stderr
<Buffer> | <null> - The stderr data as a Buffer
(or String
if the encoding
option is not buffer
) if the stderr
option is set to buffer
, otherwise null.status
<number> | <null> - The exit status of the subprocess or null if the subprocess was terminated by a signal.signal
<string> | <null> - The exit signal of the subprocess if the subprocess was terminated by a signal, otherwise null.All other options, including env
, are passed through to the underlying spawn function call.
On Windows, the command may use forward slashes, but the resolved command will always have backslashes.
Also on Windows, the command can be resolved in the specified cwd even if the local
option is false
or not set (matching the native behavior on Windows).
On Windows, when the shell
option is not set, the function will attempt to resolve the command without a file extension using the .com
, .exe
, .bat
, and .cmd
file extensions, in that order.
As a result, the base call shown in messages will have a file extension appended even though it was not originally specified.
This modification is necessary in order to ensure the spawn function invokes the correct command.
(The spawn function in Node.js does not resolve the base call using the PATHEXT environment variable when the shell option is not true).
If a match is not found, the function will throw a command not found error.
📌 NOTE
This function does its own PATHEXT resolution on Windows.
It never passes an extensionless command to spawn to ensure its behavior is predictable and within the documented parameters.
On Windows, the shell will be used under the covers (even when not specified) to run batch scripts due to a security restriction in Node.js.
The function hides this detail by automatically escaping the arguments and thus does not impose additional escaping requirements when the shell option is false
or not set.
The function escapes the following characters using a double quote enclosure: " <>&%^|
.
🔥 CAUTION
There’s still a risk that a batch script cannot read argument values correctly.
This is due to limitations in how a batch script processes arguments.
For example, a batch script could cause a child batch script to not be able to handle the sequence ="&
depending on how arguments are forwarded to the child script.
On Windows, builtins like dir
and set
can only be used when shell: true
(this is a limitation of Node.js’ spawn function).
In order to use non-ASCII characters in argument values on Windows (particularly when using the shell), it may be necessary to enable UTF-8 support. Here’s an example to test whether UTF-8 support is properly configured:
const runCommand = require('@antora/run-command-helper')
;(async () => {
await runCommand('echo', ['ACME\u2122'], { stdout: 'print', stderr: 'print', shell: true })
})()
//=> ACME™
If that still don’t work, try setting chcp 65001
as well.
Here’s an example of running a command that routes the stdout to the stdout stream of the current process.
const runCommand = require('@antora/run-command-helper')
;(async () => {
await runCommand('echo hi', { stdout: 'print', stderr: 'print' })
})()
//=> hi
Here’s an example of running a command that returns the stdout data as a Buffer.
const runCommand = require('@antora/run-command-helper')
;(async () => {
const whoiam = await runCommand('whoami')
process.stdout.write(whoiam)
// or console.log(whoiam.stdout.toString().trimEnd())
})()
//=> myusername
Here’s an example of running a command that returns the stdout data as a String.
const runCommand = require('@antora/run-command-helper')
;(async () => {
const whoiam = await runCommand('whoami', { encoding: 'utf8' })
console.log(whoiam.trimEnd())
// or process.stdout.write(Buffer.from(whoami))
})()
//=> myusername
Here’s an example of how to pass in the list of arguments instead of relying on them being parsed from the command string:
const runCommand = require('@antora/run-command-helper')
;(async () => {
await runCommand(process.execPath, ['-p', '1'], { stdout: 'print' })
})()
//=> 1
Here’s an example of how to specify a local command instead of looking for the command on the PATH:
const runCommand = require('@antora/run-command-helper')
;(async () => {
await runCommand('gradlew --status', { local: true, stdout: 'print', stderr: 'print' })
})()
//=> No Gradle daemons are running.
Here’s an example of how to pass input to the stdin stream of the command:
const runCommand = require('@antora/run-command-helper')
const { EOL } = require('node:os')
;(async () => {
const cat = process.platform === 'win32' ? 'findstr x*' : 'cat'
await runCommand(cat, { stdin: 'hi there!' + EOL, stdout: 'print' })
})()
//=> hi there!
When the value of the stdout or stderr option is ’print'`, this function routes the respective stream directly to the current process (i.e., parent, invoking process).
This is accomplished by passing the process.stdout and process.stderr streams to the respective stdio option provided by the spawn function.
(This is roughly equivalent to using the inherit
option, except it allows the tests to intercept stream writes).
In other words, this function does not attempt to capture the stdout and stderr streams and emit them to the current process in this case.
If the function were to capture and emit the data from the two streams, it would alter how the lines are interleaved in the terminal. The reason that happens is because the stdout buffer is much larger than the stderr buffer, which results in the stderr data being emitted earlier relative to the stdout data than as received. (See https://stackoverflow.com/questions/57046930/node-js-spawn-keep-stdout-and-stderr-in-the-original-order). This function avoids that problem by connecting the streams directly to the current process when configured to print them.
This behavior is only relevant when both streams are printed. Otherwise, how the streams are wired does not matter.
Copyright (C) 2024-present by OpenDevise Inc. and the individual contributors to Antora.
Use of this software is granted under the terms of the Mozilla Public License Version 2.0 (MPL-2.0).
FAQs
Provides a helper function to run an external command uniformly across platforms with numerous options to control how stdio is handled.
The npm package @antora/run-command-helper receives a total of 989 weekly downloads. As such, @antora/run-command-helper popularity was classified as not popular.
We found that @antora/run-command-helper demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.