0.0.1 • Published 2 years ago

easy-command-runner v0.0.1

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

Easy Command Runner

This is the way you've always wanted to run shell commands in nodejs.

This library is currently under active development so there may be breaking changes in the API, especially around how stdin, stdout and stderr are handled.

import { cmd } from "easy-command-runner";

const fileNames = await cmd("ls").pipe("grep", "src").get();

await cmd.file("data.txt").pipe("grep", "fruit").toFile("output.txt");

await cmd({ cmd: ["yarn", "build"], cwd: "src" });

await cmd
  .text("hi")
  .pipe("sed", "p;p;p")
  .pipe("sed", "s/$/ there/")
  .toFile("four-greetings.txt");

Overview

This library is a lightweight wrapper around the child_process library that makes it easy to run commands.

With default support for promises and many different input-output types, this library can support the most demanding process workloads while being efforless to use.

Documentation

There are two parts to a command: the executable and arguments. Each argument in this library is passed in as a separate string. While this makes commands a little harder to type, it makes development much easier because you don't need to worry about string escaping or special characters.

// Even though the second argument has a bunch of special
// characters, it will be interpreted as a string literal.
// This prevents a whole class of security vulnerabilities.
await cmd("echo", "$ENV_VAR && ls > some.txt").run();

// prints out "$ENV_VAR && ls > some.txt"

To make up for the lack of special operators like the pipe operator, there are first-class primitives for combining commands and files together.

// Use the .pipe() method to call a command on the output
// of the previous command
let specialLines = await cmd("node", "generate_data.js")
  .pipe("grep", "special.*txt")
  .get();

There is first-class support for reading and writing files.

await cmd.file("food.txt").pipe("grep", "fruit").toFile("fruits.txt");

You can pipe on string literals to easily get data into processes.

let images = await fetch_text("https://example.com/images_urls.txt");
await cmd
  .text(images)
  .pipe("grep", "fruit.*\\.png")
  .toFile("fruit_image_urls.txt");

Error Handling

All command errors are wrapped in the CmdError class which captures relevant details in a single object.

import { cmd, CmdError } from "easy-command-runner";

try {
  await cmd("command-that-fails").run();
} catch (err: unknown) {
  if (err instanceof CmdError) {
    console.log(`Failed with code=${err.code} and stderr=${err.stderr}`);
  }
}

By combining these primitives in different ways alongside built-in concurrency helpers like Promise.all(), easy-command-runner makes it easy to run commands.

Contributing

This library is still in early development so if you find an error, please submit an issue on github. Existing code is pretty well tested and new tests can be easily added when bugs are found.

0.0.1

2 years ago

0.0.0

2 years ago