From 8073561824f911d1a18d0b4f1de39f452bc69fa9 Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Mon, 10 Apr 2023 21:09:51 +0100 Subject: [PATCH] docs(builders): Add some basic documentation (#9359) --- packages/builders/src/components/ActionRow.ts | 35 ++++-- packages/builders/src/components/Component.ts | 14 ++- .../builders/src/components/Components.ts | 42 ++++++- .../builders/src/components/button/Button.ts | 32 ++--- .../components/selectMenu/BaseSelectMenu.ts | 22 ++-- .../selectMenu/ChannelSelectMenu.ts | 45 ++++--- .../selectMenu/MentionableSelectMenu.ts | 11 +- .../components/selectMenu/RoleSelectMenu.ts | 11 +- .../components/selectMenu/StringSelectMenu.ts | 62 +++++----- .../selectMenu/StringSelectMenuOption.ts | 30 ++--- .../components/selectMenu/UserSelectMenu.ts | 11 +- .../src/components/textInput/TextInput.ts | 35 +++--- packages/builders/src/index.ts | 5 +- .../ContextMenuCommandBuilder.ts | 60 ++++++---- .../builders/src/interactions/modals/Modal.ts | 32 +++-- .../slashCommands/SlashCommandBuilder.ts | 93 +++++++++------ .../slashCommands/SlashCommandSubcommands.ts | 34 ++++-- ...ionCommandNumericOptionMinMaxValueMixin.ts | 13 +- .../mixins/ApplicationCommandOptionBase.ts | 25 +++- ...plicationCommandOptionChannelTypesMixin.ts | 20 +++- ...ndOptionWithChoicesAndAutocompleteMixin.ts | 26 +++- .../mixins/NameAndDescription.ts | 41 +++++-- .../mixins/SharedSlashCommandOptions.ts | 48 +++++--- .../slashCommands/options/attachment.ts | 9 ++ .../slashCommands/options/boolean.ts | 9 ++ .../slashCommands/options/channel.ts | 9 ++ .../slashCommands/options/integer.ts | 9 ++ .../slashCommands/options/mentionable.ts | 9 ++ .../slashCommands/options/number.ts | 9 ++ .../slashCommands/options/role.ts | 9 ++ .../slashCommands/options/string.ts | 15 +++ .../slashCommands/options/user.ts | 9 ++ packages/builders/src/messages/embed/Embed.ts | 111 ++++++++++++------ packages/builders/src/util/componentUtil.ts | 5 + packages/builders/src/util/normalizeArray.ts | 13 ++ packages/builders/src/util/validation.ts | 27 ++++- 36 files changed, 690 insertions(+), 300 deletions(-) diff --git a/packages/builders/src/components/ActionRow.ts b/packages/builders/src/components/ActionRow.ts index 90dda30ca..05ed65684 100644 --- a/packages/builders/src/components/ActionRow.ts +++ b/packages/builders/src/components/ActionRow.ts @@ -18,10 +18,21 @@ import type { StringSelectMenuBuilder } from './selectMenu/StringSelectMenu.js'; import type { UserSelectMenuBuilder } from './selectMenu/UserSelectMenu.js'; import type { TextInputBuilder } from './textInput/TextInput.js'; +/** + * The builders that may be used for messages. + */ export type MessageComponentBuilder = | ActionRowBuilder | MessageActionRowComponentBuilder; + +/** + * The builders that may be used for modals. + */ export type ModalComponentBuilder = ActionRowBuilder | ModalActionRowComponentBuilder; + +/** + * The builders that may be used within an action row for messages. + */ export type MessageActionRowComponentBuilder = | ButtonBuilder | ChannelSelectMenuBuilder @@ -29,11 +40,19 @@ export type MessageActionRowComponentBuilder = | RoleSelectMenuBuilder | StringSelectMenuBuilder | UserSelectMenuBuilder; + +/** + * The builders that may be used within an action row for modals. + */ export type ModalActionRowComponentBuilder = TextInputBuilder; + +/** + * Any builder. + */ export type AnyComponentBuilder = MessageActionRowComponentBuilder | ModalActionRowComponentBuilder; /** - * Represents an action row component + * A builder that creates API-compatible JSON data for action rows. * * @typeParam T - The types of components this action row holds */ @@ -41,16 +60,16 @@ export class ActionRowBuilder extends ComponentBu APIActionRowComponent > { /** - * The components within this action row + * The components within this action row. */ public readonly components: T[]; /** - * Creates a new action row from API data + * Creates a new action row from API data. * * @param data - The API data to create this action row with * @example - * Creating an action row from an API data object + * Creating an action row from an API data object: * ```ts * const actionRow = new ActionRowBuilder({ * components: [ @@ -64,7 +83,7 @@ export class ActionRowBuilder extends ComponentBu * }); * ``` * @example - * Creating an action row using setters and API data + * Creating an action row using setters and API data: * ```ts * const actionRow = new ActionRowBuilder({ * components: [ @@ -87,7 +106,7 @@ export class ActionRowBuilder extends ComponentBu /** * Adds components to this action row. * - * @param components - The components to add to this action row. + * @param components - The components to add */ public addComponents(...components: RestOrArray) { this.components.push(...normalizeArray(components)); @@ -95,9 +114,9 @@ export class ActionRowBuilder extends ComponentBu } /** - * Sets the components in this action row + * Sets components for this action row. * - * @param components - The components to set this row to + * @param components - The components to set */ public setComponents(...components: RestOrArray) { this.components.splice(0, this.components.length, ...normalizeArray(components)); diff --git a/packages/builders/src/components/Component.ts b/packages/builders/src/components/Component.ts index 9fe213355..e5e59638d 100644 --- a/packages/builders/src/components/Component.ts +++ b/packages/builders/src/components/Component.ts @@ -6,10 +6,13 @@ import type { ComponentType, } from 'discord-api-types/v10'; +/** + * Any action row component data represented as an object. + */ export type AnyAPIActionRowComponent = APIActionRowComponent | APIActionRowComponentTypes; /** - * Represents a discord component + * The base component builder that contains common symbols for all sorts of components. * * @typeParam DataType - The type of internal API data that is stored within the component */ @@ -18,12 +21,12 @@ export abstract class ComponentBuilder< > implements JSONEncodable { /** - * The API data associated with this component + * The API data associated with this component. */ public readonly data: Partial; /** - * Serializes this component to an API-compatible JSON object + * Serializes this builder to API-compatible JSON data. * * @remarks * This method runs validations on the data before serializing it. @@ -31,6 +34,11 @@ export abstract class ComponentBuilder< */ public abstract toJSON(): AnyAPIActionRowComponent; + /** + * Constructs a new kind of component. + * + * @param data - The data to construct a component out of + */ public constructor(data: Partial) { this.data = data; } diff --git a/packages/builders/src/components/Components.ts b/packages/builders/src/components/Components.ts index d3e635ece..a8d287d05 100644 --- a/packages/builders/src/components/Components.ts +++ b/packages/builders/src/components/Components.ts @@ -14,27 +14,63 @@ import { StringSelectMenuBuilder } from './selectMenu/StringSelectMenu.js'; import { UserSelectMenuBuilder } from './selectMenu/UserSelectMenu.js'; import { TextInputBuilder } from './textInput/TextInput.js'; +/** + * Components here are mapped to their respective builder. + */ export interface MappedComponentTypes { + /** + * The action row component type is associated with an {@link ActionRowBuilder}. + */ [ComponentType.ActionRow]: ActionRowBuilder; + /** + * The button component type is associated with an {@link ButtonBuilder}. + */ [ComponentType.Button]: ButtonBuilder; + /** + * The string select component type is associated with an {@link StringSelectMenuBuilder}. + */ [ComponentType.StringSelect]: StringSelectMenuBuilder; + /** + * The text inpiut component type is associated with an {@link TextInputBuilder}. + */ [ComponentType.TextInput]: TextInputBuilder; + /** + * The user select component type is associated with an {@link UserSelectMenuBuilder}. + */ [ComponentType.UserSelect]: UserSelectMenuBuilder; + /** + * The role select component type is associated with an {@link RoleSelectMenuBuilder}. + */ [ComponentType.RoleSelect]: RoleSelectMenuBuilder; + /** + * The mentionable select component type is associated with an {@link MentionableSelectMenuBuilder}. + */ [ComponentType.MentionableSelect]: MentionableSelectMenuBuilder; + /** + * The channel select component type is associated with an {@link ChannelSelectMenuBuilder}. + */ [ComponentType.ChannelSelect]: ChannelSelectMenuBuilder; } /** - * Factory for creating components from API data + * Factory for creating components from API data. * - * @param data - The api data to transform to a component class + * @typeParam T - The type of component to use + * @param data - The API data to transform to a component class */ export function createComponentBuilder( // eslint-disable-next-line @typescript-eslint/sort-type-union-intersection-members data: (APIModalComponent | APIMessageComponent) & { type: T }, ): MappedComponentTypes[T]; + +/** + * Factory for creating components from API data. + * + * @typeParam C - The type of component to use + * @param data - The API data to transform to a component class + */ export function createComponentBuilder(data: C): C; + export function createComponentBuilder( data: APIMessageComponent | APIModalComponent | MessageComponentBuilder, ): ComponentBuilder { @@ -60,7 +96,7 @@ export function createComponentBuilder( case ComponentType.ChannelSelect: return new ChannelSelectMenuBuilder(data); default: - // @ts-expect-error: This case can still occur if we get a newer unsupported component type + // @ts-expect-error This case can still occur if we get a newer unsupported component type throw new Error(`Cannot properly serialize component type: ${data.type}`); } } diff --git a/packages/builders/src/components/button/Button.ts b/packages/builders/src/components/button/Button.ts index f6edbb863..30aad629b 100644 --- a/packages/builders/src/components/button/Button.ts +++ b/packages/builders/src/components/button/Button.ts @@ -18,15 +18,15 @@ import { import { ComponentBuilder } from '../Component.js'; /** - * Represents a button component + * A builder that creates API-compatible JSON data for buttons. */ export class ButtonBuilder extends ComponentBuilder { /** - * Creates a new button from API data + * Creates a new button from API data. * * @param data - The API data to create this button with * @example - * Creating a button from an API data object + * Creating a button from an API data object: * ```ts * const button = new ButtonBuilder({ * custom_id: 'a cool button', @@ -39,7 +39,7 @@ export class ButtonBuilder extends ComponentBuilder { * }); * ``` * @example - * Creating a button using setters and API data + * Creating a button using setters and API data: * ```ts * const button = new ButtonBuilder({ * style: ButtonStyle.Secondary, @@ -54,9 +54,9 @@ export class ButtonBuilder extends ComponentBuilder { } /** - * Sets the style of this button + * Sets the style of this button. * - * @param style - The style of the button + * @param style - The style to use */ public setStyle(style: ButtonStyle) { this.data.style = buttonStyleValidator.parse(style); @@ -64,12 +64,12 @@ export class ButtonBuilder extends ComponentBuilder { } /** - * Sets the URL for this button + * Sets the URL for this button. * * @remarks * This method is only available to buttons using the `Link` button style. - * Only three types of URL schemes are currently supported: `https://`, `http://` and `discord://` - * @param url - The URL to open when this button is clicked + * Only three types of URL schemes are currently supported: `https://`, `http://`, and `discord://`. + * @param url - The URL to use */ public setURL(url: string) { (this.data as APIButtonComponentWithURL).url = urlValidator.parse(url); @@ -77,11 +77,11 @@ export class ButtonBuilder extends ComponentBuilder { } /** - * Sets the custom id for this button + * Sets the custom id for this button. * * @remarks * This method is only applicable to buttons that are not using the `Link` button style. - * @param customId - The custom id to use for this button + * @param customId - The custom id to use */ public setCustomId(customId: string) { (this.data as APIButtonComponentWithCustomId).custom_id = customIdValidator.parse(customId); @@ -89,9 +89,9 @@ export class ButtonBuilder extends ComponentBuilder { } /** - * Sets the emoji to display on this button + * Sets the emoji to display on this button. * - * @param emoji - The emoji to display on this button + * @param emoji - The emoji to use */ public setEmoji(emoji: APIMessageComponentEmoji) { this.data.emoji = emojiValidator.parse(emoji); @@ -99,7 +99,7 @@ export class ButtonBuilder extends ComponentBuilder { } /** - * Sets whether this button is disabled + * Sets whether this button is disabled. * * @param disabled - Whether to disable this button */ @@ -109,9 +109,9 @@ export class ButtonBuilder extends ComponentBuilder { } /** - * Sets the label for this button + * Sets the label for this button. * - * @param label - The label to display on this button + * @param label - The label to use */ public setLabel(label: string) { this.data.label = buttonLabelValidator.parse(label); diff --git a/packages/builders/src/components/selectMenu/BaseSelectMenu.ts b/packages/builders/src/components/selectMenu/BaseSelectMenu.ts index cd1a306ac..458876e7f 100644 --- a/packages/builders/src/components/selectMenu/BaseSelectMenu.ts +++ b/packages/builders/src/components/selectMenu/BaseSelectMenu.ts @@ -2,13 +2,18 @@ import type { APISelectMenuComponent } from 'discord-api-types/v10'; import { customIdValidator, disabledValidator, minMaxValidator, placeholderValidator } from '../Assertions.js'; import { ComponentBuilder } from '../Component.js'; +/** + * The base select menu builder that contains common symbols for select menu builders. + * + * @typeParam SelectMenuType - The type of select menu this would be instantiated for. + */ export class BaseSelectMenuBuilder< SelectMenuType extends APISelectMenuComponent, > extends ComponentBuilder { /** - * Sets the placeholder for this select menu + * Sets the placeholder for this select menu. * - * @param placeholder - The placeholder to use for this select menu + * @param placeholder - The placeholder to use */ public setPlaceholder(placeholder: string) { this.data.placeholder = placeholderValidator.parse(placeholder); @@ -16,7 +21,7 @@ export class BaseSelectMenuBuilder< } /** - * Sets the minimum values that must be selected in the select menu + * Sets the minimum values that must be selected in the select menu. * * @param minValues - The minimum values that must be selected */ @@ -26,7 +31,7 @@ export class BaseSelectMenuBuilder< } /** - * Sets the maximum values that must be selected in the select menu + * Sets the maximum values that must be selected in the select menu. * * @param maxValues - The maximum values that must be selected */ @@ -36,9 +41,9 @@ export class BaseSelectMenuBuilder< } /** - * Sets the custom id for this select menu + * Sets the custom id for this select menu. * - * @param customId - The custom id to use for this select menu + * @param customId - The custom id to use */ public setCustomId(customId: string) { this.data.custom_id = customIdValidator.parse(customId); @@ -46,7 +51,7 @@ export class BaseSelectMenuBuilder< } /** - * Sets whether this select menu is disabled + * Sets whether this select menu is disabled. * * @param disabled - Whether this select menu is disabled */ @@ -55,6 +60,9 @@ export class BaseSelectMenuBuilder< return this; } + /** + * {@inheritDoc ComponentBuilder.toJSON} + */ public toJSON(): SelectMenuType { customIdValidator.parse(this.data.custom_id); return { diff --git a/packages/builders/src/components/selectMenu/ChannelSelectMenu.ts b/packages/builders/src/components/selectMenu/ChannelSelectMenu.ts index a2d46f35e..fe5b27b83 100644 --- a/packages/builders/src/components/selectMenu/ChannelSelectMenu.ts +++ b/packages/builders/src/components/selectMenu/ChannelSelectMenu.ts @@ -4,13 +4,16 @@ import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js'; import { channelTypesValidator, customIdValidator } from '../Assertions.js'; import { BaseSelectMenuBuilder } from './BaseSelectMenu.js'; +/** + * A builder that creates API-compatible JSON data for channel select menus. + */ export class ChannelSelectMenuBuilder extends BaseSelectMenuBuilder { /** - * Creates a new select menu from API data + * Creates a new select menu from API data. * * @param data - The API data to create this select menu with * @example - * Creating a select menu from an API data object + * Creating a select menu from an API data object: * ```ts * const selectMenu = new ChannelSelectMenuBuilder({ * custom_id: 'a cool select menu', @@ -19,39 +22,45 @@ export class ChannelSelectMenuBuilder extends BaseSelectMenuBuilder) { super({ ...data, type: ComponentType.ChannelSelect }); } + /** + * Adds channel types to this select menu. + * + * @param types - The channel types to use + */ public addChannelTypes(...types: RestOrArray) { - // eslint-disable-next-line no-param-reassign - types = normalizeArray(types); - + const normalizedTypes = normalizeArray(types); this.data.channel_types ??= []; - this.data.channel_types.push(...channelTypesValidator.parse(types)); - return this; - } - - public setChannelTypes(...types: RestOrArray) { - // eslint-disable-next-line no-param-reassign - types = normalizeArray(types); - - this.data.channel_types ??= []; - this.data.channel_types.splice(0, this.data.channel_types.length, ...channelTypesValidator.parse(types)); + this.data.channel_types.push(...channelTypesValidator.parse(normalizedTypes)); return this; } /** - * {@inheritDoc ComponentBuilder.toJSON} + * Sets channel types for this select menu. + * + * @param types - The channel types to use + */ + public setChannelTypes(...types: RestOrArray) { + const normalizedTypes = normalizeArray(types); + this.data.channel_types ??= []; + this.data.channel_types.splice(0, this.data.channel_types.length, ...channelTypesValidator.parse(normalizedTypes)); + return this; + } + + /** + * {@inheritDoc BaseSelectMenuBuilder.toJSON} */ public override toJSON(): APIChannelSelectComponent { customIdValidator.parse(this.data.custom_id); diff --git a/packages/builders/src/components/selectMenu/MentionableSelectMenu.ts b/packages/builders/src/components/selectMenu/MentionableSelectMenu.ts index c996e2b47..a3a39a975 100644 --- a/packages/builders/src/components/selectMenu/MentionableSelectMenu.ts +++ b/packages/builders/src/components/selectMenu/MentionableSelectMenu.ts @@ -2,13 +2,16 @@ import type { APIMentionableSelectComponent } from 'discord-api-types/v10'; import { ComponentType } from 'discord-api-types/v10'; import { BaseSelectMenuBuilder } from './BaseSelectMenu.js'; +/** + * A builder that creates API-compatible JSON data for mentionable select menus. + */ export class MentionableSelectMenuBuilder extends BaseSelectMenuBuilder { /** - * Creates a new select menu from API data + * Creates a new select menu from API data. * * @param data - The API data to create this select menu with * @example - * Creating a select menu from an API data object + * Creating a select menu from an API data object: * ```ts * const selectMenu = new MentionableSelectMenuBuilder({ * custom_id: 'a cool select menu', @@ -17,12 +20,12 @@ export class MentionableSelectMenuBuilder extends BaseSelectMenuBuilder) { diff --git a/packages/builders/src/components/selectMenu/RoleSelectMenu.ts b/packages/builders/src/components/selectMenu/RoleSelectMenu.ts index 818ef5b77..2055b5f53 100644 --- a/packages/builders/src/components/selectMenu/RoleSelectMenu.ts +++ b/packages/builders/src/components/selectMenu/RoleSelectMenu.ts @@ -2,13 +2,16 @@ import type { APIRoleSelectComponent } from 'discord-api-types/v10'; import { ComponentType } from 'discord-api-types/v10'; import { BaseSelectMenuBuilder } from './BaseSelectMenu.js'; +/** + * A builder that creates API-compatible JSON data for role select menus. + */ export class RoleSelectMenuBuilder extends BaseSelectMenuBuilder { /** - * Creates a new select menu from API data + * Creates a new select menu from API data. * * @param data - The API data to create this select menu with * @example - * Creating a select menu from an API data object + * Creating a select menu from an API data object: * ```ts * const selectMenu = new RoleSelectMenuBuilder({ * custom_id: 'a cool select menu', @@ -17,12 +20,12 @@ export class RoleSelectMenuBuilder extends BaseSelectMenuBuilder) { diff --git a/packages/builders/src/components/selectMenu/StringSelectMenu.ts b/packages/builders/src/components/selectMenu/StringSelectMenu.ts index e3f156be9..9c6542387 100644 --- a/packages/builders/src/components/selectMenu/StringSelectMenu.ts +++ b/packages/builders/src/components/selectMenu/StringSelectMenu.ts @@ -6,20 +6,20 @@ import { BaseSelectMenuBuilder } from './BaseSelectMenu.js'; import { StringSelectMenuOptionBuilder } from './StringSelectMenuOption.js'; /** - * Represents a string select menu component + * A builder that creates API-compatible JSON data for string select menus. */ export class StringSelectMenuBuilder extends BaseSelectMenuBuilder { /** - * The options within this select menu + * The options within this select menu. */ public readonly options: StringSelectMenuOptionBuilder[]; /** - * Creates a new select menu from API data + * Creates a new select menu from API data. * * @param data - The API data to create this select menu with * @example - * Creating a select menu from an API data object + * Creating a select menu from an API data object: * ```ts * const selectMenu = new StringSelectMenuBuilder({ * custom_id: 'a cool select menu', @@ -33,7 +33,7 @@ export class StringSelectMenuBuilder extends BaseSelectMenuBuilder) { - // eslint-disable-next-line no-param-reassign - options = normalizeArray(options); - optionsLengthValidator.parse(this.options.length + options.length); + const normalizedOptions = normalizeArray(options); + optionsLengthValidator.parse(this.options.length + normalizedOptions.length); this.options.push( - ...options.map((option) => - option instanceof StringSelectMenuOptionBuilder - ? option - : new StringSelectMenuOptionBuilder(jsonOptionValidator.parse(option)), + ...normalizedOptions.map((normalizedOption) => + normalizedOption instanceof StringSelectMenuOptionBuilder + ? normalizedOption + : new StringSelectMenuOptionBuilder(jsonOptionValidator.parse(normalizedOption)), ), ); return this; } /** - * Sets the options on this select menu + * Sets the options for this select menu. * - * @param options - The options to set on this select menu + * @param options - The options to set */ public setOptions(...options: RestOrArray) { return this.spliceOptions(0, this.options.length, ...options); } /** - * Removes, replaces, or inserts options in the string select menu. + * Removes, replaces, or inserts options for this select menu. * * @remarks * This method behaves similarly - * to {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice | Array.prototype.splice}. - * - * It's useful for modifying and adjusting order of the already-existing options of a string select menu. + * to {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice | Array.prototype.splice()}. + * It's useful for modifying and adjusting the order of existing options. * @example - * Remove the first option + * Remove the first option: * ```ts * selectMenu.spliceOptions(0, 1); * ``` * @example - * Remove the first n option + * Remove the first n option: * ```ts - * const n = 4 + * const n = 4; * selectMenu.spliceOptions(0, n); * ``` * @example - * Remove the last option + * Remove the last option: * ```ts * selectMenu.spliceOptions(-1, 1); * ``` @@ -113,30 +110,27 @@ export class StringSelectMenuBuilder extends BaseSelectMenuBuilder ) { - // eslint-disable-next-line no-param-reassign - options = normalizeArray(options); + const normalizedOptions = normalizeArray(options); const clone = [...this.options]; clone.splice( index, deleteCount, - ...options.map((option) => - option instanceof StringSelectMenuOptionBuilder - ? option - : new StringSelectMenuOptionBuilder(jsonOptionValidator.parse(option)), + ...normalizedOptions.map((normalizedOption) => + normalizedOption instanceof StringSelectMenuOptionBuilder + ? normalizedOption + : new StringSelectMenuOptionBuilder(jsonOptionValidator.parse(normalizedOption)), ), ); optionsLengthValidator.parse(clone.length); - this.options.splice(0, this.options.length, ...clone); - return this; } /** - * {@inheritDoc ComponentBuilder.toJSON} + * {@inheritDoc BaseSelectMenuBuilder.toJSON} */ public override toJSON(): APIStringSelectComponent { validateRequiredSelectMenuParameters(this.options, this.data.custom_id); diff --git a/packages/builders/src/components/selectMenu/StringSelectMenuOption.ts b/packages/builders/src/components/selectMenu/StringSelectMenuOption.ts index c43145463..3e4597087 100644 --- a/packages/builders/src/components/selectMenu/StringSelectMenuOption.ts +++ b/packages/builders/src/components/selectMenu/StringSelectMenuOption.ts @@ -8,15 +8,15 @@ import { } from '../Assertions.js'; /** - * Represents an option within a string select menu component + * A builder that creates API-compatible JSON data for string select menu options. */ export class StringSelectMenuOptionBuilder implements JSONEncodable { /** - * Creates a new string select menu option from API data + * Creates a new string select menu option from API data. * * @param data - The API data to create this string select menu option with * @example - * Creating a string select menu option from an API data object + * Creating a string select menu option from an API data object: * ```ts * const selectMenuOption = new SelectMenuOptionBuilder({ * label: 'catchy label', @@ -24,21 +24,21 @@ export class StringSelectMenuOptionBuilder implements JSONEncodable = {}) {} /** - * Sets the label of this option + * Sets the label for this option. * - * @param label - The label to show on this option + * @param label - The label to use */ public setLabel(label: string) { this.data.label = labelValueDescriptionValidator.parse(label); @@ -46,9 +46,9 @@ export class StringSelectMenuOptionBuilder implements JSONEncodable { /** - * Creates a new select menu from API data + * Creates a new select menu from API data. * * @param data - The API data to create this select menu with * @example - * Creating a select menu from an API data object + * Creating a select menu from an API data object: * ```ts * const selectMenu = new UserSelectMenuBuilder({ * custom_id: 'a cool select menu', @@ -17,12 +20,12 @@ export class UserSelectMenuBuilder extends BaseSelectMenuBuilder) { diff --git a/packages/builders/src/components/textInput/TextInput.ts b/packages/builders/src/components/textInput/TextInput.ts index 02b97cb86..42a458372 100644 --- a/packages/builders/src/components/textInput/TextInput.ts +++ b/packages/builders/src/components/textInput/TextInput.ts @@ -14,16 +14,19 @@ import { textInputStyleValidator, } from './Assertions.js'; +/** + * A builder that creates API-compatible JSON data for text inputs. + */ export class TextInputBuilder extends ComponentBuilder implements Equatable> { /** - * Creates a new text input from API data + * Creates a new text input from API data. * * @param data - The API data to create this text input with * @example - * Creating a select menu option from an API data object + * Creating a select menu option from an API data object: * ```ts * const textInput = new TextInputBuilder({ * custom_id: 'a cool select menu', @@ -32,7 +35,7 @@ export class TextInputBuilder * }); * ``` * @example - * Creating a select menu option using setters and API data + * Creating a select menu option using setters and API data: * ```ts * const textInput = new TextInputBuilder({ * label: 'Type something else', @@ -46,9 +49,9 @@ export class TextInputBuilder } /** - * Sets the custom id for this text input + * Sets the custom id for this text input. * - * @param customId - The custom id of this text input + * @param customId - The custom id to use */ public setCustomId(customId: string) { this.data.custom_id = customIdValidator.parse(customId); @@ -56,9 +59,9 @@ export class TextInputBuilder } /** - * Sets the label for this text input + * Sets the label for this text input. * - * @param label - The label for this text input + * @param label - The label to use */ public setLabel(label: string) { this.data.label = labelValidator.parse(label); @@ -66,9 +69,9 @@ export class TextInputBuilder } /** - * Sets the style for this text input + * Sets the style for this text input. * - * @param style - The style for this text input + * @param style - The style to use */ public setStyle(style: TextInputStyle) { this.data.style = textInputStyleValidator.parse(style); @@ -76,7 +79,7 @@ export class TextInputBuilder } /** - * Sets the minimum length of text for this text input + * Sets the minimum length of text for this text input. * * @param minLength - The minimum length of text for this text input */ @@ -86,7 +89,7 @@ export class TextInputBuilder } /** - * Sets the maximum length of text for this text input + * Sets the maximum length of text for this text input. * * @param maxLength - The maximum length of text for this text input */ @@ -96,9 +99,9 @@ export class TextInputBuilder } /** - * Sets the placeholder of this text input + * Sets the placeholder for this text input. * - * @param placeholder - The placeholder of this text input + * @param placeholder - The placeholder to use */ public setPlaceholder(placeholder: string) { this.data.placeholder = placeholderValidator.parse(placeholder); @@ -106,9 +109,9 @@ export class TextInputBuilder } /** - * Sets the value of this text input + * Sets the value for this text input. * - * @param value - The value for this text input + * @param value - The value to use */ public setValue(value: string) { this.data.value = valueValidator.parse(value); @@ -116,7 +119,7 @@ export class TextInputBuilder } /** - * Sets whether this text input is required + * Sets whether this text input is required. * * @param required - Whether this text input is required */ diff --git a/packages/builders/src/index.ts b/packages/builders/src/index.ts index f021c022f..7023786cf 100644 --- a/packages/builders/src/index.ts +++ b/packages/builders/src/index.ts @@ -62,8 +62,9 @@ export * from './util/validation.js'; export * from '@discordjs/util'; /** - * The {@link https://github.com/discordjs/discord.js/blob/main/packages/builders/#readme | @discordjs/builders} version + * The {@link https://github.com/discordjs/discord.js/blob/main/packages/builders#readme | @discordjs/builders} version * that you are currently using. + * + * @privateRemarks This needs to explicitly be `string` so it is not typed as a "const string" that gets injected by esbuild. */ -// This needs to explicitly be `string` so it is not typed as a "const string" that gets injected by esbuild export const version = '[VI]{{inject}}[/VI]' as string; diff --git a/packages/builders/src/interactions/contextMenuCommands/ContextMenuCommandBuilder.ts b/packages/builders/src/interactions/contextMenuCommands/ContextMenuCommandBuilder.ts index 5b936f50c..a4cb2be1d 100644 --- a/packages/builders/src/interactions/contextMenuCommands/ContextMenuCommandBuilder.ts +++ b/packages/builders/src/interactions/contextMenuCommands/ContextMenuCommandBuilder.ts @@ -15,45 +15,54 @@ import { validateDMPermission, } from './Assertions.js'; +/** + * The type a context menu command can be. + */ +export type ContextMenuCommandType = ApplicationCommandType.Message | ApplicationCommandType.User; + +/** + * A builder that creates API-compatible JSON data for context menu commands. + */ export class ContextMenuCommandBuilder { /** - * The name of this context menu command + * The name of this command. */ public readonly name: string = undefined!; /** - * The localized names for this command + * The name localizations of this command. */ public readonly name_localizations?: LocalizationMap; /** - * The type of this context menu command + * The type of this command. */ public readonly type: ContextMenuCommandType = undefined!; /** - * Whether the command is enabled by default when the app is added to a guild + * Whether this command is enabled by default when the application is added to a guild. * - * @deprecated This property is deprecated and will be removed in the future. - * You should use {@link ContextMenuCommandBuilder.setDefaultMemberPermissions} or {@link ContextMenuCommandBuilder.setDMPermission} instead. + * @deprecated Use {@link ContextMenuCommandBuilder.setDefaultMemberPermissions} or {@link ContextMenuCommandBuilder.setDMPermission} instead. */ public readonly default_permission: boolean | undefined = undefined; /** - * Set of permissions represented as a bit set for the command + * The set of permissions represented as a bit set for the command. */ public readonly default_member_permissions: Permissions | null | undefined = undefined; /** - * Indicates whether the command is available in DMs with the application, only for globally-scoped commands. - * By default, commands are visible. + * Indicates whether the command is available in direct messages with the application. + * + * @remarks + * By default, commands are visible. This property is only for global commands. */ public readonly dm_permission: boolean | undefined = undefined; /** - * Sets the name + * Sets the name of this command. * - * @param name - The name + * @param name - The name to use */ public setName(name: string) { // Assert the name matches the conditions @@ -65,9 +74,9 @@ export class ContextMenuCommandBuilder { } /** - * Sets the type + * Sets the type of this command. * - * @param type - The type + * @param type - The type to use */ public setType(type: ContextMenuCommandType) { // Assert the type is valid @@ -83,7 +92,7 @@ export class ContextMenuCommandBuilder { * * @remarks * If set to `false`, you will have to later `PUT` the permissions for this command. - * @param value - Whether or not to enable this command by default + * @param value - Whether to enable this command by default * @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions} * @deprecated Use {@link ContextMenuCommandBuilder.setDefaultMemberPermissions} or {@link ContextMenuCommandBuilder.setDMPermission} instead. */ @@ -97,7 +106,7 @@ export class ContextMenuCommandBuilder { } /** - * Sets the default permissions a member should have in order to run the command. + * Sets the default permissions a member should have in order to run this command. * * @remarks * You can set this to `'0'` to disable the command by default. @@ -114,10 +123,11 @@ export class ContextMenuCommandBuilder { } /** - * Sets if the command is available in DMs with the application, only for globally-scoped commands. - * By default, commands are visible. + * Sets if the command is available in direct messages with the application. * - * @param enabled - If the command should be enabled in DMs + * @remarks + * By default, commands are visible. This method is only for global commands. + * @param enabled - Whether the command should be enabled in direct messages * @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions} */ public setDMPermission(enabled: boolean | null | undefined) { @@ -130,10 +140,10 @@ export class ContextMenuCommandBuilder { } /** - * Sets a name localization + * Sets a name localization for this command. * - * @param locale - The locale to set a description for - * @param localizedName - The localized description for the given locale + * @param locale - The locale to set + * @param localizedName - The localized name for the given `locale` */ public setNameLocalization(locale: LocaleString, localizedName: string | null) { if (!this.name_localizations) { @@ -154,9 +164,9 @@ export class ContextMenuCommandBuilder { } /** - * Sets the name localizations + * Sets the name localizations for this command. * - * @param localizedNames - The dictionary of localized descriptions to set + * @param localizedNames - The object of localized names to set */ public setNameLocalizations(localizedNames: LocalizationMap | null) { if (localizedNames === null) { @@ -172,7 +182,7 @@ export class ContextMenuCommandBuilder { } /** - * Returns the final data that should be sent to Discord. + * Serializes this builder to API-compatible JSON data. * * @remarks * This method runs validations on the data before serializing it. @@ -186,5 +196,3 @@ export class ContextMenuCommandBuilder { return { ...this }; } } - -export type ContextMenuCommandType = ApplicationCommandType.Message | ApplicationCommandType.User; diff --git a/packages/builders/src/interactions/modals/Modal.ts b/packages/builders/src/interactions/modals/Modal.ts index 46cd4b3fc..948d774df 100644 --- a/packages/builders/src/interactions/modals/Modal.ts +++ b/packages/builders/src/interactions/modals/Modal.ts @@ -1,3 +1,5 @@ +/* eslint-disable jsdoc/check-param-names */ + import type { JSONEncodable } from '@discordjs/util'; import type { APIActionRowComponent, @@ -10,11 +12,25 @@ import { createComponentBuilder } from '../../components/Components.js'; import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js'; import { titleValidator, validateRequiredParameters } from './Assertions.js'; +/** + * A builder that creates API-compatible JSON data for modals. + */ export class ModalBuilder implements JSONEncodable { + /** + * The API data associated with this modal. + */ public readonly data: Partial; + /** + * The components within this modal. + */ public readonly components: ActionRowBuilder[] = []; + /** + * Creates a new modal from API data. + * + * @param data - The API data to create this modal with + */ public constructor({ components, ...data }: Partial = {}) { this.data = { ...data }; this.components = (components?.map((component) => createComponentBuilder(component)) ?? @@ -22,9 +38,9 @@ export class ModalBuilder implements JSONEncodable>) { this.components.splice(0, this.components.length, ...normalizeArray(components)); diff --git a/packages/builders/src/interactions/slashCommands/SlashCommandBuilder.ts b/packages/builders/src/interactions/slashCommands/SlashCommandBuilder.ts index 595272fa9..d10ba093e 100644 --- a/packages/builders/src/interactions/slashCommands/SlashCommandBuilder.ts +++ b/packages/builders/src/interactions/slashCommands/SlashCommandBuilder.ts @@ -19,76 +19,61 @@ import { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } fro import { SharedNameAndDescription } from './mixins/NameAndDescription.js'; import { SharedSlashCommandOptions } from './mixins/SharedSlashCommandOptions.js'; +/** + * A builder that creates API-compatible JSON data for slash commands. + */ @mix(SharedSlashCommandOptions, SharedNameAndDescription) export class SlashCommandBuilder { /** - * The name of this slash command + * The name of this command. */ public readonly name: string = undefined!; /** - * The localized names for this command + * The name localizations of this command. */ public readonly name_localizations?: LocalizationMap; /** - * The description of this slash command + * The description of this command. */ public readonly description: string = undefined!; /** - * The localized descriptions for this command + * The description localizations of this command. */ public readonly description_localizations?: LocalizationMap; /** - * The options of this slash command + * The options of this command. */ public readonly options: ToAPIApplicationCommandOptions[] = []; /** - * Whether the command is enabled by default when the app is added to a guild + * Whether this command is enabled by default when the application is added to a guild. * - * @deprecated This property is deprecated and will be removed in the future. - * You should use {@link SlashCommandBuilder.setDefaultMemberPermissions} or {@link SlashCommandBuilder.setDMPermission} instead. + * @deprecated Use {@link ContextMenuCommandBuilder.setDefaultMemberPermissions} or {@link ContextMenuCommandBuilder.setDMPermission} instead. */ public readonly default_permission: boolean | undefined = undefined; /** - * Set of permissions represented as a bit set for the command + * The set of permissions represented as a bit set for the command. */ public readonly default_member_permissions: Permissions | null | undefined = undefined; /** - * Indicates whether the command is available in DMs with the application, only for globally-scoped commands. - * By default, commands are visible. + * Indicates whether the command is available in direct messages with the application. + * + * @remarks + * By default, commands are visible. This property is only for global commands. */ public readonly dm_permission: boolean | undefined = undefined; /** - * Whether this command is NSFW + * Whether this command is NSFW. */ public readonly nsfw: boolean | undefined = undefined; - /** - * Returns the final data that should be sent to Discord. - * - * @remarks - * This method runs validations on the data before serializing it. - * As such, it may throw an error if the data is invalid. - */ - public toJSON(): RESTPostAPIChatInputApplicationCommandsJSONBody { - validateRequiredParameters(this.name, this.description, this.options); - - validateLocalizationMap(this.name_localizations); - validateLocalizationMap(this.description_localizations); - - return { - ...this, - options: this.options.map((option) => option.toJSON()), - }; - } - /** * Sets whether the command is enabled by default when the application is added to a guild. * @@ -125,10 +110,11 @@ export class SlashCommandBuilder { } /** - * Sets if the command is available in DMs with the application, only for globally-scoped commands. - * By default, commands are visible. + * Sets if the command is available in direct messages with the application. * - * @param enabled - If the command should be enabled in DMs + * @remarks + * By default, commands are visible. This method is only for global commands. + * @param enabled - Whether the command should be enabled in direct messages * @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions} */ public setDMPermission(enabled: boolean | null | undefined) { @@ -141,7 +127,7 @@ export class SlashCommandBuilder { } /** - * Sets whether this command is NSFW + * Sets whether this command is NSFW. * * @param nsfw - Whether this command is NSFW */ @@ -153,9 +139,9 @@ export class SlashCommandBuilder { } /** - * Adds a new subcommand group to this command + * Adds a new subcommand group to this command. * - * @param input - A function that returns a subcommand group builder, or an already built builder + * @param input - A function that returns a subcommand group builder or an already built builder */ public addSubcommandGroup( input: @@ -179,9 +165,9 @@ export class SlashCommandBuilder { } /** - * Adds a new subcommand to this command + * Adds a new subcommand to this command. * - * @param input - A function that returns a subcommand builder, or an already built builder + * @param input - A function that returns a subcommand builder or an already built builder */ public addSubcommand( input: @@ -203,18 +189,47 @@ export class SlashCommandBuilder { return this; } + + /** + * Serializes this builder to API-compatible JSON data. + * + * @remarks + * This method runs validations on the data before serializing it. + * As such, it may throw an error if the data is invalid. + */ + public toJSON(): RESTPostAPIChatInputApplicationCommandsJSONBody { + validateRequiredParameters(this.name, this.description, this.options); + + validateLocalizationMap(this.name_localizations); + validateLocalizationMap(this.description_localizations); + + return { + ...this, + options: this.options.map((option) => option.toJSON()), + }; + } } export interface SlashCommandBuilder extends SharedNameAndDescription, SharedSlashCommandOptions {} +/** + * An interface specifically for slash command subcommands. + */ export interface SlashCommandSubcommandsOnlyBuilder extends Omit> {} +/** + * An interface specifically for slash command options. + */ export interface SlashCommandOptionsOnlyBuilder extends SharedNameAndDescription, SharedSlashCommandOptions, Pick {} +/** + * An interface that ensures the `toJSON()` call will return something + * that can be serialized into API-compatible data. + */ export interface ToAPIApplicationCommandOptions { toJSON(): APIApplicationCommandOption; } diff --git a/packages/builders/src/interactions/slashCommands/SlashCommandSubcommands.ts b/packages/builders/src/interactions/slashCommands/SlashCommandSubcommands.ts index 1e65d84f3..388215376 100644 --- a/packages/builders/src/interactions/slashCommands/SlashCommandSubcommands.ts +++ b/packages/builders/src/interactions/slashCommands/SlashCommandSubcommands.ts @@ -11,31 +11,31 @@ import { SharedNameAndDescription } from './mixins/NameAndDescription.js'; import { SharedSlashCommandOptions } from './mixins/SharedSlashCommandOptions.js'; /** - * Represents a folder for subcommands + * Represents a folder for subcommands. * * @see {@link https://discord.com/developers/docs/interactions/application-commands#subcommands-and-subcommand-groups} */ @mix(SharedNameAndDescription) export class SlashCommandSubcommandGroupBuilder implements ToAPIApplicationCommandOptions { /** - * The name of this subcommand group + * The name of this subcommand group. */ public readonly name: string = undefined!; /** - * The description of this subcommand group + * The description of this subcommand group. */ public readonly description: string = undefined!; /** - * The subcommands part of this subcommand group + * The subcommands within this subcommand group. */ public readonly options: SlashCommandSubcommandBuilder[] = []; /** - * Adds a new subcommand to this group + * Adds a new subcommand to this group. * - * @param input - A function that returns a subcommand builder, or an already built builder + * @param input - A function that returns a subcommand builder or an already built builder */ public addSubcommand( input: @@ -60,6 +60,13 @@ export class SlashCommandSubcommandGroupBuilder implements ToAPIApplicationComma return this; } + /** + * Serializes this builder to API-compatible JSON data. + * + * @remarks + * This method runs validations on the data before serializing it. + * As such, it may throw an error if the data is invalid. + */ public toJSON(): APIApplicationCommandSubcommandGroupOption { validateRequiredParameters(this.name, this.description, this.options); @@ -77,27 +84,34 @@ export class SlashCommandSubcommandGroupBuilder implements ToAPIApplicationComma export interface SlashCommandSubcommandGroupBuilder extends SharedNameAndDescription {} /** - * Represents a subcommand + * A builder that creates API-compatible JSON data for slash command subcommands. * * @see {@link https://discord.com/developers/docs/interactions/application-commands#subcommands-and-subcommand-groups} */ @mix(SharedNameAndDescription, SharedSlashCommandOptions) export class SlashCommandSubcommandBuilder implements ToAPIApplicationCommandOptions { /** - * The name of this subcommand + * The name of this subcommand. */ public readonly name: string = undefined!; /** - * The description of this subcommand + * The description of this subcommand. */ public readonly description: string = undefined!; /** - * The options of this subcommand + * The options within this subcommand. */ public readonly options: ApplicationCommandOptionBase[] = []; + /** + * Serializes this builder to API-compatible JSON data. + * + * @remarks + * This method runs validations on the data before serializing it. + * As such, it may throw an error if the data is invalid. + */ public toJSON(): APIApplicationCommandSubcommandOption { validateRequiredParameters(this.name, this.description, this.options); diff --git a/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandNumericOptionMinMaxValueMixin.ts b/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandNumericOptionMinMaxValueMixin.ts index 5ac38d1f6..0cdbdbe62 100644 --- a/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandNumericOptionMinMaxValueMixin.ts +++ b/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandNumericOptionMinMaxValueMixin.ts @@ -1,17 +1,26 @@ +/** + * This mixin holds minimum and maximum symbols used for options. + */ export abstract class ApplicationCommandNumericOptionMinMaxValueMixin { + /** + * The maximum value of this option. + */ public readonly max_value?: number; + /** + * The minimum value of this option. + */ public readonly min_value?: number; /** - * Sets the maximum number value of this option + * Sets the maximum number value of this option. * * @param max - The maximum value this option can be */ public abstract setMaxValue(max: number): this; /** - * Sets the minimum number value of this option + * Sets the minimum number value of this option. * * @param min - The minimum value this option can be */ diff --git a/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandOptionBase.ts b/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandOptionBase.ts index b40ce0c96..51f450e0f 100644 --- a/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandOptionBase.ts +++ b/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandOptionBase.ts @@ -2,15 +2,26 @@ import type { APIApplicationCommandBasicOption, ApplicationCommandOptionType } f import { validateRequiredParameters, validateRequired, validateLocalizationMap } from '../Assertions.js'; import { SharedNameAndDescription } from './NameAndDescription.js'; +/** + * The base application command option builder that contains common symbols for application command builders. + */ export abstract class ApplicationCommandOptionBase extends SharedNameAndDescription { + /** + * The type of this option. + */ public abstract readonly type: ApplicationCommandOptionType; + /** + * Whether this option is required. + * + * @defaultValue `false` + */ public readonly required: boolean = false; /** - * Marks the option as required + * Sets whether this option is required. * - * @param required - If this option should be required + * @param required - Whether this option should be required */ public setRequired(required: boolean) { // Assert that you actually passed a boolean @@ -21,8 +32,18 @@ export abstract class ApplicationCommandOptionBase extends SharedNameAndDescript return this; } + /** + * Serializes this builder to API-compatible JSON data. + * + * @remarks + * This method runs validations on the data before serializing it. + * As such, it may throw an error if the data is invalid. + */ public abstract toJSON(): APIApplicationCommandBasicOption; + /** + * This method runs required validators on this builder. + */ protected runRequiredValidations() { validateRequiredParameters(this.name, this.description, []); diff --git a/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandOptionChannelTypesMixin.ts b/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandOptionChannelTypesMixin.ts index a9125ac04..c97d996e7 100644 --- a/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandOptionChannelTypesMixin.ts +++ b/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandOptionChannelTypesMixin.ts @@ -1,7 +1,12 @@ import { s } from '@sapphire/shapeshift'; import { ChannelType } from 'discord-api-types/v10'; -// Only allow valid channel types to be used. (This can't be dynamic because const enums are erased at runtime) +/** + * The allowed channel types used for a channel option in a slash command builder. + * + * @privateRemarks This can't be dynamic because const enums are erased at runtime. + * @internal + */ const allowedChannelTypes = [ ChannelType.GuildText, ChannelType.GuildVoice, @@ -14,17 +19,26 @@ const allowedChannelTypes = [ ChannelType.GuildForum, ] as const; +/** + * The type of allowed channel types used for a channel option. + */ export type ApplicationCommandOptionAllowedChannelTypes = (typeof allowedChannelTypes)[number]; const channelTypesPredicate = s.array(s.union(...allowedChannelTypes.map((type) => s.literal(type)))); +/** + * This mixin holds channel type symbols used for options. + */ export class ApplicationCommandOptionChannelTypesMixin { + /** + * The channel types of this option. + */ public readonly channel_types?: ApplicationCommandOptionAllowedChannelTypes[]; /** - * Adds channel types to this option + * Adds channel types to this option. * - * @param channelTypes - The channel types to add + * @param channelTypes - The channel types */ public addChannelTypes(...channelTypes: ApplicationCommandOptionAllowedChannelTypes[]) { if (this.channel_types === undefined) { diff --git a/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.ts b/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.ts index 5ea7105f1..29fdd1e3c 100644 --- a/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.ts +++ b/packages/builders/src/interactions/slashCommands/mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.ts @@ -11,16 +11,29 @@ const choicesPredicate = s.object({ }).array; const booleanPredicate = s.boolean; +/** + * This mixin holds choices and autocomplete symbols used for options. + */ export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin { + /** + * The choices of this option. + */ public readonly choices?: APIApplicationCommandOptionChoice[]; + /** + * Whether this option utilizes autocomplete. + */ public readonly autocomplete?: boolean; - // Since this is present and this is a mixin, this is needed + /** + * The type of this option. + * + * @privateRemarks Since this is present and this is a mixin, this is needed. + */ public readonly type!: ApplicationCommandOptionType; /** - * Adds multiple choices for this option + * Adds multiple choices to this option. * * @param choices - The choices to add */ @@ -51,6 +64,11 @@ export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin[]>(...choices: Input): this { if (choices.length > 0 && this.autocomplete) { throw new RangeError('Autocomplete and choices are mutually exclusive to each other.'); @@ -65,9 +83,9 @@ export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin { public readonly options!: ToAPIApplicationCommandOptions[]; /** - * Adds a boolean option + * Adds a boolean option. * - * @param input - A function that returns an option builder, or an already built builder + * @param input - A function that returns an option builder or an already built builder */ public addBooleanOption( input: SlashCommandBooleanOption | ((builder: SlashCommandBooleanOption) => SlashCommandBooleanOption), @@ -26,18 +31,18 @@ export class SharedSlashCommandOptions { } /** - * Adds a user option + * Adds a user option. * - * @param input - A function that returns an option builder, or an already built builder + * @param input - A function that returns an option builder or an already built builder */ public addUserOption(input: SlashCommandUserOption | ((builder: SlashCommandUserOption) => SlashCommandUserOption)) { return this._sharedAddOptionMethod(input, SlashCommandUserOption); } /** - * Adds a channel option + * Adds a channel option. * - * @param input - A function that returns an option builder, or an already built builder + * @param input - A function that returns an option builder or an already built builder */ public addChannelOption( input: SlashCommandChannelOption | ((builder: SlashCommandChannelOption) => SlashCommandChannelOption), @@ -46,18 +51,18 @@ export class SharedSlashCommandOptions { } /** - * Adds a role option + * Adds a role option. * - * @param input - A function that returns an option builder, or an already built builder + * @param input - A function that returns an option builder or an already built builder */ public addRoleOption(input: SlashCommandRoleOption | ((builder: SlashCommandRoleOption) => SlashCommandRoleOption)) { return this._sharedAddOptionMethod(input, SlashCommandRoleOption); } /** - * Adds an attachment option + * Adds an attachment option. * - * @param input - A function that returns an option builder, or an already built builder + * @param input - A function that returns an option builder or an already built builder */ public addAttachmentOption( input: SlashCommandAttachmentOption | ((builder: SlashCommandAttachmentOption) => SlashCommandAttachmentOption), @@ -66,9 +71,9 @@ export class SharedSlashCommandOptions { } /** - * Adds a mentionable option + * Adds a mentionable option. * - * @param input - A function that returns an option builder, or an already built builder + * @param input - A function that returns an option builder or an already built builder */ public addMentionableOption( input: SlashCommandMentionableOption | ((builder: SlashCommandMentionableOption) => SlashCommandMentionableOption), @@ -77,9 +82,9 @@ export class SharedSlashCommandOptions { } /** - * Adds a string option + * Adds a string option. * - * @param input - A function that returns an option builder, or an already built builder + * @param input - A function that returns an option builder or an already built builder */ public addStringOption( input: @@ -97,9 +102,9 @@ export class SharedSlashCommandOptions { } /** - * Adds an integer option + * Adds an integer option. * - * @param input - A function that returns an option builder, or an already built builder + * @param input - A function that returns an option builder or an already built builder */ public addIntegerOption( input: @@ -117,9 +122,9 @@ export class SharedSlashCommandOptions { } /** - * Adds a number option + * Adds a number option. * - * @param input - A function that returns an option builder, or an already built builder + * @param input - A function that returns an option builder or an already built builder */ public addNumberOption( input: @@ -136,6 +141,13 @@ export class SharedSlashCommandOptions { return this._sharedAddOptionMethod(input, SlashCommandNumberOption); } + /** + * Where the actual adding magic happens. ✨ + * + * @param input - The input. What else? + * @param Instance - The instance of whatever is being added + * @internal + */ private _sharedAddOptionMethod( input: | Omit diff --git a/packages/builders/src/interactions/slashCommands/options/attachment.ts b/packages/builders/src/interactions/slashCommands/options/attachment.ts index 006911033..cb31812f1 100644 --- a/packages/builders/src/interactions/slashCommands/options/attachment.ts +++ b/packages/builders/src/interactions/slashCommands/options/attachment.ts @@ -1,9 +1,18 @@ import { ApplicationCommandOptionType, type APIApplicationCommandAttachmentOption } from 'discord-api-types/v10'; import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js'; +/** + * A slash command attachment option. + */ export class SlashCommandAttachmentOption extends ApplicationCommandOptionBase { + /** + * The type of this option. + */ public override readonly type = ApplicationCommandOptionType.Attachment as const; + /** + * {@inheritDoc ApplicationCommandOptionBase.toJSON} + */ public toJSON(): APIApplicationCommandAttachmentOption { this.runRequiredValidations(); diff --git a/packages/builders/src/interactions/slashCommands/options/boolean.ts b/packages/builders/src/interactions/slashCommands/options/boolean.ts index f2c9768ba..5d82ea77c 100644 --- a/packages/builders/src/interactions/slashCommands/options/boolean.ts +++ b/packages/builders/src/interactions/slashCommands/options/boolean.ts @@ -1,9 +1,18 @@ import { ApplicationCommandOptionType, type APIApplicationCommandBooleanOption } from 'discord-api-types/v10'; import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js'; +/** + * A slash command boolean option. + */ export class SlashCommandBooleanOption extends ApplicationCommandOptionBase { + /** + * The type of this option. + */ public readonly type = ApplicationCommandOptionType.Boolean as const; + /** + * {@inheritDoc ApplicationCommandOptionBase.toJSON} + */ public toJSON(): APIApplicationCommandBooleanOption { this.runRequiredValidations(); diff --git a/packages/builders/src/interactions/slashCommands/options/channel.ts b/packages/builders/src/interactions/slashCommands/options/channel.ts index e3dac0aa6..89400820c 100644 --- a/packages/builders/src/interactions/slashCommands/options/channel.ts +++ b/packages/builders/src/interactions/slashCommands/options/channel.ts @@ -3,10 +3,19 @@ import { mix } from 'ts-mixer'; import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js'; import { ApplicationCommandOptionChannelTypesMixin } from '../mixins/ApplicationCommandOptionChannelTypesMixin.js'; +/** + * A slash command channel option. + */ @mix(ApplicationCommandOptionChannelTypesMixin) export class SlashCommandChannelOption extends ApplicationCommandOptionBase { + /** + * The type of this option. + */ public override readonly type = ApplicationCommandOptionType.Channel as const; + /** + * {@inheritDoc ApplicationCommandOptionBase.toJSON} + */ public toJSON(): APIApplicationCommandChannelOption { this.runRequiredValidations(); diff --git a/packages/builders/src/interactions/slashCommands/options/integer.ts b/packages/builders/src/interactions/slashCommands/options/integer.ts index e8a98f4c4..c51542c70 100644 --- a/packages/builders/src/interactions/slashCommands/options/integer.ts +++ b/packages/builders/src/interactions/slashCommands/options/integer.ts @@ -7,11 +7,17 @@ import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixi const numberValidator = s.number.int; +/** + * A slash command integer option. + */ @mix(ApplicationCommandNumericOptionMinMaxValueMixin, ApplicationCommandOptionWithChoicesAndAutocompleteMixin) export class SlashCommandIntegerOption extends ApplicationCommandOptionBase implements ApplicationCommandNumericOptionMinMaxValueMixin { + /** + * The type of this option. + */ public readonly type = ApplicationCommandOptionType.Integer as const; /** @@ -36,6 +42,9 @@ export class SlashCommandIntegerOption return this; } + /** + * {@inheritDoc ApplicationCommandOptionBase.toJSON} + */ public toJSON(): APIApplicationCommandIntegerOption { this.runRequiredValidations(); diff --git a/packages/builders/src/interactions/slashCommands/options/mentionable.ts b/packages/builders/src/interactions/slashCommands/options/mentionable.ts index 91a0416df..56292f612 100644 --- a/packages/builders/src/interactions/slashCommands/options/mentionable.ts +++ b/packages/builders/src/interactions/slashCommands/options/mentionable.ts @@ -1,9 +1,18 @@ import { ApplicationCommandOptionType, type APIApplicationCommandMentionableOption } from 'discord-api-types/v10'; import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js'; +/** + * A slash command mentionable option. + */ export class SlashCommandMentionableOption extends ApplicationCommandOptionBase { + /** + * The type of this option. + */ public readonly type = ApplicationCommandOptionType.Mentionable as const; + /** + * {@inheritDoc ApplicationCommandOptionBase.toJSON} + */ public toJSON(): APIApplicationCommandMentionableOption { this.runRequiredValidations(); diff --git a/packages/builders/src/interactions/slashCommands/options/number.ts b/packages/builders/src/interactions/slashCommands/options/number.ts index 80b5cd6e5..040ed97da 100644 --- a/packages/builders/src/interactions/slashCommands/options/number.ts +++ b/packages/builders/src/interactions/slashCommands/options/number.ts @@ -7,11 +7,17 @@ import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixi const numberValidator = s.number; +/** + * A slash command number option. + */ @mix(ApplicationCommandNumericOptionMinMaxValueMixin, ApplicationCommandOptionWithChoicesAndAutocompleteMixin) export class SlashCommandNumberOption extends ApplicationCommandOptionBase implements ApplicationCommandNumericOptionMinMaxValueMixin { + /** + * The type of this option. + */ public readonly type = ApplicationCommandOptionType.Number as const; /** @@ -36,6 +42,9 @@ export class SlashCommandNumberOption return this; } + /** + * {@inheritDoc ApplicationCommandOptionBase.toJSON} + */ public toJSON(): APIApplicationCommandNumberOption { this.runRequiredValidations(); diff --git a/packages/builders/src/interactions/slashCommands/options/role.ts b/packages/builders/src/interactions/slashCommands/options/role.ts index 4f5871d56..8dca05d0a 100644 --- a/packages/builders/src/interactions/slashCommands/options/role.ts +++ b/packages/builders/src/interactions/slashCommands/options/role.ts @@ -1,9 +1,18 @@ import { ApplicationCommandOptionType, type APIApplicationCommandRoleOption } from 'discord-api-types/v10'; import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js'; +/** + * A slash command role option. + */ export class SlashCommandRoleOption extends ApplicationCommandOptionBase { + /** + * The type of this option. + */ public override readonly type = ApplicationCommandOptionType.Role as const; + /** + * {@inheritDoc ApplicationCommandOptionBase.toJSON} + */ public toJSON(): APIApplicationCommandRoleOption { this.runRequiredValidations(); diff --git a/packages/builders/src/interactions/slashCommands/options/string.ts b/packages/builders/src/interactions/slashCommands/options/string.ts index 345b7934a..2136d74bf 100644 --- a/packages/builders/src/interactions/slashCommands/options/string.ts +++ b/packages/builders/src/interactions/slashCommands/options/string.ts @@ -7,12 +7,24 @@ import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixi const minLengthValidator = s.number.greaterThanOrEqual(0).lessThanOrEqual(6_000); const maxLengthValidator = s.number.greaterThanOrEqual(1).lessThanOrEqual(6_000); +/** + * A slash command string option. + */ @mix(ApplicationCommandOptionWithChoicesAndAutocompleteMixin) export class SlashCommandStringOption extends ApplicationCommandOptionBase { + /** + * The type of this option. + */ public readonly type = ApplicationCommandOptionType.String as const; + /** + * The maximum length of this option. + */ public readonly max_length?: number; + /** + * The minimum length of this option. + */ public readonly min_length?: number; /** @@ -41,6 +53,9 @@ export class SlashCommandStringOption extends ApplicationCommandOptionBase { return this; } + /** + * {@inheritDoc ApplicationCommandOptionBase.toJSON} + */ public toJSON(): APIApplicationCommandStringOption { this.runRequiredValidations(); diff --git a/packages/builders/src/interactions/slashCommands/options/user.ts b/packages/builders/src/interactions/slashCommands/options/user.ts index 609450fa5..471faf96c 100644 --- a/packages/builders/src/interactions/slashCommands/options/user.ts +++ b/packages/builders/src/interactions/slashCommands/options/user.ts @@ -1,9 +1,18 @@ import { ApplicationCommandOptionType, type APIApplicationCommandUserOption } from 'discord-api-types/v10'; import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js'; +/** + * A slash command user option. + */ export class SlashCommandUserOption extends ApplicationCommandOptionBase { + /** + * The type of this option. + */ public readonly type = ApplicationCommandOptionType.User as const; + /** + * {@inheritDoc ApplicationCommandOptionBase.toJSON} + */ public toJSON(): APIApplicationCommandUserOption { this.runRequiredValidations(); diff --git a/packages/builders/src/messages/embed/Embed.ts b/packages/builders/src/messages/embed/Embed.ts index de7742d33..ab3474b12 100644 --- a/packages/builders/src/messages/embed/Embed.ts +++ b/packages/builders/src/messages/embed/Embed.ts @@ -13,59 +13,91 @@ import { validateFieldLength, } from './Assertions.js'; +/** + * A tuple satisfying the RGB color model. + * + * @see {@link https://developer.mozilla.org/docs/Glossary/RGB} + */ export type RGBTuple = [red: number, green: number, blue: number]; +/** + * The base icon data typically used in payloads. + */ export interface IconData { /** - * The URL of the icon + * The URL of the icon. */ iconURL?: string; /** - * The proxy URL of the icon + * The proxy URL of the icon. */ proxyIconURL?: string; } +/** + * Represents the author data of an embed. + */ export type EmbedAuthorData = IconData & Omit; +/** + * Represents the author options of an embed. + */ export type EmbedAuthorOptions = Omit; +/** + * Represents the footer data of an embed. + */ export type EmbedFooterData = IconData & Omit; +/** + * Represents the footer options of an embed. + */ export type EmbedFooterOptions = Omit; +/** + * Represents the image data of an embed. + */ export interface EmbedImageData extends Omit { /** - * The proxy URL for the image + * The proxy URL for the image. */ proxyURL?: string; } + /** - * Represents a embed in a message (image/video preview, rich embed, etc.) + * A builder that creates API-compatible JSON data for embeds. */ export class EmbedBuilder { + /** + * The API data associated with this embed. + */ public readonly data: APIEmbed; + /** + * Creates a new embed from API data. + * + * @param data - The API data to create this embed with + */ public constructor(data: APIEmbed = {}) { this.data = { ...data }; if (data.timestamp) this.data.timestamp = new Date(data.timestamp).toISOString(); } /** - * Appends fields to the embed + * Appends fields to the embed. * * @remarks * This method accepts either an array of fields or a variable number of field parameters. * The maximum amount of fields that can be added is 25. * @example - * Using an array + * Using an array: * ```ts * const fields: APIEmbedField[] = ...; * const embed = new EmbedBuilder() * .addFields(fields); * ``` * @example - * Using rest parameters (variadic) + * Using rest parameters (variadic): * ```ts * const embed = new EmbedBuilder() * .addFields( @@ -76,21 +108,20 @@ export class EmbedBuilder { * @param fields - The fields to add */ public addFields(...fields: RestOrArray): this { - // eslint-disable-next-line no-param-reassign - fields = normalizeArray(fields); + const normalizedFields = normalizeArray(fields); // Ensure adding these fields won't exceed the 25 field limit - validateFieldLength(fields.length, this.data.fields); + validateFieldLength(normalizedFields.length, this.data.fields); // Data assertions - embedFieldsArrayPredicate.parse(fields); + embedFieldsArrayPredicate.parse(normalizedFields); - if (this.data.fields) this.data.fields.push(...fields); - else this.data.fields = fields; + if (this.data.fields) this.data.fields.push(...normalizedFields); + else this.data.fields = normalizedFields; return this; } /** - * Removes, replaces, or inserts fields in the embed. + * Removes, replaces, or inserts fields for this embed. * * @remarks * This method behaves similarly @@ -99,18 +130,18 @@ export class EmbedBuilder { * * It's useful for modifying and adjusting order of the already-existing fields of an embed. * @example - * Remove the first field + * Remove the first field: * ```ts * embed.spliceFields(0, 1); * ``` * @example - * Remove the first n fields + * Remove the first n fields: * ```ts - * const n = 4 + * const n = 4; * embed.spliceFields(0, n); * ``` * @example - * Remove the last field + * Remove the last field: * ```ts * embed.spliceFields(-1, 1); * ``` @@ -130,7 +161,7 @@ export class EmbedBuilder { } /** - * Sets the embed's fields + * Sets the fields for this embed. * * @remarks * This method is an alias for {@link EmbedBuilder.spliceFields}. More specifically, @@ -145,9 +176,9 @@ export class EmbedBuilder { } /** - * Sets the author of this embed + * Sets the author of this embed. * - * @param options - The options for the author + * @param options - The options to use */ public setAuthor(options: EmbedAuthorOptions | null): this { @@ -164,9 +195,9 @@ export class EmbedBuilder { } /** - * Sets the color of this embed + * Sets the color of this embed. * - * @param color - The color of the embed + * @param color - The color to use */ public setColor(color: RGBTuple | number | null): this { // Data assertions @@ -183,9 +214,9 @@ export class EmbedBuilder { } /** - * Sets the description of this embed + * Sets the description of this embed. * - * @param description - The description + * @param description - The description to use */ public setDescription(description: string | null): this { // Data assertions @@ -196,9 +227,9 @@ export class EmbedBuilder { } /** - * Sets the footer of this embed + * Sets the footer of this embed. * - * @param options - The options for the footer + * @param options - The footer to use */ public setFooter(options: EmbedFooterOptions | null): this { if (options === null) { @@ -214,9 +245,9 @@ export class EmbedBuilder { } /** - * Sets the image of this embed + * Sets the image of this embed. * - * @param url - The URL of the image + * @param url - The image URL to use */ public setImage(url: string | null): this { // Data assertions @@ -227,9 +258,9 @@ export class EmbedBuilder { } /** - * Sets the thumbnail of this embed + * Sets the thumbnail of this embed. * - * @param url - The URL of the thumbnail + * @param url - The thumbnail URL to use */ public setThumbnail(url: string | null): this { // Data assertions @@ -240,9 +271,9 @@ export class EmbedBuilder { } /** - * Sets the timestamp of this embed + * Sets the timestamp of this embed. * - * @param timestamp - The timestamp or date + * @param timestamp - The timestamp or date to use */ public setTimestamp(timestamp: Date | number | null = Date.now()): this { // Data assertions @@ -253,9 +284,9 @@ export class EmbedBuilder { } /** - * Sets the title of this embed + * Sets the title for this embed. * - * @param title - The title + * @param title - The title to use */ public setTitle(title: string | null): this { // Data assertions @@ -266,9 +297,9 @@ export class EmbedBuilder { } /** - * Sets the URL of this embed + * Sets the URL of this embed. * - * @param url - The URL + * @param url - The URL to use */ public setURL(url: string | null): this { // Data assertions @@ -279,7 +310,11 @@ export class EmbedBuilder { } /** - * Transforms the embed to a plain object + * Serializes this builder to API-compatible JSON data. + * + * @remarks + * This method runs validations on the data before serializing it. + * As such, it may throw an error if the data is invalid. */ public toJSON(): APIEmbed { return { ...this.data }; diff --git a/packages/builders/src/util/componentUtil.ts b/packages/builders/src/util/componentUtil.ts index 06ec6bf8c..f2439fb99 100644 --- a/packages/builders/src/util/componentUtil.ts +++ b/packages/builders/src/util/componentUtil.ts @@ -1,5 +1,10 @@ import type { APIEmbed } from 'discord-api-types/v10'; +/** + * Calculates the length of the embed. + * + * @param data - The embed data to check + */ export function embedLength(data: APIEmbed) { return ( (data.title?.length ?? 0) + diff --git a/packages/builders/src/util/normalizeArray.ts b/packages/builders/src/util/normalizeArray.ts index 2fda6fbdf..bf31830a3 100644 --- a/packages/builders/src/util/normalizeArray.ts +++ b/packages/builders/src/util/normalizeArray.ts @@ -1,6 +1,19 @@ +/** + * Normalizes data that is a rest parameter or an array into an array with a depth of 1. + * + * @typeParam T - The data that must satisfy {@link RestOrArray}. + * @param arr - The (possibly variadic) data to normalize + */ export function normalizeArray(arr: RestOrArray): T[] { if (Array.isArray(arr[0])) return arr[0]; return arr as T[]; } +/** + * Represents data that may be an array or came from a rest parameter. + * + * @remarks + * This type is used throughout builders to ensure both an array and variadic arguments + * may be used. It is normalized with {@link normalizeArray}. + */ export type RestOrArray = T[] | [T[]]; diff --git a/packages/builders/src/util/validation.ts b/packages/builders/src/util/validation.ts index c2830f999..37e5c224b 100644 --- a/packages/builders/src/util/validation.ts +++ b/packages/builders/src/util/validation.ts @@ -1,5 +1,26 @@ let validate = true; -export const enableValidators = () => (validate = true); -export const disableValidators = () => (validate = false); -export const isValidationEnabled = () => validate; +/** + * Enables validators. + * + * @returns Whether validation is occurring. + */ +export function enableValidators() { + return (validate = true); +} + +/** + * Disables validators. + * + * @returns Whether validation is occurring. + */ +export function disableValidators() { + return (validate = false); +} + +/** + * Checks whether validation is occurring. + */ +export function isValidationEnabled() { + return validate; +}