Skip to content

Commit

Permalink
fix: interaction#options should never be null (#108)
Browse files Browse the repository at this point in the history
* feat: always have options handler

* add changeset
  • Loading branch information
thewilloftheshadow committed Sep 16, 2024
1 parent ec43a73 commit d76feb7
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 58 deletions.
5 changes: 5 additions & 0 deletions .changeset/dry-dragons-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@buape/carbon": patch
---

fix: interaction#options should never be null
2 changes: 1 addition & 1 deletion apps/cloudo/src/commands/testing/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default class Options extends Command {

async run(interaction: CommandInteraction) {
interaction.reply({
content: `${interaction.options?.getString("str")}`
content: `${interaction.options.getString("str")}`
})
}
}
6 changes: 3 additions & 3 deletions apps/rocko/src/commands/testing/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,19 @@ export default class Options extends Command {

async run(interaction: CommandInteraction) {
await interaction.reply({
content: `Errors: ${interaction.options?.errors}\nStr: ${interaction.options?.getString("str")}\nInt: ${interaction.options?.getInteger("int")}\nNum: ${interaction.options?.getNumber("num")}\nBool: ${interaction.options?.getBoolean("bool")}\nUser: ${interaction.options?.getUser("user")}\nChannel: ${interaction.options?.getChannel("channel")}\nRole: ${interaction.options?.getRole("role")}\nMentionable: ${interaction.options?.getMentionable("mentionable")}\nAutocomplete: ${interaction.options?.getString("autocomplete")}`
content: `Str: ${interaction.options.getString("str")}\nInt: ${interaction.options.getInteger("int")}\nNum: ${interaction.options.getNumber("num")}\nBool: ${interaction.options.getBoolean("bool")}\nUser: ${interaction.options.getUser("user")}\nChannel: ${interaction.options.getChannel("channel")}\nRole: ${interaction.options.getRole("role")}\nMentionable: ${interaction.options.getMentionable("mentionable")}\nAutocomplete: ${interaction.options.getString("autocomplete")}`
})
}

async autocomplete(interaction: AutocompleteInteraction) {
await interaction.respond([
{
name: "That thing you said",
value: `${interaction.options?.getFocused() || "NONE"}`
value: `${interaction.options.getFocused() || "NONE"}`
},
{
name: "That thing you said but with a 4",
value: `4: ${interaction.options?.getFocused() || "NONE"}`
value: `4: ${interaction.options.getFocused() || "NONE"}`
}
])
}
Expand Down
27 changes: 8 additions & 19 deletions packages/carbon/src/internals/AutocompleteInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,22 @@ import {
InteractionType,
Routes
} from "discord-api-types/v10"
import type { BaseCommand } from "../abstracts/BaseCommand.js"
import {
BaseInteraction,
type InteractionDefaults
} from "../abstracts/BaseInteraction.js"
import type { Client } from "../classes/Client.js"
import { Command } from "../classes/Command.js"
import { OptionsHandler } from "./OptionsHandler.js"

export class AutocompleteInteraction extends BaseInteraction<APIApplicationCommandAutocompleteInteraction> {
/**
* This is the options of the commands, parsed from the interaction data.
*/
options?: AutocompleteOptionsHandler
options: AutocompleteOptionsHandler
constructor(
client: Client,
data: APIApplicationCommandAutocompleteInteraction,
defaults: InteractionDefaults,
command?: BaseCommand
defaults: InteractionDefaults
) {
super(client, data, defaults)
if (data.type !== InteractionType.ApplicationCommandAutocomplete) {
Expand All @@ -34,20 +31,12 @@ export class AutocompleteInteraction extends BaseInteraction<APIApplicationComma
if (data.data.type !== ApplicationCommandType.ChatInput) {
throw new Error("Invalid command type was used to create this class")
}
if (
command instanceof Command &&
!data.data.options?.find(
(x) =>
x.type === ApplicationCommandOptionType.Subcommand ||
x.type === ApplicationCommandOptionType.SubcommandGroup
)
) {
this.options = new AutocompleteOptionsHandler(
client,
(data.data.options ??
[]) as APIApplicationCommandInteractionDataBasicOption[]
)
}

this.options = new AutocompleteOptionsHandler(
client,
(data.data.options ??
[]) as APIApplicationCommandInteractionDataBasicOption[]
)
}

override async defer() {
Expand Down
12 changes: 4 additions & 8 deletions packages/carbon/src/internals/CommandHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,9 @@ export class CommandHandler extends Base {
const command = this.getCommand(rawInteraction)
if (!command) return false

const interaction = new CommandInteraction(
this.client,
rawInteraction,
{ ephemeral: command.ephemeral },
command
)
const interaction = new CommandInteraction(this.client, rawInteraction, {
ephemeral: command.ephemeral
})

try {
const command = this.getCommand(rawInteraction)
Expand All @@ -115,8 +112,7 @@ export class CommandHandler extends Base {
const interaction = new AutocompleteInteraction(
this.client,
rawInteraction,
{ ephemeral: command.ephemeral },
command
{ ephemeral: command.ephemeral }
)

try {
Expand Down
33 changes: 10 additions & 23 deletions packages/carbon/src/internals/CommandInteraction.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,40 @@
import {
type APIApplicationCommandInteraction,
type APIApplicationCommandInteractionDataBasicOption,
ApplicationCommandOptionType,
ApplicationCommandType,
InteractionType
} from "discord-api-types/v10"
import type { BaseCommand } from "../abstracts/BaseCommand.js"
import {
BaseInteraction,
type InteractionDefaults
} from "../abstracts/BaseInteraction.js"
import type { Client } from "../classes/Client.js"
import { Command } from "../classes/Command.js"
import { OptionsHandler } from "./OptionsHandler.js"
// import type { RawOptions } from "./OptionsHandler.js"

/**
* Represents a command interaction
*/
export class CommandInteraction extends BaseInteraction<APIApplicationCommandInteraction> {
/**
* This is the options of the commands, parsed from the interaction data.
* It is only available if the command is a {@link Command} class, and the command is a ChatInput command.
* It will not have any options in it if the command is not a ChatInput command.
*/
options?: OptionsHandler
options: OptionsHandler
constructor(
client: Client,
data: APIApplicationCommandInteraction,
defaults: InteractionDefaults,
command?: BaseCommand
defaults: InteractionDefaults
) {
super(client, data, defaults)
if (data.type !== InteractionType.ApplicationCommand) {
throw new Error("Invalid interaction type was used to create this class")
}
if (
command instanceof Command &&
data.data.type === ApplicationCommandType.ChatInput &&
!data.data.options?.find(
(x) =>
x.type === ApplicationCommandOptionType.Subcommand ||
x.type === ApplicationCommandOptionType.SubcommandGroup
)
) {
this.options = new OptionsHandler(
client,
(data.data.options ??
[]) as APIApplicationCommandInteractionDataBasicOption[]
)
}
this.options = new OptionsHandler(
client,
data.data.type === ApplicationCommandType.ChatInput
? ((data.data.options ??
[]) as APIApplicationCommandInteractionDataBasicOption[])
: []
)
}
}
4 changes: 0 additions & 4 deletions packages/carbon/src/internals/OptionsHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ export class OptionsHandler extends Base {
* The raw options that were in the interaction data, before they were parsed.
*/
readonly raw: APIApplicationCommandInteractionDataBasicOption[]
/**
* The errors that were encountered while parsing the options.
*/
readonly errors: Array<string> = []

constructor(
client: Client,
Expand Down

0 comments on commit d76feb7

Please sign in to comment.