Skip to content

Latest commit

 

History

History
176 lines (121 loc) · 6.36 KB

lines.md

File metadata and controls

176 lines (121 loc) · 6.36 KB
execa logo

Output lines

Simple splitting

If the lines option is true, the output is split into lines, as an array of strings.

import {execa} from 'execa';

const lines = await execa({lines: true})`npm run build`;
console.log(lines.join('\n'));

Iteration

Progressive splitting

The subprocess' return value is an async iterable. It iterates over the output's lines while the subprocess is still running.

for await (const line of execa`npm run build`) {
	if (line.includes('ERROR')) {
		console.log(line);
	}
}

Alternatively, subprocess.iterable() can be called to pass options or use iterator helpers.

The iteration waits for the subprocess to end. It throws if the subprocess fails. This means you do not need to await the subprocess' promise.

for await (const line of execa`npm run build`.iterable())) { /* ... */ }

Transforms

Transforms map or filter the input or output of a subprocess, one line at a time. Unlike subprocess.iterable(), they:

More info.

Iterator helpers

With Node 22 (and later), iterator methods can be used.

const iterable = execa`npm run build`.iterable();

for await (const line of iterable.filter(line => line.includes('ERROR')))) { /* ... */ }
const iterable = execa`npm run build`.iterable();

for await (const line of iterable.map(line => line.replaceAll('secret', '***')))) { /* ... */ }
const iterable = execa`npm run build`.iterable();

// Only first 3 lines
for await (const line of iterable.take(3)) { /* ... */ }

The subprocess' promise does not need to be awaited, except with Iterator.find(), Iterator.some() or Iterator.every(), since those specific methods return as soon as a matching line is found.

const printErrorLine = async iterable => {
	const errorLine = await iterable.find(line => line.includes('ERROR'));
	console.log(errorLine);
};

const subprocess = execa`npm run build`;
await Promise.all([subprocess, printErrorLine(subprocess.iterable())]);

Stdout/stderr

By default, the subprocess' stdout is used. The from iterable option can select a different file descriptor, such as stderr, all or fd3.

for await (const stderrLine of execa`npm run build`.iterable({from: 'stderr'})) { /* ... */ }

Newlines

Final newline

The final newline is stripped from the output's last line, unless the stripFinalNewline is false.

const {stdout} = await execa({stripFinalNewline: false})`npm run build`;
console.log(stdout.endsWith('\n')); // true

Array of lines

When using the lines option, newlines are stripped from each line, unless the stripFinalNewline is false.

// Each line now ends with '\n'.
// The last `line` might or might not end with '\n', depending on the output.
const lines = await execa({lines: true, stripFinalNewline: false})`npm run build`;
console.log(lines.join(''));

Iterable

When iterating over lines, newlines are stripped from each line, unless the preserveNewlines iterable option is true.

This option can also be used with streams produced by subprocess.readable() and subprocess.duplex() and the binary: false option.

// `line` now ends with '\n'.
// The last `line` might or might not end with '\n', depending on the output.
for await (const line of execa`npm run build`.iterable({preserveNewlines: true})) { /* ... */ }

Transforms

When using transforms, newlines are stripped from each line argument, unless the preserveNewlines transform option is true.

// `line` now ends with '\n'.
// The last `line` might or might not end with '\n', depending on the output.
const transform = function * (line) { /* ... */ };

await execa({stdout: {transform, preserveNewlines: true}})`npm run build`;

Each yield produces at least one line. Calling yield multiple times or calling yield * produces multiples lines.

const transform = function * (line) {
	yield 'Important note:';
	yield 'Read the comments below.';

	// Or:
	yield * [
		'Important note:',
		'Read the comments below.',
	];

	// Is the same as:
	yield 'Important note:\nRead the comments below.\n';

	yield line
};

await execa({stdout: transform})`npm run build`;

However, if the preserveNewlines transform option is true, multiple yields produce a single line instead.

const transform = function * (line) {
	yield 'Important note: ';
	yield 'Read the comments below.\n';

	// Is the same as:
	yield 'Important note: Read the comments below.\n';

	yield line
};

await execa({stdout: {transform, preserveNewlines: true}})`npm run build`;