Skip to content

Commit

Permalink
feat: add TemplateExpr type (#259)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret authored Apr 6, 2024
1 parent fa45cf2 commit 20ec3c2
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 12 deletions.
13 changes: 12 additions & 1 deletion mod.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ Deno.test("throws when providing an object that doesn't override toString", asyn
}
class Test {
toString() {
return 1;
return "1";
}
}
{
Expand Down Expand Up @@ -2217,6 +2217,17 @@ Deno.test("which uses same as $.which", async () => {
}
});

Deno.test("expect error undefined", async () => {
await assertRejects(async () => {
// @ts-expect-error undefined not assignable
await $`echo ${undefined}`;
});
await assertRejects(async () => {
// @ts-expect-error null not assignable
await $`echo ${null}`;
});
});

function ensurePromiseNotResolved(promise: Promise<unknown>) {
return new Promise<void>((resolve, reject) => {
promise.then(() => reject(new Error("Promise was resolved")));
Expand Down
8 changes: 5 additions & 3 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { colors, outdent, which, whichSync } from "./src/deps.ts";
import { wasmInstance } from "./src/lib/mod.ts";
import { RequestBuilder, withProgressBarFactorySymbol } from "./src/request.ts";
import { createPath, Path } from "./src/path.ts";
import { TemplateExpr } from "./src/command.ts";

export type { Delay, DelayIterator } from "./src/common.ts";
export { TimeoutError } from "./src/common.ts";
Expand All @@ -52,6 +53,7 @@ export {
KillSignal,
KillSignalController,
type KillSignalListener,
type TemplateExpr,
} from "./src/command.ts";
export type { CommandContext, CommandHandler, CommandPipeReader, CommandPipeWriter } from "./src/command_handler.ts";
export type { Closer, Reader, ShellPipeReaderKind, ShellPipeWriterKind, WriterSync } from "./src/pipes.ts";
Expand Down Expand Up @@ -126,7 +128,7 @@ export type $Type<TExtras extends ExtrasObject = {}> =

/** String literal template. */
export interface $Template {
(strings: TemplateStringsArray, ...exprs: any[]): CommandBuilder;
(strings: TemplateStringsArray, ...exprs: TemplateExpr[]): CommandBuilder;
}

/**
Expand Down Expand Up @@ -499,7 +501,7 @@ export interface $BuiltInProperties<TExtras extends ExtrasObject = {}> {
* await $`command ${exprs}`;
* ```
*/
raw(strings: TemplateStringsArray, ...exprs: any[]): CommandBuilder;
raw(strings: TemplateStringsArray, ...exprs: TemplateExpr[]): CommandBuilder;
/**
* Does the provided action until it succeeds (does not throw)
* or the specified number of retries (`count`) is hit.
Expand Down Expand Up @@ -631,7 +633,7 @@ function build$FromState<TExtras extends ExtrasObject = {}>(state: $State<TExtra
},
};
const result = Object.assign(
(strings: TemplateStringsArray, ...exprs: any[]) => {
(strings: TemplateStringsArray, ...exprs: TemplateExpr[]) => {
const textState = template(strings, exprs);
return state.commandBuilder.getValue()[setCommandTextStateSymbol](textState);
},
Expand Down
42 changes: 34 additions & 8 deletions src/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1232,17 +1232,40 @@ export function getSignalAbortCode(signal: Deno.Signal) {
}
}

export function template(strings: TemplateStringsArray, exprs: any[]) {
export function template(strings: TemplateStringsArray, exprs: TemplateExpr[]) {
return templateInner(strings, exprs, escapeArg);
}

export function templateRaw(strings: TemplateStringsArray, exprs: any[]) {
export function templateRaw(strings: TemplateStringsArray, exprs: TemplateExpr[]) {
return templateInner(strings, exprs, undefined);
}

export type TemplateExpr =
| string
| number
| boolean
| Path
| Uint8Array
| CommandResult
| { toString(): string }
| (string | number | boolean | Path | { toString(): string })[]
| ReadableStream<Uint8Array>
| {
// type is unfortuantely not that great
[readable: symbol]: () => ReadableStream<Uint8Array>;
}
| (() => ReadableStream<Uint8Array>)
// for input redirects only
| {
// type is unfortuantely not that great
[writable: symbol]: () => WritableStream<Uint8Array>;
}
| WritableStream<Uint8Array>
| (() => WritableStream<Uint8Array>);

function templateInner(
strings: TemplateStringsArray,
exprs: any[],
exprs: TemplateExpr[],
escape: ((arg: string) => string) | undefined,
): CommandBuilderStateCommand {
let nextStreamFd = 3;
Expand All @@ -1256,6 +1279,9 @@ function templateInner(
if (exprs.length > i) {
try {
const expr = exprs[i];
if (expr == null) {
throw "Expression was null or undefined.";
}
const inputOrOutputRedirect = detectInputOrOutputRedirect(text);
if (inputOrOutputRedirect === "<") {
if (expr instanceof Path) {
Expand All @@ -1271,9 +1297,9 @@ function templateInner(
);
} else if (expr instanceof ReadableStream) {
handleReadableStream(() => expr);
} else if (expr?.[symbols.readable]) {
} else if ((expr as any)?.[symbols.readable]) {
handleReadableStream(() => {
const stream = expr[symbols.readable]?.();
const stream = (expr as any)[symbols.readable]?.();
if (!(stream instanceof ReadableStream)) {
throw new Error(
"Expected a ReadableStream or an object with a [$.symbols.readable] method " +
Expand Down Expand Up @@ -1338,9 +1364,9 @@ function templateInner(
},
});
});
} else if (expr?.[symbols.writable]) {
} else if ((expr as any)?.[symbols.writable]) {
handleWritableStream(() => {
const stream = expr[symbols.writable]?.();
const stream = (expr as any)[symbols.writable]?.();
if (!(stream instanceof WritableStream)) {
throw new Error(
`Expected a WritableStream or an object with a [$.symbols.writable] method ` +
Expand Down Expand Up @@ -1435,7 +1461,7 @@ function detectInputOrOutputRedirect(text: string) {
}
}

function templateLiteralExprToString(expr: any, escape: ((arg: string) => string) | undefined): string {
function templateLiteralExprToString(expr: TemplateExpr, escape: ((arg: string) => string) | undefined): string {
let result: string;
if (typeof expr === "string") {
result = expr;
Expand Down

0 comments on commit 20ec3c2

Please sign in to comment.