Releases: google/zx
8.4.0 – Drip Detective
Try the new batch of enhancements: npm i [email protected] https://www.npmjs.com/package/zx/v/8.4.0
Changes
const cwd = tmpdir()
const external = tmpdir()
await fs.outputJson(path.join(external, 'node_modules/a/package.json'), {
name: 'a',
version: '1.0.0',
type: 'module',
exports: './index.js',
})
await fs.outputFile(
path.join(external, 'node_modules/a/index.js'),
`
export const a = 'AAA'
`
)
const script = `
import {a} from 'a'
console.log(a);
`
const out = await $`zx --cwd=${cwd} --prefer-local=${external} --test <<< ${script}`
assert.equal(out.stdout, 'AAA\n')const p = $({prefix: '', postfix: ''})`echo ${[1, '', '*', '2']}`
// before
p.cmd // `echo 1 $'*' 2`)
// after
p.cmd // `echo 1 $'' $'*' 2`) zx script.zx # Unknown file extension "\.zx"
zx --ext=mjs script.zx # OKconst err = new Error('BrokenSpawn')
const o = await $({
nothrow: true,
spawn() {
throw err
},
})`echo foo`
o.ok // false
o.exitCode // null
o.message // BrokenSpawn...
o.cause // err8.3.2 – Clogged Drain
8.3.1 – Perfect Seal
The release essence: introduced full-featured .env support #461 → #1060 #1052 #1043 #1037 #1032 #1030 #1022
API
envapi is a tiny 100 LOC dotenv-inspired parser and serializer that we've integrated into zx.
import { dotenv, fs } from 'zx'
// parse
const env = dotenv.parse('A=A\nFOO=BAR') // { A: 'A', FOO: 'BAR' }
// serialize
const raw = dotenv.stringify(env) // A=A\nFOO=BAR
await fs.writeFile('.env', raw)
// load
dotenv.load('.env') // { A: 'A', FOO: 'BAR' }
// update the process.env
dotenv.config('.env')
process.env.A // ACLI
zx --env .env script.mjs
zx --env-file .env script.mjsQnA
— Why not use dotenv directly?
— 1) Size does matter 2) We'd like to avoid internal vaults.
— Why not load .env by default?
— 1) Explicit is better than implicit 2) Runtime itself (like bun) may provide the feature.
Chore
- Provided
stdallpiping #1033 - Exposed ProcessPromise
fullCmdand uniqueid#1035 - Simplified internal regexps #1040 #1038
- Removed zx globals from unit tests scope #1039
- Added check if tempfile exists #1041
- Added ts support in markdown #1042
- Enabled CodeQL and OSV scanners #1011
- Configured pre-push git hooks #1044
- Explicitly declared permissions for test.yml #1045
- Mentioned
haltandrunAPI in docs #1046 - Fixed
timeoutoption handling for corner cases #1049 - Allowed
killSignalsetting via env vars #1054 - Added
diagnostic_channelto built-ins list #1056 - Enhanced logger: added
idfield and introducedendevent #1057 #1058 - Made
nothrown()toggleable #1066 #1029 - Handle
ZX_REPL_HISTORYenvvar #1065 - Fixed
file://protocol check #1064 - Accept
modeoption fortmpdirandtmpfile#1063 - Enhanced deno support #1062 #1061
- Optimized markdown parser #1068
- Applied zizmor suggestions #1067
- Minor code improvements #1070 #1069
- Optimized output buffers joining #1072
- Fixed predefined
_timeoutSignaloverride #1075 - Exposed
ProcessPromisestage #1077 #967 - Aligned script processing flows (CLI) #1078
- Enhanced $ options tests #1079
8.3.0 – Pipes of Steel
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 forProcessPromise#984 #998 #1000
Now you can iterate over the process output usingfor awaitloop 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
signalhandling 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
ZX_VERBOSE=true ZX_SHELL='/bin/bash' zx script.mjszx --env=/path/to/some.env script- Landed installation registry customization #994
zx --install --registry=https://registry.yarnpkg.com script.mjs- Added
--prefer-localoption #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_SHELLenv handling #1024
Docs
- Contribution guide updated #983
- Documentation is now built from the
mainbranch #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_versionto improve contributors devx #1012 - Built-in
chalkupdated to v5.4.1 #1019
Merry Christmas! 🎄🎅🎁
8.2.4 – Leaky Faucet
- Fixed bun async_hooks compatibility #959
8.2.3 – Golden Wrench
This release continues the work on pipe API enhancements:
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'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
What's Changed
- test: stdio inherit by @antongolub in #941
- fix: handle nullable stdout/stderr by @antongolub in #943
Full Changelog: 8.2.1...8.2.2
8.2.1
8.2.0
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
Today's release is a minor update that includes:
Enhancements
- We have replaced
ProcessOutputfields with lazy getters to reduce mem consumption #903, #908 - Reduced ReDos risks for codeblock patterns #906
- Kept
argvreference on update #916 - Strengthened
Shellinterface to properly handlesyncmode #915:
expectType<ProcessPromise>($`cmd`)
expectType<ProcessPromise>($({ sync: false })`cmd`)
expectType<ProcessOutput>($({ sync: true })`cmd`)
expectType<ProcessOutput>($.sync`cmd`)