Socket
Socket
Sign inDemoInstall

zx

Package Overview
Dependencies
4
Maintainers
2
Versions
128
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 8.0.2 to 8.1.0

build/cli.cjs

235

build/cli.js
#!/usr/bin/env node
"use strict";
import './deno.js'
const {
// src/cli.ts
import { createRequire } from "node:module";
import { basename, dirname, extname, join, resolve } from "node:path";
import url from "node:url";
import {
$,
ProcessOutput,
updateArgv,
fetch,
chalk,
minimist,
fs
} from "./index.js";
import { randomId } from "./util.js";
import { installDeps, parseDeps } from "./deps.js";
function printUsage() {
console.log(`
${chalk.bold("zx " + getVersion())}
A tool for writing better scripts
} = await import('./cli.cjs')
export {
${chalk.bold("Usage")}
zx [options] <script>
}
${chalk.bold("Options")}
--quiet don't echo commands
--shell=<path> custom shell binary
--prefix=<command> prefix all commands
--postfix=<command> postfix all commands
--eval=<js>, -e evaluate script
--install, -i install dependencies
--version, -v print current zx version
--help, -h print help
--repl start repl
`);
}
var argv = minimist(process.argv.slice(2), {
string: ["shell", "prefix", "postfix", "eval"],
boolean: ["version", "help", "quiet", "verbose", "install", "repl"],
alias: { e: "eval", i: "install", v: "version", h: "help" },
stopEarly: true
});
await async function main() {
const globals = "./globals.js";
await import(globals);
if (argv.verbose)
$.verbose = true;
if (argv.quiet)
$.verbose = false;
if (argv.shell)
$.shell = argv.shell;
if (argv.prefix)
$.prefix = argv.prefix;
if (argv.postfix)
$.postfix = argv.postfix;
if (argv.version) {
console.log(getVersion());
return;
}
if (argv.help) {
printUsage();
return;
}
if (argv.repl) {
await (await import("./repl.js")).startRepl();
return;
}
if (argv.eval) {
await runScript(argv.eval);
return;
}
const firstArg = argv._[0];
updateArgv(argv._.slice(firstArg === void 0 ? 0 : 1));
if (!firstArg || firstArg === "-") {
const success = await scriptFromStdin();
if (!success)
printUsage();
return;
}
if (/^https?:/.test(firstArg)) {
await scriptFromHttp(firstArg);
return;
}
const filepath = firstArg.startsWith("file:///") ? url.fileURLToPath(firstArg) : resolve(firstArg);
await importPath(filepath);
}().catch((err) => {
if (err instanceof ProcessOutput) {
console.error("Error:", err.message);
} else {
console.error(err);
}
process.exitCode = 1;
});
async function runScript(script) {
const filepath = join(process.cwd(), `zx-${randomId()}.mjs`);
await writeAndImport(script, filepath);
}
async function scriptFromStdin() {
let script = "";
if (!process.stdin.isTTY) {
process.stdin.setEncoding("utf8");
for await (const chunk of process.stdin) {
script += chunk;
}
if (script.length > 0) {
await runScript(script);
return true;
}
}
return false;
}
async function scriptFromHttp(remote) {
const res = await fetch(remote);
if (!res.ok) {
console.error(`Error: Can't get ${remote}`);
process.exit(1);
}
const script = await res.text();
const pathname = new URL(remote).pathname;
const name = basename(pathname);
const ext = extname(pathname) || ".mjs";
const filepath = join(process.cwd(), `${name}-${randomId()}${ext}`);
await writeAndImport(script, filepath);
}
async function writeAndImport(script, filepath, origin = filepath) {
await fs.writeFile(filepath, script.toString());
try {
await importPath(filepath, origin);
} finally {
await fs.rm(filepath);
}
}
async function importPath(filepath, origin = filepath) {
const ext = extname(filepath);
if (ext === "") {
const tmpFilename = fs.existsSync(`${filepath}.mjs`) ? `${basename(filepath)}-${randomId()}.mjs` : `${basename(filepath)}.mjs`;
return writeAndImport(
await fs.readFile(filepath),
join(dirname(filepath), tmpFilename),
origin
);
}
if (ext === ".md") {
return writeAndImport(
transformMarkdown(await fs.readFile(filepath)),
join(dirname(filepath), basename(filepath) + ".mjs"),
origin
);
}
if (argv.install) {
const deps = parseDeps(await fs.readFile(filepath));
await installDeps(deps, dirname(filepath));
}
const __filename = resolve(origin);
const __dirname = dirname(__filename);
const require2 = createRequire(origin);
Object.assign(global, { __filename, __dirname, require: require2 });
await import(url.pathToFileURL(filepath).toString());
}
function transformMarkdown(buf) {
const source = buf.toString();
const output = [];
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")) {
switch (state) {
case "root":
if (/^( {4}|\t)/.test(line) && prevLineIsEmpty) {
output.push(line);
state = "tab";
} else if (jsCodeBlock.test(line)) {
output.push("");
state = "js";
codeBlockEnd = line.match(jsCodeBlock)[1];
} else if (shCodeBlock.test(line)) {
output.push("await $`");
state = "bash";
codeBlockEnd = line.match(shCodeBlock)[1];
} else if (otherCodeBlock.test(line)) {
output.push("");
state = "other";
codeBlockEnd = line.match(otherCodeBlock)[1];
} else {
prevLineIsEmpty = line === "";
output.push("// " + line);
}
break;
case "tab":
if (/^( +|\t)/.test(line)) {
output.push(line);
} else if (line === "") {
output.push("");
} else {
output.push("// " + line);
state = "root";
}
break;
case "js":
if (line === codeBlockEnd) {
output.push("");
state = "root";
} else {
output.push(line);
}
break;
case "bash":
if (line === codeBlockEnd) {
output.push("`");
state = "root";
} else {
output.push(line);
}
break;
case "other":
if (line === codeBlockEnd) {
output.push("");
state = "root";
} else {
output.push("// " + line);
}
break;
}
}
return output.join("\n");
}
function getVersion() {
return createRequire(import.meta.url)("../package.json").version;
}

