Socket
Socket
Sign inDemoInstall

zx

Package Overview
Dependencies
Maintainers
2
Versions
146
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

zx - npm Package Compare versions

Comparing version 7.1.1 to 7.2.0-dev.df28f5f

19

build/cli.js

@@ -170,3 +170,7 @@ #!/usr/bin/env node

let state = 'root';
let codeBlockEnd = '';
let prevLineIsEmpty = true;
const jsCodeBlock = /^(```+|~~~+)(js|javascript)$/;
const shCodeBlock = /^(```+|~~~+)(sh|bash)$/;
const otherCodeBlock = /^(```+|~~~+)(.*)$/;
for (let line of source.split('\n')) {

@@ -179,13 +183,16 @@ switch (state) {

}
else if (/^```(js|javascript)$/.test(line)) {
else if (jsCodeBlock.test(line)) {
output.push('');
state = 'js';
codeBlockEnd = line.match(jsCodeBlock)[1];
}
else if (/^```(sh|bash)$/.test(line)) {
else if (shCodeBlock.test(line)) {
output.push('await $`');
state = 'bash';
codeBlockEnd = line.match(shCodeBlock)[1];
}
else if (/^```.*$/.test(line)) {
else if (otherCodeBlock.test(line)) {
output.push('');
state = 'other';
codeBlockEnd = line.match(otherCodeBlock)[1];
}

@@ -210,3 +217,3 @@ else {

case 'js':
if (/^```$/.test(line)) {
if (line === codeBlockEnd) {
output.push('');

@@ -220,3 +227,3 @@ state = 'root';

case 'bash':
if (/^```$/.test(line)) {
if (line === codeBlockEnd) {
output.push('`');

@@ -230,3 +237,3 @@ state = 'root';

case 'other':
if (/^```$/.test(line)) {
if (line === codeBlockEnd) {
output.push('');

@@ -233,0 +240,0 @@ state = 'root';

@@ -11,5 +11,5 @@ /// <reference types="node" resolution-mode="require"/>

import { Duration, noop, quote } from './util.js';
export declare type Shell = (pieces: TemplateStringsArray, ...args: any[]) => ProcessPromise;
export type Shell = (pieces: TemplateStringsArray, ...args: any[]) => ProcessPromise;
declare const processCwd: unique symbol;
export declare type Options = {
export type Options = {
[processCwd]: string;

@@ -27,4 +27,4 @@ cwd?: string;

export declare const $: Shell & Options;
declare type Resolve = (out: ProcessOutput) => void;
declare type IO = StdioPipe | StdioNull;
type Resolve = (out: ProcessOutput) => void;
type IO = StdioPipe | StdioNull;
export declare class ProcessPromise extends Promise<ProcessOutput> {

@@ -80,3 +80,3 @@ child?: ChildProcess;

export declare function cd(dir: string): void;
export declare type LogEntry = {
export type LogEntry = {
kind: 'cmd';

@@ -83,0 +83,0 @@ verbose: boolean;

@@ -1,6 +0,1 @@

import { Duration } from './util.js';
export declare function retry<T>(count: number, callback: () => T): Promise<T>;
export declare function retry<T>(count: number, duration: Duration | Generator<number>, callback: () => T): Promise<T>;
export declare function expBackoff(max?: Duration, rand?: Duration): Generator<number, void, unknown>;
export declare function spinner<T>(callback: () => T): Promise<T>;
export declare function spinner<T>(title: string, callback: () => T): Promise<T>;
export { spinner, retry, expBackoff, echo } from './goods.js';

@@ -14,82 +14,3 @@ // Copyright 2021 Google LLC

// limitations under the License.
import assert from 'node:assert';
import chalk from 'chalk';
import { $, within } from './core.js';
import { sleep } from './goods.js';
import { parseDuration } from './util.js';
export async function retry(count, a, b) {
const total = count;
let callback;
let delayStatic = 0;
let delayGen;
if (typeof a == 'function') {
callback = a;
}
else {
if (typeof a == 'object') {
delayGen = a;
}
else {
delayStatic = parseDuration(a);
}
assert(b);
callback = b;
}
let lastErr;
let attempt = 0;
while (count-- > 0) {
attempt++;
try {
return await callback();
}
catch (err) {
let delay = 0;
if (delayStatic > 0)
delay = delayStatic;
if (delayGen)
delay = delayGen.next().value;
$.log({
kind: 'retry',
error: chalk.bgRed.white(' FAIL ') +
` Attempt: ${attempt}${total == Infinity ? '' : `/${total}`}` +
(delay > 0 ? `; next in ${delay}ms` : ''),
});
lastErr = err;
if (count == 0)
break;
if (delay)
await sleep(delay);
}
}
throw lastErr;
}
export function* expBackoff(max = '60s', rand = '100ms') {
const maxMs = parseDuration(max);
const randMs = parseDuration(rand);
let n = 1;
while (true) {
const ms = Math.floor(Math.random() * randMs);
yield Math.min(2 ** n++, maxMs) + ms;
}
}
export async function spinner(title, callback) {
if (typeof title == 'function') {
callback = title;
title = '';
}
let i = 0;
const spin = () => process.stderr.write(` ${'⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'[i++ % 10]} ${title}\r`);
return within(async () => {
$.verbose = false;
const id = setInterval(spin, 100);
let result;
try {
result = await callback();
}
finally {
clearInterval(id);
process.stderr.write(' '.repeat(process.stdout.columns - 1) + '\r');
}
return result;
});
}
// TODO(antonmedv): Remove this export in next v8 release.
export { spinner, retry, expBackoff, echo } from './goods.js';

@@ -11,2 +11,3 @@ import * as globbyModule from 'globby';

export { default as os } from 'node:os';
export { ssh } from 'webpod';
export declare let argv: minimist.ParsedArgs;

@@ -23,1 +24,6 @@ export declare function updateArgv(args: string[]): void;

export declare function stdin(): Promise<string>;
export declare function retry<T>(count: number, callback: () => T): Promise<T>;
export declare function retry<T>(count: number, duration: Duration | Generator<number>, callback: () => T): Promise<T>;
export declare function expBackoff(max?: Duration, rand?: Duration): Generator<number, void, unknown>;
export declare function spinner<T>(callback: () => T): Promise<T>;
export declare function spinner<T>(title: string, callback: () => T): Promise<T>;

@@ -14,2 +14,3 @@ // Copyright 2022 Google LLC

// limitations under the License.
import assert from 'node:assert';
import * as globbyModule from 'globby';

@@ -19,4 +20,5 @@ import minimist from 'minimist';

import { createInterface } from 'node:readline';
import { $, ProcessOutput } from './core.js';
import { $, within, ProcessOutput } from './core.js';
import { isString, parseDuration } from './util.js';
import chalk from 'chalk';
export { default as chalk } from 'chalk';

@@ -28,2 +30,3 @@ export { default as fs } from 'fs-extra';

export { default as os } from 'node:os';
export { ssh } from 'webpod';
export let argv = minimist(process.argv.slice(2));

@@ -96,1 +99,77 @@ export function updateArgv(args) {

}
export async function retry(count, a, b) {
const total = count;
let callback;
let delayStatic = 0;
let delayGen;
if (typeof a == 'function') {
callback = a;
}
else {
if (typeof a == 'object') {
delayGen = a;
}
else {
delayStatic = parseDuration(a);
}
assert(b);
callback = b;
}
let lastErr;
let attempt = 0;
while (count-- > 0) {
attempt++;
try {
return await callback();
}
catch (err) {
let delay = 0;
if (delayStatic > 0)
delay = delayStatic;
if (delayGen)
delay = delayGen.next().value;
$.log({
kind: 'retry',
error: chalk.bgRed.white(' FAIL ') +
` Attempt: ${attempt}${total == Infinity ? '' : `/${total}`}` +
(delay > 0 ? `; next in ${delay}ms` : ''),
});
lastErr = err;
if (count == 0)
break;
if (delay)
await sleep(delay);
}
}
throw lastErr;
}
export function* expBackoff(max = '60s', rand = '100ms') {
const maxMs = parseDuration(max);
const randMs = parseDuration(rand);
let n = 1;
while (true) {
const ms = Math.floor(Math.random() * randMs);
yield Math.min(2 ** n++, maxMs) + ms;
}
}
export async function spinner(title, callback) {
if (typeof title == 'function') {
callback = title;
title = '';
}
let i = 0;
const spin = () => process.stderr.write(` ${'⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'[i++ % 10]} ${title}\r`);
return within(async () => {
$.verbose = false;
const id = setInterval(spin, 100);
let result;
try {
result = await callback();
}
finally {
clearInterval(id);
process.stderr.write(' '.repeat(process.stdout.columns - 1) + '\r');
}
return result;
});
}
import { ProcessPromise } from './core.js';
export { $, Shell, Options, ProcessPromise, ProcessOutput, within, cd, log, LogEntry, } from './core.js';
export { argv, chalk, echo, fetch, fs, glob, globby, os, path, question, sleep, stdin, which, YAML, } from './goods.js';
export * from './core.js';
export * from './goods.js';
export { Duration, quote, quotePowerShell } from './util.js';

@@ -5,0 +5,0 @@ /**

@@ -14,4 +14,4 @@ // Copyright 2022 Google LLC

// limitations under the License.
export { $, ProcessPromise, ProcessOutput, within, cd, log, } from './core.js';
export { argv, chalk, echo, fetch, fs, glob, globby, os, path, question, sleep, stdin, which, YAML, } from './goods.js';
export * from './core.js';
export * from './goods.js';
export { quote, quotePowerShell } from './util.js';

@@ -18,0 +18,0 @@ /**

@@ -10,4 +10,4 @@ import psTreeModule from 'ps-tree';

export declare function errnoMessage(errno: number | undefined): string;
export declare type Duration = number | `${number}s` | `${number}ms`;
export type Duration = number | `${number}s` | `${number}ms`;
export declare function parseDuration(d: Duration): number;
export declare function formatCmd(cmd?: string): string;
{
"name": "zx",
"version": "7.1.1",
"version": "7.2.0-dev.df28f5f",
"description": "A tool for writing better scripts.",

@@ -53,23 +53,24 @@ "type": "module",

"dependencies": {
"@types/fs-extra": "^9.0.13",
"@types/fs-extra": "^11.0.1",
"@types/minimist": "^1.2.2",
"@types/node": "^18.7.20",
"@types/node": "^18.14.2",
"@types/ps-tree": "^1.1.2",
"@types/which": "^2.0.1",
"chalk": "^5.0.1",
"fs-extra": "^10.1.0",
"globby": "^13.1.2",
"minimist": "^1.2.6",
"@types/which": "^2.0.2",
"chalk": "^5.2.0",
"fs-extra": "^11.1.0",
"globby": "^13.1.3",
"minimist": "^1.2.8",
"node-fetch": "3.2.10",
"ps-tree": "^1.2.0",
"which": "^2.0.2",
"yaml": "^2.1.1"
"webpod": "^0.0.2",
"which": "^3.0.0",
"yaml": "^2.2.1"
},
"devDependencies": {
"@stryker-mutator/core": "^6.2.2",
"c8": "^7.12.0",
"madge": "^5.0.1",
"prettier": "^2.7.1",
"tsd": "^0.24.1",
"typescript": "^4.8.3",
"@stryker-mutator/core": "^6.4.1",
"c8": "^7.13.0",
"madge": "^6.0.0",
"prettier": "^2.8.4",
"tsd": "^0.25.0",
"typescript": "^4.9.5",
"uvu": "^0.5.6"

@@ -76,0 +77,0 @@ },

@@ -38,6 +38,9 @@ # 🐚 zx

[$](#command-) · [cd()](#cd) · [fetch()](#fetch) · [question()](#question) · [sleep()](#sleep) · [echo()](#echo) · [stdin()](#stdin) · [within()](#within) ·
[$](#command-) · [cd()](#cd) · [fetch()](#fetch) · [question()](#question) · [sleep()](#sleep) · [echo()](#echo) · [stdin()](#stdin) · [within()](#within) · [retry()](#retry) · [spinner()](#spinner) ·
[chalk](#chalk-package) · [fs](#fs-package) · [os](#os-package) · [path](#path-package) · [glob](#globby-package) · [yaml](#yaml-package) · [minimist](#minimist-package) · [which](#which-package) ·
[__filename](#__filename--__dirname) · [__dirname](#__filename--__dirname) · [require()](#require)
For running commands on remote hosts,
see [webpod](https://github.com/webpod/webpod).
## Documentation

@@ -50,2 +53,3 @@

Add the following shebang to the beginning of your `zx` scripts:
```bash

@@ -56,2 +60,3 @@ #!/usr/bin/env zx

Now you will be able to run your script like so:
```bash

@@ -123,5 +128,9 @@ chmod +x ./script.mjs

exitCode: Promise<number>
pipe(dest): ProcessPromise
kill(): Promise<void>
nothrow(): this
quiet(): this

@@ -141,2 +150,3 @@ }

readonly exitCode: number
toString(): string // Combined stdout & stderr.

@@ -146,3 +156,4 @@ }

The output of the process is captured as-is. Usually, programs print a new line `\n` at the end.
The output of the process is captured as-is. Usually, programs print a new
line `\n` at the end.
If `ProcessOutput` is used as an argument to some other `$` process,

@@ -169,3 +180,4 @@ **zx** will use stdout and trim the new line.

A wrapper around the [node-fetch](https://www.npmjs.com/package/node-fetch) package.
A wrapper around the [node-fetch](https://www.npmjs.com/package/node-fetch)
package.

@@ -238,2 +250,28 @@ ```js

### `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

@@ -297,3 +335,5 @@

```js
if( argv.someFlag ){ echo('yes') }
if (argv.someFlag) {
echo('yes')
}
```

@@ -384,3 +424,4 @@

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,
`__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).

@@ -399,38 +440,2 @@

## Experimental
The zx provides a few experimental functions. Please leave feedback about
those features in [the discussion](https://github.com/google/zx/discussions/299).
To enable new features via CLI pass `--experimental` flag.
### `retry()`
Retries a callback for a few times. Will return after the first
successful attempt, or will throw after specifies attempts count.
```js
import { retry, expBackoff } from 'zx/experimental'
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
import { spinner } from 'zx/experimental'
await spinner(() => $`long-running command`)
// With a message.
await spinner('working...', () => $`sleep 99`)
```
## FAQ

@@ -447,6 +452,8 @@

When passing an array of values as an argument to `$`, items of the array will be escaped
When passing an array of values as an argument to `$`, items of the array will
be escaped
individually and concatenated via space.
Example:
```js

@@ -463,3 +470,4 @@ let files = [...]

#!/usr/bin/env node
import {$} from 'zx'
import { $ } from 'zx'
await $`date`

@@ -471,3 +479,4 @@ ```

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)
assumes that it is
an [ESM](https://nodejs.org/api/modules.html#modules_module_createrequire_filename)
module.

@@ -486,3 +495,3 @@

```ts
import {$} from 'zx'
import { $ } from 'zx'
// Or

@@ -497,3 +506,4 @@ import 'zx/globals'

Set [`"type": "module"`](https://nodejs.org/api/packages.html#packages_type)
in **package.json** and [`"module": "ESNext"`](https://www.typescriptlang.org/tsconfig/#module)
in **package.json**
and [`"module": "ESNext"`](https://www.typescriptlang.org/tsconfig/#module)
in **tsconfig.json**.

@@ -515,3 +525,3 @@

```js
zx <<'EOF'
zx << 'EOF'
await $`pwd`

@@ -534,6 +544,7 @@ EOF

import sh from 'tinysh'
sh.say('Hello, world!')
```
Add `--install` flag to the `zx` command to install missing dependencies
Add `--install` flag to the `zx` command to install missing dependencies
automatically.

@@ -545,3 +556,3 @@

You can also specify needed version by adding comment with `@` after
You can also specify needed version by adding comment with `@` after
the import.

@@ -553,6 +564,19 @@

### 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
But you are still able to do it by hand. Just attach necessary directives
to the `$.prefix`.

@@ -574,15 +598,18 @@

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v3
- name: Build
env:
FORCE_COLOR: 3
run: |
npx zx <<'EOF'
await $`...`
EOF
- 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 ⚠️️ __unstable__ in every sense.
Impatient early adopters can try the experimental zx versions.
But keep in mind: these builds are ⚠️️__beta__ in every sense.
```bash

@@ -589,0 +616,0 @@ npm i zx@dev

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc