Commit 1cc5981
Changed files (3)
src/core.ts
@@ -145,6 +145,7 @@ export interface Shell<
(opts: Partial<Omit<Options, 'sync'>>): Shell<true>
}
}
+const bound: [string, string, Options][] = []
export const $: Shell & Options = new Proxy<Shell & Options>(
function (pieces: TemplateStringsArray | Partial<Options>, ...args: any) {
@@ -164,25 +165,14 @@ export const $: Shell & Options = new Proxy<Shell & Options>(
checkShell()
checkQuote()
- let resolve: Resolve, reject: Resolve
- const process = new ProcessPromise((...args) => ([resolve, reject] = args))
const cmd = buildCmd(
$.quote as typeof quote,
pieces as TemplateStringsArray,
args
) as string
const sync = snapshot[SYNC]
-
- process._bind(
- cmd,
- from,
- resolve!,
- (v: ProcessOutput) => {
- reject!(v)
- if (sync) throw v
- },
- snapshot
- )
+ bound.push([cmd, from, snapshot])
+ const process = new ProcessPromise(noop)
if (!process.isHalted() || sync) process.run()
@@ -237,19 +227,26 @@ export class ProcessPromise extends Promise<ProcessOutput> {
private _reject: Resolve = noop
private _resolve: Resolve = noop
- _bind(
- cmd: string,
- from: string,
- resolve: Resolve,
- reject: Resolve,
- options: Options
- ) {
- this._command = cmd
- this._from = from
- this._resolve = resolve
- this._reject = reject
- this._snapshot = { ac: new AbortController(), ...options }
- if (this._snapshot.halt) this._stage = 'halted'
+ constructor(executor: (resolve: Resolve, reject: Resolve) => void) {
+ let resolve: Resolve
+ let reject: Resolve
+ super((...args) => {
+ ;[resolve, reject] = args
+ executor?.(...args)
+ })
+
+ if (bound.length) {
+ const [cmd, from, snapshot] = bound.pop()!
+ this._command = cmd
+ this._from = from
+ this._resolve = resolve!
+ this._reject = (v: ProcessOutput) => {
+ reject!(v)
+ if (snapshot[SYNC]) throw v
+ }
+ this._snapshot = { ac: new AbortController(), ...snapshot }
+ if (this._snapshot.halt) this._stage = 'halted'
+ } else ProcessPromise.disarm(this)
}
run(): ProcessPromise {
@@ -653,6 +650,17 @@ export class ProcessPromise extends Promise<ProcessOutput> {
this._stdin.removeListener(event, cb)
return this
}
+
+ // prettier-ignore
+ private static disarm(p: ProcessPromise, toggle = true): void {
+ Object.getOwnPropertyNames(ProcessPromise.prototype).forEach(k => {
+ if (k in Promise.prototype) return
+ if (!toggle) { Reflect.deleteProperty(p, k); return }
+ Object.defineProperty(p, k, { configurable: true, get() {
+ throw new Error('Inappropriate usage. Apply $ instead of direct instantiation.')
+ }})
+ })
+ }
}
type ProcessDto = {
test/core.test.js
@@ -456,12 +456,17 @@ describe('core', () => {
it('all transitions', async () => {
const { promise, resolve, reject } = Promise.withResolvers()
- const p = new ProcessPromise(noop, noop)
+ const p = new ProcessPromise(noop)
+ ProcessPromise.disarm(p, false)
assert.equal(p.stage, 'initial')
- p._bind('echo foo', 'test', resolve, reject, {
- ...defaults,
- halt: true,
- })
+
+ p._command = 'echo foo'
+ p._from = 'test'
+ p._resolve = resolve
+ p._reject = reject
+ p._snapshot = { ...defaults }
+ p._stage = 'halted'
+
assert.equal(p.stage, 'halted')
p.run()
assert.equal(p.stage, 'running')
@@ -490,6 +495,13 @@ describe('core', () => {
assert.ok(p5 !== p1)
})
+ test('asserts self instantiation', async () => {
+ const p = new ProcessPromise(() => {})
+
+ assert(typeof p.then === 'function')
+ assert.throws(() => p.stage, /Inappropriate usage/)
+ })
+
test('resolves with ProcessOutput', async () => {
const o = await $`echo foo`
assert.ok(o instanceof ProcessOutput)
.size-limit.json
@@ -9,7 +9,7 @@
{
"name": "zx/index",
"path": "build/*.{js,cjs}",
- "limit": "809 kB",
+ "limit": "809.1 kB",
"brotli": false,
"gzip": false
},