@@ -23,2 +23,4 @@ import { spawn, spawnSync, StdioOptions, IOType } from 'node:child_process';

input?: string | Buffer | Readable | ProcessOutput | ProcessPromise;
timeout?: Duration;
timeoutSignal?: string;
stdio: StdioOptions;

@@ -43,2 +45,3 @@ verbose: boolean;

export declare function usePowerShell(): void;
export declare function usePwsh(): void;
export declare function useBash(): void;

@@ -45,0 +48,0 @@ export declare const $: Shell & Options;

@@ -1,482 +0,17 @@

// src/core.ts
import assert from "node:assert";
import { spawn, spawnSync } from "node:child_process";
import { AsyncLocalStorage, createHook } from "node:async_hooks";
import { inspect } from "node:util";
import {
exec,
buildCmd,
chalk,
which,
ps
} from "./vendor.js";
import {
errnoMessage,
exitCodeInfo,
formatCmd,
getCallerLocation,
noop,
parseDuration,
quote,
quotePowerShell,
noquote
} from "./util.js";
var processCwd = Symbol("processCwd");
var syncExec = Symbol("syncExec");
var storage = new AsyncLocalStorage();
var cwdSyncHook = createHook({
init: syncCwd,
before: syncCwd,
promiseResolve: syncCwd,
after: syncCwd,
destroy: syncCwd
});
function syncProcessCwd(flag = true) {
if (flag)
cwdSyncHook.enable();
else
cwdSyncHook.disable();
}
var defaults = {
[processCwd]: process.cwd(),
[syncExec]: false,
verbose: false,
env: process.env,
sync: false,
shell: true,
stdio: ["inherit", "pipe", "pipe"],
nothrow: false,
quiet: false,
prefix: "",
postfix: "",
quote: noquote,
detached: false,
spawn,
spawnSync,
"use strict";
import './deno.js'
const {
$,
ProcessOutput,
ProcessPromise,
cd,
defaults,
kill,
log,
kill
};
function usePowerShell() {
$.shell = which.sync("powershell.exe");
$.prefix = "";
$.postfix = "; exit $LastExitCode";
$.quote = quotePowerShell;
}
function useBash() {
$.shell = which.sync("bash");
$.prefix = "set -euo pipefail;";
$.quote = quote;
}
function checkShell() {
if (!$.shell) {
throw new Error(`shell is not available: setup guide goes here`);
}
}
function getStore() {
return storage.getStore() || defaults;
}
var $ = new Proxy(
function(pieces, ...args) {
checkShell();
if (!Array.isArray(pieces)) {
return function(...args2) {
const self = this;
return within(() => {
return Object.assign($, pieces).apply(self, args2);
});
};
}
const from = getCallerLocation();
if (pieces.some((p) => p == void 0)) {
throw new Error(`Malformed command at ${from}`);
}
let resolve, reject;
const promise = new ProcessPromise((...args2) => [resolve, reject] = args2);
const cmd = buildCmd(
$.quote,
pieces,
args
);
const snapshot = getStore();
const sync = snapshot[syncExec];
const callback = () => promise.isHalted || promise.run();
promise._bind(
cmd,
from,
resolve,
(v) => {
reject(v);
if (sync)
throw v;
},
snapshot
);
sync ? callback() : setImmediate(callback);
return sync ? promise.output : promise;
},
{
set(_, key, value) {
const target = key in Function.prototype ? _ : getStore();
Reflect.set(target, key === "sync" ? syncExec : key, value);
return true;
},
get(_, key) {
if (key === "sync")
return $({ sync: true });
const target = key in Function.prototype ? _ : getStore();
return Reflect.get(target, key);
}
}
);
try {
useBash();
} catch (err) {
}
var ProcessPromise = class _ProcessPromise extends Promise {
constructor() {
super(...arguments);
this._command = "";
this._from = "";
this._resolve = noop;
this._reject = noop;
this._snapshot = getStore();
this._timeoutSignal = "SIGTERM";
this._resolved = false;
this._halted = false;
this._piped = false;
this._zurk = null;
this._output = null;
this._prerun = noop;
this._postrun = noop;
}
_bind(cmd, from, resolve, reject, options) {
this._command = cmd;
this._from = from;
this._resolve = resolve;
this._reject = reject;
this._snapshot = { ...options };
}
run() {
if (this.child)
return this;
this._prerun();
const $2 = this._snapshot;
const self = this;
const input = $2.input?.stdout ?? $2.input;
if (input)
this.stdio("pipe");
$2.log({
kind: "cmd",
cmd: this._command,
verbose: self.isVerbose()
});
this._zurk = exec({
input,
cmd: $2.prefix + self._command + $2.postfix,
cwd: $2.cwd ?? $2[processCwd],
ac: $2.ac,
signal: $2.signal,
shell: typeof $2.shell === "string" ? $2.shell : true,
env: $2.env,
spawn: $2.spawn,
spawnSync: $2.spawnSync,
stdio: self._stdio ?? $2.stdio,
sync: $2[syncExec],
detached: $2.detached,
run: (cb) => cb(),
on: {
start: () => {
if (self._timeout) {
const t = setTimeout(
() => self.kill(self._timeoutSignal),
self._timeout
);
self.finally(() => clearTimeout(t)).catch(noop);
}
},
stdout: (data) => {
if (self._piped)
return;
$2.log({ kind: "stdout", data, verbose: self.isVerbose() });
},
stderr: (data) => {
$2.log({ kind: "stderr", data, verbose: !self.isQuiet() });
},
end: ({ error, stdout, stderr, stdall, status, signal }) => {
self._resolved = true;
if (error) {
const message = ProcessOutput.getErrorMessage(error, self._from);
const output = new ProcessOutput(
null,
null,
stdout,
stderr,
stdall,
message
);
self._output = output;
self._reject(output);
} else {
const message = ProcessOutput.getExitMessage(
status,
signal,
stderr,
self._from
);
const output = new ProcessOutput(
status,
signal,
stdout,
stderr,
stdall,
message
);
self._output = output;
if (status === 0 || (self._nothrow ?? $2.nothrow)) {
self._resolve(output);
} else {
self._reject(output);
}
}
}
}
});
this._postrun();
return this;
}
get child() {
return this._zurk?.child;
}
get stdin() {
this.stdio("pipe");
this.run();
assert(this.child);
if (this.child.stdin == null)
throw new Error("The stdin of subprocess is null.");
return this.child.stdin;
}
get stdout() {
this.run();
assert(this.child);
if (this.child.stdout == null)
throw new Error("The stdout of subprocess is null.");
return this.child.stdout;
}
get stderr() {
this.run();
assert(this.child);
if (this.child.stderr == null)
throw new Error("The stderr of subprocess is null.");
return this.child.stderr;
}
get exitCode() {
return this.then(
(p) => p.exitCode,
(p) => p.exitCode
);
}
then(onfulfilled, onrejected) {
if (this.isHalted && !this.child) {
throw new Error("The process is halted!");
}
return super.then(onfulfilled, onrejected);
}
catch(onrejected) {
return super.catch(onrejected);
}
pipe(dest) {
if (typeof dest == "string")
throw new Error("The pipe() method does not take strings. Forgot $?");
if (this._resolved) {
if (dest instanceof _ProcessPromise)
dest.stdin.end();
throw new Error(
"The pipe() method shouldn't be called after promise is already resolved!"
);
}
this._piped = true;
if (dest instanceof _ProcessPromise) {
dest.stdio("pipe");
dest._prerun = this.run.bind(this);
dest._postrun = () => {
if (!dest.child)
throw new Error(
"Access to stdin of pipe destination without creation a subprocess."
);
this.stdout.pipe(dest.stdin);
};
return dest;
} else {
this._postrun = () => this.stdout.pipe(dest);
return this;
}
}
abort(reason) {
if (!this.child)
throw new Error("Trying to abort a process without creating one.");
this._zurk?.ac.abort(reason);
}
async kill(signal = "SIGTERM") {
if (!this.child)
throw new Error("Trying to kill a process without creating one.");
if (!this.child.pid)
throw new Error("The process pid is undefined.");
return $.kill(this.child.pid, signal);
}
stdio(stdin, stdout = "pipe", stderr = "pipe") {
this._stdio = [stdin, stdout, stderr];
return this;
}
nothrow() {
this._nothrow = true;
return this;
}
quiet() {
this._quiet = true;
return this;
}
isQuiet() {
return this._quiet ?? this._snapshot.quiet;
}
isVerbose() {
return this._snapshot.verbose && !this.isQuiet();
}
timeout(d, signal = "SIGTERM") {
this._timeout = parseDuration(d);
this._timeoutSignal = signal;
return this;
}
halt() {
this._halted = true;
return this;
}
get isHalted() {
return this._halted;
}
get output() {
return this._output;
}
};
var ProcessOutput = class extends Error {
constructor(code, signal, stdout, stderr, combined, message) {
super(message);
this._code = code;
this._signal = signal;
this._stdout = stdout;
this._stderr = stderr;
this._combined = combined;
}
toString() {
return this._combined;
}
valueOf() {
return this._combined.trim();
}
get stdout() {
return this._stdout;
}
get stderr() {
return this._stderr;
}
get exitCode() {
return this._code;
}
get signal() {
return this._signal;
}
static getExitMessage(code, signal, stderr, from) {
let message = `exit code: ${code}`;
if (code != 0 || signal != null) {
message = `${stderr || "\n"} at ${from}`;
message += `
exit code: ${code}${exitCodeInfo(code) ? " (" + exitCodeInfo(code) + ")" : ""}`;
if (signal != null) {
message += `
signal: ${signal}`;
}
}
return message;
}
static getErrorMessage(err, from) {
return `${err.message}
errno: ${err.errno} (${errnoMessage(err.errno)})
code: ${err.code}
at ${from}`;
}
[inspect.custom]() {
let stringify = (s, c) => s.length === 0 ? "''" : c(inspect(s));
return `ProcessOutput {
stdout: ${stringify(this.stdout, chalk.green)},
stderr: ${stringify(this.stderr, chalk.red)},
signal: ${inspect(this.signal)},
exitCode: ${(this.exitCode === 0 ? chalk.green : chalk.red)(this.exitCode)}${exitCodeInfo(this.exitCode) ? chalk.grey(" (" + exitCodeInfo(this.exitCode) + ")") : ""}
}`;
}
};
function within(callback) {
return storage.run({ ...getStore() }, callback);
}
function syncCwd() {
if ($[processCwd] != process.cwd())
process.chdir($[processCwd]);
}
function cd(dir) {
if (dir instanceof ProcessOutput) {
dir = dir.toString().trim();
}
$.log({ kind: "cd", dir });
process.chdir(dir);
$[processCwd] = process.cwd();
}
async function kill(pid, signal) {
let children = await ps.tree({ pid, recursive: true });
for (const p of children) {
try {
process.kill(+p.pid, signal);
} catch (e) {
}
}
try {
process.kill(-pid, signal);
} catch (e) {
try {
process.kill(+pid, signal);
} catch (e2) {
}
}
}
function log(entry) {
switch (entry.kind) {
case "cmd":
if (!entry.verbose)
return;
process.stderr.write(formatCmd(entry.cmd));
break;
case "stdout":
case "stderr":
if (!entry.verbose)
return;
process.stderr.write(entry.data);
break;
case "cd":
if (!$.verbose)
return;
process.stderr.write("$ " + chalk.greenBright("cd") + ` ${entry.dir}
`);
break;
case "fetch":
if (!$.verbose)
return;
const init = entry.init ? " " + inspect(entry.init) : "";
process.stderr.write(
"$ " + chalk.greenBright("fetch") + ` ${entry.url}${init}
`
);
break;
case "retry":
if (!$.verbose)
return;
process.stderr.write(entry.error + "\n");
}
}
syncProcessCwd,
useBash,
usePowerShell,
usePwsh,
within
} = await import('./core.cjs')
export {

@@ -493,3 +28,5 @@ $,

usePowerShell,
usePwsh,
within
};
}

