discordjs / discord.js

A powerful JavaScript library for interacting with the Discord API
https://discord.js.org
Apache License 2.0
25.36k stars 3.97k forks source link

Have stored values available for access for `CommandInteractionOptionResolver` #6143

Closed Jiralite closed 3 years ago

Jiralite commented 3 years ago

Is your feature request related to a problem? Please describe. Hi hi! Thank you for the CommandInteractionOptionResolver!

I have a use case for some of my Slash Commands where no options are required but sending across no options results in behaviour still (and not an error). Previously, I would be able to do if (<CommandInteraction>.options.size === 0) {...}, but it seems now that I must check each and every parameter to ensure that they are all not present to ensure this behaviour works.

Another use case of I have of my Slash Commands is "repeated" options. For example: /ignore evidence add evidence-1: ... evidence-2: ... evidence-3: ...

I would have parsed this in the past by running .filter(({ name }) => name.startsWith("evidence")).map(({ value }) => value) but now I must check each and every option individually!

I have more use cases that the implementation of CommandInteractionOptionResolver seems to make harder but...

What I'm trying to get at is that whilst CommandInteractionOptionResolver beautifully solves the issue of easily getting your arguments, this implementation alone doesn't allow you to manually parse the data should you have an interesting edge case or use case that doesn't rely on option names alone, for which I described 2 above. I do not wish to check if all my parameters exist to then enact out on some behaviour, but would rather just have the array or Collection back so I can simply check the length or size respectively or manipulate to my will.

Describe the ideal solution I'd love an array or Collection of options so I can easily run <Collection>.size again or <Array>.length on to check how many options are present or to be able to iterate over my similarly-named options. I actually see there's a private property <CommandInteractionOptionResolver>._options which looks like it solves this, but alas, it is private.

Describe alternatives you've considered The only way right now is to work with what I have, which means longer and meh code which could easily be solved by supplying the options in an array or Collection form again:

For my first described use case, I would have to check if all the parameters do not exist. This means running something like:

const option1 = interaction.options.getInteger("option1");
const option2 = interaction.options.getInteger("option2");
const option3 = interaction.options.getInteger("option3");
const option4 = interaction.options.getInteger("option4");

if ([option1, option2, option3, option4].every(option => option === null)) {
  // All options have not been sent. Proceed with no-option behaviour here!
}

The more options, the better!

For my second described use case, I would again have to check all parameters instead of being able to loop through them which results in this:

const evidence1 = interaction.options.getString("evidence-1");
const evidence2 = interaction.options.getString("evidence-2");
const evidence3 = interaction.options.getString("evidence-3");
const evidence4 = interaction.options.getString("evidence-4");
const evidence5 = interaction.options.getString("evidence-5");
const evidence6 = interaction.options.getString("evidence-6");
const evidence7 = interaction.options.getString("evidence-7");
const evidence8 = interaction.options.getString("evidence-8");
const evidence9 = interaction.options.getString("evidence-9");
const evidence10 = interaction.options.getString("evidence-10");

const evidenceToAdd = [evidence1, evidence2, evidence3, evidence4, evidence5, evidence6, evidence7, evidence8, evidence9, evidence10].filter(evidence => evidence !== null);

As a reminder, this is how I did it in the past on the options: .filter(({ name }) => name.startsWith("evidence")).map(({ value }) => value)

Additional context N/A

memikri commented 3 years ago

How about something like:

const evidence = [];

for (let i = 1; i <= 10; i++) {
  const value = interaction.options.getString(`evidence-${i}`);
  if (value !== null)
    evidence.push(value);
}

if (evidence.length === 0) {
  // No evidence provided.
} else {
  // Do stuff with evidence.
}

You could put it in a helper function in your program if you have a lot of similar commands, perhaps.

Jiralite commented 3 years ago

How about something like:

const evidence = [];

for (let i = 1; i <= 10; i++) {
  const value = interaction.options.getString(`evidence-${i}`);
  if (value !== null)
    evidence.push(value);
}

if (evidence.length === 0) {
  // No evidence provided.
} else {
  // Do stuff with evidence.
}

You could put it in a helper function in your program if you have a lot of similar commands, perhaps.

Thank you for the reply! But this only approaches one use case. For other use cases, more longer and meh code will have to be used, as opposed to before.

What I'm trying to get at as explained above is that simply providing the options again would render all the use cases solved because it allows users to manipulate the data to their will. Instead of short and sweet ways to retrieve my options, I have to work around a CommandInteractionOptionResolver.

discord.js should be able to provide this to users as it must use this data somewhere to show the CommandInteractionOptionResolver - all I am asking is to expose it once more. For example, making use of <CommandInteractionOptionResolver>._options - a private property that seems to be the original behaviour against the use case you provided a workaround for:

const evidence = <CommandInteraction>.options._options.filter(({ name }) => name.startsWith("evidence")).map(({ value }) => value);

Why would I do what you described when I can manipulate the data (as I could before) for this cute lil' one liner? Alas, I don't feel too comfortable using a private property, which is why I made this issue!