Skip to content

Add template tag for running commands  #14

@lishaduck

Description

@lishaduck

Summary

Basically, I'd like to create a new package that provides dax/zx/zurk's template literal api, but return Effects instead of promises (as Effects have to be passed to a runtime, so they can be reused, thus it doesn't need to be a thunk). Probably use tinyexec under the hood.

This doesn't entail a cli; injecting globals; ponyfilling fetch(), glob(), which(),1 etc; reexporting node:path, node:os, fs-extra, minimist, etc; etc. If it can be written using @effect/platform or straight in the shell, we shouldn't depend on an npm package, especially if we take the route Dax took of using deno_task_shell to paper over Windows compatibility. I'll need to investigate if Git Bash or deno_task_shell is more capable. Presumably Git Bash, so deno_task_shell would be a (slower?) fallack.

I'll want to ensure I support setting env variables VAR=1 cmd (zx doesn't). I need to think about logging. I don't want to depend on stuff like picocolors or picospinner, but supporting logging stdout is necessary, and at that point, I might as well include Effect-compatible loggers.

API example:

import { $, Script } from "@lishaduck/effect-script"
import { Effect, Option } from "effect"
import { DenoContext, DenoRuntime } from "@effect/platform-deno"

const program = Effect.gen(function* () {
  // Interpolate.
  const binary = "deno";
  const args = ["run", "filename.js", "hi there"];
  const command = $`DEBUG=true ${binary} ${args}`.nothrow().quiet();
  //    ^? const command: $.Command = `DEBUG=true deno run filename.js "hi there"`
  // `type Script.Command = { () => Script.Subprocess, command: string }`

  // Start a run.
  const subprocess = yield* command;
  //    ^? const run: Script.Subprocess = {...}

  // Get info.
  const output = yield* subprocess.text();
  //    ^? const output: Option.Option<string>

  // Echo to stdout.
  yield* echo`Result: ${Option.getOrNull(output)}`;

  // Run a side-effect command. Can fail with Script.ScriptException.
  yield* $`rm -rf .cache`() // Shorthand for `$.run(command)`
  // ^? Effect<void, Script.ScriptException, Script.ScriptContext>
})

DenoRuntime.runMain(program.pipe(Effect.provide(DenoContext.layer)));

Footnotes

  1. I'll want to investigate support for a preferLocal equivalent to make npx redundant.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions