Commit bfaf2ff

Anton Golub <antongolub@antongolub.com>
2024-05-13 22:44:33
Docs v8.1.0 (#808)
1 parent 330426c
.vitepress/config.mts
@@ -37,10 +37,13 @@ export default defineConfig({
           text: 'Docs',
           items: [
             {text: 'Getting Started', link: '/getting-started'},
-            {text: 'Process Promise', link: '/process-promise'},
+            {text: 'Setup', link: '/setup'},
             {text: 'API Reference', link: '/api'},
-            {text: 'Configuration', link: '/configuration'},
             {text: 'CLI Usage', link: '/cli'},
+            {text: 'Configuration', link: '/configuration'},
+            {text: 'Process Promise', link: '/process-promise'},
+            {text: 'Contribution Guide', link: '/contribution'},
+            {text: 'Migration from v7', link: '/migration-from-v7'},
           ],
         },
         {
api.md
@@ -1,5 +1,86 @@
 # API Reference
 
+## $.sync 
+Zx provides both synchronous and asynchronous command executions, returns [`ProcessOutput`](./process-output) or [`ProcessPromise`](./process-promise) respectively.
+
+```js
+const list = await $`ls -la`
+const dir = $.sync`pwd`
+```
+
+## $({...})
+
+`$` object holds the default zx [configuration](./configuration), which is used for all execution. To specify a custom preset use `$` as factory:
+
+```js
+const $$ = $({
+  verbose: false,
+  env: {NODE_ENV: 'production'},
+})
+
+const env = await $$`node -e 'console.log(process.env.NODE_ENV)'`
+const pwd = $$.sync`pwd`
+const hello = $({quiet: true})`echo "Hello!"`
+```
+
+### $({input})
+
+The input option passes the specified `stdin` to the command.
+
+```js
+const p1 = $({ input: 'foo' })`cat`
+const p2 = $({ input: Readable.from('bar') })`cat`
+const p3 = $({ input: Buffer.from('baz') })`cat`
+const p4 = $({ input: p3 })`cat`
+const p5 = $({ input: await p3 })`cat`
+```
+
+### $({signal})
+
+The signal option makes the process abortable.
+
+```js
+const {signal} = new AbortController()
+const p = $({ signal })`sleep 9999`
+
+setTimeout(() => signal.abort('reason'), 1000)
+```
+
+### $({timeout})
+
+The timeout option makes the process autokillable after the specified delay.
+
+```js
+const p = $({timeout: '1s'})`sleep 999`
+```
+
+The full options list:
+```ts
+interface Options {
+  cwd:            string
+  ac:             AbortController
+  signal:         AbortSignal
+  input:          string | Buffer | Readable | ProcessOutput | ProcessPromise
+  timeout:        Duration
+  timeoutSignal:  string
+  stdio:          StdioOptions
+  verbose:        boolean
+  sync:           boolean
+  env:            NodeJS.ProcessEnv
+  shell:          string | boolean
+  nothrow:        boolean
+  prefix:         string
+  postfix:        string
+  quote:          typeof quote
+  quiet:          boolean
+  detached:       boolean
+  spawn:          typeof spawn
+  spawnSync:      typeof spawnSync
+  log:            typeof log
+  kill:           typeof kill
+}
+```
+
 ## cd()
 
 Changes the current working directory.
@@ -133,10 +214,55 @@ The [which](https://github.com/npm/node-which) package.
 const node = await which('node')
 ```
 
-## argv
+## ps()
+
+The [@webpod/ps](https://github.com/webpod/ps) package to provide a cross-platform way to list processes.
+
+```js
+const all = await ps.lookup()
+const nodejs = await ps.lookup({ command: 'node' })
+const children = await ps.tree({ pid: 123 })
+const fulltree = await ps.tree({ pid: 123, recursive: true })
+```
+
+## kill()
+
+A process killer.
+
+```js
+await kill(123)
+await kill(123, 'SIGKILL')
+```
+
+## tmpdir()
+
+Creates a temporary directory.
+
+```js
+t1 = tmpdir()       // /os/based/tmp/zx-1ra1iofojgg/
+t2 = tmpdir('foo')  // /os/based/tmp/zx-1ra1iofojgg/foo/
+```
+
+## tmpfile()
+
+Temp file factory.
+
+```js
+f1 = tmpfile()         // /os/based/tmp/zx-1ra1iofojgg
+f2 = tmpfile('f.txt')  // /os/based/tmp/zx-1ra1iofojgg/foo.txt
+f3 = tmpfile('f.txt', 'string or buffer')
+```
+
+## minimist
 
 The [minimist](https://www.npmjs.com/package/minimist) package.
 
+```js
+const argv = minimist(process.argv.slice(2), {})
+```
+
+## argv
+
 A minimist-parsed version of the `process.argv` as `argv`.
 
 ```js
cli.md
@@ -67,6 +67,46 @@ the import.
 import sh from 'tinysh' // @^1
 ```
 
+## --quiet
+
+Suppress any outputs.
+
+## --verbose
+
+Enable verbose mode.
+
+## --shell
+
+Specify a custom shell binary.
+
+```bash
+zx --shell=/bin/bash script.mjs
+```
+
+## --prefix & --postfix
+
+Attach a command to the beginning or the end of every command.
+
+```bash
+zx --prefix='echo foo;' --postfix='; echo bar' script.mjs
+```
+
+## --cwd
+
+Set the current working directory.
+
+```bash
+zx --cwd=/foo/bar script.mjs
+```
+
+## --version
+
+Print the current version of `zx`.
+
+## --help
+
+Print help.
+
 ## __filename & __dirname
 
 In [ESM](https://nodejs.org/api/esm.html) modules, Node.js does not provide
configuration.md
@@ -14,6 +14,8 @@ Or use a CLI argument: `--shell=/bin/bash`
 
 Specifies a `spawn` api. Defaults to `require('child_process').spawn`.
 
+To override a sync API implementation, set `$.spawnSync` correspondingly.
+
 ## $.prefix
 
 Specifies the command that will be prefixed to all commands run.
@@ -22,6 +24,14 @@ Default is `set -euo pipefail;`.
 
 Or use a CLI argument: `--prefix='set -e;'`
 
+## $.postfix
+
+Like a `$.prefix`, but for the end of the command.
+
+```js
+$.postfix = '; exit $LastExitCode' // for PowerShell compatibility
+```
+
 ## $.quote
 
 Specifies a function for escaping special characters during
@@ -29,12 +39,18 @@ command substitution.
 
 ## $.verbose
 
-Specifies verbosity. Default is `true`.
+Specifies verbosity. Default is `false`.
 
 In verbose mode, `zx` prints all executed commands alongside with their
 outputs.
 
-Or use the CLI argument `--quiet` to set `$.verbose = false`.
+Or use the CLI argument: `--verbose` to set `true`.
+
+## $.quiet
+
+Suppresses all output. Default is `false`.
+
+Via CLI argument: `--quiet` sets `$.quiet = true`.
 
 ## $.env
 
contribution.md
@@ -0,0 +1,52 @@
+# Contribution Guide
+
+zx is a fully [open-source project](https://github.com/google/zx), which is developing by the community for the community. 
+We welcome contributions of any kind, including but not limited to:
+* Bug reports
+* Feature requests
+* Code contributions
+* Documentation improvements
+* Discussions
+
+## Community Guidelines
+
+This project follows [Google's Open Source Community Guidelines](https://opensource.google/conduct/).
+In short: all contributors are treated with respect and fairness.
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution;
+this simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to <https://cla.developers.google.com/> to see
+your current agreements on file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## How to Contribute
+Before proposing changes, look for similar ones in the project's [issues](https://github.com/google/zx/issues) and [pull requests](https://github.com/google/zx/pulls). If you can't decide, create a new [discussion](https://github.com/google/zx/discussions) topic, and we will help you figure it out. When ready to move on:
+* Prepare your development environment.
+  * Ensure you have Node.js 20+ installed.
+  * Bash is essential for running zx scripts. Linux and macOS users usually have it installed by default. Consider using [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install) or [Git Bash](https://git-scm.com/downloads) if you are on Windows.
+* Fork [the repository](https://github.com/google/zx).
+* Create a new branch.
+* Make your changes.
+  * If you are adding a new feature, please include additional tests. The coverage threshold is 98%.
+  * Create a [conventional-commits](https://www.conventionalcommits.org/en/v1.0.0/) compliant messages.
+* Ensure that everything is working:
+  * `npm run fmt` to format your code.
+  * `npm run cov` to run the tests.
+* Push the changes to your fork.
+* Create a pull request.
+  * Describe your changes in detail.
+  * Reference any related issues if applicable.
+
+## Code Reviews
+
+All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests.
+
+## License
+
+The project is licensed under the [Apache-2.0](https://github.com/google/zx?tab=Apache-2.0-1-ov-file#readme)
getting-started.md
@@ -35,6 +35,10 @@ gives sensible defaults.
 npm install zx
 ```
 
+```bash [bun]
+bun install zx
+```
+
 ```bash [deno]
 deno install -A npm:zx
 ```
@@ -82,7 +86,12 @@ import 'zx/globals'
 ### ``$`command` ``
 
 Executes a given command using the `spawn` func
-and returns [`ProcessPromise`](process-promise.md).
+and returns [`ProcessPromise`](process-promise.md). It supports both sync and async modes.
+
+```js
+const list = await $`ls -la`
+const dir = $.sync`pwd`
+```
 
 Everything passed through `${...}` will be automatically escaped and quoted.
 
migration-from-v7.md
@@ -0,0 +1,44 @@
+# Migration from v7 to v8
+
+[v8.0.0 release](https://github.com/google/zx/releases/tag/8.0.0) brought many features, improvements and fixes, but also has introduced a few breaking changes.
+
+1. `$.verbose` is set to `false` by default, but errors are still printed to `stderr`. Set `$.quiet = true` to suppress any output.
+```js
+$.verbose = true // everything works like in v7
+
+$.quiet = true   // to completely turn off logging
+```
+
+2. `ssh` API was dropped. Install [webpod](https://github.com/webpod/webpod) package instead.
+```js
+// import {ssh} from 'zx' ↓
+import {ssh} from 'webpod'
+
+const remote = ssh('user@host')
+await remote`echo foo`
+```
+
+3. zx is not looking for `PowerShell` anymore, on Windows by default. If you still need it, use the `usePowerShell` helper to enable:
+
+```js
+import { usePowerShell, useBash } from 'zx'
+
+usePowerShell() // to enable powershell
+useBash()       // switch to bash, the default
+```
+
+To look for modern [PowerShell v7+](https://github.com/google/zx/pull/790), invoke `usePwsh()` helper instead:
+
+```js
+import { usePwsh } from 'zx'
+
+usePwsh()
+```
+
+4. Process cwd synchronization between `$` invocations is now disabled by default. This functionality is provided via an async hook and can now be controlled directly.
+
+```js
+import { syncProcessCwd } from 'zx'
+
+syncProcessCwd() // restores legacy v7 behavior
+```
process-output.md
@@ -0,0 +1,25 @@
+# Process Output
+
+Represents a cmd execution result.
+
+```ts
+interface ProcessOutput {
+  // Exit code of the process: 0 for success, non-zero for failure
+  exitCode: number
+  
+  // Signal that caused the process to exit: SIGTERM, SIGKILL, etc.
+  signal: NodeJS.Signals | null
+  
+  // Holds the stdout of the process
+  stdout: string
+  
+  // Process errors are written to stderr
+  stderr: string
+  
+  // combined stdout and stderr
+  toString(): string
+
+  // Same as toString() but trimmed
+  valueOf(): string
+}
+```
process-promise.md
@@ -1,11 +1,11 @@
 # Process Promise
 
-The `$` returns a `ProcessPromise` instance.
+The `$` returns a `ProcessPromise` instance. When resolved, it becomes a [`ProcessOutput`](./process-output.md).
 
 ```js
-const p = $`command`
+const p = $`command` // ProcessPromise
 
-await p
+const o = await p    // ProcessOutput
 ```
 
 ## `stdin`
setup.md
@@ -0,0 +1,87 @@
+# Setup
+
+## Requirements
+* Linux, macOS, or Windows
+* JavaScript Runtime:
+  * Node.js 12.17.0 or later
+  * Bun 1.0.0 or later
+  * Deno 1.x
+* Some kind of bash or PowerShell
+
+## Install
+
+::: code-group
+
+```bash [node]
+npm install zx
+```
+
+```bash [bun]
+bun install zx
+```
+
+```bash [deno]
+deno install -A npm:zx
+
+# zx requires additional permissions: --allow-read --allow-sys --allow-env --allow-run
+```
+
+```bash [brew]
+brew install zx
+```
+
+:::
+
+Dev snapshot versions are published to npm under the [`dev` tag](https://www.npmjs.com/package/zx?activeTab=versions): `npm i zx@dev`.
+
+## Bash
+
+zx mostly relies on bash, so make sure it's available in your environment. If you're on Windows, consider using [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install) or [Git Bash](https://git-scm.com/downloads).
+By default, zx looks for bash binary, but you can switch to PowerShell by invoking `usePowerShell()` or `usePwsh()`.
+
+```js
+import { useBash, usePowerShell, usePwsh } from 'zx'
+
+usePowerShell() // Use PowerShell.exe
+usePwsh()       // Rely on pwsh binary (PowerShell v7+)
+useBash()       // Switch back to bash
+```
+
+## Package
+
+### Hybrid
+zx is distributed as a [hybrid package](https://2ality.com/2019/10/hybrid-npm-packages.html): it provides both CJS an ESM entry points.
+
+```js
+import { $ } from 'zx'
+
+const { $ } = require('zx')
+```
+
+It has also built-in TypeScript libdefs.
+
+```ts
+import { type Options } from 'zx'
+
+const opts: Options = {
+  quiet: true,
+  timeout: '5s'
+}
+```
+
+### Bundled
+
+We use [esbuild](https://dev.to/antongolub/how-and-why-do-we-bundle-zx-1ca6) to produce a static build that allows us to solve several issues at once:
+* Reduce the pkg size and install time.
+* Make npx (yarn dlx / bunx) invocations reproducible.
+* Provide support for wide range of Node.js versions: from 12 to 22.
+* Make auditing easier: complete code in one place.
+
+### Composite
+
+zx exports several entry points adapted for different use cases:
+* `zx` – the main entry point, provides all the features.
+* `zx/global` – to populate the global scope with zx functions.
+* `zx/cli` – to run zx scripts from the command line.
+* `zx/core` – to use zx template spawner as part of 3rd party libraries with alternating set of utilities.
+
typescript.md
@@ -1,28 +1,59 @@
 # TypeScript
 
-Configure your project to use [ES modules](https://nodejs.org/api/packages.html#packages_type):
+zx is written in TypeScript and provides the corresponding libdefs out of box. Typings are TS 4+ compatible.
+
+```ts
+// script.ts
+import { $ } from 'zx'
+
+const list = await $`ls -la`
+```
+
+Some runtimes like [Bun](https://bun.sh/) or [Deno](https://deno.com/) have built-in TS support. Node.js requires additional setup. Configure your project according to the [ES modules contract](https://nodejs.org/api/packages.html#packages_type):
 
 - Set [`"type": "module"`](https://nodejs.org/api/packages.html#packages_type)
 in **package.json**
 - Set [`"module": "ESNext"`](https://www.typescriptlang.org/tsconfig/#module)
 in **tsconfig.json**.
 
-It is possible to make use of `$` and other functions via explicit imports:
+Using TypeScript compiler is the most straightforward way.
 
-```ts
-import { $ } from 'zx'
+::: code-group
+
+```bash [tsc]
+npm install typescript
+
+tsc script.ts
+
+node script.js
 ```
 
-Or import globals explicitly:
+```bash [ts-node]
+npm install ts-node
 
-```ts
-import 'zx/globals'
+ts-node script.ts
+# or via node loader
+node --loader ts-node/esm script.ts
 ```
 
-Wrap your code in an async function and call it immediately:
+```bash [swc-node]
+npm install swc-node
 
-```ts
-void async function () {
-  await $`ls -la`
-}()
+swc-node script.ts
+```
+
+```bash [tsx]
+npm install tsx
+
+tsx script.ts
 ```
+
+```bash [bun]
+bun script.ts
+```
+
+```bash [deno]
+deno run --allow-read --allow-sys --allow-env --allow-run script.ts
+```
+
+:::