jog — also known as a leisurely paced run — is a simplified API for running sub-processes in TypeScript for Deno, implemented as a thin wrapper around
Deno.run
.
Using the native Deno function Deno.run
can be tedious, as we must correctly
configure the IO streams and remember to cleanup resources. In jog access to
stdout
, stdin
, and stderr
, as well as resource management is abstracted
away. Instead, the data for stdin
can be specified once as a buffer, the data
from stdout
is returned asynchronously as a buffer or mapped to a custom type,
and stderr
is thrown as an error message if the process terminates
unsuccessfully. The following table summarizes the differences between the
native Deno API and jog:
Deno.run |
jog.run |
---|---|
cmd / cwd / env |
same |
stdin |
Uint8Array / string |
stdout / output / status |
Promise<Uint8Array> |
stderr / stderrOutput |
try -catch |
The mod.ts module exports all other modules.
The run
function starts a sub-process and returns its result asynchronously.
The required cmd
and optional cwd
and env
options work exactly like their
Deno.run
counterparts. The examples assume that the mockcli.ts module is
installed as mockcli
on the command line. This example demonstrates how run
can be used to get data from stdout
:
import { Run, run } from "https://deno.land/x/jog/run.ts";
// Define a process.
const command: Run = {
cmd: ["mockcli", "answer"],
};
// Run the process.
const buffer: Uint8Array = await run(command);
// print: "42\n"
Deno.stdout.write(buffer);
Data for stdin
can be specified with the input
option, either as a string
or as a Uint8Array
:
import { run } from "https://deno.land/x/jog/run.ts";
const buffer = await run({
cmd: ["mockcli", "echo"],
input: "let's jog!",
});
// print: "let's jog!"
Deno.stdout.write(buffer);
If the process exits with an error, an Error
is thrown and the contents of
stderr
are used as the error message:
import { run } from "https://deno.land/x/jog/run.ts";
try {
await run({
cmd: ["mockcli", "fail"],
input: "oh no!",
});
} catch (error) {
// print: "oh no!"
console.log(error.message);
}
The out
function extends the run
API with an asynchronous mapping function
that is applied to the stdout
buffer. For example, instead of the buffer
itself, one could return its length:
import { Out, out } from "https://deno.land/x/jog/out.ts";
// Define a process with output mapping.
const command: Out<number> = {
cmd: ["mockcli", "answer"],
map: async (x: Promise<Uint8Array>) => (await x).length,
};
// Run the process.
const length: number = await out(command);
// print: 3 (buffer contains "42\n")
console.log(length);
The functions getLines
, getLinesNonEmpty
, getFirst
, and getSuccess
are
common mappings that can be used with the out
function. For example,
getSuccess
can be used to check whether a process succeeds:
import { out } from "https://deno.land/x/jog/out.ts";
import { getSuccess } from "https://deno.land/x/jog/map.ts";
const worked = await out({
cmd: ["mockcli", "fail"],
input: "oh no!",
map: getSuccess,
});
// print: false
console.log(worked);
Custom mapping functions can be defined with the map
and mapAsync
convenience functions. The pipe
function can be used for chaining two mapping
functions. In this example, out
returns the first line of stdout
in
uppercase letters:
import { out } from "https://deno.land/x/jog/out.ts";
import { getFirst, getLines, map, pipe } from "https://deno.land/x/jog/map.ts";
const result = await out({
cmd: ["mockcli", "echo"],
input: "first\nsecond",
map: pipe(
pipe(getLines, getFirst),
map((x) => x.toUpperCase()),
),
});
// print: "FIRST"
console.log(result);
Now, jog home.