Skip to content

Commit f3ed89a

Browse files
committed
improve
1 parent 48936f1 commit f3ed89a

File tree

2 files changed

+50
-18
lines changed

2 files changed

+50
-18
lines changed

mod.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2233,6 +2233,29 @@ Deno.test("nice error message when not awaiting a CommandBuilder", async () => {
22332233
);
22342234
});
22352235

2236+
Deno.test("type error null", async () => {
2237+
await assertRejects(
2238+
async () => {
2239+
// @ts-expect-error promise is not supported here
2240+
return await $`echo ${null}`;
2241+
},
2242+
Error,
2243+
"Failed resolving expression in command. Expression was null or undefined.",
2244+
);
2245+
});
2246+
2247+
Deno.test("type error Promise", async () => {
2248+
await assertRejects(
2249+
async () => {
2250+
const promise = Promise.resolve("");
2251+
// @ts-expect-error promise is not supported here
2252+
return await $`echo ${promise}`;
2253+
},
2254+
Error,
2255+
"Failed resolving expression in command. Provided object was a Promise. Please await it before providing it.",
2256+
);
2257+
});
2258+
22362259
Deno.test("which uses same as $.which", async () => {
22372260
{
22382261
const whichFnOutput = await $.which("deno");

src/command.ts

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -350,13 +350,13 @@ export class CommandBuilder implements PromiseLike<CommandResult> {
350350
stdout(kind: ShellPipeWriterKind, options?: StreamPipeOptions): CommandBuilder {
351351
return this.#newWithState((state) => {
352352
if (state.combinedStdoutStderr && kind !== "piped" && kind !== "inheritPiped") {
353-
throw new Error(
353+
throw new TypeError(
354354
"Cannot set stdout's kind to anything but 'piped' or 'inheritPiped' when combined is true.",
355355
);
356356
}
357357
if (options?.signal != null) {
358358
// not sure what this would mean
359-
throw new Error("Setting a signal for a stdout WritableStream is not yet supported.");
359+
throw new TypeError("Setting a signal for a stdout WritableStream is not yet supported.");
360360
}
361361
state.stdout = {
362362
kind,
@@ -371,13 +371,13 @@ export class CommandBuilder implements PromiseLike<CommandResult> {
371371
stderr(kind: ShellPipeWriterKind, options?: StreamPipeOptions): CommandBuilder {
372372
return this.#newWithState((state) => {
373373
if (state.combinedStdoutStderr && kind !== "piped" && kind !== "inheritPiped") {
374-
throw new Error(
374+
throw new TypeError(
375375
"Cannot set stderr's kind to anything but 'piped' or 'inheritPiped' when combined is true.",
376376
);
377377
}
378378
if (options?.signal != null) {
379379
// not sure what this would mean
380-
throw new Error("Setting a signal for a stderr WritableStream is not yet supported.");
380+
throw new TypeError("Setting a signal for a stderr WritableStream is not yet supported.");
381381
}
382382
state.stderr = {
383383
kind,
@@ -534,7 +534,7 @@ export class CommandBuilder implements PromiseLike<CommandResult> {
534534
return kind;
535535
default: {
536536
const _assertNever: never = kind;
537-
throw new Error(`Unhandled kind ${kind}.`);
537+
throw new TypeError(`Unhandled kind ${kind}.`);
538538
}
539539
}
540540
}
@@ -931,7 +931,7 @@ export function parseAndSpawnCommand(state: CommandBuilderState) {
931931
return "null";
932932
default: {
933933
const _assertNever: never = kind;
934-
throw new Error("Unhandled.");
934+
throw new TypeError("Unhandled.");
935935
}
936936
}
937937
}
@@ -1136,7 +1136,7 @@ export function rawArg<T>(arg: T): RawArg<T> {
11361136

11371137
function validateCommandName(command: string) {
11381138
if (command.match(/^[a-zA-Z0-9-_]+$/) == null) {
1139-
throw new Error("Invalid command name");
1139+
throw new TypeError("Invalid command name");
11401140
}
11411141
}
11421142

@@ -1282,7 +1282,7 @@ type NonRedirectTemplateExpr =
12821282
| Uint8Array
12831283
| CommandResult
12841284
| RawArg<NonRedirectTemplateExpr>
1285-
| { toString(): string };
1285+
| { toString(): string; catch?: never };
12861286
export type TemplateExpr =
12871287
| NonRedirectTemplateExpr
12881288
| NonRedirectTemplateExpr[]
@@ -1338,7 +1338,7 @@ function templateInner(
13381338
handleReadableStream(() => {
13391339
const stream = (expr as any)[symbols.readable]?.();
13401340
if (!(stream instanceof ReadableStream)) {
1341-
throw new Error(
1341+
throw new TypeError(
13421342
"Expected a ReadableStream or an object with a [$.symbols.readable] method "
13431343
+ `that returns a ReadableStream at expression ${i + 1}/${exprsCount}.`,
13441344
);
@@ -1369,7 +1369,7 @@ function templateInner(
13691369
try {
13701370
const result = expr();
13711371
if (!(result instanceof ReadableStream)) {
1372-
throw new Error("Function did not return a ReadableStream.");
1372+
throw new TypeError("Function did not return a ReadableStream.");
13731373
}
13741374
return result;
13751375
} catch (err) {
@@ -1380,7 +1380,7 @@ function templateInner(
13801380
}
13811381
});
13821382
} else {
1383-
throw new Error("Unsupported object provided to input redirect.");
1383+
throw new TypeError("Unsupported object provided to input redirect.");
13841384
}
13851385
} else if (inputOrOutputRedirect === ">") {
13861386
if (expr instanceof Path) {
@@ -1409,7 +1409,7 @@ function templateInner(
14091409
handleWritableStream(() => {
14101410
const stream = (expr as any)[symbols.writable]?.();
14111411
if (!(stream instanceof WritableStream)) {
1412-
throw new Error(
1412+
throw new TypeError(
14131413
`Expected a WritableStream or an object with a [$.symbols.writable] method `
14141414
+ `that returns a WritableStream at expression ${i + 1}/${exprsCount}.`,
14151415
);
@@ -1421,7 +1421,7 @@ function templateInner(
14211421
try {
14221422
const result = expr();
14231423
if (!(result instanceof WritableStream)) {
1424-
throw new Error("Function did not return a WritableStream.");
1424+
throw new TypeError("Function did not return a WritableStream.");
14251425
}
14261426
return result;
14271427
} catch (err) {
@@ -1432,11 +1432,11 @@ function templateInner(
14321432
}
14331433
});
14341434
} else if (typeof expr === "string") {
1435-
throw new Error(
1435+
throw new TypeError(
14361436
"Cannot provide strings to output redirects. Did you mean to provide a path instead via the `$.path(...)` API?",
14371437
);
14381438
} else {
1439-
throw new Error("Unsupported object provided to output redirect.");
1439+
throw new TypeError("Unsupported object provided to output redirect.");
14401440
}
14411441
} else {
14421442
text += templateLiteralExprToString(expr, escape);
@@ -1445,7 +1445,12 @@ function templateInner(
14451445
const startMessage = exprsCount === 1
14461446
? "Failed resolving expression in command."
14471447
: `Failed resolving expression ${i + 1}/${exprsCount} in command.`;
1448-
throw new Error(`${startMessage} ${errorToString(err)}`);
1448+
const message = `${startMessage} ${errorToString(err)}`;
1449+
if (err instanceof TypeError) {
1450+
throw new TypeError(message);
1451+
} else {
1452+
throw new Error(message);
1453+
}
14491454
}
14501455
}
14511456
}
@@ -1512,14 +1517,18 @@ function templateLiteralExprToString(expr: TemplateExpr, escape: ((arg: string)
15121517
// remove last newline
15131518
result = expr.stdout.replace(/\r?\n$/, "");
15141519
} else if (expr instanceof CommandBuilder) {
1515-
throw new Error(
1520+
throw new TypeError(
15161521
"Providing a command builder is not yet supported (https://github.com/dsherret/dax/issues/239). "
15171522
+ "Await the command builder's text before using it in an expression (ex. await $`cmd`.text()).",
15181523
);
15191524
} else if (expr instanceof RawArg) {
15201525
return templateLiteralExprToString(expr.value, undefined);
15211526
} else if (typeof expr === "object" && expr.toString === Object.prototype.toString) {
1522-
throw new Error("Provided object does not override `toString()`.");
1527+
if (expr instanceof Promise) {
1528+
throw new TypeError("Provided object was a Promise. Please await it before providing it.");
1529+
} else {
1530+
throw new TypeError("Provided object does not override `toString()`.");
1531+
}
15231532
} else {
15241533
result = `${expr}`;
15251534
}

0 commit comments

Comments
 (0)