Read property from custom Command Options

BBejasc12/14/2022
Hey folks,

I have a custom command options object, that contains a property called shortDesc.
I want to read a property from the options, inside the registerApplicationCommands method, so that I can not have to provide this value (Get a random trivia question) twice.

How do I read shortDesc? this.shortDesc didn't work the same as this.name did - I assume because name exists on the default CommandOptions object, but it's having trouble parsing the Options here as IDrpgCommandOptions ?

@ApplyOptions<IDrpgCommandOptions>({
    name: "Trivia",
    aliases: ["q", "t", "question", "trivia", "quiz"],
    shortDesc: "Get a random trivia question",
    showInHelpMenu: true,
})
export class QuestionCommand extends DrpgCommand {
    public override async registerApplicationCommands(registry: ApplicationCommandRegistry) {
        const shortDesc = "Get a random trivia question"; //TODO How to get shortDesc from above?
        registry.registerChatInputCommand((builder) => builder.setName(this.name).setDescription(shortDesc), {
            idHints: [""],
            behaviorWhenNotIdentical: RegisterBehavior.Overwrite,
        });
    }
KKrish12/14/2022
can we see DrpgCommand?
KKrish12/14/2022
if you have shortDesc there then it must work
BBejasc12/14/2022
export interface IDrpgCommandOptions extends CommandOptions {
    shortDesc?: string;
    showInHelpMenu?: boolean;
    examples?: { title: string; command: string; description?: string }[];
}

export abstract class DrpgCommand extends Command {
    public readonly fullCategory: readonly string[] = [];

    public constructor(context: PieceContext, options: IDrpgCommandOptions) {
        super(context, { ...COMMAND_OPTIONS, ...options });

        if (options.fullCategory) {
            this.fullCategory = options.fullCategory;
        } else if (this.location.directories.length) {
            this.fullCategory = this.location.directories;
        } else {
            this.fullCategory = ["uncategorized"];
        }
    }
}
BBejasc12/14/2022
COMMAND_OPTIONS is just IDrpgCommandOptions with some defaults set
BBejasc12/14/2022
it's not part of the object, it's part of the Options
KKrish12/14/2022
add public readonly shortDesc: string; in your class
KKrish12/14/2022
basically you need to add all of the extra options you added
BBejasc12/14/2022
does that change the way I add/apply those options?
KKrish12/14/2022
no
KKrish12/14/2022
that makes it a member of your class
KKrish12/14/2022
Until now your extra options were useless
BBejasc12/14/2022
I've been using them okay in a help command

const target = await args.pick("string");

            const cmd = this.store.get(target) as DrpgCommand;
            const opts = cmd.options as IDrpgCommandOptions;

            embed.setTitle(stringTitleCase(opts.name ?? cmd.name));

            if (opts.description) embed.setDescription(opts.description);

            if (cmd.aliases?.length > 0) embed.addField("Aliases", joinString(cmd.aliases.map((e) => `\`${prefix}${e}\``)));

            const categoryString = cmd.fullCategory.join(" / ");
            embed.addField("Category", categoryString);

            if (opts.examples?.length > 0) {
                const exampleText = opts.examples.map((example) => {
                    return `**${example.title}**\n_${example.description ?? opts.shortDesc}_\n\`${prefix}${example.command}\``;
                });

                embed.addField("Examples", exampleText.join("\n\n"));
            }
BBejasc12/14/2022
I think actually... another approach to the answer exists in this code above... 🫣
BBejasc12/14/2022
Thanks for the guidance though - I'll try this out tomorrow šŸ™‚
Solution
FFavna12/14/2022
First of all, the reason it works in your help command is because you're using command.options, likewise if you use this.options.shortDesc it'll also be there.

Secondly, categories are built into sapphire so whatever you're setting in the constructor there is pretty pointless. That dates back to a very old by now version of Sapphire where categories weren't integrated

Thirdly, Sapphire Command class has a detailedDescription option which can be an object of whatever you want and is set automatically so you do not even need custom properties for this at all. Just use module augmentation to modify the interface for detailedDescription then use
detailedDescription: {
  shortDesc: 'whatever'
}

and reference it with this.detailedDescription.shortDesc

Fourthly, you don't need a help command when going slash commands only because every command and every option already gets a description and if your commands/options are so convoluted that you cannot describe them in 100 characters then you should revise the command as a whole.
BBejasc12/14/2022
Thanks Favna - honestly I'm not sure what I was doing with the constructor there - it existed in whatever sample project/source material I referenced, possibly Skyra? My understanding is that it was trying to use the folder structure to automatically build the categories, if they hadn't been provided
BBejasc12/14/2022
Also, am not going slash commands only - supporting both
BBejasc12/14/2022
how new is detailedDescription? I've been out of touch the last couple of months and hadn't come across it before
BBejasc12/14/2022
That dates back to a very old by now version of Sapphire where categories weren't integrated
That'd be right - the code there is well over 12 months old some time around August/September 2021
FFavna12/14/2022
skyra hasnt had that in the constructor for ages and ages
FFavna12/14/2022
since like v1.x
BBejasc12/14/2022
Like I said - it's been there for ages and ages
BBejasc12/14/2022
before there were even docs of any kind