feat: add Python and Java regex engines

This commit is contained in:
2026-07-27 02:02:21 +02:00
parent 4951c966d4
commit 7079cde15f
95 changed files with 8866 additions and 251 deletions

View File

@@ -71,26 +71,36 @@ class ResponsiveWorker implements WorkerLike {
onmessageerror: ((event: MessageEvent<unknown>) => void) | null = null;
readonly operations: EngineWorkerOperation[] = [];
terminateCalls = 0;
private readonly flavour: RegexFlavourId;
constructor(flavour: RegexFlavourId) {
this.flavour = flavour;
}
postMessage(message: unknown): void {
const request = message as WorkerRequest<EngineWorkerOperation>;
this.operations.push(request.payload);
const payload: EngineWorkerResult =
request.payload.kind === "execute"
request.payload.kind === "load"
? {
kind: "execute",
result: result(request.payload.request.flavour),
kind: "load",
info: result(this.flavour).engine,
}
: {
kind: "replace",
result: {
execution: result(request.payload.request.flavour),
output: "",
outputBytes: 0,
outputTruncated: false,
truncated: false,
},
};
: request.payload.kind === "execute"
? {
kind: "execute",
result: result(request.payload.request.flavour),
}
: {
kind: "replace",
result: {
execution: result(request.payload.request.flavour),
output: "",
outputBytes: 0,
outputTruncated: false,
truncated: false,
},
};
const response: WorkerResponse<EngineWorkerResult> = {
protocolVersion: WORKER_PROTOCOL_VERSION,
requestId: request.requestId,
@@ -106,14 +116,34 @@ class ResponsiveWorker implements WorkerLike {
}
}
class StallingWorker implements WorkerLike {
onmessage: ((event: MessageEvent<unknown>) => void) | null = null;
onerror: ((event: ErrorEvent) => void) | null = null;
onmessageerror: ((event: MessageEvent<unknown>) => void) | null = null;
readonly operations: EngineWorkerOperation[] = [];
terminateCalls = 0;
postMessage(message: unknown): void {
const request = message as WorkerRequest<EngineWorkerOperation>;
this.operations.push(request.payload);
}
terminate(): void {
this.terminateCalls += 1;
}
}
describe("engine worker selection", () => {
it("registers the shipped ECMAScript and PCRE2 execution workers", () => {
it("registers every shipped execution worker with a startup budget", () => {
expect(
ENGINE_WORKER_REGISTRY.registrations.map(
(registration) => registration.flavour,
),
).toEqual(["ecmascript", "pcre2"]);
).toEqual(["ecmascript", "pcre2", "python", "java"]);
expect(ENGINE_WORKER_REGISTRY.require("pcre2").label).toBe("PCRE2 engine");
expect(ENGINE_WORKER_REGISTRY.require("python").startupTimeoutMs).toBe(
30_000,
);
});
it("selects and reuses a dedicated supervisor per registered flavour", async () => {
@@ -121,8 +151,9 @@ describe("engine worker selection", () => {
const registration = (flavour: RegexFlavourId) => ({
flavour,
label: `${flavour} fixture`,
startupTimeoutMs: 100,
createWorker: () => {
const worker = new ResponsiveWorker();
const worker = new ResponsiveWorker(flavour);
workers.set(flavour, [...(workers.get(flavour) ?? []), worker]);
return worker;
},
@@ -150,7 +181,14 @@ describe("engine worker selection", () => {
expect(workers.get("ecmascript")).toHaveLength(1);
expect(workers.get("pcre2")).toHaveLength(1);
expect(workers.get("ecmascript")?.[0]?.operations).toHaveLength(2);
expect(
workers
.get("ecmascript")?.[0]
?.operations.map((operation) => operation.kind),
).toEqual(["load", "execute", "execute"]);
expect(
workers.get("pcre2")?.[0]?.operations.map((operation) => operation.kind),
).toEqual(["load", "execute"]);
supervisor.dispose();
expect(workers.get("ecmascript")?.[0]?.terminateCalls).toBe(1);
@@ -165,4 +203,72 @@ describe("engine worker selection", () => {
);
supervisor.dispose();
});
it("lets the newest request supersede a shared ready-engine continuation", async () => {
const worker = new ResponsiveWorker("python");
const supervisor = new EngineSupervisor(
new EngineWorkerRegistry([
{
flavour: "python",
label: "Python fixture",
startupTimeoutMs: 100,
createWorker: () => worker,
},
]),
);
await supervisor.load("python");
const older = supervisor.execute(request("python"), 100);
const newer = supervisor.execute(request("python"), 100);
await expect(older).rejects.toMatchObject({ kind: "cancelled" });
await expect(newer).resolves.toEqual(
expect.objectContaining({
engine: expect.objectContaining({ flavour: "python" }),
}),
);
expect(worker.operations.map((operation) => operation.kind)).toEqual([
"load",
"execute",
]);
supervisor.dispose();
});
it("restarts a superseded cold runtime under the startup budget before execution", async () => {
const coldWorker = new StallingWorker();
const readyWorker = new ResponsiveWorker("python");
let factoryCalls = 0;
const supervisor = new EngineSupervisor(
new EngineWorkerRegistry([
{
flavour: "python",
label: "Python fixture",
startupTimeoutMs: 100,
createWorker: () => {
factoryCalls += 1;
return factoryCalls === 1 ? coldWorker : readyWorker;
},
},
]),
);
const older = supervisor.execute(request("python"), 1);
const newer = supervisor.execute(request("python"), 1);
await expect(older).rejects.toMatchObject({ kind: "cancelled" });
await expect(newer).resolves.toEqual(
expect.objectContaining({
engine: expect.objectContaining({ flavour: "python" }),
}),
);
expect(coldWorker.operations.map((operation) => operation.kind)).toEqual([
"load",
]);
expect(coldWorker.terminateCalls).toBe(1);
expect(readyWorker.operations.map((operation) => operation.kind)).toEqual([
"load",
"execute",
]);
supervisor.dispose();
});
});