mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-18 04:23:31 +01:00
feat: allow builders to accept rest params and arrays (#7874)
Co-authored-by: Parbez <imranbarbhuiya.fsd@gmail.com> Co-authored-by: Khafra <42794878+KhafraDev@users.noreply.github.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
import { ComponentBuilder } from './Component';
|
||||
import { createComponentBuilder } from './Components';
|
||||
import type { ButtonBuilder, SelectMenuBuilder, TextInputBuilder } from '..';
|
||||
import { normalizeArray, type RestOrArray } from '../util/normalizeArray';
|
||||
|
||||
export type MessageComponentBuilder =
|
||||
| MessageActionRowComponentBuilder
|
||||
@@ -38,8 +39,8 @@ export class ActionRowBuilder<T extends AnyComponentBuilder> extends ComponentBu
|
||||
* @param components The components to add to this action row.
|
||||
* @returns
|
||||
*/
|
||||
public addComponents(components: T[]) {
|
||||
this.components.push(...components);
|
||||
public addComponents(...components: RestOrArray<T>) {
|
||||
this.components.push(...normalizeArray(components));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -47,8 +48,8 @@ export class ActionRowBuilder<T extends AnyComponentBuilder> extends ComponentBu
|
||||
* Sets the components in this action row
|
||||
* @param components The components to set this row to
|
||||
*/
|
||||
public setComponents(components: T[]) {
|
||||
this.components.splice(0, this.components.length, ...components);
|
||||
public setComponents(...components: RestOrArray<T>) {
|
||||
this.components.splice(0, this.components.length, ...normalizeArray(components));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { APISelectMenuComponent, APISelectMenuOption } from 'discord-api-types/v10';
|
||||
import { UnsafeSelectMenuBuilder } from './UnsafeSelectMenu';
|
||||
import { UnsafeSelectMenuOptionBuilder } from './UnsafeSelectMenuOption';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
import {
|
||||
customIdValidator,
|
||||
disabledValidator,
|
||||
@@ -35,7 +36,8 @@ export class SelectMenuBuilder extends UnsafeSelectMenuBuilder {
|
||||
return super.setDisabled(disabledValidator.parse(disabled));
|
||||
}
|
||||
|
||||
public override addOptions(options: (UnsafeSelectMenuOptionBuilder | APISelectMenuOption)[]) {
|
||||
public override addOptions(...options: RestOrArray<UnsafeSelectMenuOptionBuilder | APISelectMenuOption>) {
|
||||
options = normalizeArray(options);
|
||||
optionsLengthValidator.parse(this.options.length + options.length);
|
||||
this.options.push(
|
||||
...options.map((option) =>
|
||||
@@ -47,7 +49,8 @@ export class SelectMenuBuilder extends UnsafeSelectMenuBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public override setOptions(options: (UnsafeSelectMenuOptionBuilder | APISelectMenuOption)[]) {
|
||||
public override setOptions(...options: RestOrArray<UnsafeSelectMenuOptionBuilder | APISelectMenuOption>) {
|
||||
options = normalizeArray(options);
|
||||
optionsLengthValidator.parse(options.length);
|
||||
this.options.splice(
|
||||
0,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { APISelectMenuOption, ComponentType, type APISelectMenuComponent } from 'discord-api-types/v10';
|
||||
import { UnsafeSelectMenuOptionBuilder } from './UnsafeSelectMenuOption';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
import { ComponentBuilder } from '../Component';
|
||||
|
||||
/**
|
||||
@@ -67,9 +68,9 @@ export class UnsafeSelectMenuBuilder extends ComponentBuilder<APISelectMenuCompo
|
||||
* @param options The options to add to this select menu
|
||||
* @returns
|
||||
*/
|
||||
public addOptions(options: (UnsafeSelectMenuOptionBuilder | APISelectMenuOption)[]) {
|
||||
public addOptions(...options: RestOrArray<UnsafeSelectMenuOptionBuilder | APISelectMenuOption>) {
|
||||
this.options.push(
|
||||
...options.map((option) =>
|
||||
...normalizeArray(options).map((option) =>
|
||||
option instanceof UnsafeSelectMenuOptionBuilder ? option : new UnsafeSelectMenuOptionBuilder(option),
|
||||
),
|
||||
);
|
||||
@@ -80,11 +81,11 @@ export class UnsafeSelectMenuBuilder extends ComponentBuilder<APISelectMenuCompo
|
||||
* Sets the options on this select menu
|
||||
* @param options The options to set on this select menu
|
||||
*/
|
||||
public setOptions(options: (UnsafeSelectMenuOptionBuilder | APISelectMenuOption)[]) {
|
||||
public setOptions(...options: RestOrArray<UnsafeSelectMenuOptionBuilder | APISelectMenuOption>) {
|
||||
this.options.splice(
|
||||
0,
|
||||
this.options.length,
|
||||
...options.map((option) =>
|
||||
...normalizeArray(options).map((option) =>
|
||||
option instanceof UnsafeSelectMenuOptionBuilder ? option : new UnsafeSelectMenuOptionBuilder(option),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -45,3 +45,4 @@ export * from './interactions/contextMenuCommands/ContextMenuCommandBuilder';
|
||||
export * from './util/jsonEncodable';
|
||||
export * from './util/equatable';
|
||||
export * from './util/componentUtil';
|
||||
export * from './util/normalizeArray';
|
||||
|
||||
@@ -4,6 +4,7 @@ import type {
|
||||
APIModalInteractionResponseCallbackData,
|
||||
} from 'discord-api-types/v10';
|
||||
import { ActionRowBuilder, createComponentBuilder, JSONEncodable, ModalActionRowComponentBuilder } from '../../index';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
|
||||
export class UnsafeModalBuilder implements JSONEncodable<APIModalInteractionResponseCallbackData> {
|
||||
public readonly data: Partial<APIModalInteractionResponseCallbackData>;
|
||||
@@ -38,13 +39,12 @@ export class UnsafeModalBuilder implements JSONEncodable<APIModalInteractionResp
|
||||
* @param components The components to add to this modal
|
||||
*/
|
||||
public addComponents(
|
||||
components: (
|
||||
| ActionRowBuilder<ModalActionRowComponentBuilder>
|
||||
| APIActionRowComponent<APIModalActionRowComponent>
|
||||
)[],
|
||||
...components: RestOrArray<
|
||||
ActionRowBuilder<ModalActionRowComponentBuilder> | APIActionRowComponent<APIModalActionRowComponent>
|
||||
>
|
||||
) {
|
||||
this.components.push(
|
||||
...components.map((component) =>
|
||||
...normalizeArray(components).map((component) =>
|
||||
component instanceof ActionRowBuilder
|
||||
? component
|
||||
: new ActionRowBuilder<ModalActionRowComponentBuilder>(component),
|
||||
@@ -57,8 +57,8 @@ export class UnsafeModalBuilder implements JSONEncodable<APIModalInteractionResp
|
||||
* Sets the components in this modal
|
||||
* @param components The components to set this modal to
|
||||
*/
|
||||
public setComponents(components: ActionRowBuilder<ModalActionRowComponentBuilder>[]) {
|
||||
this.components.splice(0, this.components.length, ...components);
|
||||
public setComponents(...components: RestOrArray<ActionRowBuilder<ModalActionRowComponentBuilder>>) {
|
||||
this.components.splice(0, this.components.length, ...normalizeArray(components));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,17 +12,19 @@ import {
|
||||
validateFieldLength,
|
||||
} from './Assertions';
|
||||
import { EmbedAuthorOptions, EmbedFooterOptions, RGBTuple, UnsafeEmbedBuilder } from './UnsafeEmbed';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
|
||||
/**
|
||||
* Represents a validated embed in a message (image/video preview, rich embed, etc.)
|
||||
*/
|
||||
export class EmbedBuilder extends UnsafeEmbedBuilder {
|
||||
public override addFields(fields: APIEmbedField[]): this {
|
||||
public override addFields(...fields: RestOrArray<APIEmbedField>): this {
|
||||
fields = normalizeArray(fields);
|
||||
// Ensure adding these fields won't exceed the 25 field limit
|
||||
validateFieldLength(fields.length, this.data.fields);
|
||||
|
||||
// Data assertions
|
||||
return super.addFields(embedFieldsArrayPredicate.parse(fields));
|
||||
return super.addFields(...embedFieldsArrayPredicate.parse(fields));
|
||||
}
|
||||
|
||||
public override spliceFields(index: number, deleteCount: number, ...fields: APIEmbedField[]): this {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { APIEmbed, APIEmbedAuthor, APIEmbedField, APIEmbedFooter, APIEmbedImage } from 'discord-api-types/v10';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
|
||||
export type RGBTuple = [red: number, green: number, blue: number];
|
||||
|
||||
@@ -44,7 +45,8 @@ export class UnsafeEmbedBuilder {
|
||||
*
|
||||
* @param fields The fields to add
|
||||
*/
|
||||
public addFields(fields: APIEmbedField[]): this {
|
||||
public addFields(...fields: RestOrArray<APIEmbedField>): this {
|
||||
fields = normalizeArray(fields);
|
||||
if (this.data.fields) this.data.fields.push(...fields);
|
||||
else this.data.fields = fields;
|
||||
return this;
|
||||
@@ -67,8 +69,8 @@ export class UnsafeEmbedBuilder {
|
||||
* Sets the embed's fields (max 25).
|
||||
* @param fields The fields to set
|
||||
*/
|
||||
public setFields(fields: APIEmbedField[]) {
|
||||
this.spliceFields(0, this.data.fields?.length ?? 0, ...fields);
|
||||
public setFields(...fields: RestOrArray<APIEmbedField>) {
|
||||
this.spliceFields(0, this.data.fields?.length ?? 0, ...normalizeArray(fields));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
6
packages/builders/src/util/normalizeArray.ts
Normal file
6
packages/builders/src/util/normalizeArray.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export function normalizeArray<T>(arr: RestOrArray<T>): T[] {
|
||||
if (Array.isArray(arr[0])) return arr[0];
|
||||
return arr as T[];
|
||||
}
|
||||
|
||||
export type RestOrArray<T> = T[] | [T[]];
|
||||
Reference in New Issue
Block a user