fix(grep): format files_with_matches output as clean file paths
This commit is contained in:
123
src/tools/grep/result-formatter.test.ts
Normal file
123
src/tools/grep/result-formatter.test.ts
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/// <reference types="bun-types" />
|
||||||
|
|
||||||
|
import { describe, expect, test } from "bun:test"
|
||||||
|
|
||||||
|
import { formatGrepResult } from "./result-formatter"
|
||||||
|
import type { GrepResult } from "./types"
|
||||||
|
|
||||||
|
describe("formatGrepResult", () => {
|
||||||
|
describe("#given grep result has error", () => {
|
||||||
|
describe("#when formatting result", () => {
|
||||||
|
test("#then returns error message", () => {
|
||||||
|
const result: GrepResult = {
|
||||||
|
matches: [],
|
||||||
|
totalMatches: 0,
|
||||||
|
filesSearched: 0,
|
||||||
|
truncated: false,
|
||||||
|
error: "ripgrep failed",
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatted = formatGrepResult(result)
|
||||||
|
|
||||||
|
expect(formatted).toBe("Error: ripgrep failed")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("#given grep result has no matches", () => {
|
||||||
|
describe("#when formatting result", () => {
|
||||||
|
test("#then returns no matches message", () => {
|
||||||
|
const result: GrepResult = {
|
||||||
|
matches: [],
|
||||||
|
totalMatches: 0,
|
||||||
|
filesSearched: 0,
|
||||||
|
truncated: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatted = formatGrepResult(result)
|
||||||
|
|
||||||
|
expect(formatted).toBe("No matches found")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("#given grep result is files-with-matches mode", () => {
|
||||||
|
describe("#when formatting result", () => {
|
||||||
|
test("#then prints only file paths", () => {
|
||||||
|
const result: GrepResult = {
|
||||||
|
matches: [
|
||||||
|
{ file: "src/foo.ts", line: 0, text: "" },
|
||||||
|
{ file: "src/bar.ts", line: 0, text: "" },
|
||||||
|
{ file: "src/baz.ts", line: 0, text: "" },
|
||||||
|
],
|
||||||
|
totalMatches: 3,
|
||||||
|
filesSearched: 3,
|
||||||
|
truncated: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatted = formatGrepResult(result)
|
||||||
|
|
||||||
|
expect(formatted).toBe(
|
||||||
|
"Found 3 match(es) in 3 file(s)\n\n" +
|
||||||
|
"src/foo.ts\n\n" +
|
||||||
|
"src/bar.ts\n\n" +
|
||||||
|
"src/baz.ts\n",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("#given grep result is content mode", () => {
|
||||||
|
describe("#when formatting result", () => {
|
||||||
|
test("#then prints line numbers and content", () => {
|
||||||
|
const result: GrepResult = {
|
||||||
|
matches: [
|
||||||
|
{ file: "src/foo.ts", line: 10, text: " function hello() {" },
|
||||||
|
{ file: "src/foo.ts", line: 25, text: " function world() {" },
|
||||||
|
{ file: "src/bar.ts", line: 5, text: ' import { hello } from "./foo"' },
|
||||||
|
],
|
||||||
|
totalMatches: 3,
|
||||||
|
filesSearched: 2,
|
||||||
|
truncated: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatted = formatGrepResult(result)
|
||||||
|
|
||||||
|
expect(formatted).toBe(
|
||||||
|
"Found 3 match(es) in 2 file(s)\n\n" +
|
||||||
|
"src/foo.ts\n" +
|
||||||
|
" 10: function hello() {\n" +
|
||||||
|
" 25: function world() {\n\n" +
|
||||||
|
"src/bar.ts\n" +
|
||||||
|
' 5: import { hello } from "./foo"\n',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("#given grep result has mixed file-only and content matches", () => {
|
||||||
|
describe("#when formatting result", () => {
|
||||||
|
test("#then skips file-only placeholders and prints valid content matches", () => {
|
||||||
|
const result: GrepResult = {
|
||||||
|
matches: [
|
||||||
|
{ file: "src/foo.ts", line: 0, text: "" },
|
||||||
|
{ file: "src/foo.ts", line: 10, text: " function hello() {" },
|
||||||
|
{ file: "src/bar.ts", line: 0, text: "" },
|
||||||
|
],
|
||||||
|
totalMatches: 3,
|
||||||
|
filesSearched: 2,
|
||||||
|
truncated: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatted = formatGrepResult(result)
|
||||||
|
|
||||||
|
expect(formatted).toBe(
|
||||||
|
"Found 3 match(es) in 2 file(s)\n\n" +
|
||||||
|
"src/foo.ts\n" +
|
||||||
|
" 10: function hello() {\n\n" +
|
||||||
|
"src/bar.ts\n",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -10,6 +10,7 @@ export function formatGrepResult(result: GrepResult): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const lines: string[] = []
|
const lines: string[] = []
|
||||||
|
const isFilesOnlyMode = result.matches.every((match) => match.line === 0 && match.text.trim() === "")
|
||||||
|
|
||||||
lines.push(`Found ${result.totalMatches} match(es) in ${result.filesSearched} file(s)`)
|
lines.push(`Found ${result.totalMatches} match(es) in ${result.filesSearched} file(s)`)
|
||||||
if (result.truncated) {
|
if (result.truncated) {
|
||||||
@@ -26,8 +27,14 @@ export function formatGrepResult(result: GrepResult): string {
|
|||||||
|
|
||||||
for (const [file, matches] of byFile) {
|
for (const [file, matches] of byFile) {
|
||||||
lines.push(file)
|
lines.push(file)
|
||||||
for (const match of matches) {
|
if (!isFilesOnlyMode) {
|
||||||
lines.push(` ${match.line}: ${match.text.trim()}`)
|
for (const match of matches) {
|
||||||
|
const trimmedText = match.text.trim()
|
||||||
|
if (match.line === 0 && trimmedText === "") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lines.push(` ${match.line}: ${trimmedText}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lines.push("")
|
lines.push("")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user