From a6862c00a7ba1070993b638c7210889fa40ca322 Mon Sep 17 00:00:00 2001 From: Armand Abric Date: Tue, 7 Jul 2026 11:58:12 +0200 Subject: [PATCH] Fix missing `matchedText` key in JSON result --- src/api.test.ts | 22 ++++++++++++++++++++++ src/api.ts | 14 +++++++++++++- src/output.test.ts | 2 +- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/api.test.ts b/src/api.test.ts index 83ae3bb..9ed1511 100644 --- a/src/api.test.ts +++ b/src/api.test.ts @@ -146,6 +146,28 @@ describe("fetchAllResults", () => { expect(results[0].textMatches[0].matches[0].col).toBe(1); }); + it("derives segment text from fragment when GitHub omits match text", async () => { + const fakeItem = { + path: "package.json", + html_url: "https://github.com/org/repo/blob/main/package.json", + repository: { full_name: "org/repo", archived: false }, + text_matches: [ + { + fragment: '{"dependencies":{"react-dom":"18.3.1"}}', + matches: [{ indices: [18, 27] }], + }, + ], + }; + globalThis.fetch = (async () => + new Response(JSON.stringify({ items: [fakeItem], total_count: 1 }), { + status: 200, + headers: { "content-type": "application/json" }, + })) as typeof fetch; + + const results = await fetchAllResults("react-dom filename:package.json", "org", "tok"); + expect(results[0].textMatches[0].matches[0].text).toBe("react-dom"); + }); + it("marks archived repos correctly", async () => { const fakeItem = { path: "lib/old.ts", diff --git a/src/api.ts b/src/api.ts index ab7e2b0..fc7ea31 100644 --- a/src/api.ts +++ b/src/api.ts @@ -22,6 +22,18 @@ interface RawCodeItem { text_matches?: RawTextMatch[]; } +function deriveSegmentText( + fragment: string, + indices: [number, number], + providedText?: string, +): string { + if (providedText !== undefined) return providedText; + const [rawStart, rawEnd] = indices; + const start = Math.max(0, Math.min(rawStart, fragment.length)); + const end = Math.max(start, Math.min(rawEnd, fragment.length)); + return fragment.slice(start, end); +} + interface SearchCodeResponse { items: RawCodeItem[]; total_count: number; @@ -287,7 +299,7 @@ export async function fetchAllResults( const indices = seg.indices; const { line: fragLine, col } = segmentLineCol(fragment, indices[0]); const line = fragmentStartLine + fragLine - 1; - return { text: seg.text ?? "", indices, line, col }; + return { text: deriveSegmentText(fragment, indices, seg.text), indices, line, col }; }), }; }), diff --git a/src/output.test.ts b/src/output.test.ts index 39f38e9..97d1b00 100644 --- a/src/output.test.ts +++ b/src/output.test.ts @@ -622,7 +622,7 @@ describe("buildJsonOutput — line/col fields", () => { }); it("omits matchedText when seg.text is an empty string", () => { - // api.ts normalizes missing segment text to "" — matchedText must not be emitted + // Empty segment text should not emit matchedText in JSON output. const groups: RepoGroup[] = [ { repoFullName: "myorg/repoA",