Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: default select menu values #9867

Merged
merged 12 commits into from
Nov 12, 2023
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import type { APIChannelSelectComponent, ChannelType } from 'discord-api-types/v10';
import { ComponentType } from 'discord-api-types/v10';
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
import { channelTypesValidator, customIdValidator } from '../Assertions.js';
import {
type APIChannelSelectComponent,
type ChannelType,
type Snowflake,
ComponentType,
SelectMenuDefaultValueType,
} from 'discord-api-types/v10';
import { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';
import { channelTypesValidator, customIdValidator, optionsLengthValidator } from '../Assertions.js';
import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';

/**
Expand Down Expand Up @@ -59,6 +64,43 @@ export class ChannelSelectMenuBuilder extends BaseSelectMenuBuilder<APIChannelSe
return this;
}

/**
* Adds default channels to this auto populated select menu.
*
* @param channels - The channels to add
*/
public addDefaultChannels(...channels: RestOrArray<Snowflake>) {
const normalizedValues = normalizeArray(channels);
optionsLengthValidator.parse((this.data.default_values?.length ?? 0) + normalizedValues.length);
this.data.default_values ??= [];

this.data.default_values.push(
...normalizedValues.map((id) => ({
id,
type: SelectMenuDefaultValueType.Channel as const,
})),
);

return this;
}

/**
* Sets default channels to this auto populated select menu.
*
* @param channels - The channels to set
*/
public setDefaultChannels(...channels: RestOrArray<Snowflake>) {
const normalizedValues = normalizeArray(channels);
optionsLengthValidator.parse(normalizedValues.length);

this.data.default_values = normalizedValues.map((id) => ({
id,
type: SelectMenuDefaultValueType.Channel as const,
}));

return this;
}

/**
* {@inheritDoc BaseSelectMenuBuilder.toJSON}
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import type { APIMentionableSelectComponent } from 'discord-api-types/v10';
import { ComponentType } from 'discord-api-types/v10';
import {
type APIMentionableSelectComponent,
type APISelectMenuDefaultValue,
type Snowflake,
ComponentType,
SelectMenuDefaultValueType,
} from 'discord-api-types/v10';
import { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';
import { optionsLengthValidator } from '../Assertions.js';
import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';

/**
Expand Down Expand Up @@ -31,4 +38,79 @@ export class MentionableSelectMenuBuilder extends BaseSelectMenuBuilder<APIMenti
public constructor(data?: Partial<APIMentionableSelectComponent>) {
super({ ...data, type: ComponentType.MentionableSelect });
}

/**
* Adds default roles to this auto populated select menu.
*
* @param roles - The roles to add
*/
public addDefaultRoles(...roles: RestOrArray<Snowflake>) {
const normalizedValues = normalizeArray(roles);
optionsLengthValidator.parse((this.data.default_values?.length ?? 0) + normalizedValues.length);
this.data.default_values ??= [];

this.data.default_values.push(
...normalizedValues.map((id) => ({
id,
type: SelectMenuDefaultValueType.Role as const,
})),
);

return this;
}

/**
* Adds default users to this auto populated select menu.
*
* @param users - The users to add
*/
public addDefaultUsers(...users: RestOrArray<Snowflake>) {
const normalizedValues = normalizeArray(users);
optionsLengthValidator.parse((this.data.default_values?.length ?? 0) + normalizedValues.length);
this.data.default_values ??= [];

this.data.default_values.push(
...normalizedValues.map((id) => ({
id,
type: SelectMenuDefaultValueType.User as const,
})),
);

return this;
}

/**
* Adds default values to this auto populated select menu.
*
* @param values - The values to add
*/
public addDefaultValues(
...values: RestOrArray<
| APISelectMenuDefaultValue<SelectMenuDefaultValueType.Role>
| APISelectMenuDefaultValue<SelectMenuDefaultValueType.User>
>
) {
const normalizedValues = normalizeArray(values);
optionsLengthValidator.parse((this.data.default_values?.length ?? 0) + normalizedValues.length);
this.data.default_values ??= [];
this.data.default_values.push(...normalizedValues);
return this;
}

/**
* Sets default values to this auto populated select menu.
*
* @param values - The values to set
*/
public setDefaultValues(
Jiralite marked this conversation as resolved.
Show resolved Hide resolved
...values: RestOrArray<
| APISelectMenuDefaultValue<SelectMenuDefaultValueType.Role>
| APISelectMenuDefaultValue<SelectMenuDefaultValueType.User>
>
) {
const normalizedValues = normalizeArray(values);
optionsLengthValidator.parse(normalizedValues.length);
this.data.default_values = normalizedValues.slice();
return this;
}
}
47 changes: 45 additions & 2 deletions packages/builders/src/components/selectMenu/RoleSelectMenu.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import type { APIRoleSelectComponent } from 'discord-api-types/v10';
import { ComponentType } from 'discord-api-types/v10';
import {
type APIRoleSelectComponent,
type Snowflake,
ComponentType,
SelectMenuDefaultValueType,
} from 'discord-api-types/v10';
import { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';
import { optionsLengthValidator } from '../Assertions.js';
import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';

/**
Expand Down Expand Up @@ -31,4 +37,41 @@ export class RoleSelectMenuBuilder extends BaseSelectMenuBuilder<APIRoleSelectCo
public constructor(data?: Partial<APIRoleSelectComponent>) {
super({ ...data, type: ComponentType.RoleSelect });
}

/**
* Adds default roles to this auto populated select menu.
*
* @param roles - The roles to add
*/
public addDefaultRoles(...roles: RestOrArray<Snowflake>) {
const normalizedValues = normalizeArray(roles);
optionsLengthValidator.parse((this.data.default_values?.length ?? 0) + normalizedValues.length);
this.data.default_values ??= [];

this.data.default_values.push(
...normalizedValues.map((id) => ({
id,
type: SelectMenuDefaultValueType.Role as const,
})),
);

return this;
}

/**
* Sets default roles to this auto populated select menu.
*
* @param roles - The roles to set
*/
public setDefaultRoles(...roles: RestOrArray<Snowflake>) {
const normalizedValues = normalizeArray(roles);
optionsLengthValidator.parse(normalizedValues.length);

this.data.default_values = normalizedValues.map((id) => ({
id,
type: SelectMenuDefaultValueType.Role as const,
}));

return this;
}
}
47 changes: 45 additions & 2 deletions packages/builders/src/components/selectMenu/UserSelectMenu.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import type { APIUserSelectComponent } from 'discord-api-types/v10';
import { ComponentType } from 'discord-api-types/v10';
import {
type APIUserSelectComponent,
type Snowflake,
ComponentType,
SelectMenuDefaultValueType,
} from 'discord-api-types/v10';
import { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';
import { optionsLengthValidator } from '../Assertions.js';
import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';

/**
Expand Down Expand Up @@ -31,4 +37,41 @@ export class UserSelectMenuBuilder extends BaseSelectMenuBuilder<APIUserSelectCo
public constructor(data?: Partial<APIUserSelectComponent>) {
super({ ...data, type: ComponentType.UserSelect });
}

/**
* Adds default users to this auto populated select menu.
*
* @param users - The users to add
*/
public addDefaultUsers(...users: RestOrArray<Snowflake>) {
const normalizedValues = normalizeArray(users);
optionsLengthValidator.parse((this.data.default_values?.length ?? 0) + normalizedValues.length);
this.data.default_values ??= [];

this.data.default_values.push(
...normalizedValues.map((id) => ({
id,
type: SelectMenuDefaultValueType.User as const,
})),
);

return this;
}

/**
* Sets default users to this auto populated select menu.
*
* @param users - The users to set
*/
public setDefaultUsers(...users: RestOrArray<Snowflake>) {
const normalizedValues = normalizeArray(users);
optionsLengthValidator.parse(normalizedValues.length);

this.data.default_values = normalizedValues.map((id) => ({
id,
type: SelectMenuDefaultValueType.User as const,
}));

return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const CommandInteraction = require('./CommandInteraction');
const CommandInteractionOptionResolver = require('./CommandInteractionOptionResolver');
const { transformResolved } = require('../util/Util');

/**
* Represents a command interaction.
Expand All @@ -18,7 +19,7 @@ class ChatInputCommandInteraction extends CommandInteraction {
this.options = new CommandInteractionOptionResolver(
this.client,
data.data.options?.map(option => this.transformOption(option, data.data.resolved)) ?? [],
this.transformResolved(data.data.resolved ?? {}),
transformResolved({ client: this.client, guild: this.guild, channel: this.channel }, data.data.resolved),
);
}

Expand Down
57 changes: 0 additions & 57 deletions packages/discord.js/src/structures/CommandInteraction.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use strict';

const { Collection } = require('@discordjs/collection');
const Attachment = require('./Attachment');
const BaseInteraction = require('./BaseInteraction');
const InteractionWebhook = require('./InteractionWebhook');
Expand Down Expand Up @@ -91,62 +90,6 @@ class CommandInteraction extends BaseInteraction {
* @property {Collection<Snowflake, Attachment>} [attachments] The resolved attachments
*/

/**
* Transforms the resolved received from the API.
* @param {APIInteractionDataResolved} resolved The received resolved objects
* @returns {CommandInteractionResolvedData}
* @private
*/
transformResolved({ members, users, channels, roles, messages, attachments }) {
const result = {};

if (members) {
result.members = new Collection();
for (const [id, member] of Object.entries(members)) {
const user = users[id];
result.members.set(id, this.guild?.members._add({ user, ...member }) ?? member);
}
}

if (users) {
result.users = new Collection();
for (const user of Object.values(users)) {
result.users.set(user.id, this.client.users._add(user));
}
}

if (roles) {
result.roles = new Collection();
for (const role of Object.values(roles)) {
result.roles.set(role.id, this.guild?.roles._add(role) ?? role);
}
}

if (channels) {
result.channels = new Collection();
for (const channel of Object.values(channels)) {
result.channels.set(channel.id, this.client.channels._add(channel, this.guild) ?? channel);
}
}

if (messages) {
result.messages = new Collection();
for (const message of Object.values(messages)) {
result.messages.set(message.id, this.channel?.messages?._add(message) ?? message);
}
}

if (attachments) {
result.attachments = new Collection();
for (const attachment of Object.values(attachments)) {
const patched = new Attachment(attachment);
result.attachments.set(attachment.id, patched);
}
}

return result;
}

/**
* Represents an option of a received command interaction.
* @typedef {Object} CommandInteractionOption
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { lazy } = require('@discordjs/util');
const { ApplicationCommandOptionType } = require('discord-api-types/v10');
const CommandInteraction = require('./CommandInteraction');
const CommandInteractionOptionResolver = require('./CommandInteractionOptionResolver');
const { transformResolved } = require('../util/Util');

const getMessage = lazy(() => require('./Message').Message);

Expand All @@ -21,7 +22,7 @@ class ContextMenuCommandInteraction extends CommandInteraction {
this.options = new CommandInteractionOptionResolver(
this.client,
this.resolveContextMenuOptions(data.data),
this.transformResolved(data.data.resolved),
transformResolved({ client: this.client, guild: this.guild, channel: this.channel }, data.data.resolved),
);

/**
Expand Down
Loading