Skip to content

Commit

Permalink
feat: direct piping to file shortcut (#1001)
Browse files Browse the repository at this point in the history
* feat: pipe to file shortcut

* docs: update doc to reflect the new pipe signature

---------

Co-authored-by: Anton Golub <[email protected]>
  • Loading branch information
1e9y and antongolub authored Dec 17, 2024
1 parent 2a3b19d commit 7566081
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 17 deletions.
7 changes: 7 additions & 0 deletions docs/process-promise.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ await $`echo "Hello, stdout!"`
await $`cat /tmp/output.txt`
```

You can pass a string to `pipe()` to implicitly create a receiving file. The previous example is equivalent to:

```js
await $`echo "Hello, stdout!"`
.pipe('/tmp/output.txt')
```

Pipes can be used to show a real-time output of the process:

```js
Expand Down
8 changes: 4 additions & 4 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ export class ProcessPromise extends Promise<ProcessOutput> {
pipe<D extends Writable>(dest: D): D & PromiseLike<ProcessOutput & D>
pipe<D extends ProcessPromise>(dest: D): D
pipe(
dest: Writable | ProcessPromise | TemplateStringsArray,
dest: Writable | ProcessPromise | TemplateStringsArray | string,
...args: any[]
): (Writable & PromiseLike<ProcessPromise & Writable>) | ProcessPromise {
if (isStringLiteral(dest, ...args))
Expand All @@ -347,9 +347,6 @@ export class ProcessPromise extends Promise<ProcessOutput> {
})(dest as TemplateStringsArray, ...args)
)

if (isString(dest))
throw new Error('The pipe() method does not take strings. Forgot $?')

this._piped = true
const ee = this._ee
const from = new VoidStream()
Expand All @@ -371,6 +368,8 @@ export class ProcessPromise extends Promise<ProcessOutput> {
})
}

if (isString(dest)) dest = fs.createWriteStream(dest)

if (dest instanceof ProcessPromise) {
dest._pipedFrom = this

Expand All @@ -382,6 +381,7 @@ export class ProcessPromise extends Promise<ProcessOutput> {
}
return dest
}

from.once('end', () => dest.emit('end-piped-from')).pipe(dest)
return promisifyStream(dest, this) as Writable &
PromiseLike<ProcessPromise & Writable>
Expand Down
27 changes: 14 additions & 13 deletions test/core.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,20 @@ describe('core', () => {
}
})

test('accepts file', async () => {
const file = tempfile()
try {
await $`echo foo`.pipe(file)
assert.equal((await fs.readFile(file)).toString(), 'foo\n')

const r = $`cat`
fs.createReadStream(file).pipe(r.stdin)
assert.equal((await r).stdout, 'foo\n')
} finally {
await fs.rm(file)
}
})

test('accepts ProcessPromise', async () => {
const p = await $`echo foo`.pipe($`cat`)
assert.equal(p.stdout.trim(), 'foo')
Expand All @@ -437,19 +451,6 @@ describe('core', () => {
assert.equal((await p1).stdout.trim(), 'pipe-to-stdout')
})

test('checks argument type', async () => {
let err
try {
$`echo 'test'`.pipe('str')
} catch (p) {
err = p
}
assert.equal(
err.message,
'The pipe() method does not take strings. Forgot $?'
)
})

describe('supports chaining', () => {
const getUpperCaseTransform = () =>
new Transform({
Expand Down

0 comments on commit 7566081

Please sign in to comment.