UNPKG

@sap/cds-dk

Version:

Command line client and development toolkit for the SAP Cloud Application Programming Model

91 lines (67 loc) 2.23 kB
const cache = new Map(); /** * Levenshtein distance algorithm using recursive calls and cache * * @param {string} input - search the list for a best match for this string * @param {string[]} list - a list of strings to match input against * @param {null | (s:string) => unknown} log logging method to use, might be null if no logging is wanted * @param {{maxListLength?: number, maxInputLength?: number}} [options] - optional parameters to control the search * @returns {string[]} array with best matches, is never null but might be empty in case no search was possible */ module.exports = (input, list, log, options = {}) => { const { maxListLength, maxInputLength } = {...{ maxListLength: 50, maxInputLength: 50 }, ...options}; let minDistWords = []; if (input.length > maxInputLength || list.length > maxListLength) { return minDistWords; } let minDist = Number.MAX_SAFE_INTEGER; log && log('\nword\t\tlevDist\t\ttime(ms)'); let runtime = 0; for (const word of list) { const start = log && Date.now(); const levDist = levDistance(input, word); if (log) { const duration = Date.now() - start; runtime = runtime + duration; log(`${word}\t\t${levDist}\t\t${duration}`); } if (levDist === minDist) { minDistWords.push(word); } if (levDist < minDist) { minDist = levDist; minDistWords = [word]; } } log && log(`runtime: ${runtime}ms`); return minDistWords.sort(); } const levDistance = (a, b) => { const cachedObj = cache.get(a)?.get(b); if (cachedObj) { return cachedObj; } if (a.length === 0) { return addToCache(a, b, b.length); } if (b.length === 0) { return addToCache(a, b, a.length); } const tail_a = a.substring(1); const tail_b = b.substring(1); if (a[0] === b[0]) { return levDistance(tail_a, tail_b); } const lev1 = levDistance(tail_a, b); const lev2 = levDistance(a, tail_b); const lev3 = levDistance(tail_a, tail_b); const levDist = Math.min(lev1, lev2, lev3) + 1; return addToCache(a, b, levDist); } const addToCache = (a, b, value) => { if (!cache.has(a)) { cache.set(a, new Map()); } cache.get(a).set(b, value); return value; }