import fs from 'fs/promises';
import path from 'path';
import { getSignatures } from './language.js';
/**
* Detect frameworks used in a project
* @param {string} projectPath - Path to the project directory
* @param {string[]} files - List of files in the project
* @param {Array<{name: string, key: string}>} detectedLanguages - Languages detected
* @param {object} dependencies - Parsed dependencies object
* @returns {Promise<Array<{name: string, confidence: number}>>}
*/
export async function detectFrameworks(projectPath, files, detectedLanguages, dependencies) {
const sigs = await getSignatures();
const detected = [];
const fileSet = new Set(files.map(f => path.basename(f)));
const allDeps = getAllDependencyNames(dependencies);
for (const lang of detectedLanguages) {
const frameworkRules = sigs.frameworks[lang.key];
if (!frameworkRules) continue;
for (const [fwKey, fwData] of Object.entries(frameworkRules)) {
let confidence = 0;
// Check dependencies (+0.7)
const hasDep = fwData.deps?.some(dep =>
allDeps.some(d => d.toLowerCase().includes(dep.toLowerCase()))
);
if (hasDep) {
confidence += 0.7;
}
// Check additional files (+0.2)
const hasFile = fwData.files?.some(f => fileSet.has(f));
if (hasFile) {
confidence += 0.2;
}
if (confidence > 0) {
detected.push({
name: fwData.name,
key: fwKey,
language: lang.name,
confidence: Math.round(confidence * 100) / 100
});
}
}
}
// Sort by confidence descending
detected.sort((a, b) => b.confidence - a.confidence);
// Deduplicate frameworks (same framework from different languages)
const seen = new Set();
return detected.filter(fw => {
if (seen.has(fw.name)) return false;
seen.add(fw.name);
return true;
});
}
/**
* Extract all dependency names from parsed dependencies
*/
function getAllDependencyNames(dependencies) {
const names = [];
if (dependencies.primary) {
names.push(...dependencies.primary);
}
if (dependencies.dev) {
names.push(...dependencies.dev);
}
if (dependencies.all) {
names.push(...dependencies.all);
}
return names;
}
/**
* Detect database hints from dependencies
* @param {object} dependencies - Parsed dependencies
* @returns {Promise<string[]>}
*/
export async function detectDatabaseHints(dependencies) {
const sigs = await getSignatures();
const allDeps = getAllDependencyNames(dependencies);
const detected = new Set();
for (const [dbName, hints] of Object.entries(sigs.databaseHints || {})) {
for (const hint of hints) {
if (allDeps.some(d => d.toLowerCase().includes(hint.toLowerCase()))) {
detected.add(dbName.charAt(0).toUpperCase() + dbName.slice(1));
break;
}
}
}
return Array.from(detected);
}