This commit is contained in:
125
.ai-context-generator-cli/src/utils/fileUtils.ts
Normal file
125
.ai-context-generator-cli/src/utils/fileUtils.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import ignore from 'ignore';
|
||||
import { glob } from 'glob';
|
||||
|
||||
export class FileUtils {
|
||||
private static instance: FileUtils;
|
||||
private ig: ReturnType<typeof ignore>;
|
||||
|
||||
private constructor() {
|
||||
this.ig = ignore();
|
||||
}
|
||||
|
||||
static getInstance(): FileUtils {
|
||||
if (!FileUtils.instance) {
|
||||
FileUtils.instance = new FileUtils();
|
||||
}
|
||||
return FileUtils.instance;
|
||||
}
|
||||
|
||||
async loadGitignore(dir: string): Promise<void> {
|
||||
const gitignorePath = path.join(dir, '.gitignore');
|
||||
if (await this.fileExists(gitignorePath)) {
|
||||
const content = await this.readFile(gitignorePath);
|
||||
const patterns = content
|
||||
.split('\n')
|
||||
.filter(line => line.trim() && !line.trim().startsWith('#'));
|
||||
this.ig.add(patterns);
|
||||
}
|
||||
}
|
||||
|
||||
addCustomPatterns(patterns: string[]): void {
|
||||
this.ig.add(patterns);
|
||||
}
|
||||
|
||||
isIgnored(filePath: string): boolean {
|
||||
const relativePath = path.relative(process.cwd(), filePath);
|
||||
return this.ig.ignores(relativePath);
|
||||
}
|
||||
|
||||
resolveDirectory(dir: string): string {
|
||||
if (path.isAbsolute(dir)) {
|
||||
return dir;
|
||||
}
|
||||
return path.resolve(process.cwd(), dir);
|
||||
}
|
||||
|
||||
async getFiles(
|
||||
dir: string,
|
||||
includes: string[],
|
||||
excludes: string[]
|
||||
): Promise<string[]> {
|
||||
const allFiles: string[] = [];
|
||||
|
||||
for (const pattern of includes) {
|
||||
const files = await glob(pattern, {
|
||||
cwd: dir,
|
||||
ignore: excludes,
|
||||
absolute: true,
|
||||
});
|
||||
allFiles.push(...files);
|
||||
}
|
||||
|
||||
const uniqueFiles = [...new Set(allFiles)].filter(
|
||||
file => !this.isIgnored(file)
|
||||
);
|
||||
|
||||
return uniqueFiles.sort();
|
||||
}
|
||||
|
||||
async fileExists(filePath: string): Promise<boolean> {
|
||||
try {
|
||||
await fs.promises.access(filePath, fs.constants.F_OK);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async readFile(filePath: string): Promise<string> {
|
||||
return fs.promises.readFile(filePath, 'utf-8');
|
||||
}
|
||||
|
||||
async writeFile(
|
||||
filePath: string,
|
||||
content: string
|
||||
): Promise<void> {
|
||||
const dir = path.dirname(filePath);
|
||||
if (!(await this.fileExists(dir))) {
|
||||
await fs.promises.mkdir(dir, { recursive: true });
|
||||
}
|
||||
await fs.promises.writeFile(filePath, content, 'utf-8');
|
||||
}
|
||||
|
||||
async getFileSize(filePath: string): Promise<number> {
|
||||
const stats = await fs.promises.stat(filePath);
|
||||
return stats.size;
|
||||
}
|
||||
|
||||
async getDirectoryContents(
|
||||
dir: string
|
||||
): Promise<string[]> {
|
||||
try {
|
||||
const entries = await fs.promises.readdir(dir, {
|
||||
withFileTypes: true,
|
||||
});
|
||||
return entries.map(entry => entry.name);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
getFileExtension(filePath: string): string {
|
||||
return path.extname(filePath).toLowerCase();
|
||||
}
|
||||
|
||||
isTextFile(filePath: string): boolean {
|
||||
const textExtensions = [
|
||||
'.ts', '.js', '.py', '.go', '.rs', '.java', '.c', '.cpp',
|
||||
'.h', '.hpp', '.json', '.yaml', '.yml', '.xml', '.html',
|
||||
'.css', '.scss', '.md', '.txt', '.sql', '.sh', '.bash',
|
||||
];
|
||||
return textExtensions.includes(this.getFileExtension(filePath));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user