// @ts-check import fs from "fs"; import path from "path"; import { Request, Response } from 'express'; interface SkillResult { name: string; skill: string; extension: string; } interface Config { project: string; } const languageMap: { [key: string]: string } = { "js": "JavaScript", "ts": "TypeScript", "html": "HTML", "css": "CSS", "json": "JSON", "md": "Markdown", "py": "Python", "java": "Java", "c": "C", "cpp": "C++", "cs": "C#", "go": "Go", "rb": "Ruby", "php": "PHP", "swift": "Swift", "kt": "Kotlin", "sh": "Shell Script", "xml": "XML", "yaml": "YAML", "yml": "YAML", "sql": "SQL", "jsx": "React (JavaScript)", "tsx": "React (TypeScript)", }; function walkDir(dirPath: string, counts: Map): number { let totalFiles = 0; if (!fs.existsSync(dirPath) || !fs.statSync(dirPath).isDirectory()) { console.warn(`[Skills Analyzer] Directory not found or not a directory: ${dirPath}`); return 0; } const files = fs.readdirSync(dirPath); for (const file of files) { const fullPath = path.join(dirPath, file); try { const stats = fs.statSync(fullPath); if (stats.isDirectory()) { totalFiles += walkDir(fullPath, counts); } else if (stats.isFile()) { let ext = path.extname(file); if (ext) { ext = ext.substring(1).toLowerCase(); counts.set(ext, (counts.get(ext) || 0) + 1); totalFiles++; } } } catch (error: any) { console.error(`[Skills Analyzer] Error processing file ${fullPath}:`, error.message); } } return totalFiles; } async function analyzeProjectSkills(): Promise<{ project: string; skills: SkillResult[] }> { const configPath = path.resolve(__dirname, '..', 'config.json'); console.log(`[Skills Analyzer] Attempting to read config from: ${configPath}`); let projectRoot: string; try { const configContent = fs.readFileSync(configPath, 'utf8'); const config: Config = JSON.parse(configContent); if (!config.project) { throw new Error("Missing 'project' key in config.json. Please ensure it's defined."); } projectRoot = path.resolve(path.dirname(configPath), config.project); console.log(`[Skills Analyzer] Project path from config: ${projectRoot}`); } catch (error: any) { console.error(`[Skills Analyzer] Failed to read or parse config.json:`, error.message); return { project: "Unknown Project (config error)", skills: [] }; } const languageCounts = new Map(); const totalFiles = walkDir(projectRoot, languageCounts); if (totalFiles === 0) { console.warn(`[Skills Analyzer] No files with recognized extensions found in project directory: ${projectRoot}`); return { project: projectRoot, skills: [] }; } const skills: SkillResult[] = []; for (const [ext, count] of languageCounts.entries()) { const percentage = ((count / totalFiles) * 100).toFixed(2); const name = languageMap[ext] || ext.toUpperCase(); skills.push({ name: name.toLowerCase(), skill: `${percentage}%`, extension: ext, }); } skills.sort((a, b) => parseFloat(b.skill) - parseFloat(a.skill)); console.log(`[Skills Analyzer] Analysis complete for project: ${projectRoot}. Found ${totalFiles} files.`); return { project: projectRoot, skills: skills }; } interface LoginRouteParams { req: Request; res: Response; } interface LoginExpressRouteModule { method: "get" | "post" | "put" | "delete" | "patch" | "options" | "head" | "all"; path: string; install: (params: LoginRouteParams) => Promise | void; } export const modules: LoginExpressRouteModule[] = [ { method: "post", path: "/skills", install: async ({ req, res }: { req: Request; res: Response }) => { try { const { project, skills } = await analyzeProjectSkills(); res.json([{ project: project, skills: skills }]); } catch (error: any) { console.error("[Skills Route] Error serving skills:", error.message); res.status(500).json({ error: "Failed to analyze project skills. Check server logs." }); } }, }, ];