UNPKG

@sap/eslint-plugin-cds

Version:

ESLint plugin including recommended SAP Cloud Application Programming model and environment rules

101 lines (79 loc) 2.41 kB
'use strict' const cache = new Map() /** * Levenshtein distance algorithm using recursive calls and cache * * @param input search the list for a best match for this string * @param list a list of strings to match input against * @param {Function} [log] logging method to use, might be null if no logging is wanted * @param {boolean} [keepCase] * @param {Number} [threshold] * @returns {string[]} array with best matches, is never null but might be empty in case no search was possible * * @todo: Describe in which range the threshold should be. */ module.exports = function findFuzzy(input, list, log = null, keepCase = false, threshold = Number.MAX_SAFE_INTEGER) { if (typeof input !== 'string') return [] let minDistWords = [] if (input.length > 50 || list.length > 50) { 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() let levDist if (word === word.toUpperCase() && !keepCase) { levDist = levDistance(input.toUpperCase(), word) } else { 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) { if (!threshold || (threshold && levDist < threshold)) { minDistWords.push(word) } } if (levDist < minDist) { if (!threshold || (threshold && levDist < threshold)) { minDist = levDist minDistWords = [word] } } } log && log(`runtime: ${runtime}ms`) return minDistWords.sort() } function 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 tailA = a.substring(1) const tailB = b.substring(1) if (a[0] === b[0]) { return levDistance(tailA, tailB) } const lev1 = levDistance(tailA, b) const lev2 = levDistance(a, tailB) const lev3 = levDistance(tailA, tailB) const levDist = Math.min(lev1, lev2, lev3) + 1 return addToCache(a, b, levDist) } function addToCache(a, b, value) { if (!cache.has(a)) cache.set(a, new Map()) cache.get(a).set(b, value) return value }