Skip to content

Releases: google/zx

8.3.0 – Pipes of Steel

24 Dec 08:56
759dcf6
Compare
Choose a tag to compare

A few weeks ago zx took a part in OSS Library Night 🎉
Many thanks to the organizers and contributors who have boosted the project with their pull requests!

Today we are releasing the zx with a huge bunch of new features and improvements.

Features

API

  • Implemented [Symbol.asyncIterator] API for ProcessPromise #984 #998 #1000
    Now you can iterate over the process output using for await loop from any point of the process execution.
const process = $`sleep 0.1; echo Chunk1; sleep 0.1; echo Chunk2; sleep 0.2; echo Chunk3; sleep 0.1; echo Chunk4;`
const chunks = []

await new Promise((resolve) => setTimeout(resolve, 250))
for await (const chunk of process) {
  chunks.push(chunk)
}

chunks.length //  4
chunks[0]     // 'Chunk1'
chunks[3]     // 'Chunk4'
  • zx version is available via JS API #986
import { version } from 'zx'
const [major] = (version || '').split('.').map(Number)
if (major < 6)
  throw new Error('zx >= 6 is required')

Pipes

  • Enabled stream picking for pipe() #1023
const p = $`echo foo >&2; echo bar`
const o1 = (await p.pipe.stderr`cat`).toString()
const o2 = (await p.pipe.stdout`cat`).toString()

assert.equal(o1, 'foo\n')  // <- piped from stderr
assert.equal(o2, 'bar\n')  // <- stdout
  • Added signal handling on piping #992
const ac = new AbortController()
const { signal } = ac
const p = $({ signal, nothrow: true })`echo test`.pipe`sleep 999`
setTimeout(() => ac.abort(), 50)

try {
  await p
} catch ({ message }) {
  message // The operation was aborted
}
  • Added direct piping to file shortcut #1001
// before
await $`echo "Hello, stdout!"`.pipe(fs.createWriteStream('/tmp/output.txt'))

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

CLI

  • Provided $.defaults setting via ZX_-prefixed environment variables #988 #998
ZX_VERBOSE=true ZX_SHELL='/bin/bash' zx script.mjs
  • Introduced --env option to load dotenvs 1022 #1030
zx --env=/path/to/some.env script
  • Landed installation registry customization #994
zx --install --registry=https://registry.yarnpkg.com script.mjs
  • Added --prefer-local option #1015

Fixes

  • Fixed temp assets clutter on process.exit() #993 #997
  • Handle tslib-generated string templates #966
  • Disabled spinner on CI and in quiet mode #1008 #1009 #1017
  • Added missing ZX_SHELL env handling #1024

Docs

  • Contribution guide updated #983
  • Documentation is now built from the main branch #985
  • Finally synced with the current API #1025 #1026

Chores

  • Added autotest generation for 3rd party libs export #987 #990 #1007 #1021
  • Added some jsr.io pre-publish tests #989 #991
  • Optimized package.json on publishing #1005 #1006
  • Attached .node_version to improve contributors devx #1012
  • Built-in chalk updated to v5.4.1 #1019

Merry Christmas! 🎄🎅🎁

8.2.4 – Leaky Faucet

28 Nov 20:35
0705aa1
Compare
Choose a tag to compare
  • Fixed bun async_hooks compatibility #959

8.2.3 – Golden Wrench

28 Nov 12:20
b15179f
Compare
Choose a tag to compare

This release continues the work on pipe API enhancements:

  • Autorun halted processes on the entire pipe run #951 #950
const { stdout } = await $({ halt: true })`echo "hello"`
 .pipe`awk '{print $1" world"}'`
 .pipe`tr '[a-z]' '[A-Z]'`
 .run()

stdout // 'HELLO WORLD'
  • Let $ be piped directly from streams #953
const getUpperCaseTransform = () =>
  new Transform({
    transform(chunk, encoding, callback) {
      callback(null, String(chunk).toUpperCase())
    },
  })

// $ > stream (promisified) > $ 
const o1 = await $`echo "hello"`
  .pipe(getUpperCaseTransform())
  .pipe($`cat`)

o1.stdout //  'HELLO\n'

// stream > $
const file = tempfile()
await fs.writeFile(file, 'test')
const o2 = await fs
  .createReadStream(file)
  .pipe(getUpperCaseTransform())
  .pipe($`cat`)

o2.stdout //  'TEST'
  • Mixin ProcessOutput data to promisified pipe values #954 #949
const file = tempfile()
const fileStream = fs.createWriteStream(file)
const p = $`echo "hello"`
  .pipe(getUpperCaseTransform())
  .pipe(fileStream)
const o = await p

p instanceof WriteStream             // true
o instanceof WriteStream             // true
o.stdout                             // 'hello\n'
o.exitCode;                          // 0
(await fs.readFile(file)).toString() // 'HELLO\n'

