Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/adelpro/quran-search-engine/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The getHighlightRanges() function computes non-overlapping highlight ranges for matched tokens in Arabic text. This is a pure, UI-agnostic function that returns character positions and match types, allowing you to control how highlights are rendered in your application.

Function signature

function getHighlightRanges(
  text: string,
  matchedTokens: readonly string[] | undefined,
  tokenTypes?: Record<string, MatchType>
): HighlightRange[]

Parameters

text
string
required
The Arabic text to search for highlights (typically verse.uthmani or verse.standard)
matchedTokens
readonly string[] | undefined
required
Array of matched tokens from search results (from verse.matchedTokens). If undefined or empty, returns an empty array.
tokenTypes
Record<string, MatchType>
Optional mapping of tokens to their match types (from verse.tokenTypes). If not provided, all tokens default to 'fuzzy' match type.

Return value

HighlightRange[]
array
Array of non-overlapping highlight ranges, sorted by start position
start
number
Starting character index (0-based) in the text
end
number
Ending character index (exclusive) in the text
token
string
The original query token that matched this range
matchType
MatchType
The type of match: 'exact', 'lemma', 'root', or 'fuzzy'

Usage

Basic example

import { getHighlightRanges } from 'quran-search-engine';

const ranges = getHighlightRanges(verse.uthmani, verse.matchedTokens, verse.tokenTypes);
// Example output:
// [
//   { start: 12, end: 23, token: 'الله', matchType: 'exact' },
//   { start: 30, end: 45, token: 'الرحمن', matchType: 'lemma' },
// ]

React rendering example

This example shows how to render highlighted text in React without using dangerouslySetInnerHTML:
import { getHighlightRanges, type ScoredQuranText } from 'quran-search-engine';
import type { ReactNode } from 'react';

export function Verse({ verse }: { verse: ScoredQuranText }) {
  const ranges = getHighlightRanges(verse.uthmani, verse.matchedTokens, verse.tokenTypes);
  if (ranges.length === 0) return <span>{verse.uthmani}</span>;

  const parts: ReactNode[] = [];
  let cursor = 0;

  ranges.forEach((r, i) => {
    if (cursor < r.start) parts.push(verse.uthmani.slice(cursor, r.start));
    parts.push(
      <span key={`${r.start}-${r.end}-${i}`} className={`highlight highlight-${r.matchType}`}>
        {verse.uthmani.slice(r.start, r.end)}
      </span>,
    );
    cursor = r.end;
  });

  if (cursor < verse.uthmani.length) parts.push(verse.uthmani.slice(cursor));

  return <span>{parts}</span>;
}

How it works

  1. Token matching: For each matched token, the function creates a regex pattern that:
    • Normalizes Arabic text (handles alef variants, ya/ta marbuta variations)
    • Accounts for optional diacritical marks (tashkeel)
    • Finds all occurrences in the text
  2. Priority sorting: Matches are sorted by:
    • Length (longer matches first) to prioritize more specific matches
    • Start position (earlier matches first) for stable ordering
  3. Overlap resolution: The function ensures non-overlapping ranges by:
    • Processing matches in priority order
    • Marking occupied character positions
    • Skipping matches that overlap with higher-priority matches
  4. Final ordering: Results are sorted by start position for sequential rendering

Notes

  • The function is pure and has no side effects
  • Returns an empty array if matchedTokens is undefined or empty
  • Handles Arabic text variations (alef forms, ya/ta marbuta, etc.)
  • Ignores diacritical marks when matching
  • Guarantees non-overlapping ranges for safe rendering
  • Match types default to 'fuzzy' if tokenTypes is not provided

Build docs developers (and LLMs) love