// function from https://www.tutorialspoint.com/levenshtein-distance-in-javascript
// I just randomly grabbed this... for fun
const levenshteinDistance = (str1 = '', str2 = '') => { const track = Array(str2.length + 1)
.fill(null)
.map(() => Array(str1.length + 1).fill(null));
for (let i = 0; i <= str1.length; i++) { track[0][i] = i;
}
for (let j = 0; j <= str2.length; j++) { track[j][0] = j;
}
for (let j = 1; j <= str2.length; j++) { for (let i = 1; i <= str1.length; i++) { const indicator = str1[i - 1] === str2[j - 1] ? 0 : 1;
track[j][i] = Math.min(
track[j][i - 1] + 1, // deletion
track[j - 1][i] + 1, // insertion
track[j - 1][i - 1] + indicator // substitution
);
}
}
return track[str2.length][str1.length];
};
const message = (() => { const events = {}; return { on(name, callback) { if (!events[name]) events[name] = [];
events[name].push(callback);
return message;
},
off(name, callback) { const listeners = events[name];
if (listeners != null) { for (let i = 0; i < listeners.length; i++) { if (listeners[i] === callback) { listeners.splice(i, 1);
break;
}
}
}
},
trigger(name, data) { // debug only...
console.log('trigger', name, data);
const listeners = events[name];
if (listeners != null) { for (let i = 0; i < listeners.length; i++) { if (listeners[i] != null) listeners[i](data);
}
} else { // production would never hit this `else`
// it could even be removed from production in a
// number of ways
console.warn(`no listeners for '${name}'`); let matches = [];
for (let i in events) { matches.push([levenshteinDistance(name, i), name, i]);
}
matches.sort((a, b) => a[0] - b[0]);
if (matches[0]) { console.warn(`did you mean '${matches[0][2]}' ?`, ); }
if (matches[1] && matches[1][0] < 4) { console.warn(` - or '${matches[1][2]}' ?`); }
}
},
};
})();
message.on('soda', () => {});message.on('pop', () => {});
message.on('anything', () => {});
message.trigger('anythin');
// something else that might match
message.on('mything', () => {});
message.trigger('anythi ng');