{"version":3,"file":"LanguageProcessor.cjs","sources":["../../../../src/languages/base/LanguageProcessor.ts"],"sourcesContent":["import type { LanguageProcessor, FuzzyFeature } from \"../../core/types.js\";\n\n/**\n * Abstract base class for language processors\n * Provides common functionality and enforces interface\n */\nexport abstract class BaseLanguageProcessor implements LanguageProcessor {\n  abstract readonly language: string;\n  abstract readonly displayName: string;\n  abstract readonly supportedFeatures: FuzzyFeature[];\n\n  /**\n   * Basic text normalization (override for language-specific behavior)\n   */\n  normalize(text: string): string {\n    return text.toLowerCase().trim().replace(/\\s+/g, \" \");\n  }\n\n  /**\n   * Default phonetic implementation (override for language-specific algorithms)\n   */\n  getPhoneticCode(word: string): string {\n    // Simple soundex-like algorithm as fallback\n    const normalized = this.normalize(word);\n    if (normalized.length === 0) return \"\";\n\n    let code = normalized[0].toUpperCase();\n    const consonantMap: Record<string, string> = {\n      b: \"1\",\n      f: \"1\",\n      p: \"1\",\n      v: \"1\",\n      c: \"2\",\n      g: \"2\",\n      j: \"2\",\n      k: \"2\",\n      q: \"2\",\n      s: \"2\",\n      x: \"2\",\n      z: \"2\",\n      d: \"3\",\n      t: \"3\",\n      l: \"4\",\n      m: \"5\",\n      n: \"5\",\n      r: \"6\",\n    };\n\n    for (let i = 1; i < normalized.length && code.length < 4; i++) {\n      const char = normalized[i];\n      const digit = consonantMap[char];\n      if (digit && digit !== code[code.length - 1]) {\n        code += digit;\n      }\n    }\n\n    return code.padEnd(4, \"0\");\n  }\n\n  /**\n   * Default compound word splitting (override for languages that support it)\n   * Base implementation splits on spaces for multi-word phrases\n   */\n  splitCompoundWords(word: string): string[] {\n    // Split on spaces for multi-word phrases (e.g., \"Los Angeles\" → [\"Los\", \"Angeles\"])\n    if (word.includes(' ')) {\n      return word.trim().split(/\\s+/).filter(part => part.length > 0);\n    }\n    return [word]; // No splitting for single words\n  }\n\n  /**\n   * Generate common word variants\n   * OPTIMIZATION 2: In fast mode, generate fewer prefixes to reduce index size\n   */\n  getWordVariants(word: string, performanceMode?: string): string[] {\n    const variants = new Set<string>();\n    const normalized = this.normalize(word);\n\n    variants.add(normalized);\n    variants.add(word); // Original form\n\n    // Add variants without common endings\n    const commonEndings = this.getCommonEndings();\n    for (const ending of commonEndings) {\n      if (normalized.endsWith(ending) && normalized.length > ending.length + 2) {\n        variants.add(normalized.slice(0, -ending.length));\n      }\n    }\n\n    // Add partial variants for longer words\n    // OPTIMIZATION: Limit prefix generation based on word length to reduce index size\n    if (normalized.length > 4) {\n      // Determine max prefixes based on word length and performance mode\n      let maxPrefixes: number;\n      if (performanceMode === 'fast') {\n        // Fast mode: minimal prefixes\n        maxPrefixes = normalized.length <= 6 ? 2 : (normalized.length <= 12 ? 3 : 4);\n      } else if (performanceMode === 'comprehensive') {\n        // Comprehensive mode: more prefixes but still limited\n        maxPrefixes = normalized.length <= 6 ? 3 : (normalized.length <= 12 ? 6 : 8);\n      } else {\n        // Balanced mode: moderate prefixes\n        maxPrefixes = normalized.length <= 6 ? 2 : (normalized.length <= 12 ? 4 : 6);\n      }\n      \n      // Generate evenly-spaced prefixes\n      const step = Math.max(1, Math.floor((normalized.length - 3) / maxPrefixes));\n      for (let i = 3; i < normalized.length; i += step) {\n        variants.add(normalized.slice(0, i));\n        if (variants.size - 2 >= maxPrefixes) break; // -2 for normalized and original\n      }\n    }\n\n    return Array.from(variants);\n  }\n\n  /**\n   * Get common word endings for this language (override for language-specific endings)\n   */\n  protected getCommonEndings(): string[] {\n    return [\n      //\n      \"s\",\n      \"es\",\n      \"ed\",\n      \"ing\",\n      \"er\",\n      \"est\",\n    ];\n  }\n\n  /**\n   * Default synonym lookup (override to provide language-specific synonyms)\n   */\n  getSynonyms(_word: string): string[] {\n    return []; // No built-in synonyms by default\n  }\n\n  /**\n   * Check if two characters are keyboard neighbors\n   */\n  isValidSubstitution(char1: string, char2: string): boolean {\n    const keyboardNeighbors = this.getKeyboardNeighbors();\n    const neighbors = keyboardNeighbors[char1.toLowerCase()];\n    return neighbors ? neighbors.includes(char2.toLowerCase()) : false;\n  }\n\n  /**\n   * Get keyboard neighbor mappings (QWERTY layout by default)\n   */\n  protected getKeyboardNeighbors(): Record<string, string[]> {\n    return {\n      q: [\"w\", \"a\", \"s\"],\n      w: [\"q\", \"e\", \"a\", \"s\", \"d\"],\n      e: [\"w\", \"r\", \"s\", \"d\", \"f\"],\n      r: [\"e\", \"t\", \"d\", \"f\", \"g\"],\n      t: [\"r\", \"y\", \"f\", \"g\", \"h\"],\n      y: [\"t\", \"u\", \"g\", \"h\", \"j\"],\n      u: [\"y\", \"i\", \"h\", \"j\", \"k\"],\n      i: [\"u\", \"o\", \"j\", \"k\", \"l\"],\n      o: [\"i\", \"p\", \"k\", \"l\"],\n      p: [\"o\", \"l\"],\n      a: [\"q\", \"w\", \"s\", \"z\", \"x\"],\n      s: [\"q\", \"w\", \"e\", \"a\", \"d\", \"z\", \"x\", \"c\"],\n      d: [\"w\", \"e\", \"r\", \"s\", \"f\", \"x\", \"c\", \"v\"],\n      f: [\"e\", \"r\", \"t\", \"d\", \"g\", \"c\", \"v\", \"b\"],\n      g: [\"r\", \"t\", \"y\", \"f\", \"h\", \"v\", \"b\", \"n\"],\n      h: [\"t\", \"y\", \"u\", \"g\", \"j\", \"b\", \"n\", \"m\"],\n      j: [\"y\", \"u\", \"i\", \"h\", \"k\", \"n\", \"m\"],\n      k: [\"u\", \"i\", \"o\", \"j\", \"l\", \"m\"],\n      l: [\"i\", \"o\", \"p\", \"k\"],\n      z: [\"a\", \"s\", \"x\"],\n      x: [\"a\", \"s\", \"d\", \"z\", \"c\"],\n      c: [\"s\", \"d\", \"f\", \"x\", \"v\"],\n      v: [\"d\", \"f\", \"g\", \"c\", \"b\"],\n      b: [\"f\", \"g\", \"h\", \"v\", \"n\"],\n      n: [\"g\", \"h\", \"j\", \"b\", \"m\"],\n      m: [\"h\", \"j\", \"k\", \"n\"],\n    };\n  }\n\n  /**\n   * Generate n-grams for partial matching\n   */\n  generateNgrams(word: string, n: number = 3): string[] {\n    const normalized = this.normalize(word);\n    if (normalized.length < n) return [normalized];\n\n    const ngrams: string[] = [];\n    for (let i = 0; i <= normalized.length - n; i++) {\n      ngrams.push(normalized.slice(i, i + n));\n    }\n    return ngrams;\n  }\n\n  /**\n   * Calculate basic edit distance (Levenshtein)\n   */\n  calculateEditDistance(str1: string, str2: string): number {\n    const matrix: number[][] = [];\n    const len1 = str1.length;\n    const len2 = str2.length;\n\n    // Initialize matrix\n    for (let i = 0; i <= len1; i++) {\n      matrix[i] = [i];\n    }\n    for (let j = 0; j <= len2; j++) {\n      matrix[0][j] = j;\n    }\n\n    // Fill matrix\n    for (let i = 1; i <= len1; i++) {\n      for (let j = 1; j <= len2; j++) {\n        const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;\n        matrix[i][j] = Math.min(\n          matrix[i - 1][j] + 1, // deletion\n          matrix[i][j - 1] + 1, // insertion\n          matrix[i - 1][j - 1] + cost // substitution\n        );\n      }\n    }\n\n    return matrix[len1][len2];\n  }\n}\n"],"names":[],"mappings":"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"}