{"version":3,"sources":["jsdelivr-header.js","/npm/@crucai/use-fuzzy-filter@1.0.11/src/FuzzyTrieClass.ts","/npm/@crucai/use-fuzzy-filter@1.0.11/src/index.ts"],"names":[],"mappings":"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","file":"/npm/@crucai/use-fuzzy-filter@1.0.11/dist/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/@crucai/use-fuzzy-filter@1.0.11/dist/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","/**\n * A trie data structure optimized for approximate string matching,\n * allowing for flexible yet controlled searches based on lexicographical\n * distance.\n *\n * This class provides methods to add items with associated search strings and\n * to perform searches within a specified maximum Levenshtein distance.\n *\n * Levenshtein distance is a metric used in computer science and information\n * theory to measure the difference between two sequences of characters.\n * It's also known as the edit distance.\n *\n * Specifically, the Levenshtein distance between two words is the minimum\n * number of single-character edits (insertions, deletions, or substitutions)\n * required to change one word into the other.\n *\n * For example:\n *\n * The Levenshtein distance between \"kitten\" and \"sitting\" is 3:\n *\n * kitten → sitten (substitution of \"s\" for \"k\")\n * sitten → sittin (substitution of \"i\" for \"e\")\n * sittin → sitting (insertion of \"g\" at the end)\n * The Levenshtein distance between \"book\" and \"back\" is 2:\n *\n * book → bock (substitution of \"c\" for \"o\")\n * bock → back (substitution of \"a\" for \"o\")\n *\n * Using Levenshtein distance in this class allows the search to return\n * results that are close matches to the search term, even if they're\n * not exact matches. The results are then sorted based on this distance,\n * with the closest matches (lowest Levenshtein distance) appearing first\n * in the results array.\n *\n * This approach is particularly useful for implementing features like\n * autocorrect, spell-checking, or fuzzy search functionality where you\n * want to find close matches to a given input string.\n *\n * ------------------------------------------------------------------------\n *\n * Usage:\n * 1. Create an instance of FuzzyTrie:\n *    const trie = new FuzzyTrie<YourItemType>();\n *\n * 2. Add items to the trie:\n *    trie.addItemToTrie(\"search string\", yourItem);\n *    You can add multiple items with the same or different search strings.\n *\n * 3. Perform a fuzzy search:\n *    const results = trie.searchItems(\"query string\", maxAllowedDistance);\n *    - \"query string\" is the search term\n *    - maxAllowedDistance is the maximum Levenshtein distance allowed (default is 2)\n *\n * 4. The search returns an array of items sorted by their Levenshtein distance\n *    from the query string, with the closest matches first.\n *\n * Example:\n * const trie = new FuzzyTrie<string>();\n * trie.addItemToTrie(\"apple\", \"Apple fruit\");\n * trie.addItemToTrie(\"banana\", \"Banana fruit\");\n * const results = trie.searchItems(\"aple\", 1);\n * // results will contain [\"Apple fruit\"]\n */\n\ninterface TrieNode<T> {\n  // Map of child nodes, where keys are characters and values are their corresponding TrieNode objects\n  childNodes: Map<string, TrieNode<T>>;\n  // Flag indicating if this node represents a complete word in the trie\n  isCompleteWord: boolean;\n  // Array of items associated with this node and their corresponding search strings\n  associatedItems: Array<{ storedItem: T; associatedSearchString: string }>;\n}\n\n/*\n * @class FuzzyTrie<T>\n * @template T The type of items stored in the trie\n */\nclass FuzzyTrie<T> {\n  // The root node of the Trie\n  private rootNode: TrieNode<T> = {\n    childNodes: new Map(),\n    isCompleteWord: false,\n    associatedItems: [],\n  };\n\n  // Calculates the Levenshtein distance between two strings, up to a maximum allowed distance\n  private calculateLevenshteinDistance(\n    firstString: string,\n    secondString: string,\n    maxAllowedDistance: number = Infinity\n  ): number {\n    if (firstString === secondString) return 0;\n    if (firstString.length > secondString.length)\n      [firstString, secondString] = [secondString, firstString];\n\n    const firstStringLength = firstString.length;\n    const secondStringLength = secondString.length;\n\n    // If the difference in length exceeds maxAllowedDistance, immediately return a large value\n    if (secondStringLength - firstStringLength > maxAllowedDistance)\n      return maxAllowedDistance + 1;\n\n    let previousDistanceRow = new Array(firstStringLength + 1);\n    for (let i = 0; i <= firstStringLength; i++) {\n      previousDistanceRow[i] = i;\n    }\n\n    // Iterate over each character of the second string\n    for (\n      let currentIndex = 1;\n      currentIndex <= secondStringLength;\n      currentIndex++\n    ) {\n      const currentDistanceRow = [currentIndex];\n      const secondStringChar = secondString.charCodeAt(currentIndex - 1);\n      let minimumDistanceInRow = currentIndex;\n\n      // Iterate over each character of the first string\n      for (\n        let compareIndex = 1;\n        compareIndex <= firstStringLength;\n        compareIndex++\n      ) {\n        const firstStringChar = firstString.charCodeAt(compareIndex - 1);\n        const substitutionCost = firstStringChar === secondStringChar ? 0 : 1;\n        const insertionCost = currentDistanceRow[compareIndex - 1] + 1;\n        const deletionCost = previousDistanceRow[compareIndex] + 1;\n        const substitutionOrMatchCost =\n          previousDistanceRow[compareIndex - 1] + substitutionCost;\n        // Calculate the minimum cost of substitution, insertion, or deletion\n        currentDistanceRow[compareIndex] = Math.min(\n          insertionCost,\n          deletionCost,\n          substitutionOrMatchCost\n        );\n        // Update the minimum distance in the row\n        minimumDistanceInRow = Math.min(\n          minimumDistanceInRow,\n          currentDistanceRow[compareIndex]\n        );\n      }\n\n      // If the minimum distance exceeds maxAllowedDistance, return a large value\n      if (minimumDistanceInRow > maxAllowedDistance) {\n        return maxAllowedDistance + 1;\n      }\n\n      // Update the previous distance row for the next iteration\n      previousDistanceRow = currentDistanceRow;\n    }\n\n    // Return the final Levenshtein distance between the two strings\n    return previousDistanceRow[firstStringLength];\n  }\n\n  // Adds an item to the Trie based on a search string\n  addItemToTrie(searchString: string, itemToAdd: T) {\n    let currentNode = this.rootNode;\n    const normalizedSearchString = searchString.toLowerCase();\n\n    // Traverse the Trie to find or create nodes for each character in the search string\n    for (const currentChar of normalizedSearchString) {\n      if (!currentNode.childNodes.has(currentChar)) {\n        currentNode.childNodes.set(currentChar, {\n          childNodes: new Map(),\n          isCompleteWord: false,\n          associatedItems: [],\n        });\n      }\n      currentNode = currentNode.childNodes.get(currentChar)!;\n    }\n\n    // Mark the current node as a complete word and associate it with the item\n    currentNode.isCompleteWord = true;\n    currentNode.associatedItems.push({\n      storedItem: itemToAdd,\n      associatedSearchString: normalizedSearchString,\n    });\n  }\n\n  // Searches for items based on a query string, considering a maximum allowed distance\n  searchItems(queryString: string, maxAllowedDistance: number = 2): T[] {\n    const normalizedQuery = queryString.toLowerCase();\n    const searchResults: Array<{\n      matchedItem: T;\n      levenshteinDistance: number;\n      matchedSearchString: string;\n    }> = [];\n\n    // Helper function to traverse the Trie nodes\n    const traverseTrieNodes = (\n      currentNode: TrieNode<T>,\n      currentPrefix: string\n    ) => {\n      // If the current node represents a complete word, check its associated items\n      if (currentNode.isCompleteWord) {\n        currentNode.associatedItems.forEach(\n          ({ storedItem, associatedSearchString }) => {\n            // Calculate the Levenshtein distance between the query and the associated search string\n            const calculatedDistance = this.calculateLevenshteinDistance(\n              normalizedQuery,\n              associatedSearchString,\n              maxAllowedDistance\n            );\n\n            // If the distance is within the allowed limit, add the item to the results\n            if (calculatedDistance <= maxAllowedDistance) {\n              searchResults.push({\n                matchedItem: storedItem,\n                levenshteinDistance: calculatedDistance,\n                matchedSearchString: associatedSearchString,\n              });\n            }\n          }\n        );\n      }\n\n      // Recursively traverse each child node of the current node\n      currentNode.childNodes.forEach((childNode, charToChild) => {\n        traverseTrieNodes(childNode, currentPrefix + charToChild);\n      });\n    };\n\n    // Start the traversal from the root node with an empty prefix\n    traverseTrieNodes(this.rootNode, \"\");\n\n    // Sort the matched items by their Levenshtein distance\n    const sortedMatchedItems = searchResults\n      .sort((a, b) => a.levenshteinDistance - b.levenshteinDistance)\n      .map((result) => result.matchedItem);\n\n    // Return the sorted list of matched items\n    return sortedMatchedItems;\n  }\n}\n\nexport { FuzzyTrie };\n","import { useRef, useState, useEffect, useMemo } from \"react\";\nimport { FuzzyTrie } from \"./FuzzyTrieClass\";\n\n/**\n * A React hook that implements a fuzzy search trie for efficient searching and suggestions.\n *\n * @template T The type of items stored in the trie.\n * @param {UseTrieOptions<T>} options - Configuration options for the fuzzy trie.\n * @param {T[]} [options.items=[]] - An array of items to be added to the trie.\n * @param {(item: T) => string} options.getSearchString - A function that returns the search string for each item.\n * @param {number} [options.debounceMs=150] - The debounce time in milliseconds for the search function.\n * @param {number} [options.minSearchLength=1] - The minimum length of the search term to start searching.\n * @param {number} [options.maxDistance=2] - The maximum Levenshtein distance for fuzzy matching.\n * @param {number} [options.maxResults=10] - The maximum number of results to return.\n * @returns {{\n *   search: (searchTerm: string) => void,\n *   suggestions: T[]\n * }} An object containing the search function and current suggestions.\n */\nfunction useFuzzyFilter<T>({\n  items = [],\n  getSearchString,\n  debounceMs = 150,\n  minSearchLength = 1,\n  maxDistance = 2,\n  maxResults = 10,\n}: UseTrieOptions<T>) {\n  const trieRef = useRef(new FuzzyTrie<T>());\n  const [suggestions, setSuggestions] = useState<T[]>([]);\n\n  useEffect(() => {\n    trieRef.current = new FuzzyTrie<T>();\n    items.forEach((item) => {\n      trieRef.current.addItemToTrie(getSearchString(item), item);\n    });\n  }, [items, getSearchString]);\n\n  const search = useMemo(\n    () =>\n      debounce((searchTerm: string) => {\n        if (searchTerm.length < minSearchLength) {\n          setSuggestions([]);\n          return;\n        }\n        const results = trieRef.current\n          .searchItems(searchTerm, maxDistance)\n          .slice(0, maxResults);\n\n        setSuggestions(results);\n      }, debounceMs),\n    [minSearchLength, maxDistance, maxResults, debounceMs]\n  );\n\n  return { search, suggestions };\n}\n\nfunction debounce<T extends unknown[]>(\n  func: (...args: T) => void,\n  delay: number\n): (...args: T) => void {\n  let timer: NodeJS.Timeout | undefined;\n  return (...args: T) => {\n    if (timer) {\n      clearTimeout(timer);\n    }\n    timer = setTimeout(() => {\n      func(...args);\n    }, delay);\n  };\n}\n\nexport { useFuzzyFilter };\n\ninterface UseTrieOptions<T> {\n  items?: T[];\n  getSearchString: (item: T) => string;\n  debounceMs?: number;\n  minSearchLength?: number;\n  maxDistance?: number;\n  maxResults?: number;\n}\n"]}