From 54e2a630edf0f3afecf28d07292f969431c90402 Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Wed, 13 Mar 2024 01:46:58 +0300 Subject: [PATCH] feat: provide preset api closes #600 --- src/core.ts | 48 +++++++++++++++++++++++++++-------------------- src/index.ts | 4 ++-- test/core.test.js | 8 ++++++++ 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/core.ts b/src/core.ts index a99bf3803f3..f8032445aca 100644 --- a/src/core.ts +++ b/src/core.ts @@ -41,10 +41,10 @@ import { quotePowerShell, } from './util.js' -export type Shell = ( - pieces: TemplateStringsArray, - ...args: any[] -) => ProcessPromise +export interface Shell { + (pieces: TemplateStringsArray, ...args: any[]): ProcessPromise + (opts: Partial): Shell +} const processCwd = Symbol('processCwd') @@ -54,6 +54,7 @@ export interface Options { verbose: boolean env: NodeJS.ProcessEnv shell: string | boolean + nothrow: boolean prefix: string quote: typeof quote spawn: typeof spawn @@ -75,6 +76,7 @@ export const defaults: Options = { verbose: true, env: process.env, shell: true, + nothrow: false, prefix: '', quote: () => { throw new Error('No quote function is defined: https://ï.at/no-quote-func') @@ -102,15 +104,27 @@ function getStore() { return storage.getStore() || defaults } -export const $ = new Proxy( +export const $: Shell & Options = new Proxy( function (pieces, ...args) { + if (!Array.isArray(pieces)) { + return function (this: any, ...args: any) { + const self = this + return within(() => { + return Object.assign($, pieces).apply(self, args) + }) + } + } const from = new Error().stack!.split(/^\s*at\s/m)[2].trim() if (pieces.some((p) => p == undefined)) { throw new Error(`Malformed command at ${from}`) } let resolve: Resolve, reject: Resolve const promise = new ProcessPromise((...args) => ([resolve, reject] = args)) - const cmd = buildCmd($.quote, pieces, args) as string + const cmd = buildCmd( + $.quote, + pieces as TemplateStringsArray, + args + ) as string promise._bind(cmd, from, resolve!, reject!, getStore()) // Postpone run to allow promise configuration. @@ -148,7 +162,7 @@ export class ProcessPromise extends Promise { private _reject: Resolve = noop private _snapshot = getStore() private _stdio: [IO, IO, IO] = ['inherit', 'pipe', 'pipe'] - private _nothrow = false + private _nothrow?: boolean private _quiet = false private _timeout?: number private _timeoutSignal?: string @@ -187,18 +201,10 @@ export class ProcessPromise extends Promise { this._zurk = zurk$({ cmd: $.prefix + this._command, - get cwd() { - return $.cwd ?? $[processCwd] - }, - get shell() { - return typeof $.shell === 'string' ? $.shell : true - }, - get env() { - return $.env - }, - get spawn() { - return $.spawn - }, + cwd: $.cwd ?? $[processCwd], + shell: typeof $.shell === 'string' ? $.shell : true, + env: $.env, + spawn: $.spawn, quote: (v: T): T => v, // let zx handle quoting stdio: this._stdio as any, sync: false, @@ -222,6 +228,7 @@ export class ProcessPromise extends Promise { this._zurk.then(({ error, stdout, stderr, stdall, status, signal }) => { if (error) { const message = ProcessOutput.getErrorMessage(error, self._from) + // (nothrow ? self._resolve : self._reject)( self._reject( new ProcessOutput(null, null, stdout, stderr, stdall, message) ) @@ -240,7 +247,8 @@ export class ProcessPromise extends Promise { stdall, message ) - if (status === 0 || self._nothrow) { + + if (status === 0 || (self._nothrow ?? $.nothrow)) { self._resolve(output) } else { self._reject(output) diff --git a/src/index.ts b/src/index.ts index ce88283c575..ffc250b48be 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,14 +21,14 @@ export { minimist, chalk, fs, which, YAML, ssh } from './vendor.js' export { type Duration, quote, quotePowerShell } from './util.js' /** - * @deprecated Use $.nothrow() instead. + * @deprecated Use $`cmd`.nothrow() instead. */ export function nothrow(promise: ProcessPromise) { return promise.nothrow() } /** - * @deprecated Use $.quiet() instead. + * @deprecated Use $`cmd`.quiet() instead. */ export function quiet(promise: ProcessPromise) { return promise.quiet() diff --git a/test/core.test.js b/test/core.test.js index 6cda6ffb704..1f4758ef058 100644 --- a/test/core.test.js +++ b/test/core.test.js @@ -124,6 +124,14 @@ describe('core', () => { } }) + test('provides presets', async () => { + const $$ = $({ nothrow: true }) + assert.equal( + (await $$`ffff`).stderr.toString(), + '/bin/bash: ffff: command not found\n' + ) + }) + test('ProcessPromise', async () => { let contents = '' let stream = new Writable({