zx
Version:
A tool for writing better scripts
346 lines (336 loc) • 11.9 kB
JavaScript
;
const {
__export,
__toESM,
__toCommonJS,
__async
} = require('./esblib.cjs');
const import_meta_url =
typeof document === 'undefined'
? new (require('url').URL)('file:' + __filename).href
: (document.currentScript && document.currentScript.src) ||
new URL('main.js', document.baseURI).href
// src/cli.ts
var cli_exports = {};
__export(cli_exports, {
argv: () => argv,
injectGlobalRequire: () => injectGlobalRequire,
isMain: () => isMain,
main: () => main,
normalizeExt: () => normalizeExt,
printUsage: () => printUsage,
transformMarkdown: () => transformMarkdown
});
module.exports = __toCommonJS(cli_exports);
var import_node_url = __toESM(require("url"), 1);
var import_index = require("./index.cjs");
var import_deps = require("./deps.cjs");
// src/repl.ts
var import_node_os = __toESM(require("os"), 1);
var import_node_path = __toESM(require("path"), 1);
var import_node_repl = __toESM(require("repl"), 1);
var import_node_util = require("util");
var import_core = require("./core.cjs");
var import_vendor_core = require("./vendor-core.cjs");
var import_node_process = __toESM(require("process"), 1);
var _a;
var HISTORY = (_a = import_node_process.default.env.ZX_REPL_HISTORY) != null ? _a : import_node_path.default.join(import_node_os.default.homedir(), ".zx_repl_history");
function startRepl() {
return __async(this, arguments, function* (history = HISTORY) {
import_core.defaults.verbose = false;
const r = import_node_repl.default.start({
prompt: import_vendor_core.chalk.greenBright.bold("\u276F "),
useGlobal: true,
preview: false,
writer(output) {
return output instanceof import_core.ProcessOutput ? output.toString().trimEnd() : (0, import_node_util.inspect)(output, { colors: true });
}
});
r.setupHistory(history, () => {
});
});
}
// src/cli.ts
var import_util2 = require("./util.cjs");
// src/md.ts
var import_util = require("./util.cjs");
function transformMarkdown(buf) {
var _a2;
const output = [];
const tabRe = /^( +|\t)/;
const codeBlockRe = new RegExp("^(?<fence>(`{3,20}|~{3,20}))(?:(?<js>(js|javascript|ts|typescript))|(?<bash>(sh|shell|bash))|.*)$");
let state = "root";
let codeBlockEnd = "";
let prevLineIsEmpty = true;
for (const line of (0, import_util.bufToString)(buf).split(/\r?\n/)) {
switch (state) {
case "root":
if (tabRe.test(line) && prevLineIsEmpty) {
output.push(line);
state = "tab";
continue;
}
const { fence, js, bash } = ((_a2 = line.match(codeBlockRe)) == null ? void 0 : _a2.groups) || {};
if (!fence) {
prevLineIsEmpty = line === "";
output.push("// " + line);
continue;
}
codeBlockEnd = fence;
if (js) {
state = "js";
output.push("");
} else if (bash) {
state = "bash";
output.push("await $`");
} else {
state = "other";
output.push("");
}
break;
case "tab":
if (line === "") {
output.push("");
} else if (tabRe.test(line)) {
output.push(line);
} 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");
}
// src/cli.ts
var import_vendor = require("./vendor.cjs");
var import_node_process2 = __toESM(require("process"), 1);
var import_meta = {};
var EXT = ".mjs";
var EXT_RE = /^\.[mc]?[jt]sx?$/;
var argv = (0, import_index.parseArgv)(import_node_process2.default.argv.slice(2), {
default: (0, import_index.resolveDefaults)({ ["prefer-local"]: false }, "ZX_", import_node_process2.default.env, /* @__PURE__ */ new Set(["env", "install", "registry"])),
// exclude 'prefer-local' to let minimist infer the type
string: ["shell", "prefix", "postfix", "eval", "cwd", "ext", "registry", "env"],
boolean: ["version", "help", "quiet", "verbose", "install", "repl", "experimental"],
alias: { e: "eval", i: "install", v: "version", h: "help", l: "prefer-local", "env-file": "env" },
stopEarly: true,
parseBoolean: true,
camelCase: true
});
isMain() && main().catch((err) => {
if (err instanceof import_index.ProcessOutput) {
console.error("Error:", err.message);
} else {
console.error(err);
}
import_node_process2.default.exitCode = 1;
});
function printUsage() {
console.log(`
${import_index.chalk.bold("zx " + import_index.VERSION)}
A tool for writing better scripts
${import_index.chalk.bold("Usage")}
zx [options] <script>
${import_index.chalk.bold("Options")}
--quiet suppress any outputs
--verbose enable verbose mode
--shell=<path> custom shell binary
--prefix=<command> prefix all commands
--postfix=<command> postfix all commands
--prefer-local, -l prefer locally installed packages and binaries
--cwd=<path> set current directory
--eval=<js>, -e evaluate script
--ext=<.mjs> script extension
--install, -i install dependencies
--registry=<URL> npm registry, defaults to https://registry.npmjs.org/
--version, -v print current zx version
--help, -h print help
--repl start repl
--env=<path> path to env file
--experimental enables experimental features (deprecated)
${import_index.chalk.italic("Full documentation:")} ${import_index.chalk.underline("https://google.github.io/zx/")}
`);
}
function main() {
return __async(this, null, function* () {
var _a2;
if (argv.version) {
console.log(import_index.VERSION);
return;
}
if (argv.help) {
printUsage();
return;
}
if (argv.cwd) import_index.$.cwd = argv.cwd;
if (argv.env) {
const envfile = import_index.path.resolve((_a2 = import_index.$.cwd) != null ? _a2 : import_node_process2.default.cwd(), argv.env);
import_index.dotenv.config(envfile);
(0, import_index.resolveDefaults)();
}
if (argv.verbose) import_index.$.verbose = true;
if (argv.quiet) import_index.$.quiet = true;
if (argv.shell) import_index.$.shell = argv.shell;
if (argv.prefix) import_index.$.prefix = argv.prefix;
if (argv.postfix) import_index.$.postfix = argv.postfix;
if (argv.preferLocal) import_index.$.preferLocal = argv.preferLocal;
yield require("./globals.cjs");
if (argv.repl) {
yield startRepl();
return;
}
argv.ext = normalizeExt(argv.ext);
const { script, scriptPath, tempPath } = yield readScript();
yield runScript(script, scriptPath, tempPath);
});
}
function runScript(script, scriptPath, tempPath) {
return __async(this, null, function* () {
let nmLink = "";
const rmTemp = () => {
import_index.fs.rmSync(tempPath, { force: true, recursive: true });
nmLink && import_index.fs.rmSync(nmLink, { force: true, recursive: true });
};
try {
if (tempPath) {
scriptPath = tempPath;
yield import_index.fs.writeFile(tempPath, script);
}
const cwd = import_index.path.dirname(scriptPath);
if (typeof argv.preferLocal === "string") {
nmLink = linkNodeModules(cwd, argv.preferLocal);
}
if (argv.install) {
yield (0, import_deps.installDeps)((0, import_deps.parseDeps)(script), cwd, argv.registry);
}
injectGlobalRequire(scriptPath);
import_node_process2.default.once("exit", rmTemp);
yield import(import_node_url.default.pathToFileURL(scriptPath).toString());
} finally {
rmTemp();
}
});
}
function linkNodeModules(cwd, external) {
const nm = "node_modules";
const alias = import_index.path.resolve(cwd, nm);
const target = import_index.path.basename(external) === nm ? import_index.path.resolve(external) : import_index.path.resolve(external, nm);
if (import_index.fs.existsSync(alias) || !import_index.fs.existsSync(target)) return "";
import_index.fs.symlinkSync(target, alias, "junction");
return target;
}
function readScript() {
return __async(this, null, function* () {
const [firstArg] = argv._;
let script = "";
let scriptPath = "";
let tempPath = "";
let argSlice = 1;
if (argv.eval) {
argSlice = 0;
script = argv.eval;
tempPath = getFilepath(import_index.$.cwd, "zx", argv.ext);
} else if (!firstArg || firstArg === "-") {
script = yield readScriptFromStdin();
tempPath = getFilepath(import_index.$.cwd, "zx", argv.ext);
if (script.length === 0) {
printUsage();
import_node_process2.default.exitCode = 1;
throw new Error("No script provided");
}
} else if (/^https?:/.test(firstArg)) {
const { name, ext: ext2 = argv.ext } = import_index.path.parse(new URL(firstArg).pathname);
script = yield readScriptFromHttp(firstArg);
tempPath = getFilepath(import_index.$.cwd, name, ext2);
} else {
script = yield import_index.fs.readFile(firstArg, "utf8");
scriptPath = firstArg.startsWith("file:") ? import_node_url.default.fileURLToPath(firstArg) : import_index.path.resolve(firstArg);
}
const { ext, base, dir } = import_index.path.parse(tempPath || scriptPath);
if (ext === "" || argv.ext && !EXT_RE.test(ext)) {
tempPath = getFilepath(dir, base);
}
if (ext === ".md") {
script = transformMarkdown(script);
tempPath = getFilepath(dir, base);
}
if (argSlice) (0, import_index.updateArgv)(argv._.slice(argSlice));
return { script, scriptPath, tempPath };
});
}
function readScriptFromStdin() {
return __async(this, null, function* () {
return !import_node_process2.default.stdin.isTTY ? (0, import_index.stdin)() : "";
});
}
function readScriptFromHttp(remote) {
return __async(this, null, function* () {
const res = yield (0, import_index.fetch)(remote);
if (!res.ok) {
console.error(`Error: Can't get ${remote}`);
import_node_process2.default.exit(1);
}
return res.text();
});
}
function injectGlobalRequire(origin) {
const __filename = import_index.path.resolve(origin);
const __dirname = import_index.path.dirname(__filename);
const require2 = (0, import_vendor.createRequire)(origin);
Object.assign(globalThis, { __filename, __dirname, require: require2 });
}
function isMain(metaurl = import_meta_url, scriptpath = import_node_process2.default.argv[1]) {
if (metaurl.startsWith("file:")) {
const modulePath = import_node_url.default.fileURLToPath(metaurl).replace(/\.\w+$/, "");
const mainPath = import_index.fs.realpathSync(scriptpath).replace(/\.\w+$/, "");
return mainPath === modulePath;
}
return false;
}
function normalizeExt(ext) {
return ext ? import_index.path.parse(`foo.${ext}`).ext : ext;
}
function getFilepath(cwd = ".", name = "zx", _ext) {
const ext = _ext || argv.ext || EXT;
return [
name + ext,
name + "-" + (0, import_util2.randomId)() + ext
].map((f) => import_index.path.resolve(import_node_process2.default.cwd(), cwd, f)).find((f) => !import_index.fs.existsSync(f));
}
/* c8 ignore next 100 */
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
argv,
injectGlobalRequire,
isMain,
main,
normalizeExt,
printUsage,
transformMarkdown
});