51 lines
1.7 KiB
TypeScript
51 lines
1.7 KiB
TypeScript
import { ActorDebugAdapter, DebugMessage } from "../src/debugger";
|
|
|
|
export class DebugHarness {
|
|
readonly adapter: ActorDebugAdapter;
|
|
readonly messages: DebugMessage[] = [];
|
|
private seq = 0;
|
|
private readonly listeners = new Set<() => void>();
|
|
|
|
constructor(create: (send: (message: DebugMessage) => void) => ActorDebugAdapter) {
|
|
this.adapter = create((message) => {
|
|
this.messages.push(message);
|
|
for (const listener of this.listeners) listener();
|
|
});
|
|
}
|
|
|
|
async request<T = unknown>(command: string, args?: Record<string, unknown>): Promise<T> {
|
|
const seq = ++this.seq;
|
|
const response = this.wait((message) => message.request_seq === seq);
|
|
this.adapter.handleMessage({ seq, type: "request", command, arguments: args });
|
|
const message = await response;
|
|
if (!message.success) throw new Error(message.message);
|
|
return message.body as T;
|
|
}
|
|
|
|
wait(predicate: (message: DebugMessage) => boolean, since = 0): Promise<DebugMessage> {
|
|
return new Promise((resolve, reject) => {
|
|
const check = () => {
|
|
const found = this.messages.slice(since).find(predicate);
|
|
if (!found) return;
|
|
clearTimeout(timer);
|
|
this.listeners.delete(check);
|
|
resolve(found);
|
|
};
|
|
const timer = setTimeout(() => {
|
|
this.listeners.delete(check);
|
|
reject(new Error("Timed out waiting for DAP message"));
|
|
}, 5000);
|
|
this.listeners.add(check);
|
|
check();
|
|
});
|
|
}
|
|
|
|
async attach(): Promise<void> {
|
|
await this.request("initialize");
|
|
await this.request("attach");
|
|
await this.wait((message) => message.event === "initialized");
|
|
await this.request("configurationDone");
|
|
await this.wait((message) => message.event === "stopped");
|
|
}
|
|
}
|