Commit 5e5fb36

Anton Golub <antongolub@antongolub.com>
2025-07-10 11:31:17
fix: check if `ProcessPromise` is settled on kill and abort (#1262)
* fix: check if `ProcessPromise` is settled on kill and abort * test(core): enhance `kill()` and `abort()` tests
1 parent 523ef8e
build/core.cjs
@@ -633,6 +633,7 @@ var _ProcessPromise = class _ProcessPromise extends Promise {
   }
   abort(reason) {
     var _a, _b;
+    if (this.isSettled()) throw new Error("Too late to abort the process.");
     if (this.signal !== ((_a = this._snapshot.ac) == null ? void 0 : _a.signal))
       throw new Error("The signal is controlled by another process.");
     if (!this.child)
@@ -640,6 +641,7 @@ var _ProcessPromise = class _ProcessPromise extends Promise {
     (_b = this._zurk) == null ? void 0 : _b.ac.abort(reason);
   }
   kill(signal = $.killSignal) {
+    if (this.isSettled()) throw new Error("Too late to kill the process.");
     if (!this.child)
       throw new Error("Trying to kill a process without creating one.");
     if (!this.child.pid) throw new Error("The process pid is undefined.");
src/core.ts
@@ -435,9 +435,9 @@ export class ProcessPromise extends Promise<ProcessOutput> {
   }
 
   abort(reason?: string) {
+    if (this.isSettled()) throw new Error('Too late to abort the process.')
     if (this.signal !== this._snapshot.ac?.signal)
       throw new Error('The signal is controlled by another process.')
-
     if (!this.child)
       throw new Error('Trying to abort a process without creating one.')
 
@@ -445,6 +445,7 @@ export class ProcessPromise extends Promise<ProcessOutput> {
   }
 
   kill(signal = $.killSignal): Promise<void> {
+    if (this.isSettled()) throw new Error('Too late to kill the process.')
     if (!this.child)
       throw new Error('Trying to kill a process without creating one.')
     if (!this.child.pid) throw new Error('The process pid is undefined.')
test/core.test.js
@@ -961,6 +961,13 @@ describe('core', () => {
         }
       })
 
+      test('throws if too late', async () => {
+        const p = $`echo foo`
+        await p
+
+        assert.throws(() => p.abort(), /Too late to abort the process/)
+      })
+
       test('abort signal is transmittable through pipe', async () => {
         const ac = new AbortController()
         const { signal } = ac
@@ -998,6 +1005,22 @@ describe('core', () => {
         }
         assert.equal(signal, 'SIGKILL')
       })
+
+      test('throws if too late', async () => {
+        const p = $`echo foo`
+        await p
+
+        assert.throws(() => p.kill(), /Too late to kill the process/)
+      })
+
+      test('throws if too early', async () => {
+        const p = $({ halt: true })`echo foo`
+
+        assert.throws(
+          () => p.kill(),
+          /Trying to kill a process without creating one/
+        )
+      })
     })
 
     describe('[Symbol.asyncIterator]', () => {
.size-limit.json
@@ -15,7 +15,7 @@
       "README.md",
       "LICENSE"
     ],
-    "limit": "121.90 kB",
+    "limit": "122.10 kB",
     "brotli": false,
     "gzip": false
   },
@@ -29,7 +29,7 @@
       "build/globals.js",
       "build/deno.js"
     ],
-    "limit": "812.42 kB",
+    "limit": "812.70 kB",
     "brotli": false,
     "gzip": false
   },
@@ -62,7 +62,7 @@
       "README.md",
       "LICENSE"
     ],
-    "limit": "868.45 kB",
+    "limit": "868.60 kB",
     "brotli": false,
     "gzip": false
   }