Skip to content

Instantly share code, notes, and snippets.

@antoniopresto
Created January 8, 2024 02:29
Show Gist options
  • Save antoniopresto/2959bb1109b5a3b8d9892092e6076d27 to your computer and use it in GitHub Desktop.
Save antoniopresto/2959bb1109b5a3b8d9892092e6076d27 to your computer and use it in GitHub Desktop.
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