import uFuzzy from "@leeoniya/ufuzzy"; export type OfflineResponse = { label: string; lat: number; lon: number; street?: string; neighbourhood?: string; locality?: string; region_a?: string; synonyms?: string[]; }[]; type OfflineQuery = { items: OfflineResponse; text?: string; enableSlowFullUnicodeSupport?: boolean; }; /** * Search for an address using offline geocoder * * @param {Object} $0 * @param {string} $0.text query * @para {Object} $0.items list of items to search * @return {Promise} A Promise that'll get resolved with the autocomplete result */ async function autocomplete({ items, text, enableSlowFullUnicodeSupport }: OfflineQuery): Promise { if (!text) return []; const itemsWithSynonyms = []; const synonymIndicies = []; // Add synonyms to full list // TODO: can this be done in a cleaner way? items.forEach((item, idx) => { itemsWithSynonyms.push(uFuzzy.latinize(item.label)); synonymIndicies.push(idx); if (item?.synonyms) { item.synonyms.forEach(synonym => { itemsWithSynonyms.push(uFuzzy.latinize(synonym)); synonymIndicies.push(idx); }); } }); // eslint-disable-next-line new-cap const u = new uFuzzy( enableSlowFullUnicodeSupport ? { unicode: true, interSplit: "[^\\p{L}\\d']+", intraSplit: "\\p{Ll}\\p{Lu}", intraBound: "\\p{L}\\d|\\d\\p{L}|\\p{Ll}\\p{Lu}", intraChars: "[\\p{L}\\d']", intraContr: "'\\p{L}{1,2}\\b" } : {} ); const idxs = u.filter(itemsWithSynonyms, uFuzzy.latinize(text)); return Array.from(new Set(idxs?.map(index => items[synonymIndicies[index]]))); } function search(args: OfflineQuery): Promise { return autocomplete(args); } function reverse(): Promise { console.warn("Not implemented"); return null; } export { autocomplete, reverse, search };