Commit 7cc6136

Anton Golub <antongolub@antongolub.com>
2025-07-27 13:10:57
refactor: use single internal args buffer (#1286)
* refactor: use single internal args buffer * refactor: enhance `box` type * refactor: enhance `box` API * chore: update bundle
1 parent ab7e109
build/cli.js
build/core.cjs
@@ -434,8 +434,13 @@ var defaults = resolveDefaults({
   timeoutSignal: SIGTERM
 });
 var storage = new import_node_async_hooks.AsyncLocalStorage();
-var snapshots = [];
-var delimiters = [];
+var box = ((box2 = []) => ({
+  push(item) {
+    if (box2.length > 0) throw new Fail(`Box is busy`);
+    box2.push(item);
+  },
+  loot: box2.pop.bind(box2)
+}))();
 var getStore = () => storage.getStore() || defaults;
 var getSnapshot = (opts, from, cmd) => __spreadProps(__spreadValues({}, opts), {
   ac: opts.ac || new AbortController(),
@@ -464,7 +469,7 @@ var $ = new Proxy(
       pieces,
       args
     );
-    snapshots.push(getSnapshot(opts, from, cmd));
+    box.push(getSnapshot(opts, from, cmd));
     const pp = new ProcessPromise(import_util.noop);
     if (!pp.isHalted()) pp.run();
     return pp.sync ? pp.output : pp;
@@ -501,14 +506,15 @@ var _ProcessPromise = class _ProcessPromise extends Promise {
     this._resolve = import_util.noop;
     // Stream-like API
     this.writable = true;
-    if (snapshots.length) {
-      this._snapshot = snapshots.pop();
+    const snapshot = box.loot();
+    if (snapshot) {
+      this._snapshot = snapshot;
       this._resolve = resolve;
       this._reject = (v) => {
         reject(v);
         if (this.sync) throw v;
       };
-      if (this._snapshot.halt) this._stage = "halted";
+      if (snapshot.halt) this._stage = "halted";
     } else _ProcessPromise.disarm(this);
   }
   run() {
@@ -913,7 +919,7 @@ var _ProcessOutput = class _ProcessOutput extends Error {
     return encoding === "utf8" ? this.toString() : this.buffer().toString(encoding);
   }
   lines(delimiter) {
-    delimiters.push(delimiter);
+    box.push(delimiter);
     return [...this];
   }
   toString() {
@@ -927,7 +933,7 @@ var _ProcessOutput = class _ProcessOutput extends Error {
   }
   *[Symbol.iterator]() {
     const memo = [];
-    const dlmtr = delimiters.pop() || this._dto.delimiter || $.delimiter || DLMTR;
+    const dlmtr = box.loot() || this._dto.delimiter || $.delimiter || DLMTR;
     for (const chunk of this._dto.store.stdall) {
       yield* __yieldStar((0, import_util.getLines)(chunk, memo, dlmtr));
     }
src/core.ts
@@ -162,8 +162,13 @@ export interface Shell<
 
 // Internal storages
 const storage = new AsyncLocalStorage<Options>()
-const snapshots: Snapshot[] = []
-const delimiters: Options['delimiter'][] = []
+const box = (<B extends Snapshot | Snapshot['delimiter']>(box: B[] = []) => ({
+  push(item: B): void {
+    if (box.length > 0) throw new Fail(`Box is busy`)
+    box.push(item)
+  },
+  loot: box.pop.bind(box) as <T extends B>() => T | undefined,
+}))()
 
 const getStore = () => storage.getStore() || defaults
 
@@ -202,7 +207,7 @@ export const $: $ = new Proxy<$>(
       pieces as TemplateStringsArray,
       args
     ) as string
-    snapshots.push(getSnapshot(opts, from, cmd))
+    box.push(getSnapshot(opts, from, cmd))
     const pp = new ProcessPromise(noop)
 
     if (!pp.isHalted()) pp.run()
@@ -260,14 +265,15 @@ export class ProcessPromise extends Promise<ProcessOutput> {
       executor(...args)
     })
 
-    if (snapshots.length) {
-      this._snapshot = snapshots.pop()!
+    const snapshot = box.loot<Snapshot>()
+    if (snapshot) {
+      this._snapshot = snapshot
       this._resolve = resolve!
       this._reject = (v: ProcessOutput) => {
         reject!(v)
         if (this.sync) throw v
       }
-      if (this._snapshot.halt) this._stage = 'halted'
+      if (snapshot.halt) this._stage = 'halted'
     } else ProcessPromise.disarm(this)
   }
 
@@ -800,7 +806,7 @@ export class ProcessOutput extends Error {
   }
 
   lines(delimiter?: string | RegExp): string[] {
-    delimiters.push(delimiter)
+    box.push(delimiter)
     return [...this]
   }
 
@@ -818,8 +824,8 @@ export class ProcessOutput extends Error {
 
   *[Symbol.iterator](): Iterator<string> {
     const memo: (string | undefined)[] = []
-    const dlmtr =
-      delimiters.pop() || this._dto.delimiter || $.delimiter || DLMTR
+    // prettier-ignore
+    const dlmtr = box.loot<Options['delimiter']>() || this._dto.delimiter || $.delimiter || DLMTR
 
     for (const chunk of this._dto.store.stdall) {
       yield* getLines(chunk, memo, dlmtr)
test/core.test.js
@@ -219,7 +219,7 @@ describe('core', () => {
 
       try {
         $([null])
-        throw new Err('unreachable')
+        throw new Error('unreachable')
       } catch (e) {
         assert.ok(e instanceof Fail)
         assert.match(e.message, /malformed/i)
.size-limit.json
@@ -15,7 +15,7 @@
       "README.md",
       "LICENSE"
     ],
-    "limit": "121.301 kB",
+    "limit": "121.40 kB",
     "brotli": false,
     "gzip": false
   },
@@ -29,7 +29,7 @@
       "build/globals.js",
       "build/deno.js"
     ],
-    "limit": "812.40 kB",
+    "limit": "812.46 kB",
     "brotli": false,
     "gzip": false
   },
@@ -62,7 +62,7 @@
       "README.md",
       "LICENSE"
     ],
-    "limit": "868.90 kB",
+    "limit": "869.00 kB",
     "brotli": false,
     "gzip": false
   }