{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export const highlightStrategy = {\n  WHOLE_WORD_MATCH: \"wholeWordMatch\",\n  PARTIAL_MATCH: \"partialMatch\",\n  PARTIAL_MATCH_FULL_WORD: \"partialMatchFullWord\",\n} as const;\n\nexport type HighlightStrategy =\n  (typeof highlightStrategy)[keyof typeof highlightStrategy];\n\nexport interface HighlightOptions {\n  caseSensitive?: boolean;\n  strategy?: HighlightStrategy;\n  HTMLTag?: string;\n  CSSClass?: string;\n}\nexport type Position = { start: number; end: number };\n\ntype Positions = Position[];\n\nconst defaultOptions: Required<HighlightOptions> = {\n  caseSensitive: false,\n  strategy: highlightStrategy.PARTIAL_MATCH,\n  HTMLTag: \"mark\",\n  CSSClass: \"orama-highlight\",\n};\n\nexport class Highlight {\n  private readonly options: HighlightOptions;\n  private _positions: Positions = [];\n  private _HTML: string = \"\";\n  private _searchTerm: string = \"\";\n  private _originalText: string = \"\";\n\n  constructor(options: HighlightOptions = defaultOptions) {\n    this.options = { ...defaultOptions, ...options };\n  }\n\n  public highlight(text: string, searchTerm: string): Highlight {\n    this._searchTerm = searchTerm ?? \"\";\n    this._originalText = text ?? \"\";\n\n    if (!this._searchTerm || !this._originalText) {\n      this._positions = [];\n      this._HTML = this._originalText;\n      return this;\n    }\n\n    const HTMLTag = this.options.HTMLTag ?? defaultOptions.HTMLTag;\n    const CSSClass = this.options.CSSClass ?? defaultOptions.CSSClass;\n\n    const caseSensitive =\n      this.options.caseSensitive ?? defaultOptions.caseSensitive;\n    const strategy = this.options.strategy ?? defaultOptions.strategy;\n    const regexFlags = caseSensitive ? \"g\" : \"gi\";\n    const searchTerms = this.escapeRegExp(\n      caseSensitive ? this._searchTerm : this._searchTerm.toLowerCase()\n    )\n      .trim()\n      .split(/\\s+/)\n      .join(\"|\");\n\n    let regex: RegExp;\n    if (strategy === highlightStrategy.WHOLE_WORD_MATCH) {\n      regex = new RegExp(`\\\\b${searchTerms}\\\\b`, regexFlags);\n    } else if (strategy === highlightStrategy.PARTIAL_MATCH) {\n      regex = new RegExp(searchTerms, regexFlags);\n    } else if (strategy === highlightStrategy.PARTIAL_MATCH_FULL_WORD) {\n      regex = new RegExp(`\\\\b[^\\\\s]*(${searchTerms})[^\\\\s]*\\\\b`, regexFlags);\n    } else {\n      throw new Error(\"Invalid highlighter strategy\");\n    }\n\n    const positions: Array<{ start: number; end: number }> = [];\n    const highlightedParts: string[] = [];\n\n    let match;\n    let lastEnd = 0;\n    let previousLastIndex = -1;\n\n    while ((match = regex.exec(this._originalText)) !== null) {\n      if (regex.lastIndex === previousLastIndex) {\n        break;\n      }\n      previousLastIndex = regex.lastIndex;\n\n      const start = match.index;\n      const end = start + match[0].length - 1;\n\n      positions.push({ start, end });\n\n      highlightedParts.push(this._originalText.slice(lastEnd, start));\n      highlightedParts.push(\n        `<${HTMLTag} class=\"${CSSClass}\">${match[0]}</${HTMLTag}>`\n      );\n\n      lastEnd = end + 1;\n    }\n\n    highlightedParts.push(this._originalText.slice(lastEnd));\n\n    this._positions = positions;\n    this._HTML = highlightedParts.join(\"\");\n\n    return this;\n  }\n\n  public trim(trimLength: number, ellipsis: boolean = true): string {\n    if (this._positions.length === 0) {\n      return `${this._HTML.substring(0, trimLength)}${ellipsis ? `...` : \"\"}`;\n    }\n\n    if (this._originalText.length <= trimLength) {\n      return this._HTML;\n    }\n\n    const firstMatch = this._positions[0].start;\n    const start = Math.max(firstMatch - Math.floor(trimLength / 2), 0);\n    const end = Math.min(start + trimLength, this._originalText.length);\n    const trimmedContent = `${\n      start === 0 || !ellipsis ? \"\" : \"...\"\n    }${this._originalText.slice(start, end)}${\n      end < this._originalText.length && ellipsis ? \"...\" : \"\"\n    }`;\n\n    this.highlight(trimmedContent, this._searchTerm);\n    return this._HTML;\n  }\n\n  get positions(): Positions {\n    return this._positions;\n  }\n\n  get HTML(): string {\n    return this._HTML;\n  }\n\n  private escapeRegExp(string: string): string {\n    return string.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n  }\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,eAAAE,EAAA,sBAAAC,IAAA,eAAAC,EAAAJ,GAAO,IAAMG,EAAoB,CAC/B,iBAAkB,iBAClB,cAAe,eACf,wBAAyB,sBAC3B,EAeME,EAA6C,CACjD,cAAe,GACf,SAAUF,EAAkB,cAC5B,QAAS,OACT,SAAU,iBACZ,EAEaD,EAAN,KAAgB,CACJ,QACT,WAAwB,CAAC,EACzB,MAAgB,GAChB,YAAsB,GACtB,cAAwB,GAEhC,YAAYI,EAA4BD,EAAgB,CACtD,KAAK,QAAU,CAAE,GAAGA,EAAgB,GAAGC,CAAQ,CACjD,CAEO,UAAUC,EAAcC,EAA+B,CAI5D,GAHA,KAAK,YAAcA,GAAc,GACjC,KAAK,cAAgBD,GAAQ,GAEzB,CAAC,KAAK,aAAe,CAAC,KAAK,cAC7B,YAAK,WAAa,CAAC,EACnB,KAAK,MAAQ,KAAK,cACX,KAGT,IAAME,EAAU,KAAK,QAAQ,SAAWJ,EAAe,QACjDK,EAAW,KAAK,QAAQ,UAAYL,EAAe,SAEnDM,EACJ,KAAK,QAAQ,eAAiBN,EAAe,cACzCO,EAAW,KAAK,QAAQ,UAAYP,EAAe,SACnDQ,EAAaF,EAAgB,IAAM,KACnCG,EAAc,KAAK,aACvBH,EAAgB,KAAK,YAAc,KAAK,YAAY,YAAY,CAClE,EACG,KAAK,EACL,MAAM,KAAK,EACX,KAAK,GAAG,EAEPI,EACJ,GAAIH,IAAaT,EAAkB,iBACjCY,EAAQ,IAAI,OAAO,MAAMD,CAAW,MAAOD,CAAU,UAC5CD,IAAaT,EAAkB,cACxCY,EAAQ,IAAI,OAAOD,EAAaD,CAAU,UACjCD,IAAaT,EAAkB,wBACxCY,EAAQ,IAAI,OAAO,cAAcD,CAAW,cAAeD,CAAU,MAErE,OAAM,IAAI,MAAM,8BAA8B,EAGhD,IAAMG,EAAmD,CAAC,EACpDC,EAA6B,CAAC,EAEhCC,EACAC,EAAU,EACVC,EAAoB,GAExB,MAAQF,EAAQH,EAAM,KAAK,KAAK,aAAa,KAAO,MAC9CA,EAAM,YAAcK,GADgC,CAIxDA,EAAoBL,EAAM,UAE1B,IAAMM,EAAQH,EAAM,MACdI,EAAMD,EAAQH,EAAM,CAAC,EAAE,OAAS,EAEtCF,EAAU,KAAK,CAAE,MAAAK,EAAO,IAAAC,CAAI,CAAC,EAE7BL,EAAiB,KAAK,KAAK,cAAc,MAAME,EAASE,CAAK,CAAC,EAC9DJ,EAAiB,KACf,IAAIR,CAAO,WAAWC,CAAQ,KAAKQ,EAAM,CAAC,CAAC,KAAKT,CAAO,GACzD,EAEAU,EAAUG,EAAM,CAClB,CAEA,OAAAL,EAAiB,KAAK,KAAK,cAAc,MAAME,CAAO,CAAC,EAEvD,KAAK,WAAaH,EAClB,KAAK,MAAQC,EAAiB,KAAK,EAAE,EAE9B,IACT,CAEO,KAAKM,EAAoBC,EAAoB,GAAc,CAChE,GAAI,KAAK,WAAW,SAAW,EAC7B,MAAO,GAAG,KAAK,MAAM,UAAU,EAAGD,CAAU,CAAC,GAAGC,EAAW,MAAQ,EAAE,GAGvE,GAAI,KAAK,cAAc,QAAUD,EAC/B,OAAO,KAAK,MAGd,IAAME,EAAa,KAAK,WAAW,CAAC,EAAE,MAChCJ,EAAQ,KAAK,IAAII,EAAa,KAAK,MAAMF,EAAa,CAAC,EAAG,CAAC,EAC3DD,EAAM,KAAK,IAAID,EAAQE,EAAY,KAAK,cAAc,MAAM,EAC5DG,EAAiB,GACrBL,IAAU,GAAK,CAACG,EAAW,GAAK,KAClC,GAAG,KAAK,cAAc,MAAMH,EAAOC,CAAG,CAAC,GACrCA,EAAM,KAAK,cAAc,QAAUE,EAAW,MAAQ,EACxD,GAEA,YAAK,UAAUE,EAAgB,KAAK,WAAW,EACxC,KAAK,KACd,CAEA,IAAI,WAAuB,CACzB,OAAO,KAAK,UACd,CAEA,IAAI,MAAe,CACjB,OAAO,KAAK,KACd,CAEQ,aAAaC,EAAwB,CAC3C,OAAOA,EAAO,QAAQ,sBAAuB,MAAM,CACrD,CACF","names":["src_exports","__export","Highlight","highlightStrategy","__toCommonJS","defaultOptions","options","text","searchTerm","HTMLTag","CSSClass","caseSensitive","strategy","regexFlags","searchTerms","regex","positions","highlightedParts","match","lastEnd","previousLastIndex","start","end","trimLength","ellipsis","firstMatch","trimmedContent","string"]}