From e4b7220dd0207f183c304b23bab9e1c63dae8b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20HOUZ=C3=89?= Date: Sun, 23 Aug 2026 14:18:58 +0200 Subject: [PATCH] Restore deriveSegmentText() to fix missing matchedText (#151) PR #133 introduced deriveSegmentText() to derive a text-match segment's matched text from fragment.slice(indices[0], indices[1]) when GitHub omits the text field, but the current code on this branch still defaulted to an empty string in that case. Reintroduced the helper and wired it into fetchAllResults()'s mapping, with unit tests for the helper itself and an integration test through fetchAllResults() covering the omitted-text case. Closes #151 --- src/api.test.ts | 43 +++++++++++++++++++++++++++++++++++++++++++ src/api.ts | 14 +++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/api.test.ts b/src/api.test.ts index c46791b..62c70cf 100644 --- a/src/api.test.ts +++ b/src/api.test.ts @@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, it } from "bun:test"; import { buildFetchProgress, buildLineResolutionProgress, + deriveSegmentText, fetchAllResults, fetchRepoTeams, searchCode, @@ -28,6 +29,26 @@ describe("segmentLineCol (api)", () => { }); }); +// ─── deriveSegmentText (issue #151, restores PR #133) ───────────────────────────────────── + +describe("deriveSegmentText", () => { + it("returns seg.text unchanged when GitHub provides it", () => { + expect(deriveSegmentText("hello world", { text: "hello", indices: [0, 5] })).toBe("hello"); + }); + + it("derives the text from fragment + indices when seg.text is omitted", () => { + expect(deriveSegmentText("hello world", { indices: [6, 11] })).toBe("world"); + }); + + it("returns an empty string for out-of-range indices", () => { + expect(deriveSegmentText("hello", { indices: [10, 20] })).toBe(""); + }); + + it("returns an empty string when end is before start", () => { + expect(deriveSegmentText("hello", { indices: [4, 1] })).toBe(""); + }); +}); + // ─── searchCode ─────────────────────────────────────────────────────────────── describe("searchCode", () => { @@ -146,6 +167,28 @@ describe("fetchAllResults", () => { expect(results[0].textMatches[0].matches[0].col).toBe(1); }); + it("derives matchedText from fragment + indices when GitHub omits the segment's text field (issue #151)", async () => { + const fakeItem = { + path: "src/foo.ts", + html_url: "https://github.com/org/repo/blob/main/src/foo.ts", + repository: { full_name: "org/repo", archived: false }, + text_matches: [ + { + fragment: "hello world", + matches: [{ indices: [6, 11] }], + }, + ], + }; + 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("world", "org", "tok"); + expect(results[0].textMatches[0].matches[0].text).toBe("world"); + }); + it("marks archived repos correctly", async () => { const fakeItem = { path: "lib/old.ts", diff --git a/src/api.ts b/src/api.ts index 693e435..134f138 100644 --- a/src/api.ts +++ b/src/api.ts @@ -123,6 +123,18 @@ export function segmentLineCol(fragment: string, offset: number): { line: number }; } +/** + * Derive a text-match segment's matched text from `fragment` and `indices` + * when GitHub omits the `text` field on the segment. Restores PR #133 — + * see issue #151. + */ +export function deriveSegmentText(fragment: string, seg: RawSearchSegment): string { + if (seg.text !== undefined) return seg.text; + const [start, end] = seg.indices; + if (start < 0 || end < start || end > fragment.length) return ""; + return fragment.slice(start, end); +} + export async function searchCode( q: string, org: string, @@ -296,7 +308,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, seg), indices, line, col }; }), }; }),