// engine/spec-coverage/keyword-extractor.ts — Keyword extraction and test name parsing.
// Extracted from criteria-mapper.ts to keep file sizes within limits.
// ---------------------------------------------------------------------------
// Stop words for heuristic keyword extraction
// ---------------------------------------------------------------------------
export const STOP_WORDS = new Set([
    'the',
    'a',
    'an',
    'is',
    'are',
    'was',
    'were',
    'be',
    'been',
    'being',
    'have',
    'has',
    'had',
    'do',
    'does',
    'did',
    'will',
    'would',
    'could',
    'should',
    'may',
    'might',
    'shall',
    'must',
    'can',
    'to',
    'of',
    'in',
    'on',
    'at',
    'by',
    'for',
    'with',
    'from',
    'as',
    'and',
    'or',
    'but',
    'not',
    'no',
    'if',
    'when',
    'where',
    'that',
    'which',
    'this',
    'it',
    'its',
    'el',
    'la',
    'los',
    'las',
    'un',
    'una',
    'de',
    'del',
    'en',
    'que',
    'se',
    'por',
    'para',
    'con',
    'al',
    'lo',
    'le',
    'les',
    'y',
    'o',
]);
/** Extracts 3-5 meaningful keywords from an AC description text. */
export function extractKeywords(text) {
    const words = text
        .toLowerCase()
        .replace(/[^a-zA-Z0-9\s_àáéíóúñüÀÁÉÍÓÚÑÜ]/g, ' ')
        .split(/\s+/)
        .filter((w) => w.length >= 3 && !STOP_WORDS.has(w));
    // De-duplicate preserving order
    const seen = new Set();
    const unique = [];
    for (const w of words) {
        if (!seen.has(w)) {
            seen.add(w);
            unique.push(w);
        }
    }
    return unique.slice(0, 5);
}
// ---------------------------------------------------------------------------
// Test name extraction helpers
// ---------------------------------------------------------------------------
/** Patterns for extracting test block names from source code. */
export const TEST_NAME_PATTERNS = [
    /(?:describe|it|test|context|suite|feature|scenario)\s*\(\s*['"`](.*?)['"`]/g,
    /(?:func\s+Test\w+)\s*\(/g, // Go: func TestXxx(
    /(?:def\s+test_\w+)\s*\(/g, // Python: def test_xxx(
    /#\[test\]\s*(?:fn\s+(\w+))/g, // Rust: #[test] fn name
    /(?:func|fun)\s+(test\w+)\s*\(/gi, // Swift/Kotlin
];
/** Extracts the first matching test name from source code. */
export function extractTestName(content, nearPattern) {
    // Find the line with the pattern match, then look for a nearby test name
    const lines = content.split('\n');
    for (let i = 0; i < lines.length; i++) {
        /* v8 ignore next 1 */
        const line = lines[i] ?? '';
        if (!nearPattern.test(line)) {
            continue;
        }
        // Look in ±5 lines for a test name
        const start = Math.max(0, i - 5);
        const end = Math.min(lines.length - 1, i + 5);
        for (let j = start; j <= end; j++) {
            /* v8 ignore next 1 */
            const nearby = lines[j] ?? '';
            const nameMatch = /(?:describe|it|test|context)\s*\(\s*['"`](.*?)['"`]/.exec(nearby);
            if (nameMatch?.[1]) {
                return nameMatch[1];
            }
        }
        return line.trim().slice(0, 80);
    }
    return '';
}
/** Extracts all test/describe block names from source code. */
export function extractAllTestNames(content) {
    const names = [];
    for (const pattern of TEST_NAME_PATTERNS) {
        pattern.lastIndex = 0;
        let match;
        while ((match = pattern.exec(content)) !== null) {
            /* v8 ignore next 1 */
            const name = match[1] ?? match[0];
            /* v8 ignore next 1 */
            if (name) {
                names.push(name);
            }
        }
    }
    return names;
}
//# sourceMappingURL=keyword-extractor.js.map