dsherret / dax

Cross-platform shell tools for Deno and Node.js inspired by zx.
MIT License
964 stars 33 forks source link

feat: ability to provide JavaScript objects and streams as file descriptors for redirects #230

Closed dsherret closed 5 months ago

dsherret commented 5 months ago

This adds to Dax what's available in Bun's shell where instead of providing objects to the entire command like so:

const request = $.request("https://plugins.dprint.dev/info.json")
  .showProgress();
const bytes = await `gzip`.stdin(request).bytes(); // obviously, gzip doesn't work on windows

You can now do:

const request = $.request("https://plugins.dprint.dev/info.json")
  .showProgress();
const bytes = await `gzip < ${request}`.bytes();

// makes the request after 5 seconds instead of immediately
// (not possible without two separate statements before)
const bytes2 = await `sleep 5 && gzip < ${request}`.bytes();

You can also now redirect into any WritableStream:

const buffer = new Buffer();
await $`cat data.txt > ${toWritableStream(buffer)}`; // toWritableStream from deno_std

Or do an input redirect from any ReadableStream:

const text = "testing".repeat(1000);
const bytes = new TextEncoder().encode(text);
const stream = new ReadableStream({
  start(controller) {
    controller.enqueue(bytes);
    controller.close();
  },
});
const bytes = await $`gzip < ${stream}`.bytes();

// don't do that example though, just do:
const bytes = await $`gzip`.stdinText(text).bytes();

Or provide bytes:

const text = "testing".repeat(1000);
const bytes = new TextEncoder().encode(text);
const output = await $`gzip < ${bytes}`.bytes();

Or Response objects:

const response = new Response("testing".repeat(1000));
const output = await $`gzip < ${response}`.bytes();

Other supported objects:

Additionally, the $.symbols.writable (Symbol.for("dax.writableStream")) and $.symbols.readable (Symbol.for("dax.readableStream")) symbols can be attached to any object to make them work in these positions (still debating this).

Unsupported objects in this position will cause an error:

assertThrows(
  () => $`echo 1 > ${new TextEncoder()}`,
  Error,
  "Failed resolving expression in command. Unsupported object provided to output redirect.",
);