{"version":3,"file":"highlights.mjs","sources":["../../../../src/tools/search/highlights.ts"],"sourcesContent":["import type * as t from './types';\n\n// 2. Pre-compile all regular expressions (only do this once)\n// Group patterns by priority for early returns\nconst priorityPatterns = [\n  // High priority patterns (structural)\n  [\n    { regex: /\\n\\n/g }, // Double newline (paragraph break)\n    { regex: /\\n/g }, // Single newline\n    { regex: /={3,}\\s*\\n|-{3,}\\s*\\n/g }, // Section separators\n  ],\n  // Medium priority (semantic)\n  [\n    { regex: /[.!?][\")\\]]?\\s/g }, // End of sentence\n    { regex: /;\\s/g }, // Semicolon\n    { regex: /:\\s/g }, // Colon\n  ],\n  // Low priority (any breaks)\n  [\n    { regex: /,\\s/g }, // Comma\n    { regex: /\\s-\\s/g }, // Dash surrounded by spaces\n    { regex: /\\s/g }, // Any space\n  ],\n];\n\nfunction findFirstMatch(text: string, regex: RegExp): number {\n  // Reset regex\n  regex.lastIndex = 0;\n\n  // For very long texts, try chunking\n  if (text.length > 10000) {\n    const chunkSize = 2000;\n    let position = 0;\n\n    while (position < text.length) {\n      const chunk = text.substring(position, position + chunkSize);\n      regex.lastIndex = 0;\n\n      const match = regex.exec(chunk);\n      if (match) {\n        return position + match.index;\n      }\n\n      // Move to next chunk with some overlap\n      position += chunkSize - 100;\n      if (position >= text.length) break;\n    }\n    return -1;\n  }\n\n  // For shorter texts, normal regex search\n  const match = regex.exec(text);\n  return match ? match.index : -1;\n}\n\n// 3. Optimized boundary finding functions\nfunction findLastMatch(text: string, regex: RegExp): number {\n  // Reset regex state\n  regex.lastIndex = 0;\n\n  let lastIndex = -1;\n  let lastLength = 0;\n  let match;\n\n  // For very long texts, use a different approach to avoid regex engine slowdowns\n  if (text.length > 10000) {\n    // Try dividing the text into chunks for faster processing\n    const chunkSize = 2000;\n    let startPosition = Math.max(0, text.length - chunkSize);\n\n    while (startPosition >= 0) {\n      const chunk = text.substring(startPosition, startPosition + chunkSize);\n      regex.lastIndex = 0;\n\n      let chunkLastIndex = -1;\n      let chunkLastLength = 0;\n\n      while ((match = regex.exec(chunk)) !== null) {\n        chunkLastIndex = match.index;\n        chunkLastLength = match[0].length;\n      }\n\n      if (chunkLastIndex !== -1) {\n        return startPosition + chunkLastIndex + chunkLastLength;\n      }\n\n      // Move to previous chunk with some overlap\n      startPosition = Math.max(0, startPosition - chunkSize + 100) - 1;\n      if (startPosition <= 0) break;\n    }\n    return -1;\n  }\n\n  // For shorter texts, normal regex search\n  while ((match = regex.exec(text)) !== null) {\n    lastIndex = match.index;\n    lastLength = match[0].length;\n  }\n\n  return lastIndex === -1 ? -1 : lastIndex + lastLength;\n}\n\n// 4. Find the best boundary with priority groups\nfunction findBestBoundary(text: string, direction = 'backward'): number {\n  if (!text || text.length === 0) return 0;\n\n  // Try each priority group\n  for (const patternGroup of priorityPatterns) {\n    for (const pattern of patternGroup) {\n      const position =\n        direction === 'backward'\n          ? findLastMatch(text, pattern.regex)\n          : findFirstMatch(text, pattern.regex);\n\n      if (position !== -1) {\n        return position;\n      }\n    }\n  }\n\n  // No match found, use character boundary\n  return direction === 'backward' ? text.length : 0;\n}\n\n/**\n * Tracks references used in a highlight without changing their numbers\n */\nfunction trackReferencesInHighlight(\n  text: string,\n  sourceResult: t.ValidSource // Source containing the original references\n): {\n  references: {\n    type: 'link' | 'image' | 'video';\n    originalIndex: number;\n    reference: t.MediaReference; // Original reference object\n  }[];\n} {\n  // Track used references\n  const references: {\n    type: 'link' | 'image' | 'video';\n    originalIndex: number;\n    reference: t.MediaReference;\n  }[] = [];\n\n  if (!text || text.length === 0 || !text.includes('#')) {\n    return { references }; // Early return\n  }\n\n  // Quick check for reference markers\n  if (\n    !text.includes('link#') &&\n    !text.includes('image#') &&\n    !text.includes('video#')\n  ) {\n    return { references };\n  }\n\n  // Get references from the source if available\n  const sourceRefs = sourceResult.references || {\n    links: [],\n    images: [],\n    videos: [],\n  };\n\n  // Find references but don't modify text\n  const refRegex = /\\((link|image|video)#(\\d+)(?:\\s+\"([^\"]*)\")?\\)/g;\n  let match;\n\n  while ((match = refRegex.exec(text)) !== null) {\n    const [, type, indexStr] = match;\n    const originalIndex = parseInt(indexStr, 10) - 1; // Convert to 0-based\n\n    // Get the source array for this type\n    const refType = type as 'link' | 'image' | 'video';\n    const sourceArray = sourceRefs[`${refType}s`] as\n      | t.MediaReference[]\n      | undefined;\n\n    // Skip if invalid reference\n    if (\n      !sourceArray ||\n      originalIndex < 0 ||\n      originalIndex >= sourceArray.length\n    ) {\n      continue; // Skip invalid references\n    }\n\n    // Get original reference\n    const reference = sourceArray[originalIndex];\n\n    // Track if not already tracked\n    const alreadyTracked = references.some(\n      (ref) => ref.type === refType && ref.originalIndex === originalIndex\n    );\n\n    if (!alreadyTracked) {\n      references.push({\n        type: refType,\n        originalIndex,\n        reference,\n      });\n    }\n  }\n\n  return { references };\n}\n\n/**\n * Expand highlights in search results using smart boundary detection.\n *\n * This implementation finds natural text boundaries like paragraphs, sentences,\n * and phrases to provide context while maintaining readability.\n *\n * @param searchResults - Search results object\n * @param mainExpandBy - Primary expansion size on each side (default: 300)\n * @param separatorExpandBy - Additional range to look for separators (default: 150)\n * @returns Copy of search results with expanded highlights and tracked references\n */\nexport function expandHighlights(\n  searchResults: t.SearchResultData,\n  mainExpandBy = 300,\n  separatorExpandBy = 150\n): t.SearchResultData {\n  // Avoid deep copy - only copy what we modify\n  const resultCopy = { ...searchResults };\n  if (resultCopy.organic) resultCopy.organic = [...resultCopy.organic];\n  if (resultCopy.topStories) resultCopy.topStories = [...resultCopy.topStories];\n\n  // Process the results efficiently\n  const processResultTypes = ['organic', 'topStories'] as const;\n\n  for (const resultType of processResultTypes) {\n    if (!resultCopy[resultType as 'organic' | 'topStories']) continue;\n\n    // Map results to new array with modified highlights\n    resultCopy[resultType] = resultCopy[resultType]?.map((result) => {\n      if (\n        result.content == null ||\n        result.content === '' ||\n        !result.highlights ||\n        result.highlights.length === 0\n      ) {\n        return result; // No modification needed\n      }\n\n      // Create a shallow copy with expanded highlights\n      const resultCopy = { ...result };\n      const content = result.content;\n      const highlights = [];\n      // Process each highlight\n      for (const highlight of result.highlights) {\n        const { references } = trackReferencesInHighlight(\n          highlight.text,\n          result\n        );\n\n        let startPos = content.indexOf(highlight.text);\n        let highlightLen = highlight.text.length;\n\n        if (startPos === -1) {\n          // Try with stripped whitespace\n          const strippedHighlight = highlight.text.trim();\n          startPos = content.indexOf(strippedHighlight);\n\n          if (startPos === -1) {\n            highlights.push({\n              text: highlight.text,\n              score: highlight.score,\n              references,\n            });\n            continue;\n          }\n          highlightLen = strippedHighlight.length;\n        }\n\n        // Calculate boundaries\n        const mainStart = Math.max(0, startPos - mainExpandBy);\n        const mainEnd = Math.min(\n          content.length,\n          startPos + highlightLen + mainExpandBy\n        );\n\n        const separatorStart = Math.max(0, mainStart - separatorExpandBy);\n        const separatorEnd = Math.min(\n          content.length,\n          mainEnd + separatorExpandBy\n        );\n\n        // Extract text segments\n        const headText = content.substring(separatorStart, mainStart);\n        const tailText = content.substring(mainEnd, separatorEnd);\n\n        // Find natural boundaries\n        const bestHeadBoundary = findBestBoundary(headText, 'backward');\n        const bestTailBoundary = findBestBoundary(tailText, 'forward');\n\n        // Calculate final positions\n        const finalStart = separatorStart + bestHeadBoundary;\n        const finalEnd = mainEnd + bestTailBoundary;\n\n        // Extract the expanded highlight\n        const expandedHighlightText = content\n          .substring(finalStart, finalEnd)\n          .trim();\n        highlights.push({\n          text: expandedHighlightText,\n          score: highlight.score,\n          references,\n        });\n      }\n\n      resultCopy.highlights = highlights;\n      delete resultCopy.content;\n      delete resultCopy.references;\n      return resultCopy;\n    });\n  }\n\n  return resultCopy;\n}\n"],"names":[],"mappings":"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"}