import { readdir, readFile, stat } from 'fs/promises';
import { join, extname } from 'path';
import { SupportedLanguage } from '../types/index.js';
export class FileUtils {
static readonly EXTENSIONS: Record<SupportedLanguage, string[]> = {
typescript: ['.ts', '.tsx'],
javascript: ['.js', '.jsx'],
python: ['.py']
};
static async getLanguage(filePath: string): Promise<SupportedLanguage | null> {
const ext = extname(filePath);
for (const [lang, exts] of Object.entries(this.EXTENSIONS)) {
if (exts.includes(ext)) {
return lang as SupportedLanguage;
}
}
return null;
}
static async readFileContent(filePath: string): Promise<string> {
try {
return await readFile(filePath, 'utf-8');
} catch (error) {
throw new Error(`Failed to read file ${filePath}: ${(error as Error).message}`);
}
}
static async findSourceFiles(directory: string, recursive = true): Promise<string[]> {
const files: string[] = [];
const validExtensions = Object.values(this.EXTENSIONS).flat();
async function scan(dir: string) {
try {
const entries = await readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
if (recursive && !entry.name.startsWith('.') && entry.name !== 'node_modules') {
await scan(fullPath);
}
} else if (entry.isFile()) {
const ext = extname(entry.name);
if (validExtensions.includes(ext)) {
files.push(fullPath);
}
}
}
} catch (error) {
throw new Error(`Failed to scan directory ${dir}: ${(error as Error).message}`);
}
}
await scan(directory);
return files;
}
static async isDirectory(path: string): Promise<boolean> {
try {
const stats = await stat(path);
return stats.isDirectory();
} catch {
return false;
}
}
}