import { ripgrep } from "ripgrep" function env() { const env = Object.fromEntries( Object.entries(process.env).filter((item): item is [string, string] => item[1] !== undefined), ) delete env.RIPGREP_CONFIG_PATH return env } function opts(cwd: string) { return { env: env(), preopens: { ".": cwd }, } } type Run = { kind: "files" | "search" cwd: string args: string[] } function text(input: unknown) { if (typeof input === "string") return input if (input instanceof ArrayBuffer) return Buffer.from(input).toString() if (ArrayBuffer.isView(input)) return Buffer.from(input.buffer, input.byteOffset, input.byteLength).toString() return String(input) } function error(input: unknown) { if (input instanceof Error) { return { message: input.message, name: input.name, stack: input.stack, } } return { message: String(input), } } function clean(file: string) { return file.replace(/^\.[\\/]/, "") } onmessage = async (evt: MessageEvent) => { const msg = evt.data try { if (msg.kind === "search") { const ret = await ripgrep(msg.args, { buffer: true, ...opts(msg.cwd), }) postMessage({ type: "result", code: ret.code ?? 0, stdout: ret.stdout ?? "", stderr: ret.stderr ?? "", }) return } let buf = "" let err = "" const out = { write(chunk: unknown) { buf += text(chunk) const lines = buf.split(/\r?\n/) buf = lines.pop() || "" for (const line of lines) { if (line) postMessage({ type: "line", line: clean(line) }) } }, } const stderr = { write(chunk: unknown) { err += text(chunk) }, } const ret = await ripgrep(msg.args, { stdout: out, stderr, ...opts(msg.cwd), }) if (buf) postMessage({ type: "line", line: clean(buf) }) postMessage({ type: "done", code: ret.code ?? 0, stderr: err, }) } catch (err) { postMessage({ type: "error", error: error(err), }) } }