import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// Load signatures
const signaturesPath = path.join(__dirname, '..', 'rules', 'signatures.json');
let signatures = null;
async function loadSignatures() {
if (!signatures) {
const data = await fs.readFile(signaturesPath, 'utf-8');
signatures = JSON.parse(data);
}
return signatures;
}
/**
* Detect programming languages used in a project
* @param {string} projectPath - Path to the project directory
* @param {string[]} files - List of files in the project (relative paths)
* @returns {Promise<Array<{name: string, confidence: number}>>}
*/
export async function detectLanguages(projectPath, files) {
const sigs = await loadSignatures();
const detected = [];
const fileSet = new Set(files.map(f => path.basename(f)));
// Count extensions
const extensionCounts = {};
for (const file of files) {
const ext = path.extname(file).toLowerCase();
if (ext) {
extensionCounts[ext] = (extensionCounts[ext] || 0) + 1;
}
}
for (const [langKey, langData] of Object.entries(sigs.languages)) {
let confidence = 0;
// Check signature files (+0.6)
const hasSignatureFile = langData.files.some(sigFile => fileSet.has(sigFile));
if (hasSignatureFile) {
confidence += 0.6;
}
// Check file extensions (+0.1 to +0.3 based on count)
const langExtensions = langData.extensions || [];
let extCount = 0;
for (const ext of langExtensions) {
extCount += extensionCounts[ext] || 0;
}
if (extCount > 0) {
// Scale confidence based on file count (max +0.3)
const extConfidence = Math.min(0.3, extCount * 0.02);
confidence += extConfidence;
}
if (confidence > 0) {
detected.push({
name: langData.name,
key: langKey,
confidence: Math.round(confidence * 100) / 100
});
}
}
// Sort by confidence descending
detected.sort((a, b) => b.confidence - a.confidence);
return detected;
}
/**
* Get signature rules
*/
export async function getSignatures() {
return loadSignatures();
}