// engine/registry/matcher.ts — Detects framework mentions and API references in spec text
// Uses registry-aware keywords to avoid false positives on plain English words.
/** Mapping of framework ID → detection keywords (aliases / common spellings). */
const FRAMEWORK_ALIASES = {
    nextjs: ['next.js', 'nextjs', 'next js', 'next/navigation', 'next/router', 'app router'],
    react: ['react', 'react dom', 'reactdom', 'jsx', 'useState', 'useEffect', 'useCallback'],
    vue: ['vue', 'vue 3', 'vue.js', 'vuejs', 'composition api', 'script setup'],
    nuxt: ['nuxt', 'nuxt 3', 'nuxt.js', 'usefetch', 'definepageeta'],
    angular: ['angular', 'angular 17', '@angular', 'standalone component', 'angularjs'],
    sveltekit: ['sveltekit', 'svelte kit', 'svelte', '+page.server.ts', 'use:enhance'],
    astro: ['astro', 'astro.js', 'astro 4', 'client:load', 'getcollection'],
    remix: ['remix', 'remix 2', '@remix-run', 'useloaderdata', 'useactiondata'],
    express: ['express', 'express.js', 'expressjs', 'express.router', 'app.get(', 'app.use('],
    nestjs: ['nestjs', 'nest.js', '@nestjs', '@injectable', '@controller', '@module'],
    django: ['django', 'django 5', 'django orm', 'models.model', 'views.py', 'urls.py'],
    fastapi: [
        'fastapi',
        'fast api',
        'fastapi route',
        '@app.get',
        '@app.post',
        'pydantic v2',
        'basemodel',
    ],
    springboot: [
        'spring boot',
        'springboot',
        '@springbootapplication',
        '@restcontroller',
        'jparepository',
    ],
    rails: ['rails', 'ruby on rails', 'activerecord', 'activesupport', 'hotwire', 'turbo'],
    laravel: ['laravel', 'laravel 11', 'eloquent', 'artisan', 'blade template'],
    gin: ['gin framework', 'gin.new()', 'gin.default()', 'c.json(', 'gin.h{', 'c.shouldbindjson'],
    actix: ['actix-web', 'actix web', 'actix 4', 'web::data', 'httpresponse', 'web::path'],
    aspnet: ['asp.net', 'aspnet', '.net core', 'dotnet', '@controller', 'iactionresult', 'blazor'],
    flutter: [
        'flutter',
        'dart flutter',
        'statefulwidget',
        'statelesswidget',
        'buildcontext',
        'scaffold(',
    ],
    swiftui: ['swiftui', 'swift ui', '@state', '@observedobject', '@stateobject', 'navigationstack'],
};
/** Regex patterns to detect API/pattern references in text. */
const API_PATTERNS = [
    // Function calls: functionName() or method.call()
    /\b([a-zA-Z$_][a-zA-Z0-9$_.]{2,})\s*\(/g,
    // Import statements
    /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g,
    // Config keys: key.subkey = value
    /\b([a-z][a-z0-9-]{2,}\.[a-z][a-z0-9-.]{2,})\s*=/g,
    // Decorator-like patterns: @SomeName
    /@([A-Z][a-zA-Z0-9]+)/g,
];
/**
 * Detect which frameworks from the registry are mentioned in the spec text.
 * A framework is considered mentioned if one of its aliases appears in the text
 * (case-insensitive). Avoids single-word generic terms without API context.
 */
export function detectFrameworks(specText, registry) {
    const lower = specText.toLowerCase();
    const detected = [];
    for (const [frameworkId, aliases] of Object.entries(FRAMEWORK_ALIASES)) {
        if (!registry.has(frameworkId)) {
            continue;
        }
        const matched = aliases.some((alias) => lower.includes(alias.toLowerCase()));
        if (matched) {
            detected.push(frameworkId);
        }
    }
    return [...new Set(detected)];
}
/**
 * Extract potential API/pattern references from spec text for specific frameworks.
 * Returns deduplicated references with framework attribution.
 */
export function extractReferences(specText, frameworkIds, registry) {
    const references = [];
    const seen = new Set();
    for (const frameworkId of frameworkIds) {
        const entry = registry.get(frameworkId);
        if (!entry) {
            continue;
        }
        // Extract all pattern-like tokens from the text
        for (const regex of API_PATTERNS) {
            const cloned = new RegExp(regex.source, regex.flags);
            let match;
            while ((match = cloned.exec(specText)) !== null) {
                const token = (match[1] ?? match[0]).trim();
                const key = `${frameworkId}::${token}`;
                if (seen.has(key) || token.length < 3) {
                    continue;
                }
                seen.add(key);
                const kind = determineKind(match[0]);
                references.push({ framework: frameworkId, text: token, kind });
            }
        }
    }
    return references;
}
/** Determine the kind of reference from the matched text. */
function determineKind(rawMatch) {
    if (rawMatch.startsWith('import')) {
        return 'import';
    }
    if (rawMatch.startsWith('@')) {
        return 'api-call';
    }
    if (/=\s*$/.test(rawMatch)) {
        return 'config-key';
    }
    return 'pattern-mention';
}
/**
 * Detect any framework names mentioned in the spec that are NOT in the registry.
 * Scans for common framework keywords in text that don't map to known entries.
 */
export function detectUnknownFrameworks(specText, registry) {
    const lower = specText.toLowerCase();
    const knownFrameworkNames = new Set([...registry.values()].map((e) => e.displayName.toLowerCase()));
    // Broad keyword scan for frameworks not in registry
    const frameworkMentionRegex = /\b((?:[a-z][a-z0-9-]{1,}\.?(?:js|ts|py|rb|php|go|rs))|(?:fastify|hono|elysia|fiber|axum|rocket|gin|echo|koa|hapi|oak|deno|bun))\b/gi;
    const unknown = [];
    const seen = new Set();
    let m;
    while ((m = frameworkMentionRegex.exec(lower)) !== null) {
        const name = (m[1] ?? '').toLowerCase();
        if (!seen.has(name) && !knownFrameworkNames.has(name) && !isInRegistry(name, registry)) {
            seen.add(name);
            unknown.push(m[1] ?? name);
        }
    }
    return unknown;
}
/** Check if a name matches any alias in the registry. */
function isInRegistry(name, registry) {
    for (const aliases of Object.values(FRAMEWORK_ALIASES)) {
        if (aliases.some((a) => a.toLowerCase() === name.toLowerCase())) {
            return true;
        }
    }
    return registry.has(name);
}
//# sourceMappingURL=matcher.js.map