Skip to content

Commit

Permalink
feat(runtime): add catch and finally methods to stdout and `std…
Browse files Browse the repository at this point in the history
…err` properties (#92)
  • Loading branch information
c4spar authored Jul 17, 2022
1 parent 76b9e72 commit 6f93d58
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 31 deletions.
52 changes: 21 additions & 31 deletions src/runtime/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Deferred, deferred, writeAll } from "./deps.ts";
import { readLines } from "./lib/readline.ts";
import { ProcessError } from "./process_error.ts";
import { ProcessOutput } from "./process_output.ts";
import { Reader } from "./reader.ts";
import { $ } from "./shell.ts";

export type RetryCallback = (error: ProcessError) => boolean | Promise<boolean>;
Expand All @@ -11,7 +12,7 @@ export interface ProcessOptions {
errorContext?: Function;
}

export class Process implements Promise<ProcessOutput> {
export class Process extends Reader<ProcessOutput> {
readonly [Symbol.toStringTag] = "Process";
readonly #cmd: string;
#proc: Deno.Process | null = null;
Expand All @@ -27,8 +28,22 @@ export class Process implements Promise<ProcessOutput> {
#throwErrors = true;
#isKilled = false;
#shouldRetry?: RetryCallback;
#stdoutReader: Reader<string>;
#stderrReader: Reader<string>;

constructor(cmd: string, { errorContext }: ProcessOptions = {}) {
super({
resolve: () => this.#resolve(),
});

this.#stdoutReader = new Reader({
resolve: () => this.#resolve().then(({ stdout }) => stdout),
});

this.#stderrReader = new Reader({
resolve: () => this.#resolve().then(({ stderr }) => stderr),
});

this.#cmd = cmd;
this.#baseError = new ProcessError({
combined: "",
Expand Down Expand Up @@ -60,6 +75,7 @@ export class Process implements Promise<ProcessOutput> {
);
}
}

return this.#proc;
}

Expand Down Expand Up @@ -99,8 +115,8 @@ export class Process implements Promise<ProcessOutput> {
* console.log(output); // -> "Hello\n"
* ```
*/
get stdout(): Promise<string> {
return this.#resolve().then(({ stdout }) => stdout);
get stdout(): Reader<string> {
return this.#stdoutReader;
}

/**
Expand All @@ -111,8 +127,8 @@ export class Process implements Promise<ProcessOutput> {
* console.log(errorOutput); // -> "World\n"
* ```
*/
get stderr(): Promise<string> {
return this.#resolve().then(({ stderr }) => stderr);
get stderr(): Reader<string> {
return this.#stderrReader;
}

retry(retries: number | RetryCallback): this {
Expand All @@ -138,32 +154,6 @@ export class Process implements Promise<ProcessOutput> {
this.#process.kill(signo);
}

then<TResult1 = ProcessOutput, TResult2 = never>(
onfulfilled?:
| ((value: ProcessOutput) => TResult1 | PromiseLike<TResult1>)
| undefined
| null,
onrejected?:
| ((reason: unknown) => TResult2 | PromiseLike<TResult2>)
| undefined
| null,
): Promise<TResult1 | TResult2> {
return this.#resolve().then(onfulfilled).catch(onrejected);
}

catch<TResult = never>(
onrejected?:
| ((reason: unknown) => TResult | PromiseLike<TResult>)
| undefined
| null,
): Promise<ProcessOutput | TResult> {
return this.#resolve().catch(onrejected);
}

finally(onfinally?: (() => void) | undefined | null): Promise<ProcessOutput> {
return this.#resolve().finally(onfinally);
}

#resolve(): Promise<ProcessOutput> {
if (this.#deferred) {
return this.#deferred;
Expand Down
37 changes: 37 additions & 0 deletions src/runtime/reader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export interface ReaderOptions<TResolve> {
resolve(): Promise<TResolve>;
}

export class Reader<TResolve> {
#opts: ReaderOptions<TResolve>;

constructor(opts: ReaderOptions<TResolve>) {
this.#opts = opts;
}

then<TResult1 = TResolve, TResult2 = never>(
onfulfilled?:
| ((value: TResolve) => TResult1 | PromiseLike<TResult1>)
| undefined
| null,
onrejected?:
| ((reason: unknown) => TResult2 | PromiseLike<TResult2>)
| undefined
| null,
): Promise<TResult1 | TResult2> {
return this.#opts.resolve().then(onfulfilled).catch(onrejected);
}

catch<TResult = never>(
onrejected?:
| ((reason: unknown) => TResult | PromiseLike<TResult>)
| undefined
| null,
): Promise<TResolve | TResult> {
return this.#opts.resolve().catch(onrejected);
}

finally(onfinally?: (() => void) | undefined | null): Promise<TResolve> {
return this.#opts.resolve().finally(onfinally);
}
}

0 comments on commit 6f93d58

Please sign in to comment.