// 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');