spawn-rx 3.0.0 → 4.0.0
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/.prettierrc +4 -0
- package/eslint.config.mjs +88 -0
- package/lib/src/index.d.ts +1 -1
- package/lib/src/index.js +82 -52
- package/lib/src/index.js.map +1 -1
- package/package.json +26 -20
- package/src/ambient.d.ts +1 -1
- package/src/index.ts +200 -129
- package/test/asserttest.ts +5 -4
- package/test/spawn.ts +86 -49
- package/test/support.ts +4 -3
- package/tsconfig.json +2 -6
- package/.travis.yml +0 -24
- package/appveyor.yml +0 -21
- package/tslint.json +0 -40
package/src/index.ts
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
-
|
2
|
-
import * as
|
3
|
-
import * as
|
4
|
-
import * as
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2
|
+
import * as path from "path";
|
3
|
+
import * as net from "net";
|
4
|
+
import * as sfs from "fs";
|
5
|
+
import * as assign from "lodash.assign";
|
5
6
|
|
6
|
-
import {
|
7
|
-
import {
|
8
|
-
import
|
7
|
+
import type { Observer, Subject } from "rxjs";
|
8
|
+
import { Observable, Subscription, AsyncSubject, of, merge } from "rxjs";
|
9
|
+
import { map, reduce } from "rxjs/operators";
|
10
|
+
import { spawn as spawnOg } from "child_process";
|
11
|
+
import Debug from "debug";
|
9
12
|
|
10
|
-
const
|
11
|
-
const isWindows = process.platform === 'win32';
|
13
|
+
const isWindows = process.platform === "win32";
|
12
14
|
|
13
|
-
const d =
|
15
|
+
const d = Debug("spawn-rx"); // tslint:disable-line:no-var-requires
|
14
16
|
|
15
17
|
/**
|
16
18
|
* stat a file but don't throw if it doesn't exist
|
@@ -23,7 +25,7 @@ const d = require('debug')('spawn-rx'); //tslint:disable-line:no-var-requires
|
|
23
25
|
function statSyncNoException(file: string): sfs.Stats | null {
|
24
26
|
try {
|
25
27
|
return sfs.statSync(file);
|
26
|
-
} catch
|
28
|
+
} catch {
|
27
29
|
return null;
|
28
30
|
}
|
29
31
|
}
|
@@ -42,26 +44,26 @@ function runDownPath(exe: string): string {
|
|
42
44
|
// Posix does
|
43
45
|
|
44
46
|
// Files with any directory path don't get this applied
|
45
|
-
if (exe.match(/[
|
46
|
-
d(
|
47
|
+
if (exe.match(/[\\/]/)) {
|
48
|
+
d("Path has slash in directory, bailing");
|
47
49
|
return exe;
|
48
50
|
}
|
49
51
|
|
50
|
-
|
52
|
+
const target = path.join(".", exe);
|
51
53
|
if (statSyncNoException(target)) {
|
52
54
|
d(`Found executable in currect directory: ${target}`);
|
53
55
|
return target;
|
54
56
|
}
|
55
57
|
|
56
|
-
|
57
|
-
for (
|
58
|
-
|
58
|
+
const haystack = process.env.PATH!.split(isWindows ? ";" : ":");
|
59
|
+
for (const p of haystack) {
|
60
|
+
const needle = path.join(p, exe);
|
59
61
|
if (statSyncNoException(needle)) {
|
60
62
|
return needle;
|
61
63
|
}
|
62
64
|
}
|
63
65
|
|
64
|
-
d(
|
66
|
+
d("Failed to find executable anywhere in path");
|
65
67
|
return exe;
|
66
68
|
}
|
67
69
|
|
@@ -81,12 +83,15 @@ function runDownPath(exe: string): string {
|
|
81
83
|
* @property {string} cmd The command to pass to spawn
|
82
84
|
* @property {Array<string>} args The arguments to pass to spawn
|
83
85
|
*/
|
84
|
-
export function findActualExecutable(
|
86
|
+
export function findActualExecutable(
|
87
|
+
exe: string,
|
88
|
+
args: Array<string>,
|
89
|
+
): {
|
85
90
|
cmd: string;
|
86
|
-
args: Array<string
|
91
|
+
args: Array<string>;
|
87
92
|
} {
|
88
93
|
// POSIX can just execute scripts directly, no need for silly goosery
|
89
|
-
if (process.platform !==
|
94
|
+
if (process.platform !== "win32") {
|
90
95
|
return { cmd: runDownPath(exe), args: args };
|
91
96
|
}
|
92
97
|
|
@@ -94,9 +99,9 @@ export function findActualExecutable(exe: string, args: Array<string>): {
|
|
94
99
|
// NB: When you write something like `surf-client ... -- surf-build` on Windows,
|
95
100
|
// a shell would normally convert that to surf-build.cmd, but since it's passed
|
96
101
|
// in as an argument, it doesn't happen
|
97
|
-
const possibleExts = [
|
98
|
-
for (
|
99
|
-
|
102
|
+
const possibleExts = [".exe", ".bat", ".cmd", ".ps1"];
|
103
|
+
for (const ext of possibleExts) {
|
104
|
+
const possibleFullPath = runDownPath(`${exe}${ext}`);
|
100
105
|
|
101
106
|
if (sfs.existsSync(possibleFullPath)) {
|
102
107
|
return findActualExecutable(possibleFullPath, args);
|
@@ -105,22 +110,35 @@ export function findActualExecutable(exe: string, args: Array<string>): {
|
|
105
110
|
}
|
106
111
|
|
107
112
|
if (exe.match(/\.ps1$/i)) {
|
108
|
-
|
109
|
-
|
113
|
+
const cmd = path.join(
|
114
|
+
process.env.SYSTEMROOT!,
|
115
|
+
"System32",
|
116
|
+
"WindowsPowerShell",
|
117
|
+
"v1.0",
|
118
|
+
"PowerShell.exe",
|
119
|
+
);
|
120
|
+
const psargs = [
|
121
|
+
"-ExecutionPolicy",
|
122
|
+
"Unrestricted",
|
123
|
+
"-NoLogo",
|
124
|
+
"-NonInteractive",
|
125
|
+
"-File",
|
126
|
+
exe,
|
127
|
+
];
|
110
128
|
|
111
129
|
return { cmd: cmd, args: psargs.concat(args) };
|
112
130
|
}
|
113
131
|
|
114
132
|
if (exe.match(/\.(bat|cmd)$/i)) {
|
115
|
-
|
116
|
-
|
133
|
+
const cmd = path.join(process.env.SYSTEMROOT!, "System32", "cmd.exe");
|
134
|
+
const cmdArgs = ["/C", exe, ...args];
|
117
135
|
|
118
136
|
return { cmd: cmd, args: cmdArgs };
|
119
137
|
}
|
120
138
|
|
121
139
|
if (exe.match(/\.(js)$/i)) {
|
122
|
-
|
123
|
-
|
140
|
+
const cmd = process.execPath;
|
141
|
+
const nodeArgs = [exe];
|
124
142
|
|
125
143
|
return { cmd: cmd, args: nodeArgs.concat(args) };
|
126
144
|
}
|
@@ -146,7 +164,11 @@ export function findActualExecutable(exe: string, args: Array<string>): {
|
|
146
164
|
* process terminates with a non-zero value,
|
147
165
|
* the Observable will terminate with onError.
|
148
166
|
*/
|
149
|
-
export function spawnDetached(
|
167
|
+
export function spawnDetached(
|
168
|
+
exe: string,
|
169
|
+
params: Array<string>,
|
170
|
+
opts: any = null,
|
171
|
+
): Observable<string> {
|
150
172
|
const { cmd, args } = findActualExecutable(exe, params);
|
151
173
|
|
152
174
|
if (!isWindows) {
|
@@ -155,8 +177,15 @@ export function spawnDetached(exe: string, params: Array<string>, opts: any = nu
|
|
155
177
|
|
156
178
|
const newParams = [cmd].concat(args);
|
157
179
|
|
158
|
-
|
159
|
-
|
180
|
+
const target = path.join(
|
181
|
+
__dirname,
|
182
|
+
"..",
|
183
|
+
"..",
|
184
|
+
"vendor",
|
185
|
+
"jobber",
|
186
|
+
"Jobber.exe",
|
187
|
+
);
|
188
|
+
const options = assign({}, opts || {}, { detached: true, jobber: true });
|
160
189
|
|
161
190
|
d(`spawnDetached: ${target}, ${newParams}`);
|
162
191
|
return spawn(target, newParams, options);
|
@@ -178,123 +207,157 @@ export function spawnDetached(exe: string, params: Array<string>, opts: any = nu
|
|
178
207
|
* the Observable will terminate with onError.
|
179
208
|
*/
|
180
209
|
|
181
|
-
export function spawn<T = string>(
|
210
|
+
export function spawn<T = string>(
|
211
|
+
exe: string,
|
212
|
+
params: Array<string> = [],
|
213
|
+
opts: any = null,
|
214
|
+
): Observable<T> {
|
182
215
|
opts = opts || {};
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
if (b.length < 1) {
|
202
|
-
return;
|
216
|
+
const spawnObs = Observable.create(
|
217
|
+
(
|
218
|
+
subj: Observer<{
|
219
|
+
source: any;
|
220
|
+
text: any;
|
221
|
+
}>,
|
222
|
+
) => {
|
223
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
224
|
+
const { _, ...optsWithoutStdIn } = opts;
|
225
|
+
const { cmd, args } = findActualExecutable(exe, params);
|
226
|
+
d(
|
227
|
+
`spawning process: ${cmd} ${args.join()}, ${JSON.stringify(
|
228
|
+
optsWithoutStdIn,
|
229
|
+
)}`,
|
230
|
+
);
|
231
|
+
const origOpts = assign({}, optsWithoutStdIn);
|
232
|
+
if ("jobber" in origOpts) {
|
233
|
+
delete origOpts.jobber;
|
203
234
|
}
|
204
|
-
|
205
|
-
|
206
|
-
if (typeof b === 'string') {
|
207
|
-
chunk = b.toString();
|
208
|
-
} else {
|
209
|
-
chunk = b.toString(origOpts.encoding || 'utf8');
|
210
|
-
}
|
211
|
-
} catch (e) {
|
212
|
-
chunk = `<< Lost chunk of process output for ${exe} - length was ${b.length}>>`;
|
235
|
+
if ("split" in origOpts) {
|
236
|
+
delete origOpts.split;
|
213
237
|
}
|
214
238
|
|
215
|
-
|
216
|
-
};
|
217
|
-
|
218
|
-
let ret = new Subscription();
|
219
|
-
|
220
|
-
if (opts.stdin) {
|
221
|
-
if (proc.stdin) {
|
222
|
-
ret.add(opts.stdin.subscribe(
|
223
|
-
(x: any) => proc.stdin.write(x),
|
224
|
-
subj.error.bind(subj),
|
225
|
-
() => proc.stdin.end()
|
226
|
-
));
|
227
|
-
} else {
|
228
|
-
subj.error(new Error(`opts.stdio conflicts with provided spawn opts.stdin observable, 'pipe' is required`));
|
229
|
-
}
|
230
|
-
}
|
231
|
-
|
232
|
-
let stderrCompleted: Subject<boolean> | Observable<boolean> | null = null;
|
233
|
-
let stdoutCompleted: Subject<boolean> | Observable<boolean> | null = null;
|
234
|
-
let noClose = false;
|
235
|
-
|
236
|
-
if (proc.stdout) {
|
237
|
-
stdoutCompleted = new AsyncSubject<boolean>();
|
238
|
-
proc.stdout.on('data', bufHandler('stdout'));
|
239
|
-
proc.stdout.on('close', () => { (stdoutCompleted! as Subject<boolean>).next(true); (stdoutCompleted! as Subject<boolean>).complete(); });
|
240
|
-
} else {
|
241
|
-
stdoutCompleted = of(true);
|
242
|
-
}
|
239
|
+
const proc = spawnOg(cmd, args, origOpts);
|
243
240
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
241
|
+
const bufHandler = (source: string) => (b: string | Buffer) => {
|
242
|
+
if (b.length < 1) {
|
243
|
+
return;
|
244
|
+
}
|
245
|
+
let chunk = "<< String sent back was too long >>";
|
246
|
+
try {
|
247
|
+
if (typeof b === "string") {
|
248
|
+
chunk = b.toString();
|
249
|
+
} else {
|
250
|
+
chunk = b.toString(origOpts.encoding || "utf8");
|
251
|
+
}
|
252
|
+
} catch {
|
253
|
+
chunk = `<< Lost chunk of process output for ${exe} - length was ${b.length}>>`;
|
254
|
+
}
|
251
255
|
|
252
|
-
|
253
|
-
|
254
|
-
subj.error(e);
|
255
|
-
});
|
256
|
+
subj.next({ source: source, text: chunk });
|
257
|
+
};
|
256
258
|
|
257
|
-
|
258
|
-
noClose = true;
|
259
|
-
let pipesClosed = merge(stdoutCompleted!, stderrCompleted!)
|
260
|
-
.pipe(reduce((acc) => acc, true));
|
259
|
+
const ret = new Subscription();
|
261
260
|
|
262
|
-
if (
|
263
|
-
|
264
|
-
|
265
|
-
|
261
|
+
if (opts.stdin) {
|
262
|
+
if (proc.stdin) {
|
263
|
+
ret.add(
|
264
|
+
opts.stdin.subscribe(
|
265
|
+
(x: any) => proc.stdin.write(x),
|
266
|
+
subj.error.bind(subj),
|
267
|
+
() => proc.stdin.end(),
|
268
|
+
),
|
269
|
+
);
|
270
|
+
} else {
|
271
|
+
subj.error(
|
272
|
+
new Error(
|
273
|
+
`opts.stdio conflicts with provided spawn opts.stdin observable, 'pipe' is required`,
|
274
|
+
),
|
275
|
+
);
|
276
|
+
}
|
266
277
|
}
|
267
|
-
});
|
268
278
|
|
269
|
-
|
270
|
-
|
271
|
-
|
279
|
+
let stderrCompleted: Subject<boolean> | Observable<boolean> | null = null;
|
280
|
+
let stdoutCompleted: Subject<boolean> | Observable<boolean> | null = null;
|
281
|
+
let noClose = false;
|
282
|
+
|
283
|
+
if (proc.stdout) {
|
284
|
+
stdoutCompleted = new AsyncSubject<boolean>();
|
285
|
+
proc.stdout.on("data", bufHandler("stdout"));
|
286
|
+
proc.stdout.on("close", () => {
|
287
|
+
(stdoutCompleted! as Subject<boolean>).next(true);
|
288
|
+
(stdoutCompleted! as Subject<boolean>).complete();
|
289
|
+
});
|
290
|
+
} else {
|
291
|
+
stdoutCompleted = of(true);
|
272
292
|
}
|
273
293
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
294
|
+
if (proc.stderr) {
|
295
|
+
stderrCompleted = new AsyncSubject<boolean>();
|
296
|
+
proc.stderr.on("data", bufHandler("stderr"));
|
297
|
+
proc.stderr.on("close", () => {
|
298
|
+
(stderrCompleted! as Subject<boolean>).next(true);
|
299
|
+
(stderrCompleted! as Subject<boolean>).complete();
|
300
|
+
});
|
279
301
|
} else {
|
280
|
-
|
302
|
+
stderrCompleted = of(true);
|
281
303
|
}
|
282
|
-
}));
|
283
304
|
|
284
|
-
|
285
|
-
|
305
|
+
proc.on("error", (e: Error) => {
|
306
|
+
noClose = true;
|
307
|
+
subj.error(e);
|
308
|
+
});
|
309
|
+
|
310
|
+
proc.on("close", (code: number) => {
|
311
|
+
noClose = true;
|
312
|
+
const pipesClosed = merge(stdoutCompleted!, stderrCompleted!).pipe(
|
313
|
+
reduce((acc) => acc, true),
|
314
|
+
);
|
286
315
|
|
287
|
-
|
316
|
+
if (code === 0) {
|
317
|
+
pipesClosed.subscribe(() => subj.complete());
|
318
|
+
} else {
|
319
|
+
pipesClosed.subscribe(() => {
|
320
|
+
const e: any = new Error(`Failed with exit code: ${code}`);
|
321
|
+
e.exitCode = code;
|
322
|
+
|
323
|
+
subj.error(e);
|
324
|
+
});
|
325
|
+
}
|
326
|
+
});
|
327
|
+
|
328
|
+
ret.add(
|
329
|
+
new Subscription(() => {
|
330
|
+
if (noClose) {
|
331
|
+
return;
|
332
|
+
}
|
333
|
+
|
334
|
+
d(`Killing process: ${cmd} ${args.join()}`);
|
335
|
+
if (opts.jobber) {
|
336
|
+
// NB: Connecting to Jobber's named pipe will kill it
|
337
|
+
net.connect(`\\\\.\\pipe\\jobber-${proc.pid}`);
|
338
|
+
setTimeout(() => proc.kill(), 5 * 1000);
|
339
|
+
} else {
|
340
|
+
proc.kill();
|
341
|
+
}
|
342
|
+
}),
|
343
|
+
);
|
344
|
+
|
345
|
+
return ret;
|
346
|
+
},
|
347
|
+
);
|
348
|
+
|
349
|
+
return opts.split ? spawnObs : spawnObs.pipe(map((x: any) => x?.text));
|
288
350
|
}
|
289
351
|
|
290
352
|
function wrapObservableInPromise<T>(obs: Observable<T>) {
|
291
353
|
return new Promise<string>((res, rej) => {
|
292
|
-
let out =
|
354
|
+
let out = "";
|
293
355
|
|
294
356
|
obs.subscribe(
|
295
|
-
(x) => out += x,
|
357
|
+
(x) => (out += x),
|
296
358
|
(e) => rej(new Error(`${out}\n${e.message}`)),
|
297
|
-
() => res(out)
|
359
|
+
() => res(out),
|
360
|
+
);
|
298
361
|
});
|
299
362
|
}
|
300
363
|
|
@@ -312,7 +375,11 @@ function wrapObservableInPromise<T>(obs: Observable<T>) {
|
|
312
375
|
* non-zero value, the Promise will resolve with
|
313
376
|
* an Error.
|
314
377
|
*/
|
315
|
-
export function spawnDetachedPromise(
|
378
|
+
export function spawnDetachedPromise(
|
379
|
+
exe: string,
|
380
|
+
params: Array<string>,
|
381
|
+
opts: any = null,
|
382
|
+
): Promise<string> {
|
316
383
|
return wrapObservableInPromise<string>(spawnDetached(exe, params, opts));
|
317
384
|
}
|
318
385
|
|
@@ -329,6 +396,10 @@ export function spawnDetachedPromise(exe: string, params: Array<string>, opts: a
|
|
329
396
|
* non-zero value, the Promise will resolve with
|
330
397
|
* an Error.
|
331
398
|
*/
|
332
|
-
export function spawnPromise(
|
399
|
+
export function spawnPromise(
|
400
|
+
exe: string,
|
401
|
+
params: Array<string>,
|
402
|
+
opts: any = null,
|
403
|
+
): Promise<string> {
|
333
404
|
return wrapObservableInPromise<string>(spawn(exe, params, opts));
|
334
405
|
}
|
package/test/asserttest.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
import
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
2
|
+
import { expect } from "chai";
|
3
|
+
import "./support";
|
3
4
|
|
4
5
|
function delay(ms: number) {
|
5
6
|
return new Promise((resolve) => {
|
@@ -7,8 +8,8 @@ function delay(ms: number) {
|
|
7
8
|
});
|
8
9
|
}
|
9
10
|
|
10
|
-
describe(
|
11
|
-
it(
|
11
|
+
describe("The test runner", function () {
|
12
|
+
it("should pass this test", async function () {
|
12
13
|
await delay(1000);
|
13
14
|
expect(true).to.be.ok;
|
14
15
|
});
|
package/test/spawn.ts
CHANGED
@@ -1,102 +1,139 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2
|
+
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
3
|
+
import { expect } from "chai";
|
4
|
+
import "./support";
|
3
5
|
|
4
|
-
import { spawn, spawnPromise, spawnDetachedPromise } from
|
6
|
+
import { spawn, spawnPromise, spawnDetachedPromise } from "../src/index";
|
5
7
|
|
6
|
-
import { Observable
|
8
|
+
import type { Observable } from "rxjs";
|
9
|
+
import { of } from "rxjs";
|
7
10
|
|
8
|
-
const uuidRegex =
|
11
|
+
const uuidRegex =
|
12
|
+
/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
|
9
13
|
|
10
|
-
describe(
|
11
|
-
it(
|
14
|
+
describe("The spawnPromise method", function () {
|
15
|
+
it("should return a uuid when we call uuid", async function () {
|
12
16
|
// NB: Since we get run via npm run test, we know that npm bins are in our
|
13
17
|
// PATH.
|
14
|
-
|
18
|
+
const result = await spawnPromise("uuid", []);
|
15
19
|
expect(result.match(uuidRegex)).to.be.ok;
|
16
20
|
});
|
17
21
|
});
|
18
22
|
|
19
|
-
describe(
|
20
|
-
it(
|
23
|
+
describe("The spawnDetachedPromise method", function () {
|
24
|
+
it("should return a uuid when we call uuid", async function () {
|
21
25
|
// NB: Since we get run via npm run test, we know that npm bins are in our
|
22
26
|
// PATH.
|
23
|
-
|
27
|
+
const result = await spawnDetachedPromise("uuid", ["--help"]);
|
24
28
|
expect(result.length > 10).to.be.ok;
|
25
29
|
});
|
26
30
|
});
|
27
31
|
|
28
|
-
function wrapSplitObservableInPromise(
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
function wrapSplitObservableInPromise(
|
33
|
+
obs: Observable<{
|
34
|
+
source: any;
|
35
|
+
text: any;
|
36
|
+
}>,
|
37
|
+
): Promise<{
|
38
|
+
stderr: string;
|
39
|
+
stdout: string;
|
40
|
+
error: Error | undefined;
|
35
41
|
}> {
|
36
42
|
return new Promise((res) => {
|
37
|
-
|
43
|
+
const out = { stderr: "", stdout: "", error: undefined };
|
38
44
|
|
39
45
|
obs.subscribe(
|
40
46
|
(x) => {
|
41
|
-
if (x.source ===
|
47
|
+
if (x.source === "stdout") {
|
42
48
|
out.stdout += x.text;
|
43
49
|
} else {
|
44
50
|
out.stderr += x.text;
|
45
51
|
}
|
46
52
|
},
|
47
|
-
(e) => {
|
48
|
-
|
53
|
+
(e) => {
|
54
|
+
out.error = e;
|
55
|
+
res(out);
|
56
|
+
},
|
57
|
+
() => res(out),
|
58
|
+
);
|
49
59
|
});
|
50
60
|
}
|
51
61
|
|
52
|
-
describe(
|
53
|
-
it(
|
62
|
+
describe("The spawn method", function () {
|
63
|
+
it("should return a disposable subscription", async function () {
|
54
64
|
// this only check the unsubscribe goes w/o error, not that the spawned process is killed
|
55
65
|
// (difficult to do that, maybe iterate through child processes and check ?)
|
56
|
-
spawn(
|
66
|
+
spawn("sleep", ["2"]).subscribe().unsubscribe();
|
57
67
|
});
|
58
68
|
|
59
|
-
it(
|
69
|
+
it("should return split stderr in a inner tag when called with split", async function () {
|
60
70
|
// provide an invalid param to uuid so it complains on stderr
|
61
|
-
|
62
|
-
|
71
|
+
const rxSpawn: Observable<{ source: any; text: any }> = spawn(
|
72
|
+
"uuid",
|
73
|
+
["foo"],
|
74
|
+
{ split: true },
|
75
|
+
) as any;
|
76
|
+
const result = await wrapSplitObservableInPromise(rxSpawn);
|
63
77
|
expect(result.stderr.length > 10).to.be.ok;
|
64
78
|
expect(result.stdout).to.be.empty;
|
65
|
-
expect(result.error).to.be.an(
|
79
|
+
expect(result.error).to.be.an("error");
|
66
80
|
});
|
67
81
|
|
68
|
-
it(
|
69
|
-
|
70
|
-
|
82
|
+
it("should return split stdout in a inner tag when called with split", async function () {
|
83
|
+
const rxSpawn: Observable<{ source: any; text: any }> = spawn("uuid", [], {
|
84
|
+
split: true,
|
85
|
+
});
|
86
|
+
const result = await wrapSplitObservableInPromise(rxSpawn);
|
71
87
|
expect(result.stdout.match(uuidRegex)).to.be.ok;
|
72
88
|
expect(result.stderr).to.be.empty;
|
73
89
|
expect(result.error).to.be.undefined;
|
74
90
|
});
|
75
91
|
|
76
|
-
it(
|
77
|
-
|
78
|
-
|
92
|
+
it("should ignore stderr if options.stdio = ignore", async function () {
|
93
|
+
const rxSpawn: Observable<{ source: any; text: any }> = spawn(
|
94
|
+
"uuid",
|
95
|
+
["foo"],
|
96
|
+
{ split: true, stdio: [null, null, "ignore"] },
|
97
|
+
);
|
98
|
+
const result = await wrapSplitObservableInPromise(rxSpawn);
|
79
99
|
expect(result.stderr).to.be.empty;
|
80
100
|
});
|
81
101
|
|
82
|
-
it(
|
83
|
-
|
84
|
-
|
102
|
+
it("should ignore stdout if options.stdio = inherit", async function () {
|
103
|
+
const rxSpawn: Observable<{ source: any; text: any }> = spawn("uuid", [], {
|
104
|
+
split: true,
|
105
|
+
stdio: [null, "inherit", null],
|
106
|
+
});
|
107
|
+
const result = await wrapSplitObservableInPromise(rxSpawn);
|
85
108
|
expect(result.stdout).to.be.empty;
|
86
109
|
});
|
87
110
|
|
88
|
-
it(
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
111
|
+
it("should croak if stdin is provided but stdio.stdin is disabled", async function () {
|
112
|
+
const stdin = of("a");
|
113
|
+
const rxSpawn: Observable<{ source: any; text: any }> = spawn(
|
114
|
+
"marked",
|
115
|
+
[],
|
116
|
+
{
|
117
|
+
split: true,
|
118
|
+
stdin: stdin,
|
119
|
+
stdio: ["ignore", null, null],
|
120
|
+
},
|
121
|
+
);
|
122
|
+
const result = await wrapSplitObservableInPromise(rxSpawn);
|
123
|
+
expect(result.error).to.be.an("error");
|
93
124
|
});
|
94
125
|
|
95
|
-
it(
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
126
|
+
it("should subscribe to provided stdin", async function () {
|
127
|
+
const stdin = of("a");
|
128
|
+
const rxSpawn: Observable<{ source: any; text: any }> = spawn(
|
129
|
+
"marked",
|
130
|
+
[],
|
131
|
+
{
|
132
|
+
split: true,
|
133
|
+
stdin: stdin,
|
134
|
+
},
|
135
|
+
);
|
136
|
+
const result = await wrapSplitObservableInPromise(rxSpawn);
|
137
|
+
expect(result.stdout.trim()).to.be.equal("<p>a</p>");
|
100
138
|
});
|
101
|
-
|
102
139
|
});
|