Skip to content

Commit 999db3d

Browse files
authored
feat: enable stream picking on pipe() (#1023)
* feat: provide stdall piping for `ProcessPromise` * refactor: bind pipe helpers to proto instead of instance itself * chore: linting
1 parent 6aac978 commit 999db3d

File tree

3 files changed

+46
-17
lines changed

3 files changed

+46
-17
lines changed

.size-limit.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
{
33
"name": "zx/core",
44
"path": ["build/core.cjs", "build/util.cjs", "build/vendor-core.cjs"],
5-
"limit": "75 kB",
5+
"limit": "76 kB",
66
"brotli": false,
77
"gzip": false
88
},
@@ -30,7 +30,7 @@
3030
{
3131
"name": "all",
3232
"path": "build/*",
33-
"limit": "840 kB",
33+
"limit": "841 kB",
3434
"brotli": false,
3535
"gzip": false
3636
}

src/core.ts

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,13 @@ export const $: Shell & Options = new Proxy<Shell & Options>(
200200

201201
type Resolve = (out: ProcessOutput) => void
202202

203+
type PipeDest = Writable | ProcessPromise | TemplateStringsArray | string
204+
type PipeMethod = {
205+
(dest: TemplateStringsArray, ...args: any[]): ProcessPromise
206+
<D extends Writable>(dest: D): D & PromiseLike<ProcessOutput & D>
207+
<D extends ProcessPromise>(dest: D): D
208+
}
209+
203210
export class ProcessPromise extends Promise<ProcessOutput> {
204211
private _command = ''
205212
private _from = ''
@@ -336,15 +343,26 @@ export class ProcessPromise extends Promise<ProcessOutput> {
336343
}
337344

338345
// Essentials
339-
pipe(dest: TemplateStringsArray, ...args: any[]): ProcessPromise
340-
pipe<D extends Writable>(dest: D): D & PromiseLike<ProcessOutput & D>
341-
pipe<D extends ProcessPromise>(dest: D): D
342-
pipe(
343-
dest: Writable | ProcessPromise | TemplateStringsArray | string,
346+
pipe!: PipeMethod & {
347+
stdout: PipeMethod
348+
stderr: PipeMethod
349+
}
350+
// prettier-ignore
351+
static {
352+
Object.defineProperty(this.prototype, 'pipe', { get() {
353+
const self = this
354+
const pipeStdout: PipeMethod = function (dest: PipeDest, ...args: any[]) { return self._pipe.call(self, 'stdout', dest, ...args) }
355+
const pipeStderr: PipeMethod = function (dest: PipeDest, ...args: any[]) { return self._pipe.call(self, 'stderr', dest, ...args) }
356+
return Object.assign(pipeStdout, { stderr: pipeStderr, stdout: pipeStdout })
357+
}})
358+
}
359+
private _pipe(
360+
source: 'stdout' | 'stderr',
361+
dest: PipeDest,
344362
...args: any[]
345363
): (Writable & PromiseLike<ProcessPromise & Writable>) | ProcessPromise {
346364
if (isStringLiteral(dest, ...args))
347-
return this.pipe(
365+
return this.pipe[source](
348366
$({
349367
halt: true,
350368
ac: this._snapshot.ac,
@@ -356,19 +374,18 @@ export class ProcessPromise extends Promise<ProcessOutput> {
356374
const ee = this._ee
357375
const from = new VoidStream()
358376
const fill = () => {
359-
for (const chunk of this._zurk!.store.stdout) from.write(chunk)
377+
for (const chunk of this._zurk!.store[source]) from.write(chunk)
378+
return true
360379
}
380+
const fillEnd = () => this._resolved && fill() && from.end()
361381

362-
if (this._resolved) {
363-
fill()
364-
from.end()
365-
} else {
366-
const onStdout = (chunk: string | Buffer) => from.write(chunk)
367-
ee.once('stdout', () => {
382+
if (!this._resolved) {
383+
const onData = (chunk: string | Buffer) => from.write(chunk)
384+
ee.once(source, () => {
368385
fill()
369-
ee.on('stdout', onStdout)
386+
ee.on(source, onData)
370387
}).once('end', () => {
371-
ee.removeListener('stdout', onStdout)
388+
ee.removeListener(source, onData)
372389
from.end()
373390
})
374391
}
@@ -384,10 +401,12 @@ export class ProcessPromise extends Promise<ProcessOutput> {
384401
this.catch((e) => (dest.isNothrow() ? noop : dest._reject(e)))
385402
from.pipe(dest.run()._stdin)
386403
}
404+
fillEnd()
387405
return dest
388406
}
389407

390408
from.once('end', () => dest.emit('end-piped-from')).pipe(dest)
409+
fillEnd()
391410
return promisifyStream(dest, this) as Writable &
392411
PromiseLike<ProcessPromise & Writable>
393412
}

test/core.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
usePwsh,
3535
useBash,
3636
} from '../build/core.js'
37+
import { which } from '../build/vendor.js'
3738

3839
describe('core', () => {
3940
describe('resolveDefaults()', () => {
@@ -614,6 +615,15 @@ describe('core', () => {
614615
assert.equal(r2.reason.stdout, 'foo\n')
615616
assert.equal(r2.reason.exitCode, 1)
616617
})
618+
619+
test('pipes particular stream: stdout ot stderr', async () => {
620+
const p = $`echo foo >&2; echo bar`
621+
const o1 = (await p.pipe.stderr`cat`).toString()
622+
const o2 = (await p.pipe.stdout`cat`).toString()
623+
624+
assert.equal(o1, 'foo\n')
625+
assert.equal(o2, 'bar\n')
626+
})
617627
})
618628

619629
describe('abort()', () => {

0 commit comments

Comments
 (0)