@sap/eslint-plugin-cds
Version:
ESLint plugin including recommended SAP Cloud Application Programming model and environment rules
101 lines (79 loc) • 2.41 kB
JavaScript
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
}