refactor(ripgrep): use embedded wasm backend (#21703)
This commit is contained in:
@@ -6,6 +6,21 @@ import path from "path"
|
||||
import { tmpdir } from "../fixture/fixture"
|
||||
import { Ripgrep } from "../../src/file/ripgrep"
|
||||
|
||||
async function seed(dir: string, count: number, size = 16) {
|
||||
const txt = "a".repeat(size)
|
||||
await Promise.all(Array.from({ length: count }, (_, i) => Bun.write(path.join(dir, `file-${i}.txt`), `${txt}${i}\n`)))
|
||||
}
|
||||
|
||||
function env(name: string, value: string | undefined) {
|
||||
const prev = process.env[name]
|
||||
if (value === undefined) delete process.env[name]
|
||||
else process.env[name] = value
|
||||
return () => {
|
||||
if (prev === undefined) delete process.env[name]
|
||||
else process.env[name] = prev
|
||||
}
|
||||
}
|
||||
|
||||
describe("file.ripgrep", () => {
|
||||
test("defaults to include hidden", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
@@ -16,11 +31,9 @@ describe("file.ripgrep", () => {
|
||||
},
|
||||
})
|
||||
|
||||
const files = await Array.fromAsync(Ripgrep.files({ cwd: tmp.path }))
|
||||
const hasVisible = files.includes("visible.txt")
|
||||
const hasHidden = files.includes(path.join(".opencode", "thing.json"))
|
||||
expect(hasVisible).toBe(true)
|
||||
expect(hasHidden).toBe(true)
|
||||
const files = await Array.fromAsync(await Ripgrep.files({ cwd: tmp.path }))
|
||||
expect(files.includes("visible.txt")).toBe(true)
|
||||
expect(files.includes(path.join(".opencode", "thing.json"))).toBe(true)
|
||||
})
|
||||
|
||||
test("hidden false excludes hidden", async () => {
|
||||
@@ -32,15 +45,11 @@ describe("file.ripgrep", () => {
|
||||
},
|
||||
})
|
||||
|
||||
const files = await Array.fromAsync(Ripgrep.files({ cwd: tmp.path, hidden: false }))
|
||||
const hasVisible = files.includes("visible.txt")
|
||||
const hasHidden = files.includes(path.join(".opencode", "thing.json"))
|
||||
expect(hasVisible).toBe(true)
|
||||
expect(hasHidden).toBe(false)
|
||||
const files = await Array.fromAsync(await Ripgrep.files({ cwd: tmp.path, hidden: false }))
|
||||
expect(files.includes("visible.txt")).toBe(true)
|
||||
expect(files.includes(path.join(".opencode", "thing.json"))).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("Ripgrep.Service", () => {
|
||||
test("search returns empty when nothing matches", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
@@ -48,15 +57,119 @@ describe("Ripgrep.Service", () => {
|
||||
},
|
||||
})
|
||||
|
||||
const result = await Effect.gen(function* () {
|
||||
const rg = yield* Ripgrep.Service
|
||||
return yield* rg.search({ cwd: tmp.path, pattern: "needle" })
|
||||
}).pipe(Effect.provide(Ripgrep.defaultLayer), Effect.runPromise)
|
||||
|
||||
const result = await Ripgrep.search({ cwd: tmp.path, pattern: "needle" })
|
||||
expect(result.partial).toBe(false)
|
||||
expect(result.items).toEqual([])
|
||||
})
|
||||
|
||||
test("search returns match metadata with normalized path", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
await fs.mkdir(path.join(dir, "src"), { recursive: true })
|
||||
await Bun.write(path.join(dir, "src", "match.ts"), "const needle = 1\n")
|
||||
},
|
||||
})
|
||||
|
||||
const result = await Ripgrep.search({ cwd: tmp.path, pattern: "needle" })
|
||||
expect(result.partial).toBe(false)
|
||||
expect(result.items).toHaveLength(1)
|
||||
expect(result.items[0]?.path.text).toBe(path.join("src", "match.ts"))
|
||||
expect(result.items[0]?.line_number).toBe(1)
|
||||
expect(result.items[0]?.lines.text).toContain("needle")
|
||||
})
|
||||
|
||||
test("files returns empty when glob matches no files in worker mode", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
await fs.mkdir(path.join(dir, "packages", "console"), { recursive: true })
|
||||
await Bun.write(path.join(dir, "packages", "console", "package.json"), "{}")
|
||||
},
|
||||
})
|
||||
|
||||
const ctl = new AbortController()
|
||||
const files = await Array.fromAsync(
|
||||
await Ripgrep.files({
|
||||
cwd: tmp.path,
|
||||
glob: ["packages/*"],
|
||||
signal: ctl.signal,
|
||||
}),
|
||||
)
|
||||
|
||||
expect(files).toEqual([])
|
||||
})
|
||||
|
||||
test("ignores RIPGREP_CONFIG_PATH in direct mode", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
await Bun.write(path.join(dir, "match.ts"), "const needle = 1\n")
|
||||
},
|
||||
})
|
||||
|
||||
const restore = env("RIPGREP_CONFIG_PATH", path.join(tmp.path, "missing-ripgreprc"))
|
||||
try {
|
||||
const result = await Ripgrep.search({ cwd: tmp.path, pattern: "needle" })
|
||||
expect(result.items).toHaveLength(1)
|
||||
} finally {
|
||||
restore()
|
||||
}
|
||||
})
|
||||
|
||||
test("ignores RIPGREP_CONFIG_PATH in worker mode", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
await Bun.write(path.join(dir, "match.ts"), "const needle = 1\n")
|
||||
},
|
||||
})
|
||||
|
||||
const restore = env("RIPGREP_CONFIG_PATH", path.join(tmp.path, "missing-ripgreprc"))
|
||||
try {
|
||||
const ctl = new AbortController()
|
||||
const result = await Ripgrep.search({
|
||||
cwd: tmp.path,
|
||||
pattern: "needle",
|
||||
signal: ctl.signal,
|
||||
})
|
||||
expect(result.items).toHaveLength(1)
|
||||
} finally {
|
||||
restore()
|
||||
}
|
||||
})
|
||||
|
||||
test("aborts files scan in worker mode", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
await seed(dir, 4000)
|
||||
},
|
||||
})
|
||||
|
||||
const ctl = new AbortController()
|
||||
const iter = await Ripgrep.files({ cwd: tmp.path, signal: ctl.signal })
|
||||
const pending = Array.fromAsync(iter)
|
||||
setTimeout(() => ctl.abort(), 0)
|
||||
|
||||
const err = await pending.catch((err) => err)
|
||||
expect(err).toBeInstanceOf(Error)
|
||||
expect(err.name).toBe("AbortError")
|
||||
}, 15_000)
|
||||
|
||||
test("aborts search in worker mode", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
await seed(dir, 512, 64 * 1024)
|
||||
},
|
||||
})
|
||||
|
||||
const ctl = new AbortController()
|
||||
const pending = Ripgrep.search({ cwd: tmp.path, pattern: "needle", signal: ctl.signal })
|
||||
setTimeout(() => ctl.abort(), 0)
|
||||
|
||||
const err = await pending.catch((err) => err)
|
||||
expect(err).toBeInstanceOf(Error)
|
||||
expect(err.name).toBe("AbortError")
|
||||
}, 15_000)
|
||||
})
|
||||
|
||||
describe("Ripgrep.Service", () => {
|
||||
test("search returns matched rows", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
init: async (dir) => {
|
||||
|
||||
Reference in New Issue
Block a user