Created
January 8, 2024 02:29
-
-
Save antoniopresto/2959bb1109b5a3b8d9892092e6076d27 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function createWorker(items: string[]) { | |
const code = makeCode(JSON.stringify(items)); | |
const blob = new Blob(code, { | |
type: 'text/javascript', | |
}); | |
const blobUrl = URL.createObjectURL(blob); | |
const worker = new Worker(blobUrl); | |
return { | |
worker, | |
search(term: string) { | |
return new Promise<{ distance: number; value: string }[]>((resolve) => { | |
worker.postMessage(term); | |
function listener(message: { | |
data: { distance: number; value: string }[]; | |
}) { | |
if (Array.isArray(message.data)) { | |
worker.removeEventListener('message', listener); | |
resolve(message.data); | |
} | |
} | |
worker.addEventListener('message', listener); | |
}); | |
}, | |
}; | |
} | |
function makeCode(items: string) { | |
const leven = ` | |
// https://github.com/sindresorhus/leven | |
const array = []; | |
const charCodeCache = []; | |
const leven = (left, right) => { | |
if (left === right) { | |
return 0; | |
} | |
const swap = left; | |
if (left.length > right.length) { | |
left = right; | |
right = swap; | |
} | |
let leftLength = left.length; | |
let rightLength = right.length; | |
while (leftLength > 0 && (left.charCodeAt(~-leftLength) === right.charCodeAt(~-rightLength))) { | |
leftLength--; | |
rightLength--; | |
} | |
let start = 0; | |
while (start < leftLength && (left.charCodeAt(start) === right.charCodeAt(start))) { | |
start++; | |
} | |
leftLength -= start; | |
rightLength -= start; | |
if (leftLength === 0) { | |
return rightLength; | |
} | |
let bCharCode; | |
let result; | |
let temp; | |
let temp2; | |
let i = 0; | |
let j = 0; | |
while (i < leftLength) { | |
charCodeCache[i] = left.charCodeAt(start + i); | |
array[i] = ++i; | |
} | |
while (j < rightLength) { | |
bCharCode = right.charCodeAt(start + j); | |
temp = j++; | |
result = j; | |
for (i = 0; i < leftLength; i++) { | |
temp2 = bCharCode === charCodeCache[i] ? temp : temp + 1; | |
temp = array[i]; | |
result = array[i] = temp > result ? temp2 > result ? result + 1 : temp2 : temp2 > temp ? temp + 1 : temp2; | |
} | |
} | |
return result; | |
};`; | |
const code = ` | |
${leven}; | |
const cache = new Map(); | |
function findCached(term, value){ | |
const key = \`\${term}##\${value}\`; | |
if(cache.has(key)) return cache.get(key); | |
term = term.toLowerCase(); | |
value = value.toLowerCase(); | |
const dist = (() => { | |
const dist = Math.min(leven(term,value)); | |
if(term.length >=4) { | |
if(value.startsWith(term)) return Math.min(dist, 1); | |
if(value.includes(term)) return Math.min(dist, 1.5); | |
} | |
return dist; | |
})(); | |
cache.set(key, dist); | |
return dist; | |
} | |
const items = ${items}; | |
function findClosestMatches(term) { | |
return items.map(value => { | |
return [ | |
{ value, distance: findCached(term, value) }, | |
// { value, distance: findCached(term.slice(0,4), value.slice(0,4)) } | |
]; | |
}) | |
.flat() | |
.sort((a, b) => a.distance - b.distance) | |
.filter(el => el.distance < 5) | |
.slice(0, 50); | |
} | |
self.onmessage = function (message) { | |
const term = message.data; | |
try { | |
self.postMessage(findClosestMatches(term)); | |
} catch (e) { | |
console.info(e); | |
} | |
}`; | |
return [code]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment