You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

195 lines
5.8 KiB
JavaScript

const fs = require('fs');
const commands = module.exports = {};
const msgRegex = /^!([a-zA-Z0-9]+) ([a-zA-Z0-9]+) ([a-zA-Z0-9]+) ?(.*)$/;
// Compute the edit distance between the two given strings
function getEditDistance(sourceString, targetString) {
if (sourceString.length === 0) return targetString.length;
if (targetString.length === 0) return sourceString.length;
let matrix = [];
// increment along the first column of each row
for (let i = 0; i <= targetString.length; i++) {
matrix[i] = [i];
}
// increment each column in the first row
for (let j = 0; j <= sourceString.length; j++) {
matrix[0][j] = j;
}
// Fill in the rest of the matrix
for (let i = 1; i <= targetString.length; i++) {
for (let j = 1; j <= sourceString.length; j++) {
let cost = 1;
if (targetString.charAt(i-1) === sourceString.charAt(j-1)) {
cost = 0;
}
matrix[i][j] = Math.min(matrix[i-1][j-1] + cost, // substitution
matrix[i][j-1] + 1, // insertion
matrix[i-1][j] + 1 // deletion
);
}
}
return matrix[targetString.length][sourceString.length];
}
function getSuggestions(input, list, threshhold){
let candidates = {};
let bestDistance = null;
for(let key in list){
let distance = getEditDistance(input, key);
console.log("new it. key: "+key+" dist:"+distance);
if(distance >= threshhold) continue;
if(bestDistance === distance){ //another candidate
candidates[candidates.length] = key;
console.log("other candidate");
}
else if(bestDistance > distance || bestDistance === null){ //new best candidate
candidates = [key];
bestDistance = distance;
console.log("new best candidate");
}
}
return candidates;
}
function suggestFix(msg, projects){
const shortcuts = msg.match(msgRegex);
const expansion = {};
if(shortcuts === null){
return null;
}
expansion.project = findShortcut(shortcuts[1], projects);
if(expansion.project) {
expansion.project = expansion.project.toLowerCase();
} else {
return getSuggestions(shortcuts[1], projects);
}
expansion.service = findShortcut(shortcuts[2], projects[expansion.project]);
if(expansion.service) {
expansion.service = expansion.service.toLowerCase();
} else {
return getSuggestions(shortcuts[2], projects[expansion.project]);
}
expansion.subcommand = findShortcut(shortcuts[3], projects[expansion.project][expansion.service]);
if(expansion.subcommand) {
return null;
} else {
return getSuggestions(shortcuts[3], projects[expansion.project][expansion.service]);
}
}
commands.suggestFix = suggestFix;
commands.getEditDistance = getEditDistance;
const findShortcut = (shortcut, objects) => {
const regex = new RegExp('^' + shortcut + '.*');
let expansionCount = 0;
let expansion = false;
for(let key in objects) {
if(regex.test(key)) {
expansionCount++;
if(expansionCount > 1) {
return false;
};
expansion = key;
};
};
return expansion;
};
commands.expandCommand = (msg, projects) => {
return new Promise((resolve, reject) => {
const shortcuts = msg.match(msgRegex);
const expansion = {};
if(shortcuts === null){
reject('No regex match.');
return;
}
expansion.project = findShortcut(shortcuts[1], projects);
if(expansion.project) {
expansion.project = expansion.project.toLowerCase();
} else {
reject('could not resolve project: ' + shortcuts[1]);
return;
}
expansion.service = findShortcut(shortcuts[2], projects[expansion.project]);
if(expansion.service) {
expansion.service = expansion.service.toLowerCase();
} else {
reject('could not resolve service: ' + shortcuts[2]);
return;
}
expansion.subcommand = findShortcut(shortcuts[3], projects[expansion.project][expansion.service]);
if(expansion.subcommand) {
expansion.subcommand = expansion.subcommand.toLowerCase();
} else {
reject('could not resolve subcommand: ' + shortcuts[4]);
return;
}
// if args are given, write them in command
if(shortcuts[4]) expansion.args = shortcuts[4];
resolve(expansion);
return;
});
};
commands.projects = {};
fs.readdirSync('./projects').forEach((file) => {
let project = file.match(/^([a-z]*)\.js$/);
if(!project) {
//skip current forEach pass
return;
}
project = project[1];
commands.projects[project] = require('./projects/' + file);
});
/* //Test code
const commands = {};
commands['homeserver'] = {};
commands['homeserver']['register'] = {};
commands['homeserver']['register'].regex = /([a-zA-Z0-9])/;
commands['homeserver']['register'].usage = '<user localpart>';
commands['homeserver']['register'].exec = (args) => {
//args is a <user input args string>.match with .regex
};
commands['imninja'] = {};
commands['imninja']['register'] = {};
commands['imninja']['register'].regex = /([a-zA-Z0-9])/;
commands['imninja']['register'].usage = '<user localpart>';
commands['imninja']['register'].exec = (args) => {
//args is a <user input args string>.match with .regex
};
console.log(getSuggestions("inminja", commands)); // -> imninja
console.log(getSuggestions("34C21", commands, 4)); // -> {}*/
//console.log(getEditDistance("saturday", "sunday")); //should be 3
/*
expandCommand('!lubi infra reb saeifsaef', commands.projects)
.then((success) => {
console.log(success);
}, (fail) => {
console.log(fail);
});
*/