Transforms map or filter the input or output of a subprocess. They are defined by passing a generator function or a transform options object to the stdin
, stdout
, stderr
or stdio
option. It can be async
.
import {execa} from 'execa';
const transform = function * (line) {
const prefix = line.includes('error') ? 'ERROR' : 'INFO';
yield `${prefix}: ${line}`;
};
const {stdout} = await execa({stdout: transform})`npm run build`;
console.log(stdout); // HELLO
yield
can be called 0, 1 or multiple times. Not calling yield
enables filtering a specific line.
import {execa} from 'execa';
const transform = function * (line) {
if (!line.includes('secret')) {
yield line;
}
};
const {stdout} = await execa({stdout: transform})`echo ${'This is a secret'}`;
console.log(stdout); // ''
By default, stdout
and stderr
's transforms must return a string or an Uint8Array
.
However, if the objectMode
transform option is true
, any type can be returned instead, except null
or undefined
. The subprocess' result.stdout
/result.stderr
will be an array of values.
const transform = function * (line) {
yield JSON.parse(line);
};
const {stdout} = await execa({stdout: {transform, objectMode: true}})`node jsonlines-output.js`;
for (const data of stdout) {
console.log(stdout); // {...}
}
stdin
can also use objectMode: true
.
const transform = function * (line) {
yield JSON.stringify(line);
};
const input = [{event: 'example'}, {event: 'otherExample'}];
await execa({stdin: [input, {transform, objectMode: true}]})`node jsonlines-input.js`;
State can be shared between calls of the transform
and final
functions.
let count = 0
// Prefix line number
const transform = function * (line) {
yield `[${count++}] ${line}`;
};
To create additional lines after the last one, a final
generator function can be used.
let count = 0;
const transform = function * (line) {
count += 1;
yield line;
};
const final = function * () {
yield `Number of lines: ${count}`;
};
const {stdout} = await execa({stdout: {transform, final}})`npm run build`;
console.log(stdout); // Ends with: 'Number of lines: 54'
A Duplex
stream, Node.js Transform
stream or web TransformStream
can be used instead of a generator function.
Like generator functions, web TransformStream
can be passed either directly or as a {transform}
plain object. But Duplex
and Transform
must always be passed as a {transform}
plain object.
The objectMode
transform option can be used, but not the binary
nor preserveNewlines
options.
import {createGzip} from 'node:zlib';
import {execa} from 'execa';
const {stdout} = await execa({stdout: {transform: createGzip()}})`npm run build`;
console.log(stdout); // `stdout` is compressed with gzip
const {stdout} = await execa({stdout: new CompressionStream('gzip')})`npm run build`;
console.log(stdout); // `stdout` is compressed with gzip
The stdin
, stdout
, stderr
and stdio
options can accept an array of values. While this is not specific to transforms, this can be useful with them too. For example, the following transform impacts the value printed by inherit
.
await execa({stdout: [transform, 'inherit']})`npm run build`;
This also allows using multiple transforms.
await execa({stdout: [transform, otherTransform]})`npm run build`;
Or saving to files.
await execa({stdout: [new CompressionStream('gzip'), {file: './output.gz'}]})`npm run build`;
A transform or an array of transforms can be passed to the stdin
, stdout
, stderr
or stdio
option.
A transform is either a generator function or a plain object with the following members.
Type: GeneratorFunction<string | Uint8Array | unknown>
| AsyncGeneratorFunction<string | Uint8Array | unknown>
Map or filter the input or output of the subprocess.
Type: GeneratorFunction<string | Uint8Array | unknown>
| AsyncGeneratorFunction<string | Uint8Array | unknown>
Create additional lines after the last one.
Type: boolean
Default: false
If true
, iterate over arbitrary chunks of Uint8Array
s instead of line string
s.
Type: boolean
Default: false
If true
, keep newlines in each line
argument. Also, this allows multiple yield
s to produces a single line.
Type: boolean
Default: false
If true
, allow transformOptions.transform
and transformOptions.final
to return any type, not just string
or Uint8Array
.