Repository: sindresorhus/execa
Pull request #193 (2019-03-15 14:08:04)

Replace `null` by `undefined`
Follow up of https://github.com/sindresorhus/execa/issues/191#issuecomment-473248327

Replace all `null` by `undefined`.

`null` are still allowed as input for the options `stdin`, `stdout`, `stderr`, `input` and `encoding` to be compatible with the core Node.js API. But they are not produced in output for `stdin`, `stdout`, `stderr` and `signal`.


Patch:
diff --git a/index.js b/index.js
index 297a24d..d7c6058 100644
--- a/index.js
+++ b/index.js
@@ -94,7 +94,7 @@ function handleShell(fn, command, options) {
 
 function makeAllStream(spawned) {
 	if (!spawned.stdout && !spawned.stderr) {
-		return null;
+		return;
 	}
 
 	const mixed = mergeStream();
@@ -112,7 +112,7 @@ function makeAllStream(spawned) {
 
 function getStream(process, stream, {encoding, buffer, maxBuffer}) {
 	if (!process[stream]) {
-		return null;
+		return;
 	}
 
 	let ret;
@@ -161,7 +161,9 @@ function makeError(result, options) {
 	error.stdout = stdout;
 	error.stderr = stderr;
 	error.failed = true;
-	error.signal = signal || null;
+	// `signal` emitted on `spawned.on('exit')` event can be `null`. We normalize
+	// it to `undefined`
+	error.signal = signal || undefined;
 	error.cmd = joinedCommand;
 	error.timedOut = Boolean(timedOut);
 
@@ -237,13 +239,13 @@ module.exports = (command, args, options) => {
 		});
 	}
 
-	let timeoutId = null;
+	let timeoutId;
 	let timedOut = false;
 
 	const cleanup = () => {
-		if (timeoutId) {
+		if (timeoutId !== undefined) {
 			clearTimeout(timeoutId);
-			timeoutId = null;
+			timeoutId = undefined;
 		}
 
 		if (removeExitHandler) {
@@ -253,7 +255,7 @@ module.exports = (command, args, options) => {
 
 	if (parsed.options.timeout > 0) {
 		timeoutId = setTimeout(() => {
-			timeoutId = null;
+			timeoutId = undefined;
 			timedOut = true;
 			spawned.kill(parsed.options.killSignal);
 		}, parsed.options.timeout);
@@ -332,7 +334,6 @@ module.exports = (command, args, options) => {
 			exitCodeName: 'SUCCESS',
 			failed: false,
 			killed: false,
-			signal: null,
 			cmd: joinedCommand,
 			timedOut: false
 		};
@@ -401,7 +402,6 @@ module.exports.sync = (command, args, options) => {
 		exitCode: 0,
 		exitCodeName: 'SUCCESS',
 		failed: false,
-		signal: null,
 		cmd: joinedCommand,
 		timedOut: false
 	};
diff --git a/lib/errname.js b/lib/errname.js
index 8f9e1fb..151c53f 100644
--- a/lib/errname.js
+++ b/lib/errname.js
@@ -16,7 +16,7 @@ if (typeof util.getSystemErrorName === 'function') {
 		}
 	} catch (error) {
 		console.error('execa/lib/errname: unable to establish process.binding(\'uv\')', error);
-		uv = null;
+		uv = undefined;
 	}
 
 	module.exports = code => errname(uv, code);
@@ -26,7 +26,7 @@ if (typeof util.getSystemErrorName === 'function') {
 module.exports.__test__ = errname;
 
 function errname(uv, code) {
-	if (uv) {
+	if (uv !== undefined) {
 		return uv.errname(code);
 	}
 
diff --git a/lib/stdio.js b/lib/stdio.js
index a82d468..5b4cb9e 100644
--- a/lib/stdio.js
+++ b/lib/stdio.js
@@ -5,7 +5,7 @@ const hasAlias = opts => alias.some(x => Boolean(opts[x]));
 
 module.exports = opts => {
 	if (!opts) {
-		return null;
+		return;
 	}
 
 	if (opts.stdio && hasAlias(opts)) {
@@ -26,7 +26,7 @@ module.exports = opts => {
 	const len = Math.max(stdio.length, alias.length);
 
 	for (let i = 0; i < len; i++) {
-		let value = null;
+		let value;
 
 		if (stdio[i] !== undefined) {
 			value = stdio[i];
diff --git a/readme.md b/readme.md
index c6d9d83..26cbdbc 100644
--- a/readme.md
+++ b/readme.md
@@ -68,7 +68,6 @@ const execa = require('execa');
 			stderr: '',
 			all: '',
 			failed: true,
-			signal: null,
 			cmd: 'exit 3',
 			timedOut: false,
 			killed: false
@@ -91,7 +90,6 @@ try {
 		stdout: '',
 		stderr: '',
 		failed: true,
-		signal: null,
 		cmd: 'exit 3',
 		timedOut: false
 	}


Test patch:
diff --git a/test.js b/test.js
index 9c043a4..1265c65 100644
--- a/test.js
+++ b/test.js
@@ -210,7 +210,7 @@ test('opts.stdout:ignore - stdout will not collect data', async t => {
 		input: 'hello',
 		stdio: [null, 'ignore', null]
 	});
-	t.is(stdout, null);
+	t.is(stdout, undefined);
 });
 
 test('helpful error trying to provide an input stream in sync mode', t => {
@@ -367,13 +367,13 @@ if (process.platform !== 'win32') {
 	});
 }
 
-test('result.signal is null for successful execution', async t => {
-	t.is((await execa('noop')).signal, null);
+test('result.signal is undefined for successful execution', async t => {
+	t.is((await execa('noop')).signal, undefined);
 });
 
-test('result.signal is null if process failed, but was not killed', async t => {
+test('result.signal is undefined if process failed, but was not killed', async t => {
 	const error = await t.throwsAsync(execa('exit', [2]), {message: getExitRegExp('2')});
-	t.is(error.signal, null);
+	t.is(error.signal, undefined);
 });
 
 async function code(t, num) {
diff --git a/test/errname.js b/test/errname.js
index d47720d..001c148 100644
--- a/test/errname.js
+++ b/test/errname.js
@@ -4,7 +4,7 @@ import errname from '../lib/errname';
 const isWindows = process.platform === 'win32';
 
 // Simulates failure to capture `process.binding('uv');`
-const fallback = code => errname.__test__(null, code);
+const fallback = code => errname.__test__(undefined, code);
 
 function makeTests(name, m, expected) {
 	test(`${name}: >=0 exit codes`, t => {
diff --git a/test/stdio.js b/test/stdio.js
index 23e6570..e51fc7d 100644
--- a/test/stdio.js
+++ b/test/stdio.js
@@ -21,27 +21,27 @@ function macro(t, input, expected) {
 
 macro.title = (providedTitle, input) => providedTitle || util.inspect(input, {colors: true});
 
-test(macro, undefined, null);
-test(macro, null, null);
+test(macro, undefined, undefined);
+test(macro, null, undefined);
 
 test(macro, {stdio: 'inherit'}, 'inherit');
 test(macro, {stdio: 'pipe'}, 'pipe');
 test(macro, {stdio: 'ignore'}, 'ignore');
 test(macro, {stdio: [0, 1, 2]}, [0, 1, 2]);
 
-test(macro, {}, [null, null, null]);
-test(macro, {stdio: []}, [null, null, null]);
-test(macro, {stdin: 'pipe'}, ['pipe', null, null]);
-test(macro, {stdout: 'ignore'}, [null, 'ignore', null]);
-test(macro, {stderr: 'inherit'}, [null, null, 'inherit']);
+test(macro, {}, [undefined, undefined, undefined]);
+test(macro, {stdio: []}, [undefined, undefined, undefined]);
+test(macro, {stdin: 'pipe'}, ['pipe', undefined, undefined]);
+test(macro, {stdout: 'ignore'}, [undefined, 'ignore', undefined]);
+test(macro, {stderr: 'inherit'}, [undefined, undefined, 'inherit']);
 test(macro, {stdin: 'pipe', stdout: 'ignore', stderr: 'inherit'}, ['pipe', 'ignore', 'inherit']);
-test(macro, {stdin: 'pipe', stdout: 'ignore'}, ['pipe', 'ignore', null]);
-test(macro, {stdin: 'pipe', stderr: 'inherit'}, ['pipe', null, 'inherit']);
-test(macro, {stdout: 'ignore', stderr: 'inherit'}, [null, 'ignore', 'inherit']);
+test(macro, {stdin: 'pipe', stdout: 'ignore'}, ['pipe', 'ignore', undefined]);
+test(macro, {stdin: 'pipe', stderr: 'inherit'}, ['pipe', undefined, 'inherit']);
+test(macro, {stdout: 'ignore', stderr: 'inherit'}, [undefined, 'ignore', 'inherit']);
 test(macro, {stdin: 0, stdout: 1, stderr: 2}, [0, 1, 2]);
-test(macro, {stdin: 0, stdout: 1}, [0, 1, null]);
-test(macro, {stdin: 0, stderr: 2}, [0, null, 2]);
-test(macro, {stdout: 1, stderr: 2}, [null, 1, 2]);
+test(macro, {stdin: 0, stdout: 1}, [0, 1, undefined]);
+test(macro, {stdin: 0, stderr: 2}, [0, undefined, 2]);
+test(macro, {stdout: 1, stderr: 2}, [undefined, 1, 2]);
 
 test(macro, {stdio: {foo: 'bar'}}, new TypeError('Expected `stdio` to be of type `string` or `Array`, got `object`'));