source: trip-planner-front/node_modules/cross-spawn/lib/parse.js@ 6a3a178

Last change on this file since 6a3a178 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 4.3 KB
Line 
1'use strict';
2
3const path = require('path');
4const niceTry = require('nice-try');
5const resolveCommand = require('./util/resolveCommand');
6const escape = require('./util/escape');
7const readShebang = require('./util/readShebang');
8const semver = require('semver');
9
10const isWin = process.platform === 'win32';
11const isExecutableRegExp = /\.(?:com|exe)$/i;
12const isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
13
14// `options.shell` is supported in Node ^4.8.0, ^5.7.0 and >= 6.0.0
15const supportsShellOption = niceTry(() => semver.satisfies(process.version, '^4.8.0 || ^5.7.0 || >= 6.0.0', true)) || false;
16
17function detectShebang(parsed) {
18 parsed.file = resolveCommand(parsed);
19
20 const shebang = parsed.file && readShebang(parsed.file);
21
22 if (shebang) {
23 parsed.args.unshift(parsed.file);
24 parsed.command = shebang;
25
26 return resolveCommand(parsed);
27 }
28
29 return parsed.file;
30}
31
32function parseNonShell(parsed) {
33 if (!isWin) {
34 return parsed;
35 }
36
37 // Detect & add support for shebangs
38 const commandFile = detectShebang(parsed);
39
40 // We don't need a shell if the command filename is an executable
41 const needsShell = !isExecutableRegExp.test(commandFile);
42
43 // If a shell is required, use cmd.exe and take care of escaping everything correctly
44 // Note that `forceShell` is an hidden option used only in tests
45 if (parsed.options.forceShell || needsShell) {
46 // Need to double escape meta chars if the command is a cmd-shim located in `node_modules/.bin/`
47 // The cmd-shim simply calls execute the package bin file with NodeJS, proxying any argument
48 // Because the escape of metachars with ^ gets interpreted when the cmd.exe is first called,
49 // we need to double escape them
50 const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
51
52 // Normalize posix paths into OS compatible paths (e.g.: foo/bar -> foo\bar)
53 // This is necessary otherwise it will always fail with ENOENT in those cases
54 parsed.command = path.normalize(parsed.command);
55
56 // Escape command & arguments
57 parsed.command = escape.command(parsed.command);
58 parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
59
60 const shellCommand = [parsed.command].concat(parsed.args).join(' ');
61
62 parsed.args = ['/d', '/s', '/c', `"${shellCommand}"`];
63 parsed.command = process.env.comspec || 'cmd.exe';
64 parsed.options.windowsVerbatimArguments = true; // Tell node's spawn that the arguments are already escaped
65 }
66
67 return parsed;
68}
69
70function parseShell(parsed) {
71 // If node supports the shell option, there's no need to mimic its behavior
72 if (supportsShellOption) {
73 return parsed;
74 }
75
76 // Mimic node shell option
77 // See https://github.com/nodejs/node/blob/b9f6a2dc059a1062776133f3d4fd848c4da7d150/lib/child_process.js#L335
78 const shellCommand = [parsed.command].concat(parsed.args).join(' ');
79
80 if (isWin) {
81 parsed.command = typeof parsed.options.shell === 'string' ? parsed.options.shell : process.env.comspec || 'cmd.exe';
82 parsed.args = ['/d', '/s', '/c', `"${shellCommand}"`];
83 parsed.options.windowsVerbatimArguments = true; // Tell node's spawn that the arguments are already escaped
84 } else {
85 if (typeof parsed.options.shell === 'string') {
86 parsed.command = parsed.options.shell;
87 } else if (process.platform === 'android') {
88 parsed.command = '/system/bin/sh';
89 } else {
90 parsed.command = '/bin/sh';
91 }
92
93 parsed.args = ['-c', shellCommand];
94 }
95
96 return parsed;
97}
98
99function parse(command, args, options) {
100 // Normalize arguments, similar to nodejs
101 if (args && !Array.isArray(args)) {
102 options = args;
103 args = null;
104 }
105
106 args = args ? args.slice(0) : []; // Clone array to avoid changing the original
107 options = Object.assign({}, options); // Clone object to avoid changing the original
108
109 // Build our parsed object
110 const parsed = {
111 command,
112 args,
113 options,
114 file: undefined,
115 original: {
116 command,
117 args,
118 },
119 };
120
121 // Delegate further parsing to shell or non-shell
122 return options.shell ? parseShell(parsed) : parseNonShell(parsed);
123}
124
125module.exports = parse;
Note: See TracBrowser for help on using the repository browser.