@@ -1,103 +0,11 @@

// src/deps.ts
import { $ } from "./core.js";
import { spinner } from "./goods.js";
import { depseek } from "./vendor.js";
async function installDeps(dependencies, prefix) {
const packages = Object.entries(dependencies).map(
([name, version]) => `${name}@${version}`
);
const flags = prefix ? `--prefix=${prefix}` : "";
if (packages.length === 0) {
return;
}
await spinner(
`npm i ${packages.join(" ")}`,
() => $`npm install --no-save --no-audit --no-fund ${flags} ${packages}`.nothrow()
);
}
var builtins = /* @__PURE__ */ new Set([
"_http_agent",
"_http_client",
"_http_common",
"_http_incoming",
"_http_outgoing",
"_http_server",
"_stream_duplex",
"_stream_passthrough",
"_stream_readable",
"_stream_transform",
"_stream_wrap",
"_stream_writable",
"_tls_common",
"_tls_wrap",
"assert",
"async_hooks",
"buffer",
"child_process",
"cluster",
"console",
"constants",
"crypto",
"dgram",
"dns",
"domain",
"events",
"fs",
"http",
"http2",
"https",
"inspector",
"module",
"net",
"os",
"path",
"perf_hooks",
"process",
"punycode",
"querystring",
"readline",
"repl",
"stream",
"string_decoder",
"sys",
"timers",
"tls",
"trace_events",
"tty",
"url",
"util",
"v8",
"vm",
"wasi",
"worker_threads",
"zlib"
]);
var nameRe = /^(?<name>(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*)\/?.*$/i;
var versionRe = /^@(?<version>[~^]?(v?[\dx*]+([-.][\d*a-z-]+)*))/i;
function parseDeps(content) {
return depseek(content.toString() + "\n", { comments: true }).reduce((m, { type, value }, i, list) => {
if (type === "dep") {
const meta = list[i + 1];
const name = parsePackageName(value);
const version = meta?.type === "comment" && parseVersion(meta?.value.trim()) || "latest";
if (name)
m[name] = version;
}
return m;
}, {});
}
function parsePackageName(path) {
if (!path)
return;
const name = nameRe.exec(path)?.groups?.name;
if (name && !builtins.has(name)) {
return name;
}
}
function parseVersion(line) {
return versionRe.exec(line)?.groups?.version || "latest";
}
"use strict";
import './deno.js'
const {
installDeps,
parseDeps
} = await import('./deps.cjs')
export {
installDeps,
parseDeps
};
}

