diff --git a/.vitepress/config.mts b/.vitepress/config.mts
index ceea130b85..48c198bb85 100644
--- a/.vitepress/config.mts
+++ b/.vitepress/config.mts
@@ -35,8 +35,19 @@ export default defineConfig({
items: [
{text: 'Getting Started', link: '/getting-started'},
{text: 'Process Promise', link: '/process-promise'},
+ {text: 'API Reference', link: '/api'},
+ {text: 'Configuration', link: '/configuration'},
+ {text: 'CLI Usage', link: '/cli'},
+ ],
+ },
+ {
+ text: 'FAQ',
+ link: '/faq',
+ items: [
{text: 'Quotes', link: '/quotes'},
+ {text: 'TypeScript', link: '/typescript'},
{text: 'Markdown Scripts', link: '/markdown-scripts'},
+ {text: 'Known Issues', link: '/known-issues'},
],
},
],
@@ -45,6 +56,10 @@ export default defineConfig({
{icon: 'github', link: 'https://github.com/google/zx'},
],
+ editLink: {
+ pattern: 'https://github.com/google/zx/blob/gh-pages/:path',
+ },
+
footer: {
message: 'Disclaimer: This is not an officially supported Google product.',
},
diff --git a/api.md b/api.md
new file mode 100644
index 0000000000..76e7c0b07d
--- /dev/null
+++ b/api.md
@@ -0,0 +1,200 @@
+# API Reference
+
+## cd()
+
+Changes the current working directory.
+
+```js
+cd('/tmp')
+await $`pwd` // => /tmp
+```
+
+Like `echo`, in addition to `string` arguments, `cd` accepts and trims
+trailing newlines from `ProcessOutput` enabling common idioms like:
+
+```js
+cd(await $`mktemp -d`)
+```
+
+## fetch()
+
+A wrapper around the [node-fetch](https://www.npmjs.com/package/node-fetch)
+package.
+
+```js
+let resp = await fetch('https://medv.io')
+```
+
+## question()
+
+A wrapper around the [readline](https://nodejs.org/api/readline.html) package.
+
+```js
+let bear = await question('What kind of bear is best? ')
+```
+
+## sleep()
+
+A wrapper around the `setTimeout` function.
+
+```js
+await sleep(1000)
+```
+
+## echo()
+
+A `console.log()` alternative which can take [ProcessOutput](#processoutput).
+
+```js
+let branch = await $`git branch --show-current`
+
+echo`Current branch is ${branch}.`
+// or
+echo('Current branch is', branch)
+```
+
+## stdin()
+
+Returns the stdin as a string.
+
+```js
+let content = JSON.parse(await stdin())
+```
+
+## within()
+
+Creates a new async context.
+
+```js
+await $`pwd` // => /home/path
+
+within(async () => {
+ cd('/tmp')
+
+ setTimeout(async () => {
+ await $`pwd` // => /tmp
+ }, 1000)
+})
+
+await $`pwd` // => /home/path
+```
+
+```js
+await $`node --version` // => v20.2.0
+
+let version = await within(async () => {
+ $.prefix += 'export NVM_DIR=$HOME/.nvm; source $NVM_DIR/nvm.sh; nvm use 16;'
+
+ return $`node --version`
+})
+
+echo(version) // => v16.20.0
+```
+
+## retry()
+
+Retries a callback for a few times. Will return after the first
+successful attempt, or will throw after specifies attempts count.
+
+```js
+let p = await retry(10, () => $`curl https://medv.io`)
+
+// With a specified delay between attempts.
+let p = await retry(20, '1s', () => $`curl https://medv.io`)
+
+// With an exponential backoff.
+let p = await retry(30, expBackoff(), () => $`curl https://medv.io`)
+```
+
+## spinner()
+
+Starts a simple CLI spinner.
+
+```js
+await spinner(() => $`long-running command`)
+
+// With a message.
+await spinner('working...', () => $`sleep 99`)
+```
+
+## glob()
+
+The [globby](https://github.com/sindresorhus/globby) package.
+
+```js
+let packages = await glob(['package.json', 'packages/*/package.json'])
+```
+
+## which()
+
+The [which](https://github.com/npm/node-which) package.
+
+```js
+let node = await which('node')
+```
+
+## argv
+
+The [minimist](https://www.npmjs.com/package/minimist) package.
+
+A minimist-parsed version of the `process.argv` as `argv`.
+
+```js
+if (argv.someFlag) {
+ echo('yes')
+}
+```
+
+Use minimist options to customize the parsing:
+
+```js
+const myCustomArgv = minimist(process.argv.slice(2), {
+ boolean: [
+ 'force',
+ 'help',
+ ],
+ alias: {
+ h: 'help',
+ },
+})
+```
+
+## chalk
+
+The [chalk](https://www.npmjs.com/package/chalk) package.
+
+```js
+console.log(chalk.blue('Hello world!'))
+```
+
+## fs
+
+The [fs-extra](https://www.npmjs.com/package/fs-extra) package.
+
+```js
+let {version} = await fs.readJson('./package.json')
+```
+
+## os
+
+The [os](https://nodejs.org/api/os.html) package.
+
+```js
+await $`cd ${os.homedir()} && mkdir example`
+```
+
+## path
+
+The [path](https://nodejs.org/api/path.html) package.
+
+```js
+await $`mkdir ${path.join(basedir, 'output')}`
+```
+
+## yaml
+
+The [yaml](https://www.npmjs.com/package/yaml) package.
+
+```js
+console.log(YAML.parse('foo: bar').foo)
+```
diff --git a/cli.md b/cli.md
new file mode 100644
index 0000000000..78403dd874
--- /dev/null
+++ b/cli.md
@@ -0,0 +1,96 @@
+# CLI Usage
+
+Zx provides a CLI for running scripts. It is installed with the package and can be used as `zx` executable.
+
+```sh
+zx script.mjs
+```
+
+## Scripts without extensions
+
+If script does not have a file extension (like `.git/hooks/pre-commit`), zx
+assumes that it is
+an [ESM](https://nodejs.org/api/modules.html#modules_module_createrequire_filename)
+module.
+
+```bash
+zx docs/markdown.md
+```
+
+## Executing remote scripts
+
+If the argument to the `zx` executable starts with `https://`, the file will be
+downloaded and executed.
+
+```bash
+zx https://medv.io/game-of-life.js
+```
+
+## Executing scripts from stdin
+
+The `zx` supports executing scripts from stdin.
+
+```js
+zx << 'EOF'
+await $`pwd`
+EOF
+```
+
+## Executing scripts via --eval
+
+Evaluate the following argument as a script.
+
+```bash
+cat package.json | zx --eval 'let v = JSON.parse(await stdin()).version; echo(v)'
+```
+
+## Installing dependencies via --install
+
+```js
+// script.mjs:
+import sh from 'tinysh'
+
+sh.say('Hello, world!')
+```
+
+Add `--install` flag to the `zx` command to install missing dependencies
+automatically.
+
+```bash
+zx --install script.mjs
+```
+
+You can also specify needed version by adding comment with `@` after
+the import.
+
+```js
+import sh from 'tinysh' // @^1
+```
+
+## Executing commands on remote hosts
+
+The `zx` uses [webpod](https://github.com/webpod/webpod) to execute commands on
+remote hosts.
+
+```js
+import {ssh} from 'zx'
+
+await ssh('user@host')`echo Hello, world!`
+```
+
+## `__filename` and `__dirname`
+
+In [ESM](https://nodejs.org/api/esm.html) modules, Node.js does not provide
+`__filename` and `__dirname` globals. As such globals are really handy in scripts,
+zx provides these for use in `.mjs` files (when using the `zx` executable).
+
+## require()
+
+In [ESM](https://nodejs.org/api/modules.html#modules_module_createrequire_filename)
+modules, the `require()` function is not defined.
+The `zx` provides `require()` function, so it can be used with imports in `.mjs`
+files (when using `zx` executable).
+
+```js
+let {version} = require('./package.json')
+```
diff --git a/configuration.md b/configuration.md
new file mode 100644
index 0000000000..ad5b968543
--- /dev/null
+++ b/configuration.md
@@ -0,0 +1,69 @@
+# Configuration
+
+## $.shell
+
+Specifies what shell is used. Default is `which bash`.
+
+```js
+$.shell = '/usr/bin/bash'
+```
+
+Or use a CLI argument: `--shell=/bin/bash`
+
+## $.spawn
+
+Specifies a `spawn` api. Defaults to `require('child_process').spawn`.
+
+## $.prefix
+
+Specifies the command that will be prefixed to all commands run.
+
+Default is `set -euo pipefail;`.
+
+Or use a CLI argument: `--prefix='set -e;'`
+
+## $.quote
+
+Specifies a function for escaping special characters during
+command substitution.
+
+## $.verbose
+
+Specifies verbosity. Default is `true`.
+
+In verbose mode, `zx` prints all executed commands alongside with their
+outputs.
+
+Or use the CLI argument `--quiet` to set `$.verbose = false`.
+
+## $.env
+
+Specifies an environment variables map.
+
+Defaults to `process.env`.
+
+## $.cwd
+
+Specifies a current working directory of all processes created with the `$`.
+
+The [cd()](#cd) func changes only `process.cwd()` and if no `$.cwd` specified,
+all `$` processes use `process.cwd()` by default (same as `spawn` behavior).
+
+## $.log
+
+Specifies a [logging function](src/core.ts).
+
+```ts
+import {LogEntry, log} from 'zx/core'
+
+$.log = (entry: LogEntry) => {
+ switch (entry.kind) {
+ case 'cmd':
+ // for example, apply custom data masker for cmd printing
+ process.stderr.write(masker(entry.cmd))
+ break
+ default:
+ log(entry)
+ }
+}
+```
diff --git a/faq.md b/faq.md
new file mode 100644
index 0000000000..f582971811
--- /dev/null
+++ b/faq.md
@@ -0,0 +1,73 @@
+# FAQ
+
+## Passing env variables
+
+```js
+process.env.FOO = 'bar'
+await $`echo $FOO`
+```
+
+## Passing array of values
+
+When passing an array of values as an argument to `$`, items of the array will
+be escaped
+individually and concatenated via space.
+
+Example:
+
+```js
+let files = [...]
+await $`tar cz ${files}`
+```
+
+## Importing into other scripts
+
+It is possible to make use of `$` and other functions via explicit imports:
+
+```js
+#!/usr/bin/env node
+import {$} from 'zx'
+
+await $`date`
+```
+
+## Attaching a profile
+
+By default `child_process` does not include aliases and bash functions.
+But you are still able to do it by hand. Just attach necessary directives
+to the `$.prefix`.
+
+```js
+$.prefix += 'export NVM_DIR=$HOME/.nvm; source $NVM_DIR/nvm.sh; '
+await $`nvm -v`
+```
+
+## Using GitHub Actions
+
+The default GitHub Action runner comes with `npx` installed.
+
+```yaml
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Build
+ env:
+ FORCE_COLOR: 3
+ run: |
+ npx zx <<'EOF'
+ await $`...`
+ EOF
+```
+
+## Canary / Beta / RC builds
+
+Impatient early adopters can try the experimental zx versions.
+But keep in mind: these builds are ⚠️️__beta__ in every sense.
+
+```bash
+npm i zx@dev
+npx zx@dev --install --quiet <<< 'import _ from "lodash" /* 4.17.15 */; console.log(_.VERSION)'
+```
diff --git a/getting-started.md b/getting-started.md
index c4a1fd75e9..7049799320 100644
--- a/getting-started.md
+++ b/getting-started.md
@@ -1,16 +1,39 @@
# Getting Started
-## Install
+## Overview
-```bash
-npm i -g zx
+```js
+#!/usr/bin/env zx
+
+await $`cat package.json | grep name`
+
+let branch = await $`git branch --show-current`
+await $`dep deploy --branch=${branch}`
+
+await Promise.all([
+ $`sleep 1; echo 1`,
+ $`sleep 2; echo 2`,
+ $`sleep 3; echo 3`,
+])
+
+let name = 'foo bar'
+await $`mkdir /tmp/${name}`
```
-**Requirement**: Node version >= 16.0.0
+Bash is great, but when it comes to writing more complex scripts,
+many people prefer a more convenient programming language.
+JavaScript is a perfect choice, but the Node.js standard library
+requires additional hassle before using. The `zx` package provides
+useful wrappers around `child_process`, escapes arguments and
+gives sensible defaults.
+
+## Install
-## Documentation
+```bash
+npm install zx
+```
-
+## Usage
Write your scripts in a file with an `.mjs` extension in order to
use `await` at the top level. If you prefer the `.js` extension,
@@ -29,7 +52,7 @@ chmod +x ./script.mjs
./script.mjs
```
-Or via the `zx` executable:
+Or via the [CLI](cli.md):
```bash
zx ./script.mjs
@@ -47,7 +70,7 @@ import 'zx/globals'
### ``$`command` ``
Executes a given command using the `spawn` func
-and returns [`ProcessPromise`](#processpromise).
+and returns [`ProcessPromise`](process-promise.md).
Everything passed through `${...}` will be automatically escaped and quoted.
@@ -82,27 +105,6 @@ try {
}
```
-### `ProcessPromise`
-
-```ts
-class ProcessPromise extends Promise {
- stdin: Writable
- stdout: Readable
- stderr: Readable
- exitCode: Promise
-
- pipe(dest): ProcessPromise
-
- kill(): Promise
-
- nothrow(): this
-
- quiet(): this
-}
-```
-
-Read more about the [ProcessPromise](process-promise.md).
-
### `ProcessOutput`
```ts
@@ -126,460 +128,6 @@ let date = await $`date`
await $`echo Current date is ${date}.`
```
-## Functions
-
-### `cd()`
-
-Changes the current working directory.
-
-```js
-cd('/tmp')
-await $`pwd` // => /tmp
-```
-
-Like `echo`, in addition to `string` arguments, `cd` accepts and trims
-trailing newlines from `ProcessOutput` enabling common idioms like:
-
-```js
-cd(await $`mktemp -d`)
-```
-
-### `fetch()`
-
-A wrapper around the [node-fetch](https://www.npmjs.com/package/node-fetch)
-package.
-
-```js
-let resp = await fetch('https://medv.io')
-```
-
-### `question()`
-
-A wrapper around the [readline](https://nodejs.org/api/readline.html) package.
-
-```js
-let bear = await question('What kind of bear is best? ')
-```
-
-### `sleep()`
-
-A wrapper around the `setTimeout` function.
-
-```js
-await sleep(1000)
-```
-
-### `echo()`
-
-A `console.log()` alternative which can take [ProcessOutput](#processoutput).
-
-```js
-let branch = await $`git branch --show-current`
-
-echo`Current branch is ${branch}.`
-// or
-echo('Current branch is', branch)
-```
-
-### `stdin()`
-
-Returns the stdin as a string.
-
-```js
-let content = JSON.parse(await stdin())
-```
-
-### `within()`
-
-Creates a new async context.
-
-```js
-await $`pwd` // => /home/path
-
-within(async () => {
- cd('/tmp')
-
- setTimeout(async () => {
- await $`pwd` // => /tmp
- }, 1000)
-})
-
-await $`pwd` // => /home/path
-```
-
-```js
-await $`node --version` // => v20.2.0
-
-let version = await within(async () => {
- $.prefix += 'export NVM_DIR=$HOME/.nvm; source $NVM_DIR/nvm.sh; nvm use 16;'
-
- return $`node --version`
-})
-
-echo(version) // => v16.20.0
-```
-
-### `retry()`
-
-Retries a callback for a few times. Will return after the first
-successful attempt, or will throw after specifies attempts count.
-
-```js
-let p = await retry(10, () => $`curl https://medv.io`)
-
-// With a specified delay between attempts.
-let p = await retry(20, '1s', () => $`curl https://medv.io`)
-
-// With an exponential backoff.
-let p = await retry(30, expBackoff(), () => $`curl https://medv.io`)
-```
-
-### `spinner()`
-
-Starts a simple CLI spinner.
-
-```js
-await spinner(() => $`long-running command`)
-
-// With a message.
-await spinner('working...', () => $`sleep 99`)
-```
-
-## Packages
-
-The following packages are available without importing inside scripts.
-
-### `chalk` package
-
-The [chalk](https://www.npmjs.com/package/chalk) package.
-
-```js
-console.log(chalk.blue('Hello world!'))
-```
-
-### `fs` package
-
-The [fs-extra](https://www.npmjs.com/package/fs-extra) package.
-
-```js
-let {version} = await fs.readJson('./package.json')
-```
-
-### `os` package
-
-The [os](https://nodejs.org/api/os.html) package.
-
-```js
-await $`cd ${os.homedir()} && mkdir example`
-```
-
-### `path` package
-
-The [path](https://nodejs.org/api/path.html) package.
-
-```js
-await $`mkdir ${path.join(basedir, 'output')}`
-```
-
-### `globby` package
-
-The [globby](https://github.com/sindresorhus/globby) package.
-
-```js
-let packages = await glob(['package.json', 'packages/*/package.json'])
-```
-
-### `yaml` package
-
-The [yaml](https://www.npmjs.com/package/yaml) package.
-
-```js
-console.log(YAML.parse('foo: bar').foo)
-```
-
-### `minimist` package
-
-The [minimist](https://www.npmjs.com/package/minimist) package.
-
-```js
-let myCustomArgv = minimist(process.argv.slice(2), { boolean: ["force", "help"] })
-```
-
-A minimist-parsed version of the process args as `argv` (parsed without any config).
-
-```js
-if (argv.someFlag) {
- echo('yes')
-}
-```
-
-### `which` package
-
-The [which](https://github.com/npm/node-which) package.
-
-```js
-let node = await which('node')
-```
-
-## Configuration
-
-### `$.shell`
-
-Specifies what shell is used. Default is `which bash`.
-
-```js
-$.shell = '/usr/bin/bash'
-```
-
-Or use a CLI argument: `--shell=/bin/bash`
-
-### `$.spawn`
-
-Specifies a `spawn` api. Defaults to `require('child_process').spawn`.
-
-### `$.prefix`
-
-Specifies the command that will be prefixed to all commands run.
-
-Default is `set -euo pipefail;`.
-
-Or use a CLI argument: `--prefix='set -e;'`
-
-### `$.quote`
-
-Specifies a function for escaping special characters during
-command substitution.
-
-### `$.verbose`
-
-Specifies verbosity. Default is `true`.
-
-In verbose mode, `zx` prints all executed commands alongside with their
-outputs.
-
-Or use the CLI argument `--quiet` to set `$.verbose = false`.
-
-### `$.env`
-
-Specifies an environment variables map.
-
-Defaults to `process.env`.
-
-### `$.cwd`
-
-Specifies a current working directory of all processes created with the `$`.
-
-The [cd()](#cd) func changes only `process.cwd()` and if no `$.cwd` specified,
-all `$` processes use `process.cwd()` by default (same as `spawn` behavior).
-
-### `$.log`
-
-Specifies a [logging function](src/core.ts).
-
-```ts
-import { LogEntry, log } from 'zx/core'
-
-$.log = (entry: LogEntry) => {
- switch (entry.kind) {
- case 'cmd':
- // for example, apply custom data masker for cmd printing
- process.stderr.write(masker(entry.cmd))
- break
- default:
- log(entry)
- }
-}
-```
-
-## Polyfills
-
-### `__filename` & `__dirname`
-
-In [ESM](https://nodejs.org/api/esm.html) modules, Node.js does not provide
-`__filename` and `__dirname` globals. As such globals are really handy in
-scripts,
-`zx` provides these for use in `.mjs` files (when using the `zx` executable).
-
-### `require()`
-
-In [ESM](https://nodejs.org/api/modules.html#modules_module_createrequire_filename)
-modules, the `require()` function is not defined.
-The `zx` provides `require()` function, so it can be used with imports in `.mjs`
-files (when using `zx` executable).
-
-```js
-let {version} = require('./package.json')
-```
-
-## FAQ
-
-### Passing env variables
-
-```js
-process.env.FOO = 'bar'
-await $`echo $FOO`
-```
-
-### Passing array of values
-
-When passing an array of values as an argument to `$`, items of the array will
-be escaped
-individually and concatenated via space.
-
-Example:
-
-```js
-let files = [...]
-await $`tar cz ${files}`
-```
-
-### Importing into other scripts
-
-It is possible to make use of `$` and other functions via explicit imports:
-
-```js
-#!/usr/bin/env node
-import { $ } from 'zx'
-
-await $`date`
-```
-
-### Scripts without extensions
-
-If script does not have a file extension (like `.git/hooks/pre-commit`), zx
-assumes that it is
-an [ESM](https://nodejs.org/api/modules.html#modules_module_createrequire_filename)
-module.
-
-### Markdown scripts
-
-The `zx` can execute [scripts written as markdown](markdown-scripts.md):
-
-```bash
-zx docs/markdown.md
-```
-
-### TypeScript scripts
-
-```ts
-import { $ } from 'zx'
-// Or
-import 'zx/globals'
-
-void async function () {
- await $`ls -la`
-}()
-```
-
-Set [`"type": "module"`](https://nodejs.org/api/packages.html#packages_type)
-in **package.json**
-and [`"module": "ESNext"`](https://www.typescriptlang.org/tsconfig/#module)
-in **tsconfig.json**.
-
-### Executing remote scripts
-
-If the argument to the `zx` executable starts with `https://`, the file will be
-downloaded and executed.
-
-```bash
-zx https://medv.io/game-of-life.js
-```
-
-### Executing scripts from stdin
-
-The `zx` supports executing scripts from stdin.
-
-```js
-zx << 'EOF'
-await $`pwd`
-EOF
-```
-
-### Executing scripts via --eval
-
-Evaluate the following argument as a script.
-
-```bash
-cat package.json | zx --eval 'let v = JSON.parse(await stdin()).version; echo(v)'
-```
-
-### Installing dependencies via --install
-
-```js
-// script.mjs:
-import sh from 'tinysh'
-
-sh.say('Hello, world!')
-```
-
-Add `--install` flag to the `zx` command to install missing dependencies
-automatically.
-
-```bash
-zx --install script.mjs
-```
-
-You can also specify needed version by adding comment with `@` after
-the import.
-
-```js
-import sh from 'tinysh' // @^1
-```
-
-### Executing commands on remote hosts
-
-The `zx` uses [webpod](https://github.com/webpod/webpod) to execute commands on
-remote hosts.
-
-```js
-import { ssh } from 'zx'
-
-await ssh('user@host')`echo Hello, world!`
-```
-
-
-
-### Attaching a profile
-
-By default `child_process` does not include aliases and bash functions.
-But you are still able to do it by hand. Just attach necessary directives
-to the `$.prefix`.
-
-```js
-$.prefix += 'export NVM_DIR=$HOME/.nvm; source $NVM_DIR/nvm.sh; '
-await $`nvm -v`
-```
-
-### Using GitHub Actions
-
-The default GitHub Action runner comes with `npx` installed.
-
-```yaml
-jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
-
- - name: Build
- env:
- FORCE_COLOR: 3
- run: |
- npx zx <<'EOF'
- await $`...`
- EOF
-```
-
-### Canary / Beta / RC builds
-
-Impatient early adopters can try the experimental zx versions.
-But keep in mind: these builds are ⚠️️__beta__ in every sense.
-
-```bash
-npm i zx@dev
-npx zx@dev --install --quiet <<< 'import _ from "lodash" /* 4.17.15 */; console.log(_.VERSION)'
-```
-
## License
[Apache-2.0](https://github.com/google/zx/blob/main/LICENSE)
diff --git a/markdown-scripts.md b/markdown-scripts.md
index 6005bcabed..3dfb11f09a 100644
--- a/markdown-scripts.md
+++ b/markdown-scripts.md
@@ -37,6 +37,6 @@ Other code blocks are ignored:
```css
body .hero {
- margin: 42px;
+ margin: 42px;
}
```
diff --git a/process-promise.md b/process-promise.md
index ea86fe8746..e5435783cf 100644
--- a/process-promise.md
+++ b/process-promise.md
@@ -1,4 +1,4 @@
-# ProcessPromise
+# Process Promise
The `$` returns a `ProcessPromise` instance.
@@ -40,7 +40,7 @@ Returns a promise which resolves to the exit code of the process.
```js
if (await $`[[ -d path ]]`.exitCode == 0) {
- ...
+...
}
```
@@ -120,13 +120,13 @@ If only the `exitCode` is needed, you can use [`exitCode`](#exitcode) directly:
```js
if (await $`[[ -d path ]]`.exitCode == 0) {
- ...
+...
}
// Equivalent of:
if ((await $`[[ -d path ]]`.nothrow()).exitCode == 0) {
- ...
+...
}
```
diff --git a/typescript.md b/typescript.md
new file mode 100644
index 0000000000..83a08c2ba7
--- /dev/null
+++ b/typescript.md
@@ -0,0 +1,28 @@
+# TypeScript
+
+Configure your project to use [ES modules](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:
+
+```ts
+import { $ } from 'zx'
+```
+
+Or import globals explicitly:
+
+```ts
+import 'zx/globals'
+```
+
+Wrap your code in an async function and call it immediately:
+
+```ts
+void async function () {
+ await $`ls -la`
+}()
+```