mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-20 16:57:46 +00:00
feat(git): Refactor gitignore handling to use ignore library instead of minimatch (#864)
This commit is contained in:
@@ -6,18 +6,17 @@
|
||||
|
||||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
import { minimatch } from 'minimatch';
|
||||
import ignore, { Ignore } from 'ignore';
|
||||
import { isGitRepository } from './gitUtils.js';
|
||||
|
||||
export interface GitIgnoreFilter {
|
||||
isIgnored(filePath: string): boolean;
|
||||
getIgnoredPatterns(): string[];
|
||||
}
|
||||
|
||||
export class GitIgnoreParser implements GitIgnoreFilter {
|
||||
private ignorePatterns: string[] = [];
|
||||
private projectRoot: string;
|
||||
private isGitRepo: boolean = false;
|
||||
private ig: Ignore = ignore();
|
||||
|
||||
constructor(projectRoot: string) {
|
||||
this.projectRoot = path.resolve(projectRoot);
|
||||
@@ -32,13 +31,13 @@ export class GitIgnoreParser implements GitIgnoreFilter {
|
||||
];
|
||||
|
||||
// Always ignore .git directory regardless of .gitignore content
|
||||
this.ignorePatterns = ['.git/**', '.git'];
|
||||
this.addPatterns(['.git']);
|
||||
|
||||
for (const gitIgnoreFile of gitIgnoreFiles) {
|
||||
try {
|
||||
const content = await fs.readFile(gitIgnoreFile, 'utf-8');
|
||||
const patterns = this.parseGitIgnoreContent(content);
|
||||
this.ignorePatterns.push(...patterns);
|
||||
const patterns = content.split('\n').map((p) => p.trim());
|
||||
this.addPatterns(patterns);
|
||||
} catch (_error) {
|
||||
// File doesn't exist or can't be read, continue silently
|
||||
}
|
||||
@@ -46,71 +45,33 @@ export class GitIgnoreParser implements GitIgnoreFilter {
|
||||
}
|
||||
}
|
||||
|
||||
private parseGitIgnoreContent(content: string): string[] {
|
||||
return content
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line && !line.startsWith('#'))
|
||||
.map((pattern) => {
|
||||
// Handle negation patterns (!) - for now we'll skip them
|
||||
if (pattern.startsWith('!')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Convert gitignore patterns to minimatch-compatible patterns
|
||||
if (pattern.endsWith('/')) {
|
||||
// Directory pattern - match directory and all contents
|
||||
const dirPattern = pattern.slice(0, -1); // Remove trailing slash
|
||||
return [dirPattern, dirPattern + '/**'];
|
||||
}
|
||||
|
||||
// If pattern doesn't contain /, it should match at any level
|
||||
if (!pattern.includes('/') && !pattern.startsWith('**/')) {
|
||||
return '**/' + pattern;
|
||||
}
|
||||
|
||||
return pattern;
|
||||
})
|
||||
.filter((pattern) => pattern !== null)
|
||||
.flat() as string[];
|
||||
private addPatterns(patterns: string[]) {
|
||||
this.ig.add(patterns);
|
||||
}
|
||||
|
||||
isIgnored(filePath: string): boolean {
|
||||
// If not a git repository, nothing is ignored
|
||||
if (!this.isGitRepo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normalize the input path (handle ./ prefixes)
|
||||
let cleanPath = filePath;
|
||||
if (cleanPath.startsWith('./')) {
|
||||
cleanPath = cleanPath.slice(2);
|
||||
}
|
||||
const relativePath = path.isAbsolute(filePath)
|
||||
? path.relative(this.projectRoot, filePath)
|
||||
: filePath;
|
||||
|
||||
// Convert to relative path from project root
|
||||
const relativePath = path.relative(
|
||||
this.projectRoot,
|
||||
path.resolve(this.projectRoot, cleanPath),
|
||||
);
|
||||
|
||||
// Handle paths that go outside project root
|
||||
if (relativePath.startsWith('..')) {
|
||||
if (relativePath === '' || relativePath.startsWith('..')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normalize path separators for cross-platform compatibility
|
||||
const normalizedPath = relativePath.replace(/\\/g, '/');
|
||||
let normalizedPath = relativePath.replace(/\\/g, '/');
|
||||
if (normalizedPath.startsWith('./')) {
|
||||
normalizedPath = normalizedPath.substring(2);
|
||||
}
|
||||
|
||||
return this.ignorePatterns.some((pattern) =>
|
||||
minimatch(normalizedPath, pattern, {
|
||||
dot: true,
|
||||
matchBase: false,
|
||||
flipNegate: false,
|
||||
}),
|
||||
);
|
||||
const ignored = this.ig.ignores(normalizedPath);
|
||||
return ignored;
|
||||
}
|
||||
|
||||
getIgnoredPatterns(): string[] {
|
||||
return [...this.ignorePatterns];
|
||||
getGitRepoRoot(): string {
|
||||
return this.projectRoot;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user