We've also slightly tweaked up dist contents for better compatibility with bundlers #957

8.2.2

12 Nov 16:52
3b6c120
Compare
Choose a tag to compare

What's Changed

Full Changelog: 8.2.1...8.2.2

8.2.1

08 Nov 13:41
880c4f4
Compare
Choose a tag to compare
  • #936 fixes endless streams piping
  • #930 enables custom extensions support

8.2.0

31 Oct 20:01
6eb540f
Compare
Choose a tag to compare

Pipes supercharge today! 🚀

Features

  • Delayed piping. You can fill dependent streams at any time during the origin process lifecycle (even when finished) without losing data. #914
const result = $`echo 1; sleep 1; echo 2; sleep 1; echo 3`
const piped1 = result.pipe`cat`
let piped2

setTimeout(() => {
  piped2 = result.pipe`cat`
}, 1500)

await piped1
assert.equal((await piped1).toString(), '1\n2\n3\n')
assert.equal((await piped2).toString(), '1\n2\n3\n')
const file = tempfile()
const fileStream = fs.createWriteStream(file)
const p = $`echo "hello"`
  .pipe(
    new Transform({
      transform(chunk, encoding, callback) {
        callback(null, String(chunk).toUpperCase())
      },
    })
  )
  .pipe(fileStream)

p instanceof WriteStream             // true
await p === fileStream               // true
(await fs.readFile(file)).toString() // 'HELLO\n'

Chore

8.1.9

06 Oct 19:34
c3061ab
Compare
Choose a tag to compare

Today's release is a minor update that includes:

Enhancements

  • We have replaced ProcessOutput fields with lazy getters to reduce mem consumption #903, #908
  • Reduced ReDos risks for codeblock patterns #906
  • Kept argv reference on update #916
  • Strengthened Shell interface to properly handle sync mode #915:
expectType<ProcessPromise>($`cmd`)
expectType<ProcessPromise>($({ sync: false })`cmd`)
expectType<ProcessOutput>($({ sync: true })`cmd`)
expectType<ProcessOutput>($.sync`cmd`)

Fixes

  • Corrected stdall fill for $.sync calls: #911, #912

8.1.8

19 Sep 15:18
9354a39
Compare
Choose a tag to compare
  • Apply the proper TeplateStringArray detection #904, #905
  • PromiseProcess got lazy getters to optimize mem usage #903

8.1.7

17 Sep 12:36
5038ec5
Compare
Choose a tag to compare

Step by step on the road to improvements

Fixes

Finally, we've fixed the issue with piped process rejection #640 #899:

const p1 = $`exit 1`.pipe($`echo hello`)
try {
  await p1
} catch (e) {
  assert.equal(e.exitCode, 1)
}

const p2 = await $({ nothrow: true })`echo hello && exit 1`.pipe($`cat`)
assert.equal(p2.exitCode, 0)
assert.equal(p2.stdout.trim(), 'hello')

Enhancements

Added cmd display to ProcessPromise #891:

const foo = 'bar'
const p = $`echo ${foo}`

p.cmd // 'echo bar'

and duration field to ProcessOutput #892:

const p = $`sleep 1`.nothrow()
const o = await p

o.duration // ~1000 (in ms)

Enabled zurk-like pipe string literals #900:

const p = await $`echo foo`.pipe`cat`
p.stdout.trim() // 'foo'

8.1.6

11 Sep 13:00
ac2567f
Compare
Choose a tag to compare

Improvements & Fixes

  • The $.preferLocal option now also accepts a directory #886, #887.
$.preferLocal = true             // injects node_modules/.bin to the $PATH
$.preferLocal = '/foo/bar'       // attaches /foo/bar to the $PATH
$.preferLocal = ['/bar', '/baz'] // now the $PATH includes both /bar and /baz

Why not just $.env['PATH'] = 'extra:' + '$.env['PATH']?
Well, the API internally does the same, but also handles the win paths peculiarities.

  • Provided $.killSignal option for the symmetry with the $.timeoutSignal. You can override the default termination flow #885:
$.killSignal = 'SIGKILL'

const p = $({nothrow: true})`sleep 10000`
setTimeout(p.kill, 100)
  
(await p).signal // SIGKILL
  • $ opt presets became chainable #883:
const $$ = $({ nothrow: true })
assert.equal((await $$`exit 1`).exitCode, 1)

const $$$ = $$({ sync: true }) // Both {nothrow: true, sync: true} are applied
assert.equal($$$`exit 2`.exitCode, 2)
  • Enhanced the internal Duration parser #884:
const p = $({timeout: '1mss'})`sleep 999` // raises an error now
  • Abortion signal listeners are now removed after the process completes #881, #889, zurk#12, zurk#13.
  • Extended integration tests matrix, added nodejs-nightly builds and TS dev snapshots #888