refactor: remove makeRuntime facades from File and Ripgrep (#22513)
This commit is contained in:
@@ -1,10 +1,9 @@
|
|||||||
import { EOL } from "os"
|
import { EOL } from "os"
|
||||||
import { Effect } from "effect"
|
|
||||||
import { AppRuntime } from "@/effect/app-runtime"
|
import { AppRuntime } from "@/effect/app-runtime"
|
||||||
import { File } from "../../../file"
|
import { File } from "../../../file"
|
||||||
|
import { Ripgrep } from "@/file/ripgrep"
|
||||||
import { bootstrap } from "../../bootstrap"
|
import { bootstrap } from "../../bootstrap"
|
||||||
import { cmd } from "../cmd"
|
import { cmd } from "../cmd"
|
||||||
import { Ripgrep } from "@/file/ripgrep"
|
|
||||||
|
|
||||||
const FileSearchCommand = cmd({
|
const FileSearchCommand = cmd({
|
||||||
command: "search <query>",
|
command: "search <query>",
|
||||||
@@ -17,11 +16,7 @@ const FileSearchCommand = cmd({
|
|||||||
}),
|
}),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap(process.cwd(), async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
const results = await AppRuntime.runPromise(
|
const results = await AppRuntime.runPromise(File.Service.use((svc) => svc.search({ query: args.query })))
|
||||||
Effect.gen(function* () {
|
|
||||||
return yield* File.Service.use((svc) => svc.search({ query: args.query }))
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
process.stdout.write(results.join(EOL) + EOL)
|
process.stdout.write(results.join(EOL) + EOL)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -38,11 +33,7 @@ const FileReadCommand = cmd({
|
|||||||
}),
|
}),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap(process.cwd(), async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
const content = await AppRuntime.runPromise(
|
const content = await AppRuntime.runPromise(File.Service.use((svc) => svc.read(args.path)))
|
||||||
Effect.gen(function* () {
|
|
||||||
return yield* File.Service.use((svc) => svc.read(args.path))
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
process.stdout.write(JSON.stringify(content, null, 2) + EOL)
|
process.stdout.write(JSON.stringify(content, null, 2) + EOL)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -54,11 +45,7 @@ const FileStatusCommand = cmd({
|
|||||||
builder: (yargs) => yargs,
|
builder: (yargs) => yargs,
|
||||||
async handler() {
|
async handler() {
|
||||||
await bootstrap(process.cwd(), async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
const status = await AppRuntime.runPromise(
|
const status = await AppRuntime.runPromise(File.Service.use((svc) => svc.status()))
|
||||||
Effect.gen(function* () {
|
|
||||||
return yield* File.Service.use((svc) => svc.status())
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
process.stdout.write(JSON.stringify(status, null, 2) + EOL)
|
process.stdout.write(JSON.stringify(status, null, 2) + EOL)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -75,11 +62,7 @@ const FileListCommand = cmd({
|
|||||||
}),
|
}),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap(process.cwd(), async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
const files = await AppRuntime.runPromise(
|
const files = await AppRuntime.runPromise(File.Service.use((svc) => svc.list(args.path)))
|
||||||
Effect.gen(function* () {
|
|
||||||
return yield* File.Service.use((svc) => svc.list(args.path))
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
process.stdout.write(JSON.stringify(files, null, 2) + EOL)
|
process.stdout.write(JSON.stringify(files, null, 2) + EOL)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -95,8 +78,10 @@ const FileTreeCommand = cmd({
|
|||||||
default: process.cwd(),
|
default: process.cwd(),
|
||||||
}),
|
}),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
const files = await Ripgrep.tree({ cwd: args.dir, limit: 200 })
|
await bootstrap(process.cwd(), async () => {
|
||||||
console.log(JSON.stringify(files, null, 2))
|
const tree = await AppRuntime.runPromise(Ripgrep.Service.use((svc) => svc.tree({ cwd: args.dir, limit: 200 })))
|
||||||
|
console.log(JSON.stringify(tree, null, 2))
|
||||||
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { EOL } from "os"
|
import { EOL } from "os"
|
||||||
|
import { Effect, Stream } from "effect"
|
||||||
import { AppRuntime } from "../../../effect/app-runtime"
|
import { AppRuntime } from "../../../effect/app-runtime"
|
||||||
import { Ripgrep } from "../../../file/ripgrep"
|
import { Ripgrep } from "../../../file/ripgrep"
|
||||||
import { Instance } from "../../../project/instance"
|
import { Instance } from "../../../project/instance"
|
||||||
@@ -21,7 +22,10 @@ const TreeCommand = cmd({
|
|||||||
}),
|
}),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap(process.cwd(), async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
process.stdout.write((await Ripgrep.tree({ cwd: Instance.directory, limit: args.limit })) + EOL)
|
const tree = await AppRuntime.runPromise(
|
||||||
|
Ripgrep.Service.use((svc) => svc.tree({ cwd: Instance.directory, limit: args.limit })),
|
||||||
|
)
|
||||||
|
process.stdout.write(tree + EOL)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -45,14 +49,21 @@ const FilesCommand = cmd({
|
|||||||
}),
|
}),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap(process.cwd(), async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
const files: string[] = []
|
const files = await AppRuntime.runPromise(
|
||||||
for await (const file of await Ripgrep.files({
|
Effect.gen(function* () {
|
||||||
|
const rg = yield* Ripgrep.Service
|
||||||
|
return yield* rg
|
||||||
|
.files({
|
||||||
cwd: Instance.directory,
|
cwd: Instance.directory,
|
||||||
glob: args.glob ? [args.glob] : undefined,
|
glob: args.glob ? [args.glob] : undefined,
|
||||||
})) {
|
})
|
||||||
files.push(file)
|
.pipe(
|
||||||
if (args.limit && files.length >= args.limit) break
|
Stream.take(args.limit ?? Infinity),
|
||||||
}
|
Stream.runCollect,
|
||||||
|
Effect.map((c) => [...c]),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
process.stdout.write(files.join(EOL) + EOL)
|
process.stdout.write(files.join(EOL) + EOL)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { BusEvent } from "@/bus/bus-event"
|
import { BusEvent } from "@/bus/bus-event"
|
||||||
import { InstanceState } from "@/effect/instance-state"
|
import { InstanceState } from "@/effect/instance-state"
|
||||||
import { makeRuntime } from "@/effect/run-service"
|
|
||||||
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
|
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
|
||||||
import { Git } from "@/git"
|
import { Git } from "@/git"
|
||||||
import { Effect, Layer, Context } from "effect"
|
import { Effect, Layer, Context } from "effect"
|
||||||
@@ -653,26 +653,4 @@ export namespace File {
|
|||||||
Layer.provide(AppFileSystem.defaultLayer),
|
Layer.provide(AppFileSystem.defaultLayer),
|
||||||
Layer.provide(Git.defaultLayer),
|
Layer.provide(Git.defaultLayer),
|
||||||
)
|
)
|
||||||
|
|
||||||
const { runPromise } = makeRuntime(Service, defaultLayer)
|
|
||||||
|
|
||||||
export function init() {
|
|
||||||
return runPromise((svc) => svc.init())
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function status() {
|
|
||||||
return runPromise((svc) => svc.status())
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function read(file: string): Promise<Content> {
|
|
||||||
return runPromise((svc) => svc.read(file))
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function list(dir?: string) {
|
|
||||||
return runPromise((svc) => svc.list(dir))
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function search(input: { query: string; limit?: number; dirs?: boolean; type?: "file" | "directory" }) {
|
|
||||||
return runPromise((svc) => svc.search(input))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { fileURLToPath } from "url"
|
|||||||
import z from "zod"
|
import z from "zod"
|
||||||
import { Cause, Context, Effect, Layer, Queue, Stream } from "effect"
|
import { Cause, Context, Effect, Layer, Queue, Stream } from "effect"
|
||||||
import { ripgrep } from "ripgrep"
|
import { ripgrep } from "ripgrep"
|
||||||
import { makeRuntime } from "@/effect/run-service"
|
|
||||||
import { Filesystem } from "@/util/filesystem"
|
import { Filesystem } from "@/util/filesystem"
|
||||||
import { Log } from "@/util/log"
|
import { Log } from "@/util/log"
|
||||||
|
|
||||||
@@ -572,18 +572,4 @@ export namespace Ripgrep {
|
|||||||
)
|
)
|
||||||
|
|
||||||
export const defaultLayer = layer
|
export const defaultLayer = layer
|
||||||
|
|
||||||
const { runPromise } = makeRuntime(Service, defaultLayer)
|
|
||||||
|
|
||||||
export function files(input: FilesInput) {
|
|
||||||
return runPromise((svc) => Stream.toAsyncIterableEffect(svc.files(input)))
|
|
||||||
}
|
|
||||||
|
|
||||||
export function tree(input: TreeInput) {
|
|
||||||
return runPromise((svc) => svc.tree(input))
|
|
||||||
}
|
|
||||||
|
|
||||||
export function search(input: SearchInput) {
|
|
||||||
return runPromise((svc) => svc.search(input))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,20 +6,8 @@ import path from "path"
|
|||||||
import { tmpdir } from "../fixture/fixture"
|
import { tmpdir } from "../fixture/fixture"
|
||||||
import { Ripgrep } from "../../src/file/ripgrep"
|
import { Ripgrep } from "../../src/file/ripgrep"
|
||||||
|
|
||||||
async function seed(dir: string, count: number, size = 16) {
|
const run = <A>(effect: Effect.Effect<A, unknown, Ripgrep.Service>) =>
|
||||||
const txt = "a".repeat(size)
|
effect.pipe(Effect.provide(Ripgrep.defaultLayer), Effect.runPromise)
|
||||||
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", () => {
|
describe("file.ripgrep", () => {
|
||||||
test("defaults to include hidden", async () => {
|
test("defaults to include hidden", async () => {
|
||||||
@@ -31,7 +19,14 @@ describe("file.ripgrep", () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const files = await Array.fromAsync(await Ripgrep.files({ cwd: tmp.path }))
|
const files = await run(
|
||||||
|
Ripgrep.Service.use((rg) =>
|
||||||
|
rg.files({ cwd: tmp.path }).pipe(
|
||||||
|
Stream.runCollect,
|
||||||
|
Effect.map((c) => [...c]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
expect(files.includes("visible.txt")).toBe(true)
|
expect(files.includes("visible.txt")).toBe(true)
|
||||||
expect(files.includes(path.join(".opencode", "thing.json"))).toBe(true)
|
expect(files.includes(path.join(".opencode", "thing.json"))).toBe(true)
|
||||||
})
|
})
|
||||||
@@ -45,7 +40,14 @@ describe("file.ripgrep", () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const files = await Array.fromAsync(await Ripgrep.files({ cwd: tmp.path, hidden: false }))
|
const files = await run(
|
||||||
|
Ripgrep.Service.use((rg) =>
|
||||||
|
rg.files({ cwd: tmp.path, hidden: false }).pipe(
|
||||||
|
Stream.runCollect,
|
||||||
|
Effect.map((c) => [...c]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
expect(files.includes("visible.txt")).toBe(true)
|
expect(files.includes("visible.txt")).toBe(true)
|
||||||
expect(files.includes(path.join(".opencode", "thing.json"))).toBe(false)
|
expect(files.includes(path.join(".opencode", "thing.json"))).toBe(false)
|
||||||
})
|
})
|
||||||
@@ -57,7 +59,7 @@ describe("file.ripgrep", () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = await Ripgrep.search({ cwd: tmp.path, pattern: "needle" })
|
const result = await run(Ripgrep.Service.use((rg) => rg.search({ cwd: tmp.path, pattern: "needle" })))
|
||||||
expect(result.partial).toBe(false)
|
expect(result.partial).toBe(false)
|
||||||
expect(result.items).toEqual([])
|
expect(result.items).toEqual([])
|
||||||
})
|
})
|
||||||
@@ -70,7 +72,7 @@ describe("file.ripgrep", () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = await Ripgrep.search({ cwd: tmp.path, pattern: "needle" })
|
const result = await run(Ripgrep.Service.use((rg) => rg.search({ cwd: tmp.path, pattern: "needle" })))
|
||||||
expect(result.partial).toBe(false)
|
expect(result.partial).toBe(false)
|
||||||
expect(result.items).toHaveLength(1)
|
expect(result.items).toHaveLength(1)
|
||||||
expect(result.items[0]?.path.text).toBe(path.join("src", "match.ts"))
|
expect(result.items[0]?.path.text).toBe(path.join("src", "match.ts"))
|
||||||
@@ -78,99 +80,7 @@ describe("file.ripgrep", () => {
|
|||||||
expect(result.items[0]?.lines.text).toContain("needle")
|
expect(result.items[0]?.lines.text).toContain("needle")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("files returns empty when glob matches no files in worker mode", async () => {
|
test("search returns matched rows with glob filter", 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({
|
await using tmp = await tmpdir({
|
||||||
init: async (dir) => {
|
init: async (dir) => {
|
||||||
await Bun.write(path.join(dir, "match.ts"), "const value = 'needle'\n")
|
await Bun.write(path.join(dir, "match.ts"), "const value = 'needle'\n")
|
||||||
@@ -178,11 +88,9 @@ describe("Ripgrep.Service", () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = await Effect.gen(function* () {
|
const result = await run(
|
||||||
const rg = yield* Ripgrep.Service
|
Ripgrep.Service.use((rg) => rg.search({ cwd: tmp.path, pattern: "needle", glob: ["*.ts"] })),
|
||||||
return yield* rg.search({ cwd: tmp.path, pattern: "needle", glob: ["*.ts"] })
|
)
|
||||||
}).pipe(Effect.provide(Ripgrep.defaultLayer), Effect.runPromise)
|
|
||||||
|
|
||||||
expect(result.partial).toBe(false)
|
expect(result.partial).toBe(false)
|
||||||
expect(result.items).toHaveLength(1)
|
expect(result.items).toHaveLength(1)
|
||||||
expect(result.items[0]?.path.text).toContain("match.ts")
|
expect(result.items[0]?.path.text).toContain("match.ts")
|
||||||
@@ -198,16 +106,31 @@ describe("Ripgrep.Service", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const file = path.join(tmp.path, "match.ts")
|
const file = path.join(tmp.path, "match.ts")
|
||||||
const result = await Effect.gen(function* () {
|
const result = await run(Ripgrep.Service.use((rg) => rg.search({ cwd: tmp.path, pattern: "needle", file: [file] })))
|
||||||
const rg = yield* Ripgrep.Service
|
|
||||||
return yield* rg.search({ cwd: tmp.path, pattern: "needle", file: [file] })
|
|
||||||
}).pipe(Effect.provide(Ripgrep.defaultLayer), Effect.runPromise)
|
|
||||||
|
|
||||||
expect(result.partial).toBe(false)
|
expect(result.partial).toBe(false)
|
||||||
expect(result.items).toHaveLength(1)
|
expect(result.items).toHaveLength(1)
|
||||||
expect(result.items[0]?.path.text).toBe(file)
|
expect(result.items[0]?.path.text).toBe(file)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("files returns empty when glob matches no files", 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 files = await run(
|
||||||
|
Ripgrep.Service.use((rg) =>
|
||||||
|
rg.files({ cwd: tmp.path, glob: ["packages/*"] }).pipe(
|
||||||
|
Stream.runCollect,
|
||||||
|
Effect.map((c) => [...c]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
expect(files).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
test("files returns stream of filenames", async () => {
|
test("files returns stream of filenames", async () => {
|
||||||
await using tmp = await tmpdir({
|
await using tmp = await tmpdir({
|
||||||
init: async (dir) => {
|
init: async (dir) => {
|
||||||
@@ -216,14 +139,14 @@ describe("Ripgrep.Service", () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const files = await Effect.gen(function* () {
|
const files = await run(
|
||||||
const rg = yield* Ripgrep.Service
|
Ripgrep.Service.use((rg) =>
|
||||||
return yield* rg.files({ cwd: tmp.path }).pipe(
|
rg.files({ cwd: tmp.path }).pipe(
|
||||||
Stream.runCollect,
|
Stream.runCollect,
|
||||||
Effect.map((chunk) => [...chunk].sort()),
|
Effect.map((c) => [...c].sort()),
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}).pipe(Effect.provide(Ripgrep.defaultLayer), Effect.runPromise)
|
|
||||||
|
|
||||||
expect(files).toEqual(["a.txt", "b.txt"])
|
expect(files).toEqual(["a.txt", "b.txt"])
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -235,23 +158,57 @@ describe("Ripgrep.Service", () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const files = await Effect.gen(function* () {
|
const files = await run(
|
||||||
const rg = yield* Ripgrep.Service
|
Ripgrep.Service.use((rg) =>
|
||||||
return yield* rg.files({ cwd: tmp.path, glob: ["*.ts"] }).pipe(
|
rg.files({ cwd: tmp.path, glob: ["*.ts"] }).pipe(
|
||||||
Stream.runCollect,
|
Stream.runCollect,
|
||||||
Effect.map((chunk) => [...chunk]),
|
Effect.map((c) => [...c]),
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}).pipe(Effect.provide(Ripgrep.defaultLayer), Effect.runPromise)
|
|
||||||
|
|
||||||
expect(files).toEqual(["keep.ts"])
|
expect(files).toEqual(["keep.ts"])
|
||||||
})
|
})
|
||||||
|
|
||||||
test("files dies on nonexistent directory", async () => {
|
test("files dies on nonexistent directory", async () => {
|
||||||
const exit = await Effect.gen(function* () {
|
const exit = await Ripgrep.Service.use((rg) =>
|
||||||
const rg = yield* Ripgrep.Service
|
rg.files({ cwd: "/tmp/nonexistent-dir-12345" }).pipe(Stream.runCollect),
|
||||||
return yield* rg.files({ cwd: "/tmp/nonexistent-dir-12345" }).pipe(Stream.runCollect)
|
).pipe(Effect.provide(Ripgrep.defaultLayer), Effect.runPromiseExit)
|
||||||
}).pipe(Effect.provide(Ripgrep.defaultLayer), Effect.runPromiseExit)
|
|
||||||
|
|
||||||
expect(exit._tag).toBe("Failure")
|
expect(exit._tag).toBe("Failure")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
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 prev = process.env["RIPGREP_CONFIG_PATH"]
|
||||||
|
process.env["RIPGREP_CONFIG_PATH"] = path.join(tmp.path, "missing-ripgreprc")
|
||||||
|
try {
|
||||||
|
const result = await run(Ripgrep.Service.use((rg) => rg.search({ cwd: tmp.path, pattern: "needle" })))
|
||||||
|
expect(result.items).toHaveLength(1)
|
||||||
|
} finally {
|
||||||
|
if (prev === undefined) delete process.env["RIPGREP_CONFIG_PATH"]
|
||||||
|
else process.env["RIPGREP_CONFIG_PATH"] = prev
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
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 prev = process.env["RIPGREP_CONFIG_PATH"]
|
||||||
|
process.env["RIPGREP_CONFIG_PATH"] = path.join(tmp.path, "missing-ripgreprc")
|
||||||
|
try {
|
||||||
|
const result = await run(Ripgrep.Service.use((rg) => rg.search({ cwd: tmp.path, pattern: "needle" })))
|
||||||
|
expect(result.items).toHaveLength(1)
|
||||||
|
} finally {
|
||||||
|
if (prev === undefined) delete process.env["RIPGREP_CONFIG_PATH"]
|
||||||
|
else process.env["RIPGREP_CONFIG_PATH"] = prev
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user