-
-
Notifications
You must be signed in to change notification settings - Fork 40
@Command
discord.ts
provides a decorator allowing the implementation of command systems very simply by essentially using only two decorators @Command(commandName?: string)
and @CommandNotFound()
.
We will also use @Discord(prefix: string)
to specify a prefix for our commands within the class.
You can specify a regex
expression for your command names
For advanced usage use the @Rules
decorator, you can also specify aliases using that
Notice that the first arguments do not use
ArgsOf
, the first payload is aCommandMessage
.
import {
Discord,
On,
Client,
Command,
CommandMessage,
CommandNotFound
} from "@typeit/discord";
// Specify your prefix
@Discord("!")
abstract class AppDiscord {
// Reachable with the command: !hello
@Command("hello")
private hello(message: CommandMessage) {
}
// !bye
// !yo
@CommandNotFound()
private notFound(message: CommandMessage) {
}
}
The CommandMessage
is the first argument injected into a method using @Command
or @CommandNotFound
, it has exactly the same structure as the Message
object in discord.js
except that it includes useful information about the command that was executed such as:
-
prefix
:string
The prefix that is applied to your command. -
commandName
:string
The command name -
commandContent
:string
The message content without the prefix (-cmd hello there
becomeshello there
) -
description
:string
The command description -
infos
:InfoType
(any
)
The command infos -
args
:ArgsType
(any
)
The command arguments -
discord
:DiscordInfos
:
The linked@Discord
class infos -
argsRules
: (ArgsRulesFunction<Expression>[]
)
The rules that are applied to execute the command (advanced)
You have the ability to specify arguments for your command, as express.js
does in it's routing system. So by using ":"
(or the value specified in variablesChar
when your Client
intializes) in the name of your @Command
in front of the dynamic values, discord.ts
will extract these informations when a command is executed and inject it into the args
property of your CommandMessage
with the correct name that you indicated in the command name.
If the argument value is a number the value will be casted automaticaly
@Discord("!")
abstract class AppDiscord {
@Command("args :slug :number")
private hello(message: CommandMessage) {
const mySlug = message.args.slug;
const myNumber = message.args.number;
// Using js destructuring:
const { slug, number } = message.args;
}
}
Okay but what if my prefix or my command name of my @Discord
/ @Command
decorators depends on external datas? Well you can specify a function that will be executed when a command is executed to verify the origin and return the correct value.
You receive the Message
as the first argument and the Client
instance as the second one.
This is also applied to
@ComputedRules
// If the message has been sent in the guild with
// the name MyGuildName the prefix "." will be considered
// otherwise the prefix "$" will trigger the action.
async function prefixBehaviour(message: Message, client: Client) {
if (message.guild.name === "MyGuildName") {
return ".";
}
return "$";
}
@Discord(prefixBehaviour)
abstract class AppDiscord {
@Command("hello")
private hello(message: CommandMessage) {
// ...
}
}
With a dynamic command name:
May be for a very specific use case
// If the message has been sent in the guild with
// the name MyGuildName the prefix "." will be considered
// otherwise the prefix "$" will trigger the action.
async function prefixBehaviour(message: Message, client: Client) {
if (message.guild.name === "MyGuildName") {
return ".";
}
return "$";
}
// The command name will be yo if the message is "hello"
async function commandName(message: Message, client: Client) {
if (message.content === "hello") {
return "yo";
}
return "hello";
}
@Discord(prefixBehaviour)
abstract class AppDiscord {
@Command(commandName)
private hello(message: CommandMessage) {
// ...
}
}
If you have a directory pattern that looks like this:
Main.ts
DiscordApp.ts
commands
- Ping.ts
- Hello.ts
- Blabla.ts
events
- MessageDelete.ts
You should use the import
parameter for the @Discord
decorator.
Here, all the elements will be injected into this Discord class instance.
import * as Path from "path";
import {
Discord,
CommandNotFound
} from "@typeit/discord";
// The prefix will be applied to the imported commands
@Discord("!", {
import: [
Path.join(__dirname, "commands", "*.ts"),
Path.join(__dirname, "events", "*.ts")
// You can also specify the class directly here if you don't want to use a glob
]
})
export abstract class DiscordApp {
// This command not found is triggered
@CommandNotFound()
notFoundA(command: CommandMessage) {
command.reply("Command not found");
}
}
Here is an example of what your command file should look like: Bye.ts
import {
Command,
CommandMessage
} from "@typeit/discord";
// Do not have to decorate the class with @Discord
// It applied the parameters of the @Discord decorator that imported it
export abstract class Bye {
@Command("bye")
async bye(command: CommandMessage) {
command.reply("Bye!");
}
@Command("ciao")
async ciao(command: CommandMessage) {
command.reply("Ciao!");
}
}
MessageDelete.ts
import {
On,
ArgsOf
} from "@typeit/discord";
// Do not have to decorate the class with @Discord
// It applied the parameters of the @Discord decorator that imported it
export abstract class MessageDelete {
@On("messageDelete")
async onMessageDelete([message]: ArgsOf<"messageDelete">) {
message.reply("Bye!");
}
}