Sfoglia il codice sorgente

fix(core): handle oversized ripgrep matches

Dax Raad 2 settimane fa
parent
commit
0261f04b90
2 ha cambiato i file con 25 aggiunte e 5 eliminazioni
  1. 2 5
      packages/core/src/ripgrep.ts
  2. 23 0
      packages/core/test/ripgrep.test.ts

+ 2 - 5
packages/core/src/ripgrep.ts

@@ -16,7 +16,6 @@ import { RipgrepBinary } from "./ripgrep/binary"
  */
  */
 
 
 const ERROR_BYTES = 8 * 1024
 const ERROR_BYTES = 8 * 1024
-const MAX_RECORD_BYTES = 64 * 1024
 const MAX_SUBMATCHES = 100
 const MAX_SUBMATCHES = 100
 
 
 const RawMatch = Schema.Struct({
 const RawMatch = Schema.Struct({
@@ -231,10 +230,8 @@ const layer = Layer.effect(
             input.file ?? ".",
             input.file ?? ".",
           ],
           ],
           parse: (line) =>
           parse: (line) =>
-            (Buffer.byteLength(line, "utf8") > MAX_RECORD_BYTES
-              ? Effect.fail(failure(`Ripgrep JSON record exceeded ${MAX_RECORD_BYTES} bytes`))
-              : decodeJsonRecord(line).pipe(Effect.mapError((cause) => failure("Invalid ripgrep JSON output", cause)))
-            ).pipe(
+            decodeJsonRecord(line).pipe(
+              Effect.mapError((cause) => failure("Invalid ripgrep JSON output", cause)),
               Effect.flatMap((json) => {
               Effect.flatMap((json) => {
                 if (!json || typeof json !== "object" || !("type" in json) || json.type !== "match")
                 if (!json || typeof json !== "object" || !("type" in json) || json.type !== "match")
                   return Effect.succeed(undefined)
                   return Effect.succeed(undefined)

+ 23 - 0
packages/core/test/ripgrep.test.ts

@@ -62,4 +62,27 @@ describe("Ripgrep", () => {
       (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
       (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
     ),
     ),
   )
   )
+
+  it.live("returns a bounded preview for matches on oversized lines", () =>
+    Effect.acquireUseRelease(
+      Effect.promise(() => tmpdir()),
+      (tmp) =>
+        Effect.gen(function* () {
+          yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, "generated.ts"), `Cloudflare${"x".repeat(70 * 1024)}\n`))
+
+          const matches = yield* (yield* Ripgrep.Service).grep({
+            cwd: tmp.path,
+            pattern: "Cloudflare",
+            limit: 10,
+          })
+
+          expect(matches).toHaveLength(1)
+          expect(matches[0]?.entry.path).toBe(RelativePath.make("generated.ts"))
+          expect(matches[0]?.text).toHaveLength(2_003)
+          expect(matches[0]?.text.endsWith("...")).toBe(true)
+          expect(matches[0]?.submatches).toEqual([{ text: "Cloudflare", start: 0, end: 10 }])
+        }),
+      (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
+    ),
+  )
 })
 })