Archived
changed folder structure
This commit is contained in:
1 parent
d12657e075
commit
3ff3086e3e
14 files changed
+32
-32
No files matched your search
@@ -0,0 +1,230 @@
|
||||
import { CommandInteraction, Message } from "discord.js";
|
||||
import { MissingParameterError } from "../errors.js";
|
||||
import { BooleanParameter, InputParameter, NumberParameter, ObjectParameter, StringParameter } from "../structures/Parameter.js";
|
||||
import { Command } from "../structures/Command.js";
|
||||
import { CommandMessageStructure, PhraseOccurrenceData } from "../types/Command.js";
|
||||
import { applicationState } from "../state.js";
|
||||
|
||||
/**
|
||||
* @class Command manager
|
||||
*/
|
||||
export class CommandManager {
|
||||
private readonly _list: Command[] = [];
|
||||
/**
|
||||
* Prefix used as a way to trigger the bot using messages
|
||||
* @type {string}
|
||||
*/
|
||||
public readonly prefix?: string;
|
||||
/**
|
||||
* Separator used to split user input to a list of {@link InputParameter}s (applies to prefix interactions)
|
||||
* @type {string}
|
||||
*/
|
||||
public readonly parameterSeparator: string;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {string} [prefix] - prefix used as a way to trigger the bot using messages
|
||||
* @param {string} parameterSeparator - used to split user input to a list of {@link InputParameter}s (applies to prefix interactions)
|
||||
*/
|
||||
constructor(prefix?: string, parameterSeparator?: string) {
|
||||
this.prefix = prefix;
|
||||
this.parameterSeparator = parameterSeparator || ",";
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the command by name, alias or keyword
|
||||
* @param {string} phrase - command name, alias or keyword
|
||||
* @returns {Command | null} Retrieved {@link Command} object from the manager or *null*
|
||||
*/
|
||||
public get(phrase: string): Command | null {
|
||||
let command: Command | null = null;
|
||||
this._list.map((c) => {
|
||||
if (c.name == phrase) {
|
||||
command = c;
|
||||
}
|
||||
c.aliases &&
|
||||
c.aliases.map((a) => {
|
||||
if (a == phrase) {
|
||||
command = c;
|
||||
}
|
||||
});
|
||||
});
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of commands registered in the manager
|
||||
* @type {Array} {@link Command}
|
||||
*/
|
||||
get list() {
|
||||
return Object.freeze([...this._list]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given {@link Command} to the instance manager with initial processing
|
||||
* @param {Command} command - {@link Command} instance object
|
||||
* @returns {boolean} Whether this command has been added successfully
|
||||
*/
|
||||
public add(command: Command): boolean {
|
||||
try {
|
||||
if (applicationState.running) {
|
||||
throw new Error("Cannot add command while the application is running");
|
||||
}
|
||||
if (!(command instanceof Command)) {
|
||||
throw new TypeError("Inavlid argument type");
|
||||
}
|
||||
const nameOccurrence: PhraseOccurrenceData | null = this.findPhraseOccurrence(command.name);
|
||||
if (nameOccurrence) {
|
||||
throw new Error(`The name "${command.name}" has already been registered as ${nameOccurrence.type} in the "${nameOccurrence.command.name}" command.`);
|
||||
}
|
||||
command.aliases &&
|
||||
command.aliases.map((a, i, ar) => {
|
||||
const aliasOccurrence: PhraseOccurrenceData | null = this.findPhraseOccurrence(a);
|
||||
if (aliasOccurrence) {
|
||||
console.warn(
|
||||
`[⚠ WARN] The name "${a}" is already registered as ${aliasOccurrence.type} in the "${aliasOccurrence.command.name}" command. It will be removed from the "${command.name}" command.`
|
||||
);
|
||||
ar.splice(i, 1);
|
||||
}
|
||||
});
|
||||
command.parameters &&
|
||||
command.parameters.map((p) => {
|
||||
if (p.type != "string" && p.choices) {
|
||||
throw new Error('Parameter with defined choices must have a "string" type');
|
||||
}
|
||||
});
|
||||
this._list.push(command);
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error(`[❌ ERROR] ${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches {@link Command} and list of {@link InputParameter}s from the given {@link Message} object
|
||||
* @param {Message} message - {@link Message} object
|
||||
* @returns {CommandMessagesStructure | null} {@link CommandMessageStructure} or *null*
|
||||
*/
|
||||
public fetchFromMessage(message: Message): CommandMessageStructure | null {
|
||||
if (!this.prefix) return null;
|
||||
if (!message.author.bot && message.content.startsWith(this.prefix)) {
|
||||
const content = message.content.replace(this.prefix, "");
|
||||
const name = content.split(" ")[0];
|
||||
const command = this.get(name);
|
||||
if (command) {
|
||||
const argumentsText = content.replace(name, "");
|
||||
const paramsList = argumentsText.split(this.parameterSeparator).map((a) => {
|
||||
return a.replace(" ", "");
|
||||
});
|
||||
if ((paramsList[0] == "" || paramsList[0] == " ") && paramsList.length == 1) {
|
||||
paramsList.splice(0, 1);
|
||||
}
|
||||
const parameters: InputParameter[] = [];
|
||||
command.parameters.map((p, i) => {
|
||||
if (!p.optional && !paramsList[i]) {
|
||||
throw new MissingParameterError(p);
|
||||
} else if (p.optional && !paramsList[i]) {
|
||||
return;
|
||||
}
|
||||
switch (p.type) {
|
||||
case "mentionable":
|
||||
case "channel":
|
||||
case "role":
|
||||
case "user":
|
||||
parameters.push(new ObjectParameter(p, paramsList[i]));
|
||||
break;
|
||||
case "string":
|
||||
parameters.push(new StringParameter(p, paramsList[i]));
|
||||
break;
|
||||
case "boolean":
|
||||
parameters.push(new BooleanParameter(p, paramsList[i]));
|
||||
break;
|
||||
case "number":
|
||||
parameters.push(new NumberParameter(p, paramsList[i]));
|
||||
break;
|
||||
default:
|
||||
parameters.push(new InputParameter(p, paramsList[i]));
|
||||
break;
|
||||
}
|
||||
});
|
||||
return {
|
||||
command: command,
|
||||
parameters: parameters,
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches command and parameters from the given {@link CommandInteraction} object
|
||||
* @param {CommandInteraction} interaction - {@link CommandInteraction} object
|
||||
* @returns {CommandMessagesStructure | null} {@link CommandMessageStructure} or *null*
|
||||
*/
|
||||
public fetchFromInteraction(interaction: CommandInteraction): CommandMessageStructure | null {
|
||||
const cmd = this.get(interaction.commandName);
|
||||
if (cmd) {
|
||||
if (interaction.options?.data) {
|
||||
const paramsList = interaction.options.data;
|
||||
const parameters: InputParameter[] = [];
|
||||
cmd.parameters.map((p) => {
|
||||
const inputParam = paramsList.find((d) => d.name == p.name);
|
||||
if (!p.optional && !inputParam) {
|
||||
throw new MissingParameterError(p);
|
||||
} else if (p.optional && !inputParam) {
|
||||
return;
|
||||
}
|
||||
switch (p.type) {
|
||||
case "mentionable":
|
||||
case "channel":
|
||||
case "role":
|
||||
case "user":
|
||||
parameters.push(new ObjectParameter(p, inputParam?.value));
|
||||
break;
|
||||
case "string":
|
||||
parameters.push(new StringParameter(p, inputParam?.value));
|
||||
break;
|
||||
case "boolean":
|
||||
parameters.push(new BooleanParameter(p, inputParam?.value));
|
||||
break;
|
||||
case "number":
|
||||
parameters.push(new NumberParameter(p, inputParam?.value));
|
||||
break;
|
||||
default:
|
||||
parameters.push(new InputParameter(p, inputParam?.value));
|
||||
break;
|
||||
}
|
||||
});
|
||||
return {
|
||||
command: cmd,
|
||||
parameters: parameters,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private findPhraseOccurrence(phrase?: string): PhraseOccurrenceData | null {
|
||||
let returnValue: PhraseOccurrenceData | null = null;
|
||||
this._list.map((c) => {
|
||||
if (phrase == c.name) {
|
||||
returnValue = {
|
||||
command: c,
|
||||
type: "NAME",
|
||||
};
|
||||
} else if (c.aliases && c.aliases.indexOf(phrase || "") != -1) {
|
||||
returnValue = {
|
||||
command: c,
|
||||
type: "ALIAS",
|
||||
};
|
||||
}
|
||||
});
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user