cross-spawn
Advanced tools
Comparing version 5.1.0 to 6.0.0
@@ -1,3 +0,35 @@ | ||
## 5.0.0 - 2016-10-30 | ||
# Change Log | ||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. | ||
<a name="6.0.0"></a> | ||
# [6.0.0](https://github.com/moxystudio/node-cross-spawn/compare/5.1.0...6.0.0) (2018-01-23) | ||
### Bug Fixes | ||
* fix certain arguments not being correctly escaped or causing batch syntax error ([900cf10](https://github.com/moxystudio/node-cross-spawn/commit/900cf10)), closes [#82](https://github.com/moxystudio/node-cross-spawn/issues/82) [#51](https://github.com/moxystudio/node-cross-spawn/issues/51) [#82](https://github.com/moxystudio/node-cross-spawn/issues/82) [#51](https://github.com/moxystudio/node-cross-spawn/issues/51) | ||
### BREAKING CHANGES | ||
* remove support for older nodejs versions, only node >= 4 is supported | ||
<a name="5.1.0"></a> | ||
## [5.1.0](https://github.com/moxystudio/node-cross-spawn/compare/5.0.1...5.1.0) (2017-02-26) | ||
- Fix `options.shell` support for NodeJS [v4.8](https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V4.md#4.8.0) | ||
<a name="5.0.1"></a> | ||
## [5.0.1](https://github.com/moxystudio/node-cross-spawn/compare/5.0.0...5.0.1) (2016-11-04) | ||
- Fix `options.shell` support for NodeJS v7 | ||
<a name="5.0.0"></a> | ||
# [5.0.0](https://github.com/moxystudio/node-cross-spawn/compare/4.0.2...5.0.0) (2016-10-30) | ||
- Add support for `options.shell` | ||
@@ -4,0 +36,0 @@ - Improve parsing of shebangs by using [`shebang-command`](https://github.com/kevva/shebang-command) module |
36
index.js
'use strict'; | ||
var cp = require('child_process'); | ||
var parse = require('./lib/parse'); | ||
var enoent = require('./lib/enoent'); | ||
const cp = require('child_process'); | ||
const parse = require('./lib/parse'); | ||
const enoent = require('./lib/enoent'); | ||
var cpSpawnSync = cp.spawnSync; | ||
function spawn(command, args, options) { | ||
var parsed; | ||
var spawned; | ||
// Parse the arguments | ||
parsed = parse(command, args, options); | ||
const parsed = parse(command, args, options); | ||
// Spawn the child process | ||
spawned = cp.spawn(parsed.command, parsed.args, parsed.options); | ||
const spawned = cp.spawn(parsed.command, parsed.args, parsed.options); | ||
@@ -27,24 +22,9 @@ // Hook into child process "exit" event to emit an error if the command | ||
function spawnSync(command, args, options) { | ||
var parsed; | ||
var result; | ||
if (!cpSpawnSync) { | ||
try { | ||
cpSpawnSync = require('spawn-sync'); // eslint-disable-line global-require | ||
} catch (ex) { | ||
throw new Error( | ||
'In order to use spawnSync on node 0.10 or older, you must ' + | ||
'install spawn-sync:\n\n' + | ||
' npm install spawn-sync --save' | ||
); | ||
} | ||
} | ||
// Parse the arguments | ||
parsed = parse(command, args, options); | ||
const parsed = parse(command, args, options); | ||
// Spawn the child process | ||
result = cpSpawnSync(parsed.command, parsed.args, parsed.options); | ||
const result = cp.spawnSync(parsed.command, parsed.args, parsed.options); | ||
// Analyze if the command does not exists, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16 | ||
// Analyze if the command does not exist, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16 | ||
result.error = result.error || enoent.verifyENOENTSync(result.status, parsed); | ||
@@ -51,0 +31,0 @@ |
'use strict'; | ||
var isWin = process.platform === 'win32'; | ||
var resolveCommand = require('./util/resolveCommand'); | ||
const isWin = process.platform === 'win32'; | ||
var isNode10 = process.version.indexOf('v0.10.') === 0; | ||
function notFoundError(command, syscall) { | ||
var err; | ||
err = new Error(syscall + ' ' + command + ' ENOENT'); | ||
err.code = err.errno = 'ENOENT'; | ||
err.syscall = syscall + ' ' + command; | ||
return err; | ||
function notFoundError(original, syscall) { | ||
return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), { | ||
code: 'ENOENT', | ||
errno: 'ENOENT', | ||
syscall: `${syscall} ${original.command}`, | ||
path: original.command, | ||
spawnargs: original.args, | ||
}); | ||
} | ||
function hookChildProcess(cp, parsed) { | ||
var originalEmit; | ||
if (!isWin) { | ||
@@ -25,11 +20,10 @@ return; | ||
originalEmit = cp.emit; | ||
const originalEmit = cp.emit; | ||
cp.emit = function (name, arg1) { | ||
var err; | ||
// If emitting "exit" event and exit code is 1, we need to check if | ||
// the command exists and emit an "error" instead | ||
// See: https://github.com/IndigoUnited/node-cross-spawn/issues/16 | ||
// See https://github.com/IndigoUnited/node-cross-spawn/issues/16 | ||
if (name === 'exit') { | ||
err = verifyENOENT(arg1, parsed, 'spawn'); | ||
const err = verifyENOENT(arg1, parsed, 'spawn'); | ||
@@ -41,3 +35,3 @@ if (err) { | ||
return originalEmit.apply(cp, arguments); | ||
return originalEmit.apply(cp, arguments); // eslint-disable-line prefer-rest-params | ||
}; | ||
@@ -59,18 +53,10 @@ } | ||
// If we are in node 10, then we are using spawn-sync; if it exited | ||
// with -1 it probably means that the command does not exist | ||
if (isNode10 && status === -1) { | ||
parsed.file = isWin ? parsed.file : resolveCommand(parsed.original); | ||
if (!parsed.file) { | ||
return notFoundError(parsed.original, 'spawnSync'); | ||
} | ||
} | ||
return null; | ||
} | ||
module.exports.hookChildProcess = hookChildProcess; | ||
module.exports.verifyENOENT = verifyENOENT; | ||
module.exports.verifyENOENTSync = verifyENOENTSync; | ||
module.exports.notFoundError = notFoundError; | ||
module.exports = { | ||
hookChildProcess, | ||
verifyENOENT, | ||
verifyENOENTSync, | ||
notFoundError, | ||
}; |
104
lib/parse.js
'use strict'; | ||
var resolveCommand = require('./util/resolveCommand'); | ||
var hasEmptyArgumentBug = require('./util/hasEmptyArgumentBug'); | ||
var escapeArgument = require('./util/escapeArgument'); | ||
var escapeCommand = require('./util/escapeCommand'); | ||
var readShebang = require('./util/readShebang'); | ||
const path = require('path'); | ||
const niceTry = require('nice-try'); | ||
const resolveCommand = require('./util/resolveCommand'); | ||
const escape = require('./util/escape'); | ||
const readShebang = require('./util/readShebang'); | ||
const semver = require('semver'); | ||
var isWin = process.platform === 'win32'; | ||
var skipShellRegExp = /\.(?:com|exe)$/i; | ||
const isWin = process.platform === 'win32'; | ||
const isExecutableRegExp = /\.(?:com|exe)$/i; | ||
const isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i; | ||
// Supported in Node >= 6 and >= 4.8 | ||
var supportsShellOption = parseInt(process.version.substr(1).split('.')[0], 10) >= 6 || | ||
parseInt(process.version.substr(1).split('.')[0], 10) === 4 && parseInt(process.version.substr(1).split('.')[1], 10) >= 8; | ||
// `options.shell` is supported in Node ^4.8.0, ^5.7.0 and >= 6.0.0 | ||
const supportsShellOption = niceTry(() => semver.satisfies(process.version, '^4.8.0 || ^5.7.0 || >= 6.0.0', true)) || false; | ||
function detectShebang(parsed) { | ||
parsed.file = resolveCommand(parsed); | ||
const shebang = parsed.file && readShebang(parsed.file); | ||
if (shebang) { | ||
parsed.args.unshift(parsed.file); | ||
parsed.command = shebang; | ||
return resolveCommand(parsed); | ||
} | ||
return parsed.file; | ||
} | ||
function parseNonShell(parsed) { | ||
var shebang; | ||
var needsShell; | ||
var applyQuotes; | ||
if (!isWin) { | ||
@@ -26,25 +38,23 @@ return parsed; | ||
// Detect & add support for shebangs | ||
parsed.file = resolveCommand(parsed.command); | ||
parsed.file = parsed.file || resolveCommand(parsed.command, true); | ||
shebang = parsed.file && readShebang(parsed.file); | ||
const commandFile = detectShebang(parsed); | ||
if (shebang) { | ||
parsed.args.unshift(parsed.file); | ||
parsed.command = shebang; | ||
needsShell = hasEmptyArgumentBug || !skipShellRegExp.test(resolveCommand(shebang) || resolveCommand(shebang, true)); | ||
} else { | ||
needsShell = hasEmptyArgumentBug || !skipShellRegExp.test(parsed.file); | ||
} | ||
// We don't need a shell if the command filename is an executable | ||
const needsShell = !isExecutableRegExp.test(commandFile); | ||
// If a shell is required, use cmd.exe and take care of escaping everything correctly | ||
if (needsShell) { | ||
// Note that `forceShell` is an hidden option used only in tests | ||
if (parsed.options.forceShell || needsShell) { | ||
// Need to double escape meta chars if the command is a cmd-shim located in `node_modules/.bin/` | ||
// The cmd-shim simply calls execute the package bin file with NodeJS, proxying any argument | ||
// Because the escape of metachars with ^ gets interpreted when the cmd.exe is first called, | ||
// we need to double escape them | ||
const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile); | ||
// Escape command & arguments | ||
applyQuotes = (parsed.command !== 'echo'); // Do not quote arguments for the special "echo" command | ||
parsed.command = escapeCommand(parsed.command); | ||
parsed.args = parsed.args.map(function (arg) { | ||
return escapeArgument(arg, applyQuotes); | ||
}); | ||
parsed.command = escape.command(parsed.command); | ||
parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars)); | ||
// Make use of cmd.exe | ||
parsed.args = ['/d', '/s', '/c', '"' + parsed.command + (parsed.args.length ? ' ' + parsed.args.join(' ') : '') + '"']; | ||
const shellCommand = [parsed.command].concat(parsed.args).join(' '); | ||
parsed.args = ['/d', '/s', '/c', `"${shellCommand}"`]; | ||
parsed.command = process.env.comspec || 'cmd.exe'; | ||
@@ -58,4 +68,2 @@ parsed.options.windowsVerbatimArguments = true; // Tell node's spawn that the arguments are already escaped | ||
function parseShell(parsed) { | ||
var shellCommand; | ||
// If node supports the shell option, there's no need to mimic its behavior | ||
@@ -66,8 +74,9 @@ if (supportsShellOption) { | ||
// Mimic node shell option, see: https://github.com/nodejs/node/blob/b9f6a2dc059a1062776133f3d4fd848c4da7d150/lib/child_process.js#L335 | ||
shellCommand = [parsed.command].concat(parsed.args).join(' '); | ||
// Mimic node shell option | ||
// See https://github.com/nodejs/node/blob/b9f6a2dc059a1062776133f3d4fd848c4da7d150/lib/child_process.js#L335 | ||
const shellCommand = [parsed.command].concat(parsed.args).join(' '); | ||
if (isWin) { | ||
parsed.command = typeof parsed.options.shell === 'string' ? parsed.options.shell : process.env.comspec || 'cmd.exe'; | ||
parsed.args = ['/d', '/s', '/c', '"' + shellCommand + '"']; | ||
parsed.args = ['/d', '/s', '/c', `"${shellCommand}"`]; | ||
parsed.options.windowsVerbatimArguments = true; // Tell node's spawn that the arguments are already escaped | ||
@@ -89,7 +98,3 @@ } else { | ||
// ------------------------------------------------ | ||
function parse(command, args, options) { | ||
var parsed; | ||
// Normalize arguments, similar to nodejs | ||
@@ -101,12 +106,15 @@ if (args && !Array.isArray(args)) { | ||
args = args ? args.slice(0) : []; // Clone array to avoid changing the original | ||
options = options || {}; | ||
args = args ? args.slice(0) : []; // Clone array to avoid changing the original | ||
options = Object.assign({}, options); // Clone object to avoid changing the original | ||
// Build our parsed object | ||
parsed = { | ||
command: command, | ||
args: args, | ||
options: options, | ||
const parsed = { | ||
command: path.normalize(command), | ||
args, | ||
options, | ||
file: undefined, | ||
original: command, | ||
original: { | ||
command, | ||
args, | ||
}, | ||
}; | ||
@@ -113,0 +121,0 @@ |
'use strict'; | ||
var fs = require('fs'); | ||
var LRU = require('lru-cache'); | ||
var shebangCommand = require('shebang-command'); | ||
const fs = require('fs'); | ||
const shebangCommand = require('shebang-command'); | ||
var shebangCache = new LRU({ max: 50, maxAge: 30 * 1000 }); // Cache just for 30sec | ||
function readShebang(command) { | ||
var buffer; | ||
var fd; | ||
var shebang; | ||
// Check if it is in the cache first | ||
if (shebangCache.has(command)) { | ||
return shebangCache.get(command); | ||
} | ||
// Read the first 150 bytes from the file | ||
buffer = new Buffer(150); | ||
let fd; | ||
const buffer = new Buffer(150); | ||
@@ -26,13 +15,8 @@ try { | ||
fs.closeSync(fd); | ||
} catch (e) { /* empty */ } | ||
} catch (e) { /* Empty */ } | ||
// Attempt to extract shebang (null is returned if not a shebang) | ||
shebang = shebangCommand(buffer.toString()); | ||
// Store the shebang in the cache | ||
shebangCache.set(command, shebang); | ||
return shebang; | ||
return shebangCommand(buffer.toString()); | ||
} | ||
module.exports = readShebang; |
'use strict'; | ||
var path = require('path'); | ||
var which = require('which'); | ||
var LRU = require('lru-cache'); | ||
const path = require('path'); | ||
const which = require('which'); | ||
const pathKey = require('path-key')(); | ||
var commandCache = new LRU({ max: 50, maxAge: 30 * 1000 }); // Cache just for 30sec | ||
function resolveCommandAttempt(parsed, withPathExt) { | ||
withPathExt = !!withPathExt; | ||
function resolveCommand(command, noExtension) { | ||
var resolved; | ||
noExtension = !!noExtension; | ||
resolved = commandCache.get(command + '!' + noExtension); | ||
// Check if its resolved in the cache | ||
if (commandCache.has(command)) { | ||
return commandCache.get(command); | ||
} | ||
try { | ||
resolved = !noExtension ? | ||
which.sync(command) : | ||
which.sync(command, { pathExt: path.delimiter + (process.env.PATHEXT || '') }); | ||
} catch (e) { /* empty */ } | ||
return which.sync(parsed.command, { | ||
path: (parsed.options.env || process.env)[pathKey], | ||
pathExt: withPathExt && process.env.PATHEXT ? path.delimiter + process.env.PATHEXT : undefined, | ||
}); | ||
} catch (e) { /* Empty */ } | ||
} | ||
commandCache.set(command + '!' + noExtension, resolved); | ||
return resolved; | ||
function resolveCommand(parsed) { | ||
return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true); | ||
} | ||
module.exports = resolveCommand; |
{ | ||
"name": "cross-spawn", | ||
"version": "5.1.0", | ||
"version": "6.0.0", | ||
"description": "Cross platform child_process#spawn and child_process#spawnSync", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "node test/prepare && mocha --bail test/test", | ||
"lint": "eslint '{*.js,lib/**/*.js,test/**/*.js}'" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/IndigoUnited/node-cross-spawn/issues/" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/IndigoUnited/node-cross-spawn.git" | ||
}, | ||
"files": [ | ||
"index.js", | ||
"lib" | ||
], | ||
"keywords": [ | ||
@@ -25,17 +9,47 @@ "spawn", | ||
"windows", | ||
"cross", | ||
"platform", | ||
"path", | ||
"ext", | ||
"cross-platform", | ||
"path-ext", | ||
"path_ext", | ||
"shebang", | ||
"hashbang", | ||
"cmd", | ||
"execute" | ||
], | ||
"author": "IndigoUnited <hello@indigounited.com> (http://indigounited.com)", | ||
"author": "André Cruz <andre@moxy.studio>", | ||
"homepage": "https://github.com/moxystudio/node-cross-spawn", | ||
"repository": { | ||
"type": "git", | ||
"url": "git@github.com:moxystudio/node-cross-spawn.git" | ||
}, | ||
"license": "MIT", | ||
"main": "index.js", | ||
"files": [ | ||
"lib" | ||
], | ||
"scripts": { | ||
"lint": "eslint .", | ||
"test": "jest --env node --coverage", | ||
"prerelease": "npm t && npm run lint", | ||
"release": "standard-version", | ||
"precommit": "lint-staged", | ||
"commitmsg": "commitlint -e $GIT_PARAMS" | ||
}, | ||
"standard-version": { | ||
"scripts": { | ||
"posttag": "git push --follow-tags origin master && npm publish" | ||
} | ||
}, | ||
"lint-staged": { | ||
"*.js": [ | ||
"eslint --fix", | ||
"git add" | ||
] | ||
}, | ||
"commitlint": { | ||
"extends": [ | ||
"@commitlint/config-conventional" | ||
] | ||
}, | ||
"dependencies": { | ||
"lru-cache": "^4.0.1", | ||
"nice-try": "^1.0.4", | ||
"path-key": "^2.0.1", | ||
"semver": "^5.5.0", | ||
"shebang-command": "^1.2.0", | ||
@@ -45,11 +59,20 @@ "which": "^1.2.9" | ||
"devDependencies": { | ||
"@satazor/eslint-config": "^3.0.0", | ||
"eslint": "^3.0.0", | ||
"expect.js": "^0.3.0", | ||
"glob": "^7.0.0", | ||
"@commitlint/cli": "^6.0.0", | ||
"@commitlint/config-conventional": "^6.0.2", | ||
"babel-core": "^6.26.0", | ||
"babel-jest": "^22.1.0", | ||
"babel-preset-moxy": "^2.0.4", | ||
"eslint": "^4.3.0", | ||
"eslint-config-moxy": "^4.1.0", | ||
"husky": "^0.14.3", | ||
"jest": "^22.0.0", | ||
"lint-staged": "^6.0.0", | ||
"mkdirp": "^0.5.1", | ||
"mocha": "^3.0.2", | ||
"once": "^1.4.0", | ||
"rimraf": "^2.5.0" | ||
"regenerator-runtime": "^0.11.1", | ||
"rimraf": "^2.6.2", | ||
"standard-version": "^4.2.0" | ||
}, | ||
"engines": { | ||
"node": ">=4.8" | ||
} | ||
} |
# cross-spawn | ||
[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Build status][appveyor-image]][appveyor-url] [![Dependency status][david-dm-image]][david-dm-url] [![Dev Dependency status][david-dm-dev-image]][david-dm-dev-url] | ||
[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Build status][appveyor-image]][appveyor-url] [![Dependency status][david-dm-image]][david-dm-url] [![Dev Dependency status][david-dm-dev-image]][david-dm-dev-url] [![Greenkeeper badge][greenkeeper-image]][greenkeeper-url] | ||
@@ -8,10 +8,12 @@ [npm-url]:https://npmjs.org/package/cross-spawn | ||
[npm-image]:http://img.shields.io/npm/v/cross-spawn.svg | ||
[travis-url]:https://travis-ci.org/IndigoUnited/node-cross-spawn | ||
[travis-image]:http://img.shields.io/travis/IndigoUnited/node-cross-spawn/master.svg | ||
[travis-url]:https://travis-ci.org/moxystudio/node-cross-spawn | ||
[travis-image]:http://img.shields.io/travis/moxystudio/node-cross-spawn/master.svg | ||
[appveyor-url]:https://ci.appveyor.com/project/satazor/node-cross-spawn | ||
[appveyor-image]:https://img.shields.io/appveyor/ci/satazor/node-cross-spawn/master.svg | ||
[david-dm-url]:https://david-dm.org/IndigoUnited/node-cross-spawn | ||
[david-dm-image]:https://img.shields.io/david/IndigoUnited/node-cross-spawn.svg | ||
[david-dm-dev-url]:https://david-dm.org/IndigoUnited/node-cross-spawn#info=devDependencies | ||
[david-dm-dev-image]:https://img.shields.io/david/dev/IndigoUnited/node-cross-spawn.svg | ||
[david-dm-url]:https://david-dm.org/moxystudio/node-cross-spawn | ||
[david-dm-image]:https://img.shields.io/david/moxystudio/node-cross-spawn.svg | ||
[david-dm-dev-url]:https://david-dm.org/moxystudio/node-cross-spawn?type=dev | ||
[david-dm-dev-image]:https://img.shields.io/david/dev/moxystudio/node-cross-spawn.svg | ||
[greenkeeper-image]:https://badges.greenkeeper.io/moxystudio/node-cross-spawn.svg | ||
[greenkeeper-url]:https://greenkeeper.io/ | ||
@@ -25,7 +27,3 @@ A cross platform solution to node's spawn and spawnSync. | ||
If you are using `spawnSync` on node 0.10 or older, you will also need to install `spawn-sync`: | ||
`$ npm install spawn-sync` | ||
## Why | ||
@@ -36,5 +34,7 @@ | ||
- It ignores [PATHEXT](https://github.com/joyent/node/issues/2318) | ||
- It does not support [shebangs](http://pt.wikipedia.org/wiki/Shebang) | ||
- No `options.shell` support on node < v6 | ||
- It does not allow you to run `del` or `dir` | ||
- It does not support [shebangs](https://en.wikipedia.org/wiki/Shebang_(Unix)) | ||
- No `options.shell` support on node `<v4.8` | ||
- Has problems running commands with [spaces](https://github.com/nodejs/node/issues/7367) | ||
- Has problems running commands with posix relative paths (e.g.: `my-folder/my-executable`) | ||
- Circuvents an [issue](https://github.com/moxystudio/node-cross-spawn/issues/82) around command shims (files in node_modules/.bin/), where arguments with quotes and parenthesis would result in an [invalid syntax error](https://github.com/moxystudio/node-cross-spawn/blob/e77b8f22a416db46b6196767bcd35601d7e11d54/test/index.test.js#L149) | ||
@@ -63,17 +63,23 @@ All these issues are handled correctly by `cross-spawn`. | ||
#### `options.shell` as an alternative to `cross-spawn` | ||
### Using `options.shell` as an alternative to `cross-spawn` | ||
Starting from node v6, `spawn` has a `shell` option that allows you run commands from within a shell. This new option solves most of the problems that `cross-spawn` attempts to solve, but: | ||
Starting from node `v4.8`, `spawn` has a `shell` option that allows you run commands from within a shell. This new option solves most of the problems that `cross-spawn` attempts to solve, but: | ||
- It's not supported in node < v6 | ||
- It has no support for shebangs on Windows | ||
- It's not supported in node `<v4.8` | ||
- You must manually escape the command and arguments which is very error prone, specially when passing user input | ||
- It just solves the [PATHEXT](https://github.com/joyent/node/issues/2318) issue from the [Why](#why) section | ||
If you are using the `shell` option to spawn a command in a cross platform way, consider using `cross-spawn` instead. You have been warned. | ||
### `options.shell` support | ||
#### Shebangs | ||
While `cross-spawn` adds support for `options.shell` in node `<v4.8`, all of its enhancements are disabled. | ||
While `cross-spawn` handles shebangs on Windows, its support is limited: e.g.: it doesn't handle arguments after the path, e.g.: `#!/bin/bash -e`. | ||
This mimics the Node.js behavior. More specifically, the command and its arguments will not be automatically escaped nor shebang support will be offered. This is by design because if you are using `options.shell` you are probably targeting a specific platform anyway and you don't want things to get into your way. | ||
### Shebangs support | ||
While `cross-spawn` handles shebangs on Windows, its support is limited. More specifically, it just supports `#!/usr/bin/env <program>` where `<program>` must not contain any arguments. | ||
If you would like to have the shebang support improved, feel free to contribute via a pull-request. | ||
Remember to always test your code on Windows! | ||
@@ -80,0 +86,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
18154
0
92
5
14
10
235
1
6
2
+ Addednice-try@^1.0.4
+ Addedpath-key@^2.0.1
+ Addedsemver@^5.5.0
+ Addednice-try@1.0.5(transitive)
+ Addedpath-key@2.0.1(transitive)
+ Addedsemver@5.7.2(transitive)
- Removedlru-cache@^4.0.1
- Removedlru-cache@4.1.5(transitive)
- Removedpseudomap@1.0.2(transitive)
- Removedyallist@2.1.2(transitive)