Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion extensions/ext-bundler-esbuild/src/esbuild-bundler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { assertEquals, assertExists, assertRejects, assertStringIncludes } from
import { describe, it } from "@std/testing/bdd";
import { createRequire } from "node:module";

import { EsbuildBundler } from "./esbuild-bundler.ts";
import { EsbuildBundler, isLiveEsbuildServiceProcess } from "./esbuild-bundler.ts";
import { rebuildContextWithSignal } from "./context-build-lifecycle.ts";

const childProcess = createRequire(import.meta.url)("node:child_process") as {
Expand Down Expand Up @@ -90,6 +90,19 @@ describe("EsbuildBundler.transform", () => {
});
});

describe("esbuild service lifecycle", () => {
it("treats a Node-compatible child with unset exit fields as live", () => {
assertEquals(
isLiveEsbuildServiceProcess({
killed: false,
exitCode: undefined,
signalCode: undefined,
} as Pick<ReturnType<typeof childProcess.spawn>, "killed" | "exitCode" | "signalCode">),
true,
);
});
});

describe("abortable esbuild context lifecycle", () => {
it("cancels active work and preserves the primary abort over cleanup failures", async () => {
const controller = new AbortController();
Expand Down
18 changes: 15 additions & 3 deletions extensions/ext-bundler-esbuild/src/esbuild-bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,22 @@ function isEsbuildServiceSpawn(spawnArgs: unknown[]): boolean {
args.includes("--ping");
}

/**
* Keep lifecycle tracking tolerant of Node-compatible child-process shims.
*
* Native Node represents an active child with `null` exit fields. Some
* compatible runtimes leave those fields undefined until the child exits.
*/
export function isLiveEsbuildServiceProcess(
child: Pick<ChildProcess, "killed" | "exitCode" | "signalCode">,
): boolean {
return !child.killed &&
(child.exitCode === null || child.exitCode === undefined) &&
(child.signalCode === null || child.signalCode === undefined);
}

function isLiveService(service: EsbuildService): boolean {
return !service.child.killed &&
service.child.exitCode === null &&
service.child.signalCode === null;
return isLiveEsbuildServiceProcess(service.child);
}

function invokeEsbuild<T extends Promise<unknown>>(operation: () => T): T {
Expand Down