@lydell/node-pty 1.1.0 → 1.2.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/unixTerminal.js DELETED
@@ -1,265 +0,0 @@
1
- "use strict";
2
- var __extends = (this && this.__extends) || (function () {
3
- var extendStatics = function (d, b) {
4
- extendStatics = Object.setPrototypeOf ||
5
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
- function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
7
- return extendStatics(d, b);
8
- };
9
- return function (d, b) {
10
- extendStatics(d, b);
11
- function __() { this.constructor = d; }
12
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
13
- };
14
- })();
15
- Object.defineProperty(exports, "__esModule", { value: true });
16
- var tty = require("tty");
17
- var terminal_1 = require("./terminal");
18
- var utils_1 = require("./utils");
19
- var requireBinary_1 = require("./requireBinary");
20
- var pty = requireBinary_1.requireBinary('pty.node');
21
- var helperPath = "@lydell/node-pty-" + process.platform + "-" + process.arch + "/spawn-helper";
22
- helperPath = process.platform === 'darwin' ? require.resolve(helperPath) : 'spawn-helper-unused';
23
- helperPath = helperPath.replace('app.asar', 'app.asar.unpacked');
24
- helperPath = helperPath.replace('node_modules.asar', 'node_modules.asar.unpacked');
25
- var DEFAULT_FILE = 'sh';
26
- var DEFAULT_NAME = 'xterm';
27
- var DESTROY_SOCKET_TIMEOUT_MS = 200;
28
- var UnixTerminal = /** @class */ (function (_super) {
29
- __extends(UnixTerminal, _super);
30
- function UnixTerminal(file, args, opt) {
31
- var _a, _b;
32
- var _this = _super.call(this, opt) || this;
33
- _this._boundClose = false;
34
- _this._emittedClose = false;
35
- if (typeof args === 'string') {
36
- throw new Error('args as a string is not supported on unix.');
37
- }
38
- // Initialize arguments
39
- args = args || [];
40
- file = file || DEFAULT_FILE;
41
- opt = opt || {};
42
- opt.env = opt.env || process.env;
43
- _this._cols = opt.cols || terminal_1.DEFAULT_COLS;
44
- _this._rows = opt.rows || terminal_1.DEFAULT_ROWS;
45
- var uid = (_a = opt.uid) !== null && _a !== void 0 ? _a : -1;
46
- var gid = (_b = opt.gid) !== null && _b !== void 0 ? _b : -1;
47
- var env = utils_1.assign({}, opt.env);
48
- if (opt.env === process.env) {
49
- _this._sanitizeEnv(env);
50
- }
51
- var cwd = opt.cwd || process.cwd();
52
- env.PWD = cwd;
53
- var name = opt.name || env.TERM || DEFAULT_NAME;
54
- env.TERM = name;
55
- var parsedEnv = _this._parseEnv(env);
56
- var encoding = (opt.encoding === undefined ? 'utf8' : opt.encoding);
57
- var onexit = function (code, signal) {
58
- // XXX Sometimes a data event is emitted after exit. Wait til socket is
59
- // destroyed.
60
- if (!_this._emittedClose) {
61
- if (_this._boundClose) {
62
- return;
63
- }
64
- _this._boundClose = true;
65
- // From macOS High Sierra 10.13.2 sometimes the socket never gets
66
- // closed. A timeout is applied here to avoid the terminal never being
67
- // destroyed when this occurs.
68
- var timeout_1 = setTimeout(function () {
69
- timeout_1 = null;
70
- // Destroying the socket now will cause the close event to fire
71
- _this._socket.destroy();
72
- }, DESTROY_SOCKET_TIMEOUT_MS);
73
- _this.once('close', function () {
74
- if (timeout_1 !== null) {
75
- clearTimeout(timeout_1);
76
- }
77
- _this.emit('exit', code, signal);
78
- });
79
- return;
80
- }
81
- _this.emit('exit', code, signal);
82
- };
83
- // fork
84
- var term = pty.fork(file, args, parsedEnv, cwd, _this._cols, _this._rows, uid, gid, (encoding === 'utf8'), helperPath, onexit);
85
- _this._socket = new tty.ReadStream(term.fd);
86
- if (encoding !== null) {
87
- _this._socket.setEncoding(encoding);
88
- }
89
- // setup
90
- _this._socket.on('error', function (err) {
91
- // NOTE: fs.ReadStream gets EAGAIN twice at first:
92
- if (err.code) {
93
- if (~err.code.indexOf('EAGAIN')) {
94
- return;
95
- }
96
- }
97
- // close
98
- _this._close();
99
- // EIO on exit from fs.ReadStream:
100
- if (!_this._emittedClose) {
101
- _this._emittedClose = true;
102
- _this.emit('close');
103
- }
104
- // EIO, happens when someone closes our child process: the only process in
105
- // the terminal.
106
- // node < 0.6.14: errno 5
107
- // node >= 0.6.14: read EIO
108
- if (err.code) {
109
- if (~err.code.indexOf('errno 5') || ~err.code.indexOf('EIO')) {
110
- return;
111
- }
112
- }
113
- // throw anything else
114
- if (_this.listeners('error').length < 2) {
115
- throw err;
116
- }
117
- });
118
- _this._pid = term.pid;
119
- _this._fd = term.fd;
120
- _this._pty = term.pty;
121
- _this._file = file;
122
- _this._name = name;
123
- _this._readable = true;
124
- _this._writable = true;
125
- _this._socket.on('close', function () {
126
- if (_this._emittedClose) {
127
- return;
128
- }
129
- _this._emittedClose = true;
130
- _this._close();
131
- _this.emit('close');
132
- });
133
- _this._forwardEvents();
134
- return _this;
135
- }
136
- Object.defineProperty(UnixTerminal.prototype, "master", {
137
- get: function () { return this._master; },
138
- enumerable: true,
139
- configurable: true
140
- });
141
- Object.defineProperty(UnixTerminal.prototype, "slave", {
142
- get: function () { return this._slave; },
143
- enumerable: true,
144
- configurable: true
145
- });
146
- UnixTerminal.prototype._write = function (data) {
147
- this._socket.write(data);
148
- };
149
- Object.defineProperty(UnixTerminal.prototype, "fd", {
150
- /* Accessors */
151
- get: function () { return this._fd; },
152
- enumerable: true,
153
- configurable: true
154
- });
155
- Object.defineProperty(UnixTerminal.prototype, "ptsName", {
156
- get: function () { return this._pty; },
157
- enumerable: true,
158
- configurable: true
159
- });
160
- /**
161
- * openpty
162
- */
163
- UnixTerminal.open = function (opt) {
164
- var self = Object.create(UnixTerminal.prototype);
165
- opt = opt || {};
166
- if (arguments.length > 1) {
167
- opt = {
168
- cols: arguments[1],
169
- rows: arguments[2]
170
- };
171
- }
172
- var cols = opt.cols || terminal_1.DEFAULT_COLS;
173
- var rows = opt.rows || terminal_1.DEFAULT_ROWS;
174
- var encoding = (opt.encoding === undefined ? 'utf8' : opt.encoding);
175
- // open
176
- var term = pty.open(cols, rows);
177
- self._master = new tty.ReadStream(term.master);
178
- if (encoding !== null) {
179
- self._master.setEncoding(encoding);
180
- }
181
- self._master.resume();
182
- self._slave = new tty.ReadStream(term.slave);
183
- if (encoding !== null) {
184
- self._slave.setEncoding(encoding);
185
- }
186
- self._slave.resume();
187
- self._socket = self._master;
188
- self._pid = -1;
189
- self._fd = term.master;
190
- self._pty = term.pty;
191
- self._file = process.argv[0] || 'node';
192
- self._name = process.env.TERM || '';
193
- self._readable = true;
194
- self._writable = true;
195
- self._socket.on('error', function (err) {
196
- self._close();
197
- if (self.listeners('error').length < 2) {
198
- throw err;
199
- }
200
- });
201
- self._socket.on('close', function () {
202
- self._close();
203
- });
204
- return self;
205
- };
206
- UnixTerminal.prototype.destroy = function () {
207
- var _this = this;
208
- this._close();
209
- // Need to close the read stream so node stops reading a dead file
210
- // descriptor. Then we can safely SIGHUP the shell.
211
- this._socket.once('close', function () {
212
- _this.kill('SIGHUP');
213
- });
214
- this._socket.destroy();
215
- };
216
- UnixTerminal.prototype.kill = function (signal) {
217
- try {
218
- process.kill(this.pid, signal || 'SIGHUP');
219
- }
220
- catch (e) { /* swallow */ }
221
- };
222
- Object.defineProperty(UnixTerminal.prototype, "process", {
223
- /**
224
- * Gets the name of the process.
225
- */
226
- get: function () {
227
- if (process.platform === 'darwin') {
228
- var title = pty.process(this._fd);
229
- return (title !== 'kernel_task') ? title : this._file;
230
- }
231
- return pty.process(this._fd, this._pty) || this._file;
232
- },
233
- enumerable: true,
234
- configurable: true
235
- });
236
- /**
237
- * TTY
238
- */
239
- UnixTerminal.prototype.resize = function (cols, rows) {
240
- if (cols <= 0 || rows <= 0 || isNaN(cols) || isNaN(rows) || cols === Infinity || rows === Infinity) {
241
- throw new Error('resizing must be done using positive cols and rows');
242
- }
243
- pty.resize(this._fd, cols, rows);
244
- this._cols = cols;
245
- this._rows = rows;
246
- };
247
- UnixTerminal.prototype.clear = function () {
248
- };
249
- UnixTerminal.prototype._sanitizeEnv = function (env) {
250
- // Make sure we didn't start our server from inside tmux.
251
- delete env['TMUX'];
252
- delete env['TMUX_PANE'];
253
- // Make sure we didn't start our server from inside screen.
254
- // http://web.mit.edu/gnu/doc/html/screen_20.html
255
- delete env['STY'];
256
- delete env['WINDOW'];
257
- // Delete some variables that might confuse our terminal.
258
- delete env['WINDOWID'];
259
- delete env['TERMCAP'];
260
- delete env['COLUMNS'];
261
- delete env['LINES'];
262
- };
263
- return UnixTerminal;
264
- }(terminal_1.Terminal));
265
- exports.UnixTerminal = UnixTerminal;
package/utils.js DELETED
@@ -1,15 +0,0 @@
1
- "use strict";
2
- /**
3
- * Copyright (c) 2017, Daniel Imms (MIT License).
4
- * Copyright (c) 2018, Microsoft Corporation (MIT License).
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- function assign(target) {
8
- var sources = [];
9
- for (var _i = 1; _i < arguments.length; _i++) {
10
- sources[_i - 1] = arguments[_i];
11
- }
12
- sources.forEach(function (source) { return Object.keys(source).forEach(function (key) { return target[key] = source[key]; }); });
13
- return target;
14
- }
15
- exports.assign = assign;
@@ -1,120 +0,0 @@
1
- "use strict";
2
- /**
3
- * Copyright (c) 2020, Microsoft Corporation (MIT License).
4
- */
5
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
6
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
7
- return new (P || (P = Promise))(function (resolve, reject) {
8
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
9
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
10
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
11
- step((generator = generator.apply(thisArg, _arguments || [])).next());
12
- });
13
- };
14
- var __generator = (this && this.__generator) || function (thisArg, body) {
15
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
16
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
17
- function verb(n) { return function (v) { return step([n, v]); }; }
18
- function step(op) {
19
- if (f) throw new TypeError("Generator is already executing.");
20
- while (_) try {
21
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
22
- if (y = 0, t) op = [op[0] & 2, t.value];
23
- switch (op[0]) {
24
- case 0: case 1: t = op; break;
25
- case 4: _.label++; return { value: op[1], done: false };
26
- case 5: _.label++; y = op[1]; op = [0]; continue;
27
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
28
- default:
29
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
30
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
31
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
32
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
33
- if (t[2]) _.ops.pop();
34
- _.trys.pop(); continue;
35
- }
36
- op = body.call(thisArg, _);
37
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
38
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
39
- }
40
- };
41
- Object.defineProperty(exports, "__esModule", { value: true });
42
- var worker_threads_1 = require("worker_threads");
43
- var conout_1 = require("./shared/conout");
44
- var path_1 = require("path");
45
- var eventEmitter2_1 = require("./eventEmitter2");
46
- /**
47
- * The amount of time to wait for additional data after the conpty shell process has exited before
48
- * shutting down the worker and sockets. The timer will be reset if a new data event comes in after
49
- * the timer has started.
50
- */
51
- var FLUSH_DATA_INTERVAL = 1000;
52
- /**
53
- * Connects to and manages the lifecycle of the conout socket. This socket must be drained on
54
- * another thread in order to avoid deadlocks where Conpty waits for the out socket to drain
55
- * when `ClosePseudoConsole` is called. This happens when data is being written to the terminal when
56
- * the pty is closed.
57
- *
58
- * See also:
59
- * - https://github.com/microsoft/node-pty/issues/375
60
- * - https://github.com/microsoft/vscode/issues/76548
61
- * - https://github.com/microsoft/terminal/issues/1810
62
- * - https://docs.microsoft.com/en-us/windows/console/closepseudoconsole
63
- */
64
- var ConoutConnection = /** @class */ (function () {
65
- function ConoutConnection(_conoutPipeName) {
66
- var _this = this;
67
- this._conoutPipeName = _conoutPipeName;
68
- this._isDisposed = false;
69
- this._onReady = new eventEmitter2_1.EventEmitter2();
70
- var workerData = { conoutPipeName: _conoutPipeName };
71
- var scriptPath = __dirname.replace('node_modules.asar', 'node_modules.asar.unpacked');
72
- this._worker = new worker_threads_1.Worker(path_1.join(scriptPath, 'worker/conoutSocketWorker.js'), { workerData: workerData });
73
- this._worker.on('message', function (message) {
74
- switch (message) {
75
- case 1 /* READY */:
76
- _this._onReady.fire();
77
- return;
78
- default:
79
- console.warn('Unexpected ConoutWorkerMessage', message);
80
- }
81
- });
82
- }
83
- Object.defineProperty(ConoutConnection.prototype, "onReady", {
84
- get: function () { return this._onReady.event; },
85
- enumerable: true,
86
- configurable: true
87
- });
88
- ConoutConnection.prototype.dispose = function () {
89
- if (this._isDisposed) {
90
- return;
91
- }
92
- this._isDisposed = true;
93
- // Drain all data from the socket before closing
94
- this._drainDataAndClose();
95
- };
96
- ConoutConnection.prototype.connectSocket = function (socket) {
97
- socket.connect(conout_1.getWorkerPipeName(this._conoutPipeName));
98
- };
99
- ConoutConnection.prototype._drainDataAndClose = function () {
100
- var _this = this;
101
- if (this._drainTimeout) {
102
- clearTimeout(this._drainTimeout);
103
- }
104
- this._drainTimeout = setTimeout(function () { return _this._destroySocket(); }, FLUSH_DATA_INTERVAL);
105
- };
106
- ConoutConnection.prototype._destroySocket = function () {
107
- return __awaiter(this, void 0, void 0, function () {
108
- return __generator(this, function (_a) {
109
- switch (_a.label) {
110
- case 0: return [4 /*yield*/, this._worker.terminate()];
111
- case 1:
112
- _a.sent();
113
- return [2 /*return*/];
114
- }
115
- });
116
- });
117
- };
118
- return ConoutConnection;
119
- }());
120
- exports.ConoutConnection = ConoutConnection;
@@ -1,236 +0,0 @@
1
- "use strict";
2
- /**
3
- * Copyright (c) 2012-2015, Christopher Jeffrey, Peter Sunde (MIT License)
4
- * Copyright (c) 2016, Daniel Imms (MIT License).
5
- * Copyright (c) 2018, Microsoft Corporation (MIT License).
6
- */
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- var fs = require("fs");
9
- var path = require("path");
10
- var net_1 = require("net");
11
- var child_process_1 = require("child_process");
12
- var windowsConoutConnection_1 = require("./windowsConoutConnection");
13
- var requireBinary_1 = require("./requireBinary");
14
- var conptyNative;
15
- /**
16
- * The amount of time to wait for additional data after the conpty shell process has exited before
17
- * shutting down the socket. The timer will be reset if a new data event comes in after the timer
18
- * has started.
19
- */
20
- var FLUSH_DATA_INTERVAL = 1000;
21
- /**
22
- * This agent sits between the WindowsTerminal class and provides an interface for both conpty.
23
- */
24
- var WindowsPtyAgent = /** @class */ (function () {
25
- function WindowsPtyAgent(file, args, env, cwd, cols, rows, debug, conptyInheritCursor) {
26
- var _this = this;
27
- if (conptyInheritCursor === void 0) { conptyInheritCursor = false; }
28
- this._pid = 0;
29
- this._innerPid = 0;
30
- if (!conptyNative) {
31
- conptyNative = requireBinary_1.requireBinary('conpty.node');
32
- }
33
- this._ptyNative = conptyNative;
34
- // Sanitize input variable.
35
- cwd = path.resolve(cwd);
36
- // Compose command line
37
- var commandLine = argsToCommandLine(file, args);
38
- // Open pty session.
39
- var term = this._ptyNative.startProcess(file, cols, rows, debug, this._generatePipeName(), conptyInheritCursor);
40
- // Not available on windows.
41
- this._fd = term.fd;
42
- // Generated incremental number that has no real purpose besides using it
43
- // as a terminal id.
44
- this._pty = term.pty;
45
- // Create terminal pipe IPC channel and forward to a local unix socket.
46
- this._outSocket = new net_1.Socket();
47
- this._outSocket.setEncoding('utf8');
48
- // The conout socket must be ready out on another thread to avoid deadlocks
49
- this._conoutSocketWorker = new windowsConoutConnection_1.ConoutConnection(term.conout);
50
- this._conoutSocketWorker.onReady(function () {
51
- _this._conoutSocketWorker.connectSocket(_this._outSocket);
52
- });
53
- this._outSocket.on('connect', function () {
54
- _this._outSocket.emit('ready_datapipe');
55
- });
56
- var inSocketFD = fs.openSync(term.conin, 'w');
57
- this._inSocket = new net_1.Socket({
58
- fd: inSocketFD,
59
- readable: false,
60
- writable: true
61
- });
62
- this._inSocket.setEncoding('utf8');
63
- var connect = this._ptyNative.connect(this._pty, commandLine, cwd, env, function (c) { return _this._$onProcessExit(c); });
64
- this._innerPid = connect.pid;
65
- }
66
- Object.defineProperty(WindowsPtyAgent.prototype, "inSocket", {
67
- get: function () { return this._inSocket; },
68
- enumerable: true,
69
- configurable: true
70
- });
71
- Object.defineProperty(WindowsPtyAgent.prototype, "outSocket", {
72
- get: function () { return this._outSocket; },
73
- enumerable: true,
74
- configurable: true
75
- });
76
- Object.defineProperty(WindowsPtyAgent.prototype, "fd", {
77
- get: function () { return this._fd; },
78
- enumerable: true,
79
- configurable: true
80
- });
81
- Object.defineProperty(WindowsPtyAgent.prototype, "innerPid", {
82
- get: function () { return this._innerPid; },
83
- enumerable: true,
84
- configurable: true
85
- });
86
- Object.defineProperty(WindowsPtyAgent.prototype, "pty", {
87
- get: function () { return this._pty; },
88
- enumerable: true,
89
- configurable: true
90
- });
91
- WindowsPtyAgent.prototype.resize = function (cols, rows) {
92
- if (this._exitCode !== undefined) {
93
- throw new Error('Cannot resize a pty that has already exited');
94
- }
95
- this._ptyNative.resize(this._pty, cols, rows);
96
- };
97
- WindowsPtyAgent.prototype.clear = function () {
98
- this._ptyNative.clear(this._pty);
99
- };
100
- WindowsPtyAgent.prototype.kill = function () {
101
- var _this = this;
102
- this._inSocket.readable = false;
103
- this._outSocket.readable = false;
104
- // Tell the agent to kill the pty, this releases handles to the process
105
- this._getConsoleProcessList().then(function (consoleProcessList) {
106
- consoleProcessList.forEach(function (pid) {
107
- try {
108
- process.kill(pid);
109
- }
110
- catch (e) {
111
- // Ignore if process cannot be found (kill ESRCH error)
112
- }
113
- });
114
- _this._ptyNative.kill(_this._pty);
115
- });
116
- this._conoutSocketWorker.dispose();
117
- };
118
- WindowsPtyAgent.prototype._getConsoleProcessList = function () {
119
- var _this = this;
120
- return new Promise(function (resolve) {
121
- var agent = child_process_1.fork(path.join(__dirname, 'conpty_console_list_agent'), [_this._innerPid.toString()]);
122
- agent.on('message', function (message) {
123
- clearTimeout(timeout);
124
- resolve(message.consoleProcessList);
125
- });
126
- var timeout = setTimeout(function () {
127
- // Something went wrong, just send back the shell PID
128
- agent.kill();
129
- resolve([_this._innerPid]);
130
- }, 5000);
131
- });
132
- };
133
- Object.defineProperty(WindowsPtyAgent.prototype, "exitCode", {
134
- get: function () {
135
- return this._exitCode;
136
- },
137
- enumerable: true,
138
- configurable: true
139
- });
140
- WindowsPtyAgent.prototype._generatePipeName = function () {
141
- return "conpty-" + Math.random() * 10000000;
142
- };
143
- /**
144
- * Triggered from the native side when a contpy process exits.
145
- */
146
- WindowsPtyAgent.prototype._$onProcessExit = function (exitCode) {
147
- var _this = this;
148
- this._exitCode = exitCode;
149
- this._flushDataAndCleanUp();
150
- this._outSocket.on('data', function () { return _this._flushDataAndCleanUp(); });
151
- };
152
- WindowsPtyAgent.prototype._flushDataAndCleanUp = function () {
153
- var _this = this;
154
- if (this._closeTimeout) {
155
- clearTimeout(this._closeTimeout);
156
- }
157
- this._closeTimeout = setTimeout(function () { return _this._cleanUpProcess(); }, FLUSH_DATA_INTERVAL);
158
- };
159
- WindowsPtyAgent.prototype._cleanUpProcess = function () {
160
- this._inSocket.readable = false;
161
- this._outSocket.readable = false;
162
- this._outSocket.destroy();
163
- };
164
- return WindowsPtyAgent;
165
- }());
166
- exports.WindowsPtyAgent = WindowsPtyAgent;
167
- // Convert argc/argv into a Win32 command-line following the escaping convention
168
- // documented on MSDN (e.g. see CommandLineToArgvW documentation). Copied from
169
- // winpty project.
170
- function argsToCommandLine(file, args) {
171
- if (isCommandLine(args)) {
172
- if (args.length === 0) {
173
- return file;
174
- }
175
- return argsToCommandLine(file, []) + " " + args;
176
- }
177
- var argv = [file];
178
- Array.prototype.push.apply(argv, args);
179
- var result = '';
180
- for (var argIndex = 0; argIndex < argv.length; argIndex++) {
181
- if (argIndex > 0) {
182
- result += ' ';
183
- }
184
- var arg = argv[argIndex];
185
- // if it is empty or it contains whitespace and is not already quoted
186
- var hasLopsidedEnclosingQuote = xOr((arg[0] !== '"'), (arg[arg.length - 1] !== '"'));
187
- var hasNoEnclosingQuotes = ((arg[0] !== '"') && (arg[arg.length - 1] !== '"'));
188
- var quote = arg === '' ||
189
- (arg.indexOf(' ') !== -1 ||
190
- arg.indexOf('\t') !== -1) &&
191
- ((arg.length > 1) &&
192
- (hasLopsidedEnclosingQuote || hasNoEnclosingQuotes));
193
- if (quote) {
194
- result += '\"';
195
- }
196
- var bsCount = 0;
197
- for (var i = 0; i < arg.length; i++) {
198
- var p = arg[i];
199
- if (p === '\\') {
200
- bsCount++;
201
- }
202
- else if (p === '"') {
203
- result += repeatText('\\', bsCount * 2 + 1);
204
- result += '"';
205
- bsCount = 0;
206
- }
207
- else {
208
- result += repeatText('\\', bsCount);
209
- bsCount = 0;
210
- result += p;
211
- }
212
- }
213
- if (quote) {
214
- result += repeatText('\\', bsCount * 2);
215
- result += '\"';
216
- }
217
- else {
218
- result += repeatText('\\', bsCount);
219
- }
220
- }
221
- return result;
222
- }
223
- exports.argsToCommandLine = argsToCommandLine;
224
- function isCommandLine(args) {
225
- return typeof args === 'string';
226
- }
227
- function repeatText(text, count) {
228
- var result = '';
229
- for (var i = 0; i < count; i++) {
230
- result += text;
231
- }
232
- return result;
233
- }
234
- function xOr(arg1, arg2) {
235
- return ((arg1 && !arg2) || (!arg1 && arg2));
236
- }