discordjs / builders

A collection of builders that you can use when creating your bot.
Apache License 2.0
97 stars 37 forks source link

Can't mix subcommands and subcommand groups at the root level #25

Closed CypElf closed 3 years ago

CypElf commented 3 years ago

If we try to mix subcommands and subcommand groups at the root level of a SlashCommandBuilder, we get the following error when the call to .addSubcommand() happens : RangeError: You cannot mix subcommands and subcommand groups at the root level. Example :

new SlashCommandBuilder().setName("demo").setDescription("demo of the issue")
    .addSubcommandGroup(option => option.setName("group").setDescription("group").addSubcommand(option => option.setName("subcommand_in_group").setDescription("Subcommand in a group")))
    .addSubcommand(option => option.setName("root_subcommand").setDescription("Subcommand at the root"))

But nothing in the Discord API seems to prevent this. Actually, if we submit the command as JSON written by hand to the API or if we just comment the line that perform this check in the .addSubcommand() method, it works juste fine and the command can be successfully registered. The obvious solution is to remove the check for this from the method.

vladfrangu commented 3 years ago

You're...allowed to have a subcommand group and a subcommand on the same level? REALLY?! Can you test this and show the result, with the JSON you used and screenshots of the client please? 🥺 If that's the case, yeah the check needs to be removed but also AWESOME!

CypElf commented 3 years ago

Here is a proof of concept :

require("dotenv").config()

const { REST } = require("@discordjs/rest")
const { Routes } = require("discord-api-types/v9")

const clientId = process.env.CLIENT_ID
const guildId = process.env.DEBUG_SERVER_ID

const rest = new REST({ version: "9" }).setToken(process.env.TOKEN)

const commands = [{
    name: "demo",
    description: "demo of the issue",
    options: [
        {
            type: 2,
            name: "group",
            description: "group",
            options: [{
                type: 1,
                name: "subcommand_in_group",
                description: "Subcommand in a group",
                options: []
            }],
        },
        {
            type: 1,
            name: "root_subcommand",
            description: "Subcommand at the root",
            options: [],
        },
    ],
}];

(async () => {
    try {
        console.log("Started refreshing slash commands")

        await rest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands })

        console.log("Successfully reloaded slash commands")
    }
    catch (err) {
        console.error(err)
    }
})()

The result in Discord looks like :

image

vladfrangu commented 3 years ago

Well fuck, I didn't expect that from the way they exemplify the use of these in their docs. I'll ask to make sure this is intended, and will PR a removal of the checks if so 👍

CypElf commented 3 years ago

I agree in that the examples in their docs can lead to this kind of misunderstanding, they don't show a single example of subcommands being mixed with subcommand groups at the root, and they say to be careful with the nesting because it's very restricted. I found this out while searching for an alternative way to register such commands because my bot used to work this way with normal commands before. Glad to see it'll be possible