{"version":3,"file":"filter.mjs","sources":["../../../../src/components/Combobox/filter.ts"],"sourcesContent":["import uFuzzy from '@leeoniya/ufuzzy';\n\nimport { ALL_OPTION_VALUE, ComboboxOption } from './types';\n\n// https://catonmat.net/my-favorite-regex :)\nconst REGEXP_NON_ASCII = /[^ -~]/m;\n// https://www.asciitable.com/\n// matches only these: `~!@#$%^&*()_+-=[]\\{}|;':\",./<>?\nconst REGEXP_ONLY_SYMBOLS = /^[\\x21-\\x2F\\x3A-\\x40\\x5B-\\x60\\x7B-\\x7E]+$/m;\n// limit max terms in needle that qualify for re-ordering\nconst outOfOrderLimit = 5;\n// beyond 25 chars fall back to substring search\nconst maxNeedleLength = 25;\n// beyond 5 terms fall back to substring match\nconst maxFuzzyTerms = 5;\n// when number of matches <= 1e4, do ranking + sorting by quality\nconst rankThreshold = 1e4;\n\n// typo tolerance mode\nconst uf = new uFuzzy({ intraMode: 1 });\n\nexport function itemToString<T extends string | number>(item?: ComboboxOption<T> | null) {\n  if (item == null) {\n    return '';\n  }\n  return item.label ?? item.value.toString();\n}\n\n//TODO: Remove when MutliCombobox async has been merged\nexport function itemFilter<T extends string | number>(inputValue: string) {\n  const lowerCasedInputValue = inputValue.toLowerCase();\n\n  return (item: ComboboxOption<T>) => {\n    return (\n      !inputValue ||\n      item.label?.toLowerCase().includes(lowerCasedInputValue) ||\n      item.value?.toString().toLowerCase().includes(lowerCasedInputValue) ||\n      item.value.toString() === ALL_OPTION_VALUE\n    );\n  };\n}\n\nexport function fuzzyFind<T extends string | number>(\n  options: Array<ComboboxOption<T>>,\n  haystack: string[],\n  needle: string\n) {\n  let matches: Array<ComboboxOption<T>> = [];\n\n  if (needle === '') {\n    matches = options;\n  }\n  // fallback to substring matches to avoid badness\n  else if (\n    // contains non-ascii\n    REGEXP_NON_ASCII.test(needle) ||\n    // is only ascii symbols (operators)\n    REGEXP_ONLY_SYMBOLS.test(needle) ||\n    // too long (often copy-paste from somewhere)\n    needle.length > maxNeedleLength ||\n    uf.split(needle).length > maxFuzzyTerms\n  ) {\n    for (let i = 0; i < haystack.length; i++) {\n      let item = haystack[i];\n\n      if (item.includes(needle)) {\n        matches.push(options[i]);\n      }\n    }\n  }\n  // fuzzy search\n  else {\n    const [idxs, info, order] = uf.search(haystack, needle, outOfOrderLimit, rankThreshold);\n\n    if (idxs?.length) {\n      if (info && order) {\n        matches = order.map((idx) => options[info.idx[idx]]);\n      } else {\n        matches = idxs.map((idx) => options[idx]);\n      }\n    }\n  }\n\n  return matches;\n}\n"],"names":[],"mappings":";;AAmBW,IAAI,MAAA,CAAO,EAAE,SAAA,EAAW,GAAG"}