| 'use strict'; |
|
|
| const path = require('path'); |
| const resolveCommand = require('./util/resolveCommand'); |
| const escape = require('./util/escape'); |
| const readShebang = require('./util/readShebang'); |
|
|
| const isWin = process.platform === 'win32'; |
| const isExecutableRegExp = /\.(?:com|exe)$/i; |
| const isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i; |
|
|
| 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) { |
| if (!isWin) { |
| return parsed; |
| } |
|
|
| |
| const commandFile = detectShebang(parsed); |
|
|
| |
| const needsShell = !isExecutableRegExp.test(commandFile); |
|
|
| |
| |
| if (parsed.options.forceShell || needsShell) { |
| |
| |
| |
| |
| const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile); |
|
|
| |
| |
| parsed.command = path.normalize(parsed.command); |
|
|
| |
| parsed.command = escape.command(parsed.command); |
| parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars)); |
|
|
| const shellCommand = [parsed.command].concat(parsed.args).join(' '); |
|
|
| parsed.args = ['/d', '/s', '/c', `"${shellCommand}"`]; |
| parsed.command = process.env.comspec || 'cmd.exe'; |
| parsed.options.windowsVerbatimArguments = true; |
| } |
|
|
| return parsed; |
| } |
|
|
| function parse(command, args, options) { |
| |
| if (args && !Array.isArray(args)) { |
| options = args; |
| args = null; |
| } |
|
|
| args = args ? args.slice(0) : []; |
| options = Object.assign({}, options); |
|
|
| |
| const parsed = { |
| command, |
| args, |
| options, |
| file: undefined, |
| original: { |
| command, |
| args, |
| }, |
| }; |
|
|
| |
| return options.shell ? parsed : parseNonShell(parsed); |
| } |
|
|
| module.exports = parse; |
|
|