For a while, I've been meaning to redo some of the internals. So this is what I've been doing. Now although a lot has changed, especially with the core/internals, not a whole lot will change in terms of creating commands. That part is still largely the same, and I don't have any plans to change it.
This is a draft PR because a lot of these changes are experimental.
Changes
The custom logger changed: $.log no longer exists, it's just console.log. Now you don't have to do import $ from "../core/lib" at the top of every file that uses the custom logger.
Utility functions are no longer attached to the command menu. Stuff like $.paginate() and $(5).pluralise() instead need to be imported and used as regular functions.
The paginate function was reworked to reduce the amount of repetition you had to do.
Events are no longer loaded dynamically. What you do is import "./some-file" which will run the code in there, attaching the event to the client. Since events are no longer bound to certain files, you can keep them more organized:
Since there can be multiple listeners per event, large event files can be split up into more organized blocks.
You can also group together related events like channelCreate and channelDelete and show the relation in one single file rather than splitting them up just because they're two different events.
Lots of files were moved around:
The core folder represents the command handler and is pretty much treated as if it was an external module. That means that instead of importing different items from each file, you'd import it from its index file (which is shortened to import {} from ../core). My hope is to move this section to its own module eventually™.
Other core files that were more or less specific to the bot were moved outside, either at the top-level or into modules. This includes stuff like the library file containing utility functions as well as structures for storing/loading data. Since they're at the top now, there's less typing involved in importing them (../lib instead of ../core/lib and so on).
Commands are still dynamically loaded. This won't change.
Added more type guards to the Command class, reducing the amount of unused properties there are.
If a command has endpoint: true specified, it'll now prevent adding subcommands at compile-time rather than relying on runtime warnings.
Added a NamedCommand subclass on top-level commands (default exports) as well as keyed subcommands (basically the ones with a hardcoded value). NamedCommands have access to aliases. Having aliases on something like a numeric subcommand (ie $test 5) doesn't really make sense.
Added more features to the Command class as well:
You can now restrict certain commands to Guild-only channels or DM-only channels. Unfortunately, there's a bug in TypeScript where callbacks don't get affected by discriminated unions. So for now, if you set a command's channel type, just do a non-null assertion on guild and a TextChannel assertion for channel (and vice versa).
A command can now be designated as NSFW-only.
Added more subcommand types:
Channel: <#...>
Role: <@&...>
Emote: <a:some_name:ID>
Message: https://discordapp.com/channels/<Guild ID>/<Channel ID>/<Message ID> or <Channel ID>-<Message ID> from the "Copy Message Link" and "Copy ID" (shift) buttons.
ID: Any Discord ID. In order to use this, you have to specify which subcommand type you want to redirect it to. For example, to replicate the old behavior with plain IDs being converted to user IDs, you first implement user user: new Command(...) then do id: "user".
Some changes to subcommands:
User: <@...> and <@!...> - Its default state is more restricted. It no longer accepts standalone IDs by default.
You'll notice in a lot of commands as well as the template that properties are destructured. While using $ will work just fine, having {message, channel, guild} will let you access properties using channel instead of $.channel and so on.
Direct messaging the bot now listens for commands. You don't need a prefix when doing this, it's assumed you're running a command.
Command invocations are no longer logged every single time. Now the catch block shows the command used and the arguments, and unhandled rejections related to Discord are captured too, showing the same information.
I added Husky and I think I've got its pre-commit hook to work. If this goes as expected, the formatter should be called every commit so there aren't any more formatting commits.
Internally, the core message handler and the Command class(es) are very de-spaghettified compared to before. Its methods are a lot more modular now.
There's probably a lot that hasn't been tested with the new system, so along with trying out these new features, you might also come across some bugs.
For a while, I've been meaning to redo some of the internals. So this is what I've been doing. Now although a lot has changed, especially with the core/internals, not a whole lot will change in terms of creating commands. That part is still largely the same, and I don't have any plans to change it.
This is a draft PR because a lot of these changes are experimental.
Changes
$.log
no longer exists, it's justconsole.log
. Now you don't have to doimport $ from "../core/lib"
at the top of every file that uses the custom logger.$.paginate()
and$(5).pluralise()
instead need to be imported and used as regular functions.paginate
function was reworked to reduce the amount of repetition you had to do.import "./some-file"
which will run the code in there, attaching the event to the client. Since events are no longer bound to certain files, you can keep them more organized:channelCreate
andchannelDelete
and show the relation in one single file rather than splitting them up just because they're two different events.core
folder represents the command handler and is pretty much treated as if it was an external module. That means that instead of importing different items from each file, you'd import it from its index file (which is shortened toimport {} from ../core
). My hope is to move this section to its own module eventually™.core
files that were more or less specific to the bot were moved outside, either at the top-level or intomodules
. This includes stuff like the library file containing utility functions as well as structures for storing/loading data. Since they're at the top now, there's less typing involved in importing them (../lib
instead of../core/lib
and so on).Command
class, reducing the amount of unused properties there are.endpoint: true
specified, it'll now prevent adding subcommands at compile-time rather than relying on runtime warnings.NamedCommand
subclass on top-level commands (default exports) as well as keyed subcommands (basically the ones with a hardcoded value).NamedCommand
s have access toaliases
. Havingaliases
on something like a numeric subcommand (ie$test 5
) doesn't really make sense.Command
class as well:guild
and aTextChannel
assertion forchannel
(and vice versa).<#...>
<@&...>
<a:some_name:ID>
https://discordapp.com/channels/<Guild ID>/<Channel ID>/<Message ID>
or<Channel ID>-<Message ID>
from the "Copy Message Link" and "Copy ID" (shift) buttons.user: new Command(...)
then doid: "user"
.<@...>
and<@!...>
- Its default state is more restricted. It no longer accepts standalone IDs by default.$
will work just fine, having{message, channel, guild}
will let you access properties usingchannel
instead of$.channel
and so on.Command
class(es) are very de-spaghettified compared to before. Its methods are a lot more modular now.There's probably a lot that hasn't been tested with the new system, so along with trying out these new features, you might also come across some bugs.