UNPKG

discord-bot-cli

Version:

An easy way to build a command-based discord bot with discord.js.

238 lines (237 loc) 11.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Command = void 0; const parseFlags_1 = require("../other/parsing/parseFlags"); const parseArgs_1 = require("../other/parsing/parseArgs"); const CommandResult_1 = require("./CommandResult"); const CommandResultError_1 = require("./errors/CommandResultError"); const CommandCollection_1 = require("./CommandCollection"); const parseValue_1 = require("../other/parsing/parseValue"); const Throttler_1 = require("./Throttler"); const CommandLoadError_1 = require("./errors/CommandLoadError"); const HelpUtils_1 = require("../other/HelpUtils"); class Command { constructor( /** Path to the file that contains the command if it's a top-most command, `null` otherwise. */ filepath, /** Name of this command. */ name, /** Aliases of this command. */ aliases, /** The list of permissions the bot's user require to execute this command. */ clientPermissions, /** The list of permissions the user require to execute this command. */ userPermissions, /** The list of exemples for this command. */ examples, /** The description of the command. */ description, /** This command's parent or `null` if it's a top-most command. */ parent, /** The [[CommandSet]] that contains this command. */ commandSet, /** A [[ReadonlyCommandCollection]] of this command's sub-commands. */ subs, /** A `ReadonlyMap` with this command's arguments' [[ArgDefinition]] */ args, /** A [[RestDefinition]] if this command use the rest argument, `undefined` otherwise. */ rest, /** A `ReadonlyMap` with this command's flags' [[FlagDefinition]] */ flags, _flagsShortcuts, _executor, // eslint-disable-line @typescript-eslint/no-explicit-any _canUse, _help, throttling, _useThrottlerOnSubs, /** Either or not this command is ignored. */ ignored, /** Either or not this command can only be used by dev (see [[CommandSetOptions.devIDs]]). */ devOnly, /** Either or not this command can only be used from a guild. */ guildOnly, /** Either or not the message that executed this command is deleted after the command execution. */ deleteMessage) { var _a; this.filepath = filepath; this.name = name; this.aliases = aliases; this.clientPermissions = clientPermissions; this.userPermissions = userPermissions; this.examples = examples; this.description = description; this.parent = parent; this.commandSet = commandSet; this.subs = subs; this.args = args; this.rest = rest; this.flags = flags; this._flagsShortcuts = _flagsShortcuts; this._executor = _executor; this._canUse = _canUse; this._help = _help; this._useThrottlerOnSubs = _useThrottlerOnSubs; this.ignored = ignored; this.devOnly = devOnly; this.guildOnly = guildOnly; this.deleteMessage = deleteMessage; this._throttler = throttling ? new Throttler_1.Throttler(throttling.count, throttling.duration) : throttling; this._throttlingIncludeAdmins = (_a = throttling === null || throttling === void 0 ? void 0 : throttling.includeAdmins) !== null && _a !== void 0 ? _a : false; } /** @internal */ static load(filepath, commandSet) { const module = require(filepath); // eslint-disable-line @typescript-eslint/no-var-requires if (!module.default) throw new CommandLoadError_1.CommandLoadError("Command data must be exported as default."); return Command._build(filepath, commandSet, module.default, null, undefined); } static _build(filepath, commandSet, data, parent, parentHelp) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l; function resolveInheritance(prop, defaultValue) { var _a; return ((_a = data.def.inherit) !== null && _a !== void 0 ? _a : true) && parent ? parent[prop] : defaultValue; } const subs = new CommandCollection_1.CommandCollection(); const cmd = new Command(filepath, data.name, (_a = data.def.aliases) !== null && _a !== void 0 ? _a : [], (_b = data.def.clientPermissions) !== null && _b !== void 0 ? _b : [], data.def.userPermissions, (_c = data.def.examples) !== null && _c !== void 0 ? _c : [], (_d = data.def.description) !== null && _d !== void 0 ? _d : "", parent, commandSet, subs, new Map(data.def.args ? Object.entries(data.def.args) : []), data.def.rest, new Map(data.def.flags ? Object.entries(data.def.flags) : []), new Map(data.def.flags ? Object.entries(data.def.flags) .filter(function (a) { return a[1].shortcut !== undefined; }) .map(([k, v]) => [v.shortcut, k]) : []), data.executor, data.def.canUse, (_e = data.def.help) !== null && _e !== void 0 ? _e : parentHelp, data.def.throttling, (_f = data.def.useThrottlerForSubs) !== null && _f !== void 0 ? _f : true, (_g = data.def.ignore) !== null && _g !== void 0 ? _g : resolveInheritance("ignored", false), (_h = data.def.devOnly) !== null && _h !== void 0 ? _h : resolveInheritance("devOnly", false), (_j = data.def.guildOnly) !== null && _j !== void 0 ? _j : resolveInheritance("guildOnly", false), (_k = data.def.deleteMessage) !== null && _k !== void 0 ? _k : resolveInheritance("deleteMessage", false)); for (const subName in data.subs) subs.add(Command._build(null, commandSet, data.subs[subName], cmd, ((_l = data.def.useHelpOnSubs) !== null && _l !== void 0 ? _l : false) || (!data.def.help && !!parentHelp) ? cmd._help : undefined)); return cmd; } // === Getter ===================================================== /** * The [[Throttler]] used by this command. */ get throttler() { if (this._throttler === null) return undefined; if (this._throttler) return this._throttler; if (this.parent && this.parent._useThrottlerOnSubs) return this.parent.throttler; return undefined; } /** * Either or not this command has an executor. */ get hasExecutor() { return this._executor !== undefined; } /** * Returns an array containing all parents of this command, ordered from top-most command to this command (included). * @returns An array of this command's parent [[Command]]. */ getParents() { const parents = []; parents.unshift(this); for (let parent = this.parent; parent; parent = parent.parent) parents.unshift(parent); return parents; } /** * Determines if the bot's user have required permissions to execute this command from the guild. * @param guild The guild from which check permissions. * @returns Either or not the bot's user have required permissions to execute this command from the guild. */ hasClientPermissions(guild) { return guild.me ? guild.me.hasPermission(this.clientPermissions) : false; } /** * Determines if a member have required permissions to execute this command. * @param member * @returns Either or not the member have required permissions to execute this command. */ hasPermissions(member) { if (!this.userPermissions) { if (this.parent) return this.parent.hasPermissions(member); else return true; } return member.hasPermission(this.userPermissions); } // ===================================================== /** * Call the `canUse` handler of this command and its parents (see [[CommandDefinition.canUse]]) * and return the first negative result (`false` or a `string`) or `true`. * @param user * @param message * @returns Result of `canUse` handlers. */ canUse(user, message) { if (this.parent) { const res = this.parent.canUse(user, message); if (res !== true) return res; } if (this._canUse) return this._canUse(user, message); return true; } /** * Determines of the message author pass the [[canUse]] and the [[hasPermissions]] checks. * @param message * @returns Either or not the message author pass the [[canUse]] and the [[hasPermissions]] checks. */ checkPermissions(message) { return (this.canUse(message.author, message) === true && (!message.member || this.hasPermissions(message.member))); } /** * Call the suitable help handler for this command. * @param message * @param options */ async help(message, options) { const context = { message, options, commandSet: this.commandSet, }; if (this._help) { await this._help(this, context); } else if (this.commandSet.helpHandler) { await this.commandSet.helpHandler(this, context); } else { await HelpUtils_1.defaultHelp(this, context); } } /** @internal */ async execute(message, inputArguments, options, commandSet) { if (message.guild && !this.hasClientPermissions(message.guild)) throw new CommandResultError_1.CommandResultError(CommandResult_1.CommandResultUtils.clientPermissions(this)); /** This command throttler if is required and defined, undefined otherwise. */ const throttler = !options.devIDs.includes(message.author.id) && !(!this._throttlingIncludeAdmins && message.member && message.member.permissions.has("ADMINISTRATOR")) ? this.throttler : undefined; if (throttler === null || throttler === void 0 ? void 0 : throttler.throttled) throw new CommandResultError_1.CommandResultError(CommandResult_1.CommandResultUtils.throttling(this)); if (!this._executor) throw new CommandResultError_1.CommandResultError(CommandResult_1.CommandResultUtils.noExecutor(this)); const flags = parseFlags_1.parseFlags(message, inputArguments, this.flags, this._flagsShortcuts); const args = parseArgs_1.parseArgs(message, flags.args, this.args); const rest = []; if (this.rest) { for (const e of args.rest) { const parsed = parseValue_1.parseValue(this.rest, message, e); if (parsed.value !== undefined) rest.push(parsed.value); } } if (throttler) throttler.add(); return await this._executor(Object.fromEntries(args.argValues), Object.fromEntries(flags.flagValues), { rest: rest, message, guild: message.guild, member: message.member, channel: message.channel, options, commandSet, command: this, }); } } exports.Command = Command;