text: import Helper from './Helper';
  
  export default class FuzzySearch {
    constructor(haystack = [], keys = [], options = {}) {
      if (! Array.isArray(keys)) {
        options = keys;
        keys = [];
      }
  
      this.haystack = haystack;
      this.keys = keys;
      this.options = Object.assign({
        caseSensitive: false,
        sort: false,
      }, options);
    }
  
    search(query = '') {
      if (query === '') {
        return this.haystack;
      }
  
      const results = [];
  
      for (let i = 0; i < this.haystack.length; i++) {
        const item = this.haystack[i];
  
        if (this.keys.length === 0) {
          const score = FuzzySearch.isMatch(item, query, this.options.caseSensitive);
  
          if (score) {
            results.push({ item, score });
          }
        } else {
          for (let y = 0; y < this.keys.length; y++) {
            const propertyValues = Helper.getDescendantProperty(item, this.keys[y]);
  
            let found = false;
  
            for (let z = 0; z < propertyValues.length; z++) {
              const score = FuzzySearch.isMatch(propertyValues[z], query, this.options.caseSensitive);
  
              if (score) {
                found = true;
  
                results.push({ item, score });
  
                break;
              }
            }
  
            if (found) {
              break;
            }
          }
        }
      }
  
      if (this.options.sort) {
        results.sort((a, b) => a.score - b.score);
      }
  
      return results.map(result => result.item);
    }
  
    static isMatch(item, query, caseSensitive) {
      item = String(item);
      query = String(query);
  
      if (! caseSensitive) {
        item = item.toLocaleLowerCase();
        query = query.toLocaleLowerCase();
      }
  
      const letters = query.split('');
      const indexes = [];
  
      let index = 0;
  
      for (let i = 0; i < letters.length; i++) {
        const letter = letters[i];
  
        index = item.indexOf(letter, index);
  
        if (index === -1) {
          return false;
        }
  
        indexes.push(index);
  
        index++;
      }
  
      // Exact matches should be first.
      if (item === query) {
        return 1;
      }
  
      // If we have more than 2 letters, matches close to each other should be first.
      if (indexes.length > 1) {
        return 2 + (indexes[indexes.length - 1] - indexes[0]);
      }
  
  
      // Matches closest to the start of the string should be first.
      return 2 + indexes[0];
    }
  }
  