// SPEC-597-EXEMPT: canonical mapping (npm-package↔framework, keyword catalogue)
// — must enumerate framework names by design; no detection logic to migrate.
// engine/project-scanner/stack-detector.ts — Detect technology stack from config files
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
const FRAMEWORK_PATTERNS = [
    ['next', /^next$/],
    ['nuxt', /^nuxt$/],
    ['react', /^react$/],
    ['vue', /^vue$/],
    ['angular', /^@angular\/core$/],
    ['svelte', /^svelte$/],
    ['express', /^express$/],
    ['fastify', /^fastify$/],
    ['hono', /^hono$/],
    ['nestjs', /^@nestjs\/core$/],
    ['koa', /^koa$/],
    ['astro', /^astro$/],
];
const TEST_RUNNER_PATTERNS = [
    ['vitest', /^vitest$/],
    ['jest', /^jest$/],
    ['mocha', /^mocha$/],
    ['jasmine', /^jasmine$/],
    ['ava', /^ava$/],
    ['tap', /^tap$/],
];
const BUNDLER_PATTERNS = [
    ['vite', /^vite$/],
    ['webpack', /^webpack$/],
    ['esbuild', /^esbuild$/],
    ['rollup', /^rollup$/],
    ['parcel', /^parcel$/],
    ['turbopack', /^turbopack$/],
];
function matchFirst(deps, patterns) {
    for (const [name, pattern] of patterns) {
        if (Object.keys(deps).some((dep) => pattern.test(dep))) {
            return name;
        }
    }
    return null;
}
async function detectFromPackageJson(projectPath) {
    try {
        const raw = await readFile(join(projectPath, 'package.json'), 'utf-8');
        const pkg = JSON.parse(raw);
        const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
        const hasTypeScript = 'typescript' in allDeps || Object.keys(allDeps).some((d) => d.startsWith('@types/'));
        const language = hasTypeScript ? 'typescript' : 'javascript';
        const framework = matchFirst(allDeps, FRAMEWORK_PATTERNS);
        const testRunner = matchFirst(allDeps, TEST_RUNNER_PATTERNS);
        const linter = 'eslint' in allDeps ? 'eslint' : 'tslint' in allDeps ? 'tslint' : null;
        const formatter = 'prettier' in allDeps ? 'prettier' : null;
        const bundler = matchFirst(allDeps, BUNDLER_PATTERNS);
        return { language, framework, testRunner, linter, formatter, bundler };
    }
    catch {
        return null;
    }
}
async function detectFromPython(projectPath) {
    const files = ['pyproject.toml', 'setup.py', 'requirements.txt'];
    for (const f of files) {
        try {
            await readFile(join(projectPath, f), 'utf-8');
            return {
                language: 'python',
                framework: null,
                testRunner: 'pytest',
                linter: null,
                formatter: null,
                bundler: null,
            };
        }
        catch {
            // continue
        }
    }
    return null;
}
async function detectFromManifest(projectPath, filename, language) {
    try {
        await readFile(join(projectPath, filename), 'utf-8');
        return {
            language,
            framework: null,
            testRunner: null,
            linter: null,
            formatter: null,
            bundler: null,
        };
    }
    catch {
        return null;
    }
}
export async function detectStack(projectPath) {
    const fromNode = await detectFromPackageJson(projectPath);
    if (fromNode) {
        return fromNode;
    }
    const fromPython = await detectFromPython(projectPath);
    if (fromPython) {
        return fromPython;
    }
    const manifests = [
        ['go.mod', 'go'],
        ['Cargo.toml', 'rust'],
        ['pom.xml', 'java'],
        ['build.gradle', 'java'],
    ];
    for (const [file, lang] of manifests) {
        const result = await detectFromManifest(projectPath, file, lang);
        if (result) {
            return result;
        }
    }
    return {
        language: 'unknown',
        framework: null,
        testRunner: null,
        linter: null,
        formatter: null,
        bundler: null,
    };
}
//# sourceMappingURL=stack-detector.js.map