fix(coding): preserve conflict and unicode search results

This commit is contained in:
2026-08-23 18:31:53 +08:00
parent 9520872d2f
commit 365c2b0f76
6 changed files with 152 additions and 19 deletions

View File

@@ -25,6 +25,10 @@ async function git(root: string, ...args: string[]): Promise<void> {
await exec('git', ['-C', root, ...args], { windowsHide: true });
}
async function gitOutput(root: string, ...args: string[]): Promise<string> {
return (await exec('git', ['-C', root, ...args], { windowsHide: true })).stdout.trim();
}
async function initializeRepository(root: string): Promise<void> {
await git(root, 'init');
await git(root, 'config', 'user.email', 'pi-files@example.invalid');
@@ -79,11 +83,33 @@ describe('PI-105 project file service', () => {
await expect(service.content(root, 'binary.bin')).rejects.toThrow('Binary project files');
});
it('keeps reachable Git merge conflicts visible in file status', async () => {
const root = await temporaryRoot('makelore-pi-files-conflict-');
await initializeRepository(root);
const baseBranch = await gitOutput(root, 'branch', '--show-current');
await writeFile(path.join(root, 'conflict.txt'), 'baseline\n', 'utf8');
await git(root, 'add', 'conflict.txt');
await git(root, 'commit', '-m', 'conflict baseline');
await git(root, 'switch', '-c', 'conflicting-change');
await writeFile(path.join(root, 'conflict.txt'), 'branch change\n', 'utf8');
await git(root, 'commit', '-am', 'branch change');
await git(root, 'switch', baseBranch);
await writeFile(path.join(root, 'conflict.txt'), 'base change\n', 'utf8');
await git(root, 'commit', '-am', 'base change');
await expect(exec('git', ['-C', root, 'merge', 'conflicting-change'], { windowsHide: true }))
.rejects.toThrow();
expect(await new CodingProjectFileService().status(root)).toContainEqual({
path: 'conflict.txt', name: 'conflict.txt', type: 'file', status: 'conflicted',
});
});
it('searches literal text with bounded relative matches and falls back outside Git', async () => {
const root = await temporaryRoot('makelore-pi-files-search-');
await mkdir(path.join(root, 'docs'), { recursive: true });
await mkdir(path.join(root, 'node_modules', 'private-package'), { recursive: true });
await writeFile(path.join(root, 'docs', 'guide.md'), 'First line\nNeedle and needle again\n', 'utf8');
await writeFile(path.join(root, 'docs', 'unicode.md'), 'İx needle and NEEDLE\n', 'utf8');
await writeFile(path.join(root, 'node_modules', 'private-package', 'secret.txt'), 'needle\n', 'utf8');
const service = new CodingProjectFileService({
async run() {
@@ -95,7 +121,7 @@ describe('PI-105 project file service', () => {
'docs/guide.md',
]);
const matches = await service.search(root, 'needle');
expect(matches).toEqual([{
expect(matches).toContainEqual({
path: 'docs/guide.md',
name: 'guide.md',
lineNumber: 2,
@@ -104,8 +130,20 @@ describe('PI-105 project file service', () => {
{ text: 'Needle', start: 0, end: 6 },
{ text: 'needle', start: 11, end: 17 },
],
}]);
});
expect(JSON.stringify(matches)).not.toContain(root);
expect(JSON.stringify(matches)).not.toContain('private-package');
expect(await service.search(root, 'i')).toContainEqual(expect.objectContaining({
path: 'docs/unicode.md',
submatches: [{ text: 'İ', start: 0, end: 1 }],
}));
expect(await service.search(root, 'needle')).toContainEqual(expect.objectContaining({
path: 'docs/unicode.md',
submatches: [
{ text: 'needle', start: 3, end: 9 },
{ text: 'NEEDLE', start: 14, end: 20 },
],
}));
});
});