diff --git a/lib/parse.js b/lib/parse.js index 0129d74..bf486bb 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -4,6 +4,7 @@ const path = require('path'); const resolveCommand = require('./util/resolveCommand'); const escape = require('./util/escape'); const readShebang = require('./util/readShebang'); +const readCmdShim = require('read-cmd-shim'); const isWin = process.platform === 'win32'; const isExecutableRegExp = /\.(?:com|exe)$/i; @@ -24,6 +25,23 @@ function detectShebang(parsed) { return parsed.file; } +function isCmdShim(commandFile) { + // Check if file is located in `node_modules/.bin/` + if (isCmdShimRegExp.test(commandFile)) { + return true; + } + // A cmd-shim does not necessarily have to be in `node_modules/.bin/`, + // such as one installed globally through 'npm i -g'. So we test by reading + // its contents and see if we can obtain the wrapped command. + try { + const dest = readCmdShim.sync(commandFile.toLowerCase()); + + return !!dest; + } catch (error) { + return false; + } +} + function parseNonShell(parsed) { if (!isWin) { return parsed; @@ -38,11 +56,11 @@ function parseNonShell(parsed) { // If a shell is required, use cmd.exe and take care of escaping everything correctly // 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/` + // Need to double escape meta chars if the command is a cmd-shim. // 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); + const needsDoubleEscapeMetaChars = isCmdShim(commandFile); // Normalize posix paths into OS compatible paths (e.g.: foo/bar -> foo\bar) // This is necessary otherwise it will always fail with ENOENT in those cases diff --git a/package-lock.json b/package-lock.json index 0c703dc..9ddcaf1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "path-key": "^3.1.0", + "read-cmd-shim": "^4.0.0", "shebang-command": "^2.0.0", "which": "^2.0.1" }, @@ -11701,6 +11702,15 @@ "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==", "dev": true }, + "node_modules/read-cmd-shim": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz", + "integrity": "sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -14067,6 +14077,12 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "read-cmd-shim": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz", + "integrity": "sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==", + "extraneous": true } } } diff --git a/package.json b/package.json index 24b2eb4..2c96e8b 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ }, "dependencies": { "path-key": "^3.1.0", + "read-cmd-shim": "^4.0.0", "shebang-command": "^2.0.0", "which": "^2.0.1" },