diff --git a/src/utils/fileUtils.ts b/src/utils/fileUtils.ts new file mode 100644 index 0000000..a484f6f --- /dev/null +++ b/src/utils/fileUtils.ts @@ -0,0 +1,126 @@ +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; + + private constructor() { + this.ig = ignore(); + } + + static getInstance(): FileUtils { + if (!FileUtils.instance) { + FileUtils.instance = new FileUtils(); + } + return FileUtils.instance; + } + + async loadGitignore(dir: string): Promise { + 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 { + const path = require('path'); + if (path.isAbsolute(dir)) { + return dir; + } + return path.resolve(process.cwd(), dir); + } + + async getFiles( + dir: string, + includes: string[], + excludes: string[] + ): Promise { + 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 { + try { + await fs.promises.access(filePath, fs.constants.F_OK); + return true; + } catch { + return false; + } + } + + async readFile(filePath: string): Promise { + return fs.promises.readFile(filePath, 'utf-8'); + } + + async writeFile( + filePath: string, + content: string + ): Promise { + 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 { + const stats = await fs.promises.stat(filePath); + return stats.size; + } + + async getDirectoryContents( + dir: string + ): Promise { + 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)); + } +}