@@ -27,7 +27,12 @@ import * as _ from './index.js';

var retry: typeof _.retry;
var usePowerShell: typeof _.usePowerShell;
var useBash: typeof _.useBash;
var sleep: typeof _.sleep;
var spinner: typeof _.spinner;
var stdin: typeof _.stdin;
var tempdir: typeof _.tempdir;
var tempfile: typeof _.tempfile;
var tmpdir: typeof _.tempdir;
var tmpfile: typeof _.tempfile;
var usePowerShell: typeof _.usePowerShell;
var usePwsh: typeof _.usePwsh;
var useBash: typeof _.useBash;
var which: typeof _.which;

@@ -34,0 +39,0 @@ var within: typeof _.within;

@@ -1,3 +0,9 @@

// src/globals.ts
import * as _ from "./index.js";
Object.assign(global, _);
"use strict";
import './deno.js'
const {
} = await import('./globals.cjs')
export {
}

@@ -1,143 +0,17 @@

// src/goods.ts
import assert from "node:assert";
import { createInterface } from "node:readline";
import { $, within, ProcessOutput } from "./core.js";
import { isString, parseDuration } from "./util.js";
import {
chalk,
minimist,
nodeFetch
} from "./vendor.js";
import { default as default2 } from "node:path";
import * as os from "node:os";
var argv = minimist(process.argv.slice(2));
function updateArgv(args) {
argv = minimist(args);
global.argv = argv;
}
function sleep(duration) {
return new Promise((resolve) => {
setTimeout(resolve, parseDuration(duration));
});
}
async function fetch(url, init) {
$.log({ kind: "fetch", url, init });
return nodeFetch(url, init);
}
function echo(pieces, ...args) {
let msg;
const lastIdx = pieces.length - 1;
if (Array.isArray(pieces) && pieces.every(isString) && lastIdx === args.length) {
msg = args.map((a, i) => pieces[i] + stringify(a)).join("") + pieces[lastIdx];
} else {
msg = [pieces, ...args].map(stringify).join(" ");
}
console.log(msg);
}
function stringify(arg) {
if (arg instanceof ProcessOutput) {
return arg.toString().replace(/\n$/, "");
}
return `${arg}`;
}
async function question(query, options) {
let completer = void 0;
if (options && Array.isArray(options.choices)) {
completer = function completer2(line) {
const completions = options.choices;
const hits = completions.filter((c) => c.startsWith(line));
return [hits.length ? hits : completions, line];
};
}
const rl = createInterface({
input: process.stdin,
output: process.stdout,
terminal: true,
completer
});
return new Promise(
(resolve) => rl.question(query ?? "", (answer) => {
rl.close();
resolve(answer);
})
);
}
async function stdin() {
let buf = "";
process.stdin.setEncoding("utf8");
for await (const chunk of process.stdin) {
buf += chunk;
}
return buf;
}
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;
}
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;
}
}
async function spinner(title, callback) {
if (typeof title == "function") {
callback = title;
title = "";
}
let i = 0;
const spin = () => process.stderr.write(` ${"\u280B\u2819\u2839\u2838\u283C\u2834\u2826\u2827\u2807\u280F"[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) - 1) + "\r");
}
return result;
});
}
"use strict";
import './deno.js'
const {
argv,
echo,
expBackoff,
fetch,
os,
path,
question,
retry,
sleep,
spinner,
stdin,
updateArgv
} = await import('./goods.cjs')
export {

@@ -149,3 +23,3 @@ argv,

os,
default2 as path,
path,
question,

@@ -157,2 +31,3 @@ retry,

updateArgv
};
}

@@ -5,3 +5,3 @@ import { ProcessPromise } from './core.js';

export { minimist, chalk, fs, which, YAML, ps, glob, glob as globby, } from './vendor.js';
export { type Duration, quote, quotePowerShell } from './util.js';
export { type Duration, quote, quotePowerShell, tempdir, tempdir as tmpdir, tempfile, tempfile as tmpfile, } from './util.js';
/**

@@ -8,0 +8,0 @@ * @deprecated Use $`cmd`.nothrow() instead.

@@ -1,21 +0,45 @@

// src/index.ts
export * from "./core.js";
export * from "./goods.js";
import {
minimist,
"use strict";
import './deno.js'
const {
YAML,
chalk,
fs,
glob,
globby,
minimist,
nothrow,
ps,
quiet,
quote,
quotePowerShell,
tempdir,
tempfile,
tmpdir,
tmpfile,
which,
YAML,
ps,
glob,
glob as glob2
} from "./vendor.js";
import { quote, quotePowerShell } from "./util.js";
function nothrow(promise) {
return promise.nothrow();
}
function quiet(promise) {
return promise.quiet();
}
$,
ProcessOutput,
ProcessPromise,
cd,
defaults,
kill,
log,
syncProcessCwd,
useBash,
usePowerShell,
usePwsh,
within,
argv,
echo,
expBackoff,
fetch,
os,
path,
question,
retry,
sleep,
spinner,
stdin,
updateArgv
} = await import('./index.cjs')
export {

@@ -26,3 +50,3 @@ YAML,

glob,
glob2 as globby,
globby,
minimist,

@@ -34,3 +58,32 @@ nothrow,

quotePowerShell,
which
};
tempdir,
tempfile,
tmpdir,
tmpfile,
which,
$,
ProcessOutput,
ProcessPromise,
cd,
defaults,
kill,
log,
syncProcessCwd,
useBash,
usePowerShell,
usePwsh,
within,
argv,
echo,
expBackoff,
fetch,
os,
path,
question,
retry,
sleep,
spinner,
stdin,
updateArgv
}

@@ -1,25 +0,9 @@

// src/repl.ts
import os from "node:os";
import path from "node:path";
import { inspect } from "node:util";
import { ProcessOutput, defaults } from "./core.js";
import { chalk } from "./vendor.js";
async function startRepl() {
defaults.verbose = false;
const r = (await import("node:repl")).start({
prompt: chalk.greenBright.bold("\u276F "),
useGlobal: true,
preview: false,
writer(output) {
if (output instanceof ProcessOutput) {
return output.toString().replace(/\n$/, "");
}
return inspect(output, { colors: true });
}
});
r.setupHistory(path.join(os.homedir(), ".zx_repl_history"), () => {
});
}
"use strict";
import './deno.js'
const {
startRepl
} = await import('./repl.cjs')
export {
startRepl
};
}

@@ -0,1 +1,3 @@

export declare function tempdir(prefix?: string): string;
export declare function tempfile(name?: string, data?: string | Buffer): string;
export declare function noop(): void;

@@ -2,0 +4,0 @@ export declare function randomId(): string;

@@ -1,341 +0,20 @@

// src/util.ts
import { chalk, parseLine } from "./vendor.js";
function noop() {
}
function randomId() {
return Math.random().toString(36).slice(2);
}
function isString(obj) {
return typeof obj === "string";
}
var pad = (v) => v === " " ? " " : "";
function normalizeMultilinePieces(pieces) {
return Object.assign(
pieces.map(
(p, i) => p.trim() ? pad(p[0]) + parseLine(p).words.map(({ w }) => w === "\\" ? "" : w.trim()).join(" ") + pad(p[p.length - 1]) : pieces[i]
),
{ raw: pieces.raw }
);
}
function noquote() {
throw new Error("No quote function is defined: https://\xEF.at/no-quote-func");
}
function quote(arg) {
if (/^[a-z0-9/_.\-@:=]+$/i.test(arg) || arg === "") {
return arg;
}
return `$'` + arg.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\f/g, "\\f").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replace(/\v/g, "\\v").replace(/\0/g, "\\0") + `'`;
}
function quotePowerShell(arg) {
if (/^[a-z0-9/_.\-]+$/i.test(arg) || arg === "") {
return arg;
}
return `'` + arg.replace(/'/g, "''") + `'`;
}
function exitCodeInfo(exitCode) {
return {
2: "Misuse of shell builtins",
126: "Invoked command cannot execute",
127: "Command not found",
128: "Invalid exit argument",
129: "Hangup",
130: "Interrupt",
131: "Quit and dump core",
132: "Illegal instruction",
133: "Trace/breakpoint trap",
134: "Process aborted",
135: 'Bus error: "access to undefined portion of memory object"',
136: 'Floating point exception: "erroneous arithmetic operation"',
137: "Kill (terminate immediately)",
138: "User-defined 1",
139: "Segmentation violation",
140: "User-defined 2",
141: "Write to pipe with no one reading",
142: "Signal raised by alarm",
143: "Termination (request to terminate)",
145: "Child process terminated, stopped (or continued*)",
146: "Continue if stopped",
147: "Stop executing temporarily",
148: "Terminal stop signal",
149: 'Background process attempting to read from tty ("in")',
150: 'Background process attempting to write to tty ("out")',
151: "Urgent data available on socket",
152: "CPU time limit exceeded",
153: "File size limit exceeded",
154: 'Signal raised by timer counting virtual time: "virtual timer expired"',
155: "Profiling timer expired",
157: "Pollable event",
159: "Bad syscall"
}[exitCode || -1];
}
function errnoMessage(errno) {
if (errno === void 0) {
return "Unknown error";
}
return {
0: "Success",
1: "Not super-user",
2: "No such file or directory",
3: "No such process",
4: "Interrupted system call",
5: "I/O error",
6: "No such device or address",
7: "Arg list too long",
8: "Exec format error",
9: "Bad file number",
10: "No children",
11: "No more processes",
12: "Not enough core",
13: "Permission denied",
14: "Bad address",
15: "Block device required",
16: "Mount device busy",
17: "File exists",
18: "Cross-device link",
19: "No such device",
20: "Not a directory",
21: "Is a directory",
22: "Invalid argument",
23: "Too many open files in system",
24: "Too many open files",
25: "Not a typewriter",
26: "Text file busy",
27: "File too large",
28: "No space left on device",
29: "Illegal seek",
30: "Read only file system",
31: "Too many links",
32: "Broken pipe",
33: "Math arg out of domain of func",
34: "Math result not representable",
35: "File locking deadlock error",
36: "File or path name too long",
37: "No record locks available",
38: "Function not implemented",
39: "Directory not empty",
40: "Too many symbolic links",
42: "No message of desired type",
43: "Identifier removed",
44: "Channel number out of range",
45: "Level 2 not synchronized",
46: "Level 3 halted",
47: "Level 3 reset",
48: "Link number out of range",
49: "Protocol driver not attached",
50: "No CSI structure available",
51: "Level 2 halted",
52: "Invalid exchange",
53: "Invalid request descriptor",
54: "Exchange full",
55: "No anode",
56: "Invalid request code",
57: "Invalid slot",
59: "Bad font file fmt",
60: "Device not a stream",
61: "No data (for no delay io)",
62: "Timer expired",
63: "Out of streams resources",
64: "Machine is not on the network",
65: "Package not installed",
66: "The object is remote",
67: "The link has been severed",
68: "Advertise error",
69: "Srmount error",
70: "Communication error on send",
71: "Protocol error",
72: "Multihop attempted",
73: "Cross mount point (not really error)",
74: "Trying to read unreadable message",
75: "Value too large for defined data type",
76: "Given log. name not unique",
77: "f.d. invalid for this operation",
78: "Remote address changed",
79: "Can access a needed shared lib",
80: "Accessing a corrupted shared lib",
81: ".lib section in a.out corrupted",
82: "Attempting to link in too many libs",
83: "Attempting to exec a shared library",
84: "Illegal byte sequence",
86: "Streams pipe error",
87: "Too many users",
88: "Socket operation on non-socket",
89: "Destination address required",
90: "Message too long",
91: "Protocol wrong type for socket",
92: "Protocol not available",
93: "Unknown protocol",
94: "Socket type not supported",
95: "Not supported",
96: "Protocol family not supported",
97: "Address family not supported by protocol family",
98: "Address already in use",
99: "Address not available",
100: "Network interface is not configured",
101: "Network is unreachable",
102: "Connection reset by network",
103: "Connection aborted",
104: "Connection reset by peer",
105: "No buffer space available",
106: "Socket is already connected",
107: "Socket is not connected",
108: "Can't send after socket shutdown",
109: "Too many references",
110: "Connection timed out",
111: "Connection refused",
112: "Host is down",
113: "Host is unreachable",
114: "Socket already connected",
115: "Connection already in progress",
116: "Stale file handle",
122: "Quota exceeded",
123: "No medium (in tape drive)",
125: "Operation canceled",
130: "Previous owner died",
131: "State not recoverable"
}[-errno] || "Unknown error";
}
function parseDuration(d) {
if (typeof d == "number") {
if (isNaN(d) || d < 0)
throw new Error(`Invalid duration: "${d}".`);
return d;
} else if (/\d+s/.test(d)) {
return +d.slice(0, -1) * 1e3;
} else if (/\d+ms/.test(d)) {
return +d.slice(0, -2);
} else if (/\d+m/.test(d)) {
return +d.slice(0, -1) * 1e3 * 60;
}
throw new Error(`Unknown duration: "${d}".`);
}
function formatCmd(cmd) {
if (cmd == void 0)
return chalk.grey("undefined");
const chars = [...cmd];
let out = "$ ";
let buf = "";
let ch;
let state = root;
let wordCount = 0;
while (state) {
ch = chars.shift() || "EOF";
if (ch == "\n") {
out += style(state, buf) + "\n> ";
buf = "";
continue;
}
const next = ch == "EOF" ? void 0 : state();
if (next != state) {
out += style(state, buf);
buf = "";
}
state = next == root ? next() : next;
buf += ch;
}
function style(state2, s) {
if (s == "")
return "";
if (reservedWords.includes(s)) {
return chalk.cyanBright(s);
}
if (state2 == word && wordCount == 0) {
wordCount++;
return chalk.greenBright(s);
}
if (state2 == syntax) {
wordCount = 0;
return chalk.cyanBright(s);
}
if (state2 == dollar)
return chalk.yellowBright(s);
if (state2?.name.startsWith("str"))
return chalk.yellowBright(s);
return s;
}
function isSyntax(ch2) {
return "()[]{}<>;:+|&=".includes(ch2);
}
function root() {
if (/\s/.test(ch))
return space;
if (isSyntax(ch))
return syntax;
if (/[$]/.test(ch))
return dollar;
if (/["]/.test(ch))
return strDouble;
if (/[']/.test(ch))
return strSingle;
return word;
}
function space() {
if (/\s/.test(ch))
return space;
return root;
}
function word() {
if (/[0-9a-z/_.]/i.test(ch))
return word;
return root;
}
function syntax() {
if (isSyntax(ch))
return syntax;
return root;
}
function dollar() {
if (/[']/.test(ch))
return str;
return root;
}
function str() {
if (/[']/.test(ch))
return strEnd;
if (/[\\]/.test(ch))
return strBackslash;
return str;
}
function strBackslash() {
return strEscape;
}
function strEscape() {
return str;
}
function strDouble() {
if (/["]/.test(ch))
return strEnd;
return strDouble;
}
function strSingle() {
if (/[']/.test(ch))
return strEnd;
return strSingle;
}
function strEnd() {
return root;
}
return out + "\n";
}
var reservedWords = [
"if",
"then",
"else",
"elif",
"fi",
"case",
"esac",
"for",
"select",
"while",
"until",
"do",
"done",
"in"
];
function getCallerLocation(err = new Error()) {
return getCallerLocationFromString(err.stack);
}
function getCallerLocationFromString(stackString = "unknown") {
return stackString.split(/^\s*(at\s)?/m).filter((s) => s?.includes(":"))[2]?.trim() || stackString;
}
"use strict";
import './deno.js'
const {
errnoMessage,
exitCodeInfo,
formatCmd,
getCallerLocation,
getCallerLocationFromString,
isString,
noop,
noquote,
normalizeMultilinePieces,
parseDuration,
quote,
quotePowerShell,
randomId,
tempdir,
tempfile
} = await import('./util.cjs')
export {

@@ -354,3 +33,6 @@ errnoMessage,

quotePowerShell,
randomId
};
randomId,
tempdir,
tempfile
}

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

// Generated by dts-bundle-generator v9.3.1
// Generated by dts-bundle-generator v9.5.1
/// <reference types="node" />
import { parseLine } from '@webpod/ingrid';
import * as fs from 'fs';

@@ -10,2 +9,3 @@ import * as cp from 'node:child_process';

import { Readable, Stream, Writable } from 'node:stream';
import { URL as URL$1 } from 'node:url';

@@ -694,2 +694,11 @@ declare type ErrnoException = NodeJS.ErrnoException;

}
type TLineDigest = {
spaces: number[];
words: {
s: number;
e: number;
w: string;
}[];
};
export declare const parseLine: (line: string, sep?: string) => TLineDigest;
type TPsLookupCallback = (err: any, processList?: TPsLookupEntry[]) => void;

@@ -723,2 +732,3 @@ type TPsLookupEntry = {

};
export declare const createRequire: (filename: string | URL$1) => NodeRequire;
export type RequestInfo = Parameters<typeof fetch$1>[0];

@@ -760,5 +770,4 @@ type RequestInit$1 = Parameters<typeof fetch$1>[1];

fs$1 as fs,
parseLine,
};
export {};
{
"name": "zx",
"version": "8.0.2",
"version": "8.1.0",
"description": "A tool for writing better scripts",

@@ -25,6 +25,26 @@ "type": "module",

"exports": {
".": "./build/index.js",
"./globals": "./build/globals.js",
"./cli": "./build/cli.js",
"./core": "./build/core.js",
".": {
"import": "./build/index.js",
"require": "./build/index.cjs",
"types": "./build/index.d.ts",
"default": "./build/index.js"
},
"./globals": {
"import": "./build/globals.js",
"require": "./build/globals.cjs",
"types": "./build/globals.d.ts",
"default": "./build/globals.js"
},
"./cli": {
"import": "./build/cli.js",
"require": "./build/cli.cjs",
"types": "./build/cli.d.ts",
"default": "./build/cli.js"
},
"./core": {
"import": "./build/core.js",
"require": "./build/core.cjs",
"types": "./build/core.d.ts",
"default": "./build/core.js"
},
"./package.json": "./package.json"

@@ -35,4 +55,9 @@ },

},
"man": "./man/zx.1",
"files": [
"build",
"man"
],
"engines": {
"node": ">= 16.0.0"
"node": ">= 12.17.0"
},

@@ -44,12 +69,20 @@ "scripts": {

"build:check": "tsc",
"build:js": "node scripts/build-js.mjs --format=esm --entry=src/*.ts && npm run build:vendor",
"build:vendor": "node scripts/build-js.mjs --format=esm --entry=src/vendor.ts --bundle=all --banner",
"build:js": "node scripts/build-js.mjs --format=cjs --hybrid --entry=src/*.ts && npm run build:vendor",
"build:vendor": "node scripts/build-js.mjs --format=cjs --entry=src/vendor.ts --bundle=all",
"build:dts": "tsc --project tsconfig.prod.json && node scripts/build-dts.mjs",
"test": "npm run build && npm run test:unit && npm run test:types",
"pretest": "npm run build",
"test": "npm run test:unit && npm run test:types && npm run test:license",
"test:unit": "node ./test/all.test.js",
"test:circular": "madge --circular src/*",
"test:types": "tsd",
"test:license": "node ./test/extra.test.js",
"test:smoke:tsx": "tsx test/smoke/ts.test.ts",
"test:smoke:tsc": "cd test/smoke && mkdir -p node_modules && ln -s ../../../ ./node_modules/zx; tsc --esModuleInterop --module node16 --rootDir . --outdir ./temp ts.test.ts && node ./temp/ts.test.js",
"test:smoke:ts-node": "node --loader ts-node/esm test/smoke/ts.test.ts",
"test:smoke:bun": "bun test ./test/smoke/bun.test.js",
"test:smoke:win32": "node ./test/smoke/win32.test.js",
"coverage": "c8 -x build/vendor.js -x 'test/**' -x scripts --check-coverage npm test",
"circular": "madge --circular src/*",
"test:smoke:cjs": "node ./test/smoke/node.test.cjs",
"test:smoke:mjs": "node ./test/smoke/node.test.mjs",
"test:smoke:deno": "deno test ./test/smoke/deno.test.js --allow-read --allow-sys --allow-env --allow-run",
"coverage": "c8 -x build/deno.js -x build/vendor.cjs -x build/esblib.cjs -x 'test/**' -x scripts --check-coverage npm test",
"version": "cat package.json | fx .version"

@@ -59,3 +92,3 @@ },

"@types/fs-extra": "^11.0.4",
"@types/node": ">=20.12.5"
"@types/node": ">=20.12.11"
},

@@ -67,23 +100,31 @@ "devDependencies": {

"@types/which": "^3.0.3",
"@webpod/ingrid": "^0.0.0-beta.3",
"@webpod/ps": "^0.0.0-beta.3",
"@webpod/ingrid": "^0.0.0-beta.3",
"c8": "^9.1.0",
"chalk": "^5.3.0",
"create-require": "^1.1.1",
"depseek": "^0.4.1",
"dts-bundle-generator": "^9.3.1",
"esbuild": "^0.20.2",
"esbuild-node-externals": "^1.13.0",
"esbuild-plugin-entry-chunks": "^0.1.12",
"dts-bundle-generator": "^9.5.1",
"esbuild": "^0.21.1",
"esbuild-node-externals": "^1.13.1",
"esbuild-plugin-entry-chunks": "^0.1.14",
"esbuild-plugin-extract-helpers": "^0.0.5",
"esbuild-plugin-hybrid-export": "^0.2.3",
"esbuild-plugin-transform-hook": "^0.0.3",
"esbuild-plugin-utils": "^0.0.1",
"fs-extra": "^11.2.0",
"fx": "*",
"globby": "^14.0.1",
"madge": "^6.1.0",
"madge": "^7.0.0",
"minimist": "^1.2.8",
"node-abort-controller": "^3.1.1",
"node-fetch-native": "^1.6.4",
"prettier": "^3.2.5",
"ts-node": "^10.9.2",
"tsd": "^0.31.0",
"typescript": "^5.4.4",
"tsx": "^4.9.4",
"typescript": "^5.4.5",
"which": "^4.0.0",
"yaml": "^2.4.1",
"zurk": "^0.1.2"
"yaml": "^2.4.2",
"zurk": "^0.1.4"
},

@@ -93,5 +134,15 @@ "publishConfig": {

},
"files": [
"build",
"zx.js"
"keywords": [
"shell",
"script",
"bash",
"bin",
"binary",
"child",
"process",
"exec",
"execute",
"invoke",
"call",
"spawn"
],

@@ -98,0 +149,0 @@ "prettier": {

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc