{"version":3,"sources":["../src/index.ts","../src/tokenizer.ts","../src/constants.ts"],"sourcesContent":["import { Worker } from 'worker_threads';\r\nimport { Tokenizer } from './tokenizer';\r\nimport type {\r\n  BM25Options,\r\n  SearchResult,\r\n  FieldBoosts,\r\n  Document,\r\n  SerializableResult,\r\n} from './types';\r\nimport { DEFAULT_OPTIONS } from './constants';\r\nimport { cpus } from 'os';\r\nimport path from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\n/**\r\n * Implementation of the Okapi BM25 ranking algorithm with field boosting support\r\n */\r\nexport class BM25 {\r\n  private readonly termFrequencySaturation: number;\r\n  private readonly lengthNormalizationFactor: number;\r\n  private readonly tokenizer: Tokenizer;\r\n  private documentLengths: Uint32Array;\r\n  private averageDocLength: number;\r\n  private readonly termToIndex: Map<string, number>;\r\n  private documentFrequency: Uint32Array;\r\n  private readonly termFrequencies: Map<number, Map<number, number>>;\r\n  private readonly fieldBoosts: FieldBoosts;\r\n  private readonly workerOptions: Omit<BM25Options, 'stemWords'> & {\r\n    fieldBoosts?: FieldBoosts;\r\n  };\r\n  private documents: Document[];\r\n\r\n  /**\r\n   * Creates a new BM25 search instance\r\n   * @param docs - Optional array of documents to index\r\n   * @param options - BM25 algorithm options and field boost settings\r\n   */\r\n  constructor(\r\n    docs?: Document[],\r\n    options: BM25Options & { fieldBoosts?: FieldBoosts } = {},\r\n  ) {\r\n    const opts = { ...DEFAULT_OPTIONS, ...options };\r\n    this.termFrequencySaturation = opts.k1;\r\n    this.lengthNormalizationFactor = opts.b;\r\n    this.tokenizer = new Tokenizer(opts);\r\n    this.fieldBoosts = opts.fieldBoosts || {};\r\n    const { stemWords: _stemWords, ...workerOptions } = opts;\r\n    this.workerOptions = workerOptions;\r\n\r\n    // Initialize empty data structures\r\n    this.documents = [];\r\n    this.documentLengths = new Uint32Array(0);\r\n    this.termToIndex = new Map();\r\n    this.documentFrequency = new Uint32Array(0);\r\n    this.averageDocLength = 0;\r\n    this.termFrequencies = new Map();\r\n\r\n    // Process documents if provided\r\n    if (docs && docs.length > 0) {\r\n      this.documents = [...docs];\r\n      const {\r\n        documentLengths,\r\n        termToIndex,\r\n        documentFrequency,\r\n        averageDocLength,\r\n        termFrequencies,\r\n      } = this.processDocuments(docs);\r\n\r\n      this.documentLengths = documentLengths;\r\n      this.termToIndex = termToIndex;\r\n      this.documentFrequency = documentFrequency;\r\n      this.averageDocLength = averageDocLength;\r\n      this.termFrequencies = termFrequencies;\r\n    }\r\n  }\r\n\r\n  private processDocuments(docs: Document[]): {\r\n    documentLengths: Uint32Array;\r\n    termToIndex: Map<string, number>;\r\n    documentFrequency: Uint32Array;\r\n    averageDocLength: number;\r\n    termFrequencies: Map<number, Map<number, number>>;\r\n  } {\r\n    const documentLengths = new Uint32Array(docs.length);\r\n    const termToIndex = new Map<string, number>();\r\n    const termDocs = new Map<string, Set<number>>();\r\n    const termFrequencies = new Map<number, Map<number, number>>();\r\n    let totalLength = 0;\r\n    let nextTermIndex = 0;\r\n\r\n    docs.forEach((doc, docIndex) => {\r\n      let docLength = 0;\r\n      Object.entries(doc).forEach(([field, content]) => {\r\n        const fieldBoost = this.fieldBoosts[field] || 1;\r\n        const { tokens } = this.tokenizer.tokenize(content);\r\n        docLength += tokens.length * fieldBoost;\r\n\r\n        const uniqueTerms = new Set(tokens);\r\n        uniqueTerms.forEach((term) => {\r\n          if (!termToIndex.has(term)) {\r\n            termToIndex.set(term, nextTermIndex++);\r\n          }\r\n          const termIndex = termToIndex.get(term)!;\r\n\r\n          if (!termDocs.has(term)) {\r\n            termDocs.set(term, new Set());\r\n          }\r\n          termDocs.get(term)!.add(docIndex);\r\n\r\n          if (!termFrequencies.has(termIndex)) {\r\n            termFrequencies.set(termIndex, new Map());\r\n          }\r\n          const freq = tokens.filter((t) => t === term).length * fieldBoost; // Apply boost to term frequency\r\n          const existingFreq =\r\n            termFrequencies.get(termIndex)!.get(docIndex) || 0;\r\n          termFrequencies.get(termIndex)!.set(docIndex, existingFreq + freq);\r\n        });\r\n      });\r\n\r\n      documentLengths[docIndex] = docLength;\r\n      totalLength += docLength;\r\n    });\r\n\r\n    const documentFrequency = new Uint32Array(termToIndex.size);\r\n    termDocs.forEach((docs, term) => {\r\n      const termIndex = termToIndex.get(term)!;\r\n      documentFrequency[termIndex] = docs.size;\r\n    });\r\n\r\n    return {\r\n      documentLengths,\r\n      termToIndex,\r\n      documentFrequency,\r\n      averageDocLength: totalLength / docs.length,\r\n      termFrequencies,\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Adds multiple documents to the index using parallel processing\r\n   * @param docs - Array of documents to add\r\n   */\r\n  public async addDocumentsParallel(docs: Document[]): Promise<void> {\r\n    if (!docs || docs.length === 0) return;\r\n\r\n    const numWorkers = Math.min(\r\n      docs.length,\r\n      Math.max(1, Math.ceil(cpus().length / 2)),\r\n    );\r\n    const batchSize = Math.ceil(docs.length / numWorkers);\r\n    const workers: Worker[] = [];\r\n\r\n    try {\r\n      const workerPromises = Array.from({ length: numWorkers }, (_, i) => {\r\n        const start = i * batchSize;\r\n        const end = Math.min(start + batchSize, docs.length);\r\n        const isCommonJs =\r\n          typeof module !== 'undefined' &&\r\n          typeof module.exports !== 'undefined';\r\n        const workerPath = isCommonJs\r\n          ? path.resolve(__dirname, './worker.cjs')\r\n          : fileURLToPath(new URL('./worker.js', import.meta.url));\r\n        const worker = new Worker(workerPath);\r\n        workers.push(worker);\r\n\r\n        return new Promise<SerializableResult>((resolve, reject) => {\r\n          worker.on('message', resolve);\r\n          worker.on('error', reject);\r\n          worker.postMessage({\r\n            docs: docs.slice(start, end),\r\n            options: this.workerOptions,\r\n          });\r\n        });\r\n      });\r\n\r\n      const results = await Promise.all(workerPromises);\r\n\r\n      // Initialize arrays with proper size\r\n      const totalDocs = docs.length;\r\n      const newDocLengths = new Uint32Array(\r\n        this.documentLengths.length + totalDocs,\r\n      );\r\n      newDocLengths.set(this.documentLengths);\r\n      this.documentLengths = newDocLengths;\r\n\r\n      // Store new documents\r\n      const startIndex = this.documents.length;\r\n      this.documents.push(...docs);\r\n\r\n      let offset = startIndex;\r\n      results.forEach((result) => {\r\n        // Update document lengths\r\n        for (let i = 0; i < result.documentLengths.length; i++) {\r\n          this.documentLengths[offset + i] = result.documentLengths[i];\r\n        }\r\n\r\n        // Merge term mappings and frequencies\r\n        result.termToIndex.forEach(([term, index]) => {\r\n          if (!this.termToIndex.has(term)) {\r\n            this.termToIndex.set(term, this.termToIndex.size);\r\n          }\r\n          const newIndex = this.termToIndex.get(term)!;\r\n\r\n          // Update term frequencies with correct document offset\r\n          const freqMap = new Map(\r\n            result.termFrequencies\r\n              .filter(([tIndex]) => tIndex === index)\r\n              .flatMap(([_, docFreqs]) => docFreqs)\r\n              .map(([docIdx, freq]) => [docIdx + offset, freq]),\r\n          );\r\n\r\n          if (!this.termFrequencies.has(newIndex)) {\r\n            this.termFrequencies.set(newIndex, freqMap);\r\n          } else {\r\n            freqMap.forEach((freq, docIdx) => {\r\n              this.termFrequencies.get(newIndex)!.set(docIdx, freq);\r\n            });\r\n          }\r\n        });\r\n\r\n        offset += result.documentCount;\r\n      });\r\n\r\n      // Recalculate document frequency and average length\r\n      this.updateDocumentFrequency();\r\n      this.recalculateAverageLength();\r\n    } finally {\r\n      workers.forEach((worker) => worker.terminate());\r\n    }\r\n  }\r\n\r\n  private updateDocumentFrequency(): void {\r\n    this.documentFrequency = new Uint32Array(this.termToIndex.size);\r\n    this.termFrequencies.forEach((docFreqs, termIndex) => {\r\n      this.documentFrequency[termIndex] = docFreqs.size;\r\n    });\r\n  }\r\n\r\n  private recalculateAverageLength(): void {\r\n    const totalLength = this.documentLengths.reduce((sum, len) => sum + len, 0);\r\n    this.averageDocLength = totalLength / this.documentLengths.length;\r\n  }\r\n\r\n  /**\r\n   * Searches the indexed documents using BM25 ranking\r\n   * @param query - Search query text\r\n   * @param limit - Maximum number of results to return\r\n   * @returns Array of search results sorted by relevance score\r\n   */\r\n  public search(query: string, topK: number = 10): SearchResult[] {\r\n    const { tokens: queryTokens } = this.tokenizer.tokenize(query);\r\n    const scores = new Float32Array(this.documentLengths.length);\r\n\r\n    queryTokens.forEach((term) => {\r\n      const termIndex = this.termToIndex.get(term);\r\n      if (termIndex === undefined) return;\r\n\r\n      const idf = this.calculateIDF(termIndex);\r\n      const termFreqs = this.termFrequencies.get(termIndex)!;\r\n\r\n      termFreqs.forEach((tf, docIndex) => {\r\n        const docLength = this.documentLengths[docIndex];\r\n        const normalizedTF =\r\n          (tf * (this.termFrequencySaturation + 1)) /\r\n          (tf +\r\n            this.termFrequencySaturation *\r\n              (1 -\r\n                this.lengthNormalizationFactor +\r\n                (this.lengthNormalizationFactor * docLength) /\r\n                  this.averageDocLength));\r\n        scores[docIndex] += idf * normalizedTF;\r\n      });\r\n    });\r\n\r\n    return Array.from({ length: scores.length }, (_, i) => ({\r\n      index: i,\r\n      score: scores[i],\r\n    }))\r\n      .filter((result) => result.score > 0)\r\n      .sort((a, b) => b.score - a.score)\r\n      .slice(0, topK);\r\n  }\r\n\r\n  public searchPhrase(phrase: string, topK: number = 10): SearchResult[] {\r\n    const { tokens: phraseTokens } = this.tokenizer.tokenize(phrase);\r\n    const candidateDocs = new Set<number>();\r\n\r\n    // Find documents containing all terms in the phrase\r\n    phraseTokens.forEach((term) => {\r\n      const termIndex = this.termToIndex.get(term);\r\n      if (termIndex !== undefined) {\r\n        const docs = this.termFrequencies.get(termIndex)!.keys();\r\n        if (candidateDocs.size === 0) {\r\n          for (const doc of docs) {\r\n            candidateDocs.add(doc);\r\n          }\r\n        } else {\r\n          for (const doc of candidateDocs) {\r\n            if (!this.termFrequencies.get(termIndex)!.has(doc)) {\r\n              candidateDocs.delete(doc);\r\n            }\r\n          }\r\n        }\r\n      }\r\n    });\r\n\r\n    // Check for exact phrase matches and calculate scores\r\n    const scores = new Map<number, number>();\r\n    candidateDocs.forEach((docIndex) => {\r\n      const doc = this.getDocument(docIndex);\r\n      let hasMatch = false;\r\n\r\n      // Search through each field separately\r\n      Object.entries(doc).forEach(([field, content]) => {\r\n        const fieldBoost = this.fieldBoosts[field] || 1;\r\n        const { tokens: docTokens } = this.tokenizer.tokenize(content);\r\n\r\n        for (let i = 0; i <= docTokens.length - phraseTokens.length; i++) {\r\n          if (phraseTokens.every((token, j) => token === docTokens[i + j])) {\r\n            const score =\r\n              this.calculatePhraseScore(phraseTokens, docIndex) * fieldBoost;\r\n            scores.set(docIndex, (scores.get(docIndex) || 0) + score);\r\n            hasMatch = true;\r\n            break;\r\n          }\r\n        }\r\n      });\r\n    });\r\n\r\n    return Array.from(scores.entries())\r\n      .map(([index, score]) => ({ index, score }))\r\n      .sort((a, b) => b.score - a.score)\r\n      .slice(0, topK);\r\n  }\r\n\r\n  private calculatePhraseScore(\r\n    phraseTokens: string[],\r\n    docIndex: number,\r\n  ): number {\r\n    return phraseTokens.reduce((score, term) => {\r\n      const termIndex = this.termToIndex.get(term);\r\n      if (termIndex === undefined) return score;\r\n\r\n      const idf = this.calculateIDF(termIndex);\r\n      const tf = this.termFrequencies.get(termIndex)!.get(docIndex) || 0;\r\n      const docLength = this.documentLengths[docIndex];\r\n      const normalizedTF =\r\n        (tf * (this.termFrequencySaturation + 1)) /\r\n        (tf +\r\n          this.termFrequencySaturation *\r\n            (1 -\r\n              this.lengthNormalizationFactor +\r\n              (this.lengthNormalizationFactor * docLength) /\r\n                this.averageDocLength));\r\n      return score + idf * normalizedTF;\r\n    }, 0);\r\n  }\r\n\r\n  /**\r\n   * Adds a new document to the index\r\n   * @param doc - Document to add\r\n   */\r\n  public async addDocument(doc: Document): Promise<void> {\r\n    if (!doc) throw new Error('Document cannot be null');\r\n\r\n    const docIndex = this.documentLengths.length;\r\n    this.documents.push(doc);\r\n\r\n    let docLength = 0;\r\n\r\n    Object.entries(doc).forEach(([field, content]) => {\r\n      const { tokens } = this.tokenizer.tokenize(content);\r\n      docLength += tokens.length * (this.fieldBoosts[field] || 1);\r\n\r\n      const uniqueTerms = new Set(tokens);\r\n      uniqueTerms.forEach((term) => {\r\n        if (!this.termToIndex.has(term)) {\r\n          this.termToIndex.set(term, this.termToIndex.size);\r\n        }\r\n        const termIndex = this.termToIndex.get(term)!;\r\n\r\n        if (this.documentFrequency.length <= termIndex) {\r\n          const newDocFreq = new Uint32Array(\r\n            Math.max(termIndex + 1, this.documentFrequency.length * 2, 1),\r\n          );\r\n          newDocFreq.set(this.documentFrequency);\r\n          this.documentFrequency = newDocFreq;\r\n        }\r\n        this.documentFrequency[termIndex]++;\r\n\r\n        if (!this.termFrequencies.has(termIndex)) {\r\n          this.termFrequencies.set(termIndex, new Map());\r\n        }\r\n        const freq = tokens.filter((t) => t === term).length;\r\n        this.termFrequencies.get(termIndex)!.set(docIndex, freq);\r\n      });\r\n    });\r\n\r\n    const newDocLengths = new Uint32Array(this.documentLengths.length + 1);\r\n    newDocLengths.set(this.documentLengths);\r\n    newDocLengths[docIndex] = docLength;\r\n    this.documentLengths = newDocLengths;\r\n\r\n    const totalLength = this.documentLengths.reduce(\r\n      (sum, length) => sum + length,\r\n      0,\r\n    );\r\n    this.averageDocLength = totalLength / this.documentLengths.length;\r\n  }\r\n\r\n  private calculateIDF(termIndex: number): number {\r\n    const docFreq = this.documentFrequency[termIndex];\r\n    if (docFreq === 0) return 0;\r\n\r\n    const N = this.documentLengths.length;\r\n    return Math.log((N - docFreq + 0.5) / (docFreq + 0.5) + 1);\r\n  }\r\n\r\n  private getTermFrequency(termIndex: number, docIndex: number): number {\r\n    return this.termFrequencies.get(termIndex)?.get(docIndex) || 0;\r\n  }\r\n\r\n  private getDocument(index: number): Document {\r\n    if (index < 0 || index >= this.documents.length) {\r\n      throw new Error('Document index out of bounds');\r\n    }\r\n    return this.documents[index];\r\n  }\r\n\r\n  public clearDocuments(): void {\r\n    this.documents = [];\r\n    this.documentLengths = new Uint32Array(0);\r\n    this.termToIndex.clear();\r\n    this.documentFrequency = new Uint32Array(0);\r\n    this.averageDocLength = 0;\r\n    this.termFrequencies.clear();\r\n  }\r\n\r\n  public getDocumentCount(): number {\r\n    return this.documents.length;\r\n  }\r\n\r\n  public async addDocuments(docs: Document[]): Promise<void> {\r\n    docs.forEach((doc) => this.addDocument(doc));\r\n  }\r\n}\r\n","import { stem } from 'porter2';\r\nimport type {\r\n  TokenizerOptions,\r\n  TokenizationResult,\r\n  TokenizationStats,\r\n  StemmingRule,\r\n} from './types';\r\n\r\n/**\r\n * Text tokenization with configurable filters and stemming\r\n */\r\nexport class Tokenizer {\r\n  private readonly stopWords: Set<string>;\r\n  private readonly minLength: number;\r\n  private readonly stemming: boolean;\r\n  private readonly stemmingRules: StemmingRule[];\r\n\r\n  private static readonly DEFAULT_OPTIONS: Required<TokenizerOptions> = {\r\n    stopWords: new Set<string>(),\r\n    minLength: 2,\r\n    stemming: false,\r\n    stemmingRules: [],\r\n  };\r\n\r\n  /**\r\n   * Creates a new tokenizer instance\r\n   * @param options - Tokenization options including stop words and stemming\r\n   */\r\n  constructor(options: TokenizerOptions = {}) {\r\n    const mergedOptions = { ...Tokenizer.DEFAULT_OPTIONS, ...options };\r\n    this.stopWords = mergedOptions.stopWords;\r\n    this.minLength = mergedOptions.minLength;\r\n    this.stemming = mergedOptions.stemming;\r\n    this.stemmingRules = mergedOptions.stemmingRules.map((rule) => ({\r\n      ...rule,\r\n      pattern:\r\n        typeof rule.pattern === 'string'\r\n          ? new RegExp(rule.pattern)\r\n          : rule.pattern,\r\n    }));\r\n  }\r\n  /**\r\n   * Tokenize text into an array of terms with optional statistics\r\n   * @param text - Input text to tokenize\r\n   * @param includeStats - Whether to include tokenization statistics\r\n   * @returns TokenizationResult containing tokens and optional stats\r\n   * @throws {Error} If input text is null or empty\r\n   */\r\n  public tokenize(text: string, includeStats = false): TokenizationResult {\r\n    if (!text) {\r\n      throw new Error('Input text cannot be null or empty');\r\n    }\r\n\r\n    const startTime = Date.now();\r\n    const originalWords = text.split(/\\s+/).filter((word) => word.length > 0);\r\n\r\n    const cleaned = this.cleanText(text);\r\n    const tokens = cleaned\r\n      .split(/\\s+/)\r\n      .filter((token) => this.isValidToken(token))\r\n      .map((token) => (this.stemming ? this.stemWord(token) : token));\r\n\r\n    const stats: TokenizationStats = includeStats\r\n      ? {\r\n          originalWordCount: originalWords.length,\r\n          stopWordsRemoved: originalWords.length - tokens.length,\r\n          stemmedWords: this.stemming ? tokens.length : 0,\r\n          processingTimeMs: Date.now() - startTime,\r\n        }\r\n      : {\r\n          originalWordCount: 0,\r\n          stopWordsRemoved: 0,\r\n          stemmedWords: 0,\r\n          processingTimeMs: 0,\r\n        };\r\n\r\n    return { tokens, stats };\r\n  }\r\n\r\n  /**\r\n   * Cleans and normalizes text by removing unwanted characters while preserving meaningful content.\r\n   * Handles Unicode, emojis, symbols, accents, and multiple writing systems automatically.\r\n   *\r\n   * @param text - Input text to clean\r\n   * @returns Cleaned and normalized text\r\n   *\r\n   * @example\r\n   * cleanText(\"Hello, World™!\") // \"hello world\"\r\n   * cleanText(\"héllo 👋\") // \"hello\"\r\n   * cleanText(\"Hello 世界!\") // \"hello 世界\"\r\n   * cleanText(\"I'm don't\") // \"i'm don't\"\r\n   * cleanText(\"test©2023\") // \"test 2023\"\r\n   */\r\n  private cleanText(text: string): string {\r\n    return (\r\n      text\r\n        .toLowerCase()\r\n        // Normalize Unicode characters to their canonical form\r\n        .normalize('NFKD')\r\n        // Remove control characters and zero-width characters\r\n        .replace(/[\\u0000-\\u001F\\u007F-\\u009F\\u200B-\\u200D\\uFEFF]/g, '')\r\n        // Remove combining diacritical marks\r\n        .replace(/[\\u0300-\\u036f]/g, '')\r\n        // Remove emojis and symbols while preserving basic punctuation\r\n        // .replace(\r\n        //   /[\\p{Extended_Pictographic}\\p{Emoji}\\p{Emoji_Component}\\p{Symbol}\\p{So}]/gu,\r\n        //   '',\r\n        // )\r\n        .replace(/[\\p{Emoji_Presentation}\\p{Extended_Pictographic}]/gu, '')\r\n        // Remove trademark, copyright, and similar symbols\r\n        .replace(/[™®©℠‼]/g, '')\r\n        // Replace punctuation with space\r\n        .replace(/[\\p{P}]/gu, ' ')\r\n        // Keep alphanumeric, CJK, Hangul intact and replace others with space\r\n        .replace(\r\n          /[^a-z0-9\\u3040-\\u30FF\\u3400-\\u4DBF\\u4E00-\\u9FFF\\uAC00-\\uD7AF\\s]/gu,\r\n          ' ',\r\n        )\r\n        // Normalize whitespace: collapse multiple spaces and trim\r\n        .replace(/\\s+/g, ' ')\r\n        .trim()\r\n    );\r\n  }\r\n\r\n  /**\r\n   * Check if a token is valid based on length and stop words\r\n   * @param token - Token to validate\r\n   * @returns Whether the token is valid\r\n   */\r\n  private isValidToken(token: string): boolean {\r\n    const isNumeric = /^\\d+$/.test(token);\r\n    return (\r\n      (token.length >= this.minLength || isNumeric) &&\r\n      !this.stopWords.has(token)\r\n    );\r\n  }\r\n\r\n  /**\r\n   * Apply stemming rules to a word\r\n   * @param word - Word to stem\r\n   * @returns Stemmed word\r\n   */\r\n  private stemWord(word: string): string {\r\n    if (word.length < 3) return word;\r\n    let customRule = false;\r\n\r\n    let stemmed = word;\r\n\r\n    // Apply custom stemming rules first\r\n    for (const rule of this.stemmingRules) {\r\n      const match = stemmed.match(rule.pattern);\r\n      if (match) {\r\n        customRule = true;\r\n        if (!rule.minMeasure || this.measure(stemmed) >= rule.minMeasure) {\r\n          if (typeof rule.replacement === 'string') {\r\n            // Handle string replacement\r\n            stemmed = stemmed.replace(rule.pattern, rule.replacement);\r\n          } else {\r\n            // Handle function replacement\r\n            stemmed = stemmed.replace(rule.pattern, rule.replacement);\r\n          }\r\n        }\r\n      }\r\n    }\r\n\r\n    // Skip default stemming rules if a custom rule matched\r\n    if (customRule) return stemmed;\r\n\r\n    stemmed = stem(stemmed);\r\n\r\n    return stemmed;\r\n  }\r\n\r\n  private isConsonant(word: string, i: number): boolean {\r\n    const char = word[i];\r\n    if ('aeiou'.includes(char)) return false;\r\n    return char !== 'y' || (i === 0 ? true : !this.isConsonant(word, i - 1));\r\n  }\r\n\r\n  private measure(word: string): number {\r\n    let m = 0;\r\n    let vowelSeen = false;\r\n    for (let i = 0; i < word.length; i++) {\r\n      if (this.isConsonant(word, i)) {\r\n        if (vowelSeen) {\r\n          m++;\r\n          vowelSeen = false;\r\n        }\r\n      } else {\r\n        vowelSeen = true;\r\n      }\r\n    }\r\n    return m;\r\n  }\r\n}\r\n","import type { BM25Options } from './types';\r\n\r\nexport const DEFAULT_OPTIONS: Required<BM25Options> = {\r\n  k1: 1.2,\r\n  b: 0.75,\r\n  minLength: 2,\r\n  stopWords: new Set([\r\n    'a',\r\n    'an',\r\n    'and',\r\n    'are',\r\n    'as',\r\n    'at',\r\n    'be',\r\n    'by',\r\n    'for',\r\n    'from',\r\n    'has',\r\n    'he',\r\n    'in',\r\n    'is',\r\n    'it',\r\n    'its',\r\n    'of',\r\n    'on',\r\n    'that',\r\n    'the',\r\n    'to',\r\n    'was',\r\n    'were',\r\n    'will',\r\n    'with',\r\n  ]),\r\n  stemming: false,\r\n  stemWords: (word: string) => word,\r\n};\r\n"],"mappings":"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","names":["docs","path"]}