Skip to content

Commit

Permalink
refactor: use cliffy for command line interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
c4spar committed May 11, 2021
1 parent 9daafd2 commit 51c234b
Show file tree
Hide file tree
Showing 14 changed files with 211 additions and 123 deletions.
60 changes: 7 additions & 53 deletions dzx.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,12 @@
/// <reference path="./types.d.ts" />
import { $, io, path } from "./mod.ts";
import { bundle } from "./src/bundle.ts";
import { compile } from "./src/compile.ts";
import { error } from "./src/_utils.ts";

if (import.meta.main) {
if (Deno.args[0] === "bundle") {
const script = Deno.args[Deno.args.length - 1];
console.log(
await bundle(script, new URL("./mod.ts", import.meta.url).href),
);
Deno.exit(0);
} else if (Deno.args[0] === "compile") {
const args = [...Deno.args];
args.shift();
const script = args.pop();
if (!script) {
throw error(`usage: dzx compile <script>`);
}
await compile(
script,
args,
new URL("./mod.ts", import.meta.url).href,
);
Deno.exit(0);
}
import { dzx } from "./src/cli/mod.ts";

const script = Deno.args[Deno.args.length - 1];

try {
if (!script) {
if (!Deno.isatty(Deno.stdin.rid)) {
const data = new TextDecoder().decode(await io.readAll(Deno.stdin));
if (data) {
await import(
`data:application/typescript,${encodeURIComponent(data)}`
);
} else {
error(`usage: dzx <script>`, 2);
}
} else {
error(`usage: dzx <script>`);
}
} else if (
script.startsWith("http://") || script.startsWith("https://") ||
script.startsWith("file://")
) {
await import(script);
} else if (script) {
await import("file://" + path.join($.cwd, script));
} else {
error(`usage: dzx <script>`);
}
} catch (err) {
error(err);
if (import.meta.main) {
const start = performance.now();
await dzx().parse(Deno.args);
if ($.verbose) {
const end = performance.now();
console.log($.bold("time: %ss"), Math.round(end - start) / 1000);
}
}
38 changes: 1 addition & 37 deletions mod.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1 @@
import { colors, flags, fs, io, log, path, shq } from "./deps.ts";
import { cd } from "./src/cd.ts";
import { exec } from "./src/exec.ts";
import { quote } from "./src/quote.ts";

export type $ = typeof exec & typeof colors & {
verbose: boolean;
cwd: string;
shell: string;
quote: typeof shq;
throwErors: boolean;
};

export const $: $ = exec as $;

Object.setPrototypeOf($, Object.getPrototypeOf(colors));

$._stack = [];
$.shell = "/bin/sh";
$.verbose = false;
$.cwd = Deno.cwd();
$.quote = shq;
$.throwErors = false;

// dzx
window.$ = $;
window.cd = cd;
window.quote = quote;

// x
window.path = path;
window.io = io;
window.fs = fs;
window.log = log;
window.flags = flags;

export { cd, flags, fs, io, log, path, quote };
export * from "./src/runtime/mod.ts";
34 changes: 29 additions & 5 deletions src/bundle.ts → src/cli/bundle.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,37 @@
import { error } from "./_utils.ts";
import { Command, ValidationError } from "./deps.ts";
import { error } from "../_utils.ts";
import { fs, path } from "../../mod.ts";

export function bundleCommand() {
return new Command<void>()
.description("Bundle an dzx script to a standalone deno sript.")
.arguments("[script:string]")
.option<{ check: boolean }>("--no-check", "Skip type checking modules.")
.action(async ({ check }, script?: string) => {
if (!script) {
if (Deno.isatty(Deno.stdin.rid)) {
throw new ValidationError(`Missing argument(s): script`);
}
script = await Deno.makeTempFile({ suffix: ".ts" });
const tmpFile = await Deno.open(script, { write: true });
await Deno.copy(Deno.stdin, tmpFile);
tmpFile.close();
}
console.log("Deno.mainModule:", Deno.mainModule);
console.log(
await bundle(script, {
check,
}),
);
});
}

export async function bundle(
script: string,
dzxModuleUrl: string,
options: Deno.EmitOptions = {},
): Promise<string> {
const { shebang, tmpFile } = await prepareBundle(
script,
dzxModuleUrl,
options,
);

Expand All @@ -24,7 +48,6 @@ export async function bundle(

export async function prepareBundle(
script: string,
dzxModuleUrl: string,
options: Deno.EmitOptions = {},
): Promise<{ shebang: string; tmpFile: string }> {
if (!await fs.exists(script)) {
Expand All @@ -42,7 +65,8 @@ export async function prepareBundle(
check: true,
...options,
});
const bundleContent = `import "${dzxModuleUrl}";\n` +
const bundleContent =
`import "${new URL("./mod.ts", Deno.mainModule).href}";\n` +
Object.values(scriptResult.files)[0] as string;

const tmpDir = await Deno.makeTempDir();
Expand Down
78 changes: 78 additions & 0 deletions src/cli/compile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { prepareBundle } from "./bundle.ts";
import { error } from "../_utils.ts";
import { Command, ValidationError } from "./deps.ts";

export function compileCommand() {
return new Command<void>()
.description("Combile an dzx script to a standalone binary.")
.arguments("[script:string] [compile-options...:string[]]")
.option("-A, --allow-all", "Allow all permissions.")
.option("--allow-env [allow-env:string]", "Allow environment access.")
.option("--allow-hrtime", "Allow high resolution time measurement.")
.option("--allow-net [allow-net:string]", "Allow network access.")
.option("--allow-plugin", "Allow loading plugins.")
.option(
"--allow-read [allow-read:string]",
"Allow file system read access.",
)
.option(
"--allow-run [allow-run:string]",
"Allow running subprocesses.",
)
.option(
"--allow-write [allow-write:string]",
"Allow file system write access.",
)
.option("--no-check", "Skip type checking modules.")
.option("--lite", "Use lite deno runtime.")
.option("--unstable", "Enable unstable features and APIs of Deno.")
.useRawArgs()
.action(
async function (_: void, script?: string, ...args: Array<string>) {
if (script && args[0]?.[0] === "-") {
args = [script, ...args];
script = args.pop();
}
if (!script) {
if (Deno.isatty(Deno.stdin.rid)) {
throw new ValidationError(`Missing argument(s): script`);
}
script = await Deno.makeTempFile();
const tmpFile = await Deno.open(script);
await Deno.copy(Deno.stdin, tmpFile);
}
if (["-h", "--help"].includes(script)) {
this.showHelp();
} else {
await compile(
script,
args,
);
}
},
);
}

export async function compile(
script: string,
args: Array<string>,
): Promise<void> {
const { tmpFile } = await prepareBundle(script);

const p = Deno.run({
cmd: [
"deno",
"compile",
"--no-check",
...args.filter((arg) => arg !== "--no-check"),
tmpFile,
],
});

const { success } = await p.status();
p.close();

if (!success) {
error(`Failed to compile: ${script}`);
}
}
6 changes: 6 additions & 0 deletions src/cli/deps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export {
Command,
CompletionsCommand,
HelpCommand,
ValidationError,
} from "https://deno.land/x/cliffy@v0.18.2/command/mod.ts";
52 changes: 52 additions & 0 deletions src/cli/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { io, path } from "../../mod.ts";
import { bundleCommand } from "./bundle.ts";
import { compileCommand } from "./compile.ts";
import {
Command,
CompletionsCommand,
HelpCommand,
ValidationError,
} from "./deps.ts";

export function dzx() {
return new Command<void>()
.version("0.2.0")
.name("dzx")
.description("🦕 A custom deno runtime for writing quickly scripts.")
.stopEarly()
.arguments<[script?: string, args?: Array<string>]>(
"[script:string] [args...:string[]]",
)
.action(async (_, script?: string, _args?: Array<string>) => {
if (!script) {
if (!Deno.isatty(Deno.stdin.rid)) {
const data = new TextDecoder().decode(await io.readAll(Deno.stdin));
if (data) {
await import(
`data:application/typescript,${encodeURIComponent(data)}`
);
} else {
// @TODO: add support for exit code in ValidationError
// throw new ValidationError(`Failed to read from stdin.`, 2);
throw new ValidationError(`Failed to read from stdin.`);
}
} else {
throw new ValidationError(`Missing argument(s): script`);
}
} else if (
script.startsWith("http://") || script.startsWith("https://") ||
script.startsWith("file://")
) {
await import(script);
} else {
await import(
"file://" +
(path.isAbsolute(script) ? script : path.join(Deno.cwd(), script))
);
}
})
.command("bundle", bundleCommand())
.command("compile", compileCommand())
.command("help", new HelpCommand().global())
.command("completions", new CompletionsCommand());
}
27 changes: 0 additions & 27 deletions src/compile.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/cd.ts → src/runtime/cd.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { error } from "./_utils.ts";
import { error } from "../_utils.ts";

export function cd(path: string) {
if ($.verbose) {
Expand Down
File renamed without changes.
File renamed without changes.
37 changes: 37 additions & 0 deletions src/runtime/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { colors, flags, fs, io, log, path, shq } from "./deps.ts";
import { cd } from "./cd.ts";
import { exec } from "./exec.ts";
import { quote } from "./quote.ts";

export type $ = typeof exec & typeof colors & {
verbose: boolean;
cwd: string;
shell: string;
quote: typeof shq;
throwErors: boolean;
};

export const $: $ = exec as $;

Object.setPrototypeOf($, Object.getPrototypeOf(colors));

$._stack = [];
$.shell = "/bin/sh";
$.verbose = false;
$.cwd = Deno.cwd();
$.quote = shq;
$.throwErors = false;

// dzx
window.$ = $;
window.cd = cd;
window.quote = quote;

// x
window.path = path;
window.io = io;
window.fs = fs;
window.log = log;
window.flags = flags;

export { cd, flags, fs, io, log, path, quote };
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 51c234b

Please sign in to comment.