190 lines
4.4 KiB
TypeScript
190 lines
4.4 KiB
TypeScript
|
/**
|
||
|
* SAMPLE CODE
|
||
|
* Reference for how to extend a command option and implement a custom
|
||
|
* command that inherits a custom superclass while being compatible with the parser by implementing the interface
|
||
|
*/
|
||
|
|
||
|
|
||
|
/* eslint-disable max-classes-per-file */
|
||
|
import { ICommand, OptionType, CommandOpts, SubcommandOption, SubcommandGroupOption } from '@navy.gif/commandparser';
|
||
|
import ExtendedCommandOption from './ExtendedCommandOption.js';
|
||
|
|
||
|
|
||
|
type Snowflake = string
|
||
|
type DiscordClient = {
|
||
|
//
|
||
|
}
|
||
|
|
||
|
type ComponentOptions = {
|
||
|
//
|
||
|
}
|
||
|
|
||
|
type CommandDefinition = {
|
||
|
aliases: never[];
|
||
|
help: string | undefined;
|
||
|
restricted: boolean;
|
||
|
disabled: boolean;
|
||
|
guildOnly: boolean;
|
||
|
dmOnly: boolean;
|
||
|
limited: null;
|
||
|
options: ExtendedCommandOption[];
|
||
|
}
|
||
|
|
||
|
type User = {
|
||
|
//
|
||
|
}
|
||
|
|
||
|
class Component
|
||
|
{
|
||
|
// eslint-disable-next-line no-useless-constructor
|
||
|
constructor (_client: DiscordClient, _options: ComponentOptions)
|
||
|
{
|
||
|
//
|
||
|
}
|
||
|
|
||
|
get name ()
|
||
|
{
|
||
|
return '';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class CommandError extends Error
|
||
|
{
|
||
|
constructor (_command: Command, _options: object)
|
||
|
{
|
||
|
super();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
abstract class Command extends Component implements ICommand
|
||
|
{
|
||
|
#aliases: string[];
|
||
|
#options: ExtendedCommandOption[];
|
||
|
#help?: string | undefined;
|
||
|
|
||
|
#restricted: boolean; // Developer only
|
||
|
#disabled: boolean;
|
||
|
#guildOnly: boolean;
|
||
|
#dmOnly: boolean;
|
||
|
#limited: Snowflake[] | null; // Limited to specific roles
|
||
|
|
||
|
constructor (client: DiscordClient, def: CommandDefinition)
|
||
|
{
|
||
|
super(client, {
|
||
|
...def,
|
||
|
type: 'command'
|
||
|
});
|
||
|
|
||
|
this.#aliases = def.aliases ?? [];
|
||
|
this.#help = def.help;
|
||
|
|
||
|
this.#restricted = def.restricted ?? false;
|
||
|
this.#disabled = def.disabled ?? false;
|
||
|
this.#guildOnly = def.guildOnly ?? false;
|
||
|
this.#dmOnly = def.dmOnly ?? false;
|
||
|
this.#limited = def.limited ?? null;
|
||
|
|
||
|
this.#options = [];
|
||
|
|
||
|
if (def.options)
|
||
|
{
|
||
|
for (const opt of def.options)
|
||
|
{
|
||
|
if (opt instanceof ExtendedCommandOption)
|
||
|
this.#options.push(opt);
|
||
|
else
|
||
|
this.#options.push(new ExtendedCommandOption(opt));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (this.options.some(opt => [ OptionType.SUB_COMMAND, OptionType.SUB_COMMAND_GROUP ].includes(opt.type))
|
||
|
&& this.options.some(opt => ![ OptionType.SUB_COMMAND, OptionType.SUB_COMMAND_GROUP ].includes(opt.type) && opt.name !== 'help'))
|
||
|
throw new Error('Cannot have subcommand(group)s on the same level as an option');
|
||
|
|
||
|
}
|
||
|
|
||
|
abstract execute(message: unknown, args: CommandOpts): Promise<unknown>;
|
||
|
|
||
|
protected timeout (user?: User)
|
||
|
{
|
||
|
throw new CommandError(this, { reason: 'Command timed out', user });
|
||
|
}
|
||
|
|
||
|
get restricted ()
|
||
|
{
|
||
|
return this.#restricted;
|
||
|
}
|
||
|
|
||
|
get limited ()
|
||
|
{
|
||
|
return this.#limited;
|
||
|
}
|
||
|
|
||
|
get disabled ()
|
||
|
{
|
||
|
return this.#disabled;
|
||
|
}
|
||
|
|
||
|
get guildOnly ()
|
||
|
{
|
||
|
return this.#guildOnly;
|
||
|
}
|
||
|
|
||
|
get dmOnly ()
|
||
|
{
|
||
|
return this.#dmOnly;
|
||
|
}
|
||
|
|
||
|
get aliases ()
|
||
|
{
|
||
|
return this.#aliases;
|
||
|
}
|
||
|
|
||
|
get options ()
|
||
|
{
|
||
|
return this.#options;
|
||
|
}
|
||
|
|
||
|
get help ()
|
||
|
{
|
||
|
return this.#help;
|
||
|
}
|
||
|
|
||
|
get subcommands (): SubcommandOption[]
|
||
|
{
|
||
|
return this._subcommands(this.options);
|
||
|
}
|
||
|
|
||
|
get subcommandGroups (): SubcommandGroupOption[]
|
||
|
{
|
||
|
return this.options.filter((opt) => opt.type === OptionType.SUB_COMMAND_GROUP);
|
||
|
}
|
||
|
|
||
|
subcommand (name: string): SubcommandOption | null
|
||
|
{
|
||
|
name = name.toLowerCase();
|
||
|
return this.subcommands.find((cmd) => cmd.name === name || cmd.aliases.includes(name)) || null;
|
||
|
}
|
||
|
|
||
|
subcommandGroup (name: string): SubcommandGroupOption | null
|
||
|
{
|
||
|
name = name.toLowerCase();
|
||
|
return this.subcommandGroups.find((grp) => grp.name === name || grp.aliases.includes(name)) || null;
|
||
|
}
|
||
|
|
||
|
private _subcommands (options: ExtendedCommandOption[]): SubcommandOption[]
|
||
|
{
|
||
|
const subcommands: SubcommandOption[] = [];
|
||
|
for (const opt of options)
|
||
|
{
|
||
|
if (opt.type === OptionType.SUB_COMMAND)
|
||
|
subcommands.push(opt);
|
||
|
else if (opt.type === OptionType.SUB_COMMAND_GROUP)
|
||
|
subcommands.push(...this._subcommands(opt.options));
|
||
|
}
|
||
|
|
||
|
return subcommands;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export default Command;
|