Skip to content

Commit 4ff3ea4

Browse files
jaw0r3kJiralite
andauthored
feat: default select menu values (#9867)
* feat: default select menu values * feat(Message): support * fix: fix crashes when an array is supplied and remove assertion * docs(transformResolved): `BaseChannel` is the correct type * refactor: prefer assignment * chore: export function again * fix(Util): fix circular dependency * refactor(MentionableSelectMenu): clone in method * docs: remove semicolon * feat(MentionableSelectMenu): add `addDefaultValues()` * refactor: reduce overhead * types: adjust `channel` --------- Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
1 parent b5e23ec commit 4ff3ea4

File tree

10 files changed

+320
-73
lines changed

10 files changed

+320
-73
lines changed

packages/builders/src/components/selectMenu/ChannelSelectMenu.ts

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
import type { APIChannelSelectComponent, ChannelType } from 'discord-api-types/v10';
2-
import { ComponentType } from 'discord-api-types/v10';
3-
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
4-
import { channelTypesValidator, customIdValidator } from '../Assertions.js';
1+
import {
2+
type APIChannelSelectComponent,
3+
type ChannelType,
4+
type Snowflake,
5+
ComponentType,
6+
SelectMenuDefaultValueType,
7+
} from 'discord-api-types/v10';
8+
import { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';
9+
import { channelTypesValidator, customIdValidator, optionsLengthValidator } from '../Assertions.js';
510
import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';
611

712
/**
@@ -59,6 +64,43 @@ export class ChannelSelectMenuBuilder extends BaseSelectMenuBuilder<APIChannelSe
5964
return this;
6065
}
6166

67+
/**
68+
* Adds default channels to this auto populated select menu.
69+
*
70+
* @param channels - The channels to add
71+
*/
72+
public addDefaultChannels(...channels: RestOrArray<Snowflake>) {
73+
const normalizedValues = normalizeArray(channels);
74+
optionsLengthValidator.parse((this.data.default_values?.length ?? 0) + normalizedValues.length);
75+
this.data.default_values ??= [];
76+
77+
this.data.default_values.push(
78+
...normalizedValues.map((id) => ({
79+
id,
80+
type: SelectMenuDefaultValueType.Channel as const,
81+
})),
82+
);
83+
84+
return this;
85+
}
86+
87+
/**
88+
* Sets default channels to this auto populated select menu.
89+
*
90+
* @param channels - The channels to set
91+
*/
92+
public setDefaultChannels(...channels: RestOrArray<Snowflake>) {
93+
const normalizedValues = normalizeArray(channels);
94+
optionsLengthValidator.parse(normalizedValues.length);
95+
96+
this.data.default_values = normalizedValues.map((id) => ({
97+
id,
98+
type: SelectMenuDefaultValueType.Channel as const,
99+
}));
100+
101+
return this;
102+
}
103+
62104
/**
63105
* {@inheritDoc BaseSelectMenuBuilder.toJSON}
64106
*/

packages/builders/src/components/selectMenu/MentionableSelectMenu.ts

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1-
import type { APIMentionableSelectComponent } from 'discord-api-types/v10';
2-
import { ComponentType } from 'discord-api-types/v10';
1+
import {
2+
type APIMentionableSelectComponent,
3+
type APISelectMenuDefaultValue,
4+
type Snowflake,
5+
ComponentType,
6+
SelectMenuDefaultValueType,
7+
} from 'discord-api-types/v10';
8+
import { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';
9+
import { optionsLengthValidator } from '../Assertions.js';
310
import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';
411

512
/**
@@ -31,4 +38,79 @@ export class MentionableSelectMenuBuilder extends BaseSelectMenuBuilder<APIMenti
3138
public constructor(data?: Partial<APIMentionableSelectComponent>) {
3239
super({ ...data, type: ComponentType.MentionableSelect });
3340
}
41+
42+
/**
43+
* Adds default roles to this auto populated select menu.
44+
*
45+
* @param roles - The roles to add
46+
*/
47+
public addDefaultRoles(...roles: RestOrArray<Snowflake>) {
48+
const normalizedValues = normalizeArray(roles);
49+
optionsLengthValidator.parse((this.data.default_values?.length ?? 0) + normalizedValues.length);
50+
this.data.default_values ??= [];
51+
52+
this.data.default_values.push(
53+
...normalizedValues.map((id) => ({
54+
id,
55+
type: SelectMenuDefaultValueType.Role as const,
56+
})),
57+
);
58+
59+
return this;
60+
}
61+
62+
/**
63+
* Adds default users to this auto populated select menu.
64+
*
65+
* @param users - The users to add
66+
*/
67+
public addDefaultUsers(...users: RestOrArray<Snowflake>) {
68+
const normalizedValues = normalizeArray(users);
69+
optionsLengthValidator.parse((this.data.default_values?.length ?? 0) + normalizedValues.length);
70+
this.data.default_values ??= [];
71+
72+
this.data.default_values.push(
73+
...normalizedValues.map((id) => ({
74+
id,
75+
type: SelectMenuDefaultValueType.User as const,
76+
})),
77+
);
78+
79+
return this;
80+
}
81+
82+
/**
83+
* Adds default values to this auto populated select menu.
84+
*
85+
* @param values - The values to add
86+
*/
87+
public addDefaultValues(
88+
...values: RestOrArray<
89+
| APISelectMenuDefaultValue<SelectMenuDefaultValueType.Role>
90+
| APISelectMenuDefaultValue<SelectMenuDefaultValueType.User>
91+
>
92+
) {
93+
const normalizedValues = normalizeArray(values);
94+
optionsLengthValidator.parse((this.data.default_values?.length ?? 0) + normalizedValues.length);
95+
this.data.default_values ??= [];
96+
this.data.default_values.push(...normalizedValues);
97+
return this;
98+
}
99+
100+
/**
101+
* Sets default values to this auto populated select menu.
102+
*
103+
* @param values - The values to set
104+
*/
105+
public setDefaultValues(
106+
...values: RestOrArray<
107+
| APISelectMenuDefaultValue<SelectMenuDefaultValueType.Role>
108+
| APISelectMenuDefaultValue<SelectMenuDefaultValueType.User>
109+
>
110+
) {
111+
const normalizedValues = normalizeArray(values);
112+
optionsLengthValidator.parse(normalizedValues.length);
113+
this.data.default_values = normalizedValues.slice();
114+
return this;
115+
}
34116
}

packages/builders/src/components/selectMenu/RoleSelectMenu.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
import type { APIRoleSelectComponent } from 'discord-api-types/v10';
2-
import { ComponentType } from 'discord-api-types/v10';
1+
import {
2+
type APIRoleSelectComponent,
3+
type Snowflake,
4+
ComponentType,
5+
SelectMenuDefaultValueType,
6+
} from 'discord-api-types/v10';
7+
import { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';
8+
import { optionsLengthValidator } from '../Assertions.js';
39
import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';
410

511
/**
@@ -31,4 +37,41 @@ export class RoleSelectMenuBuilder extends BaseSelectMenuBuilder<APIRoleSelectCo
3137
public constructor(data?: Partial<APIRoleSelectComponent>) {
3238
super({ ...data, type: ComponentType.RoleSelect });
3339
}
40+
41+
/**
42+
* Adds default roles to this auto populated select menu.
43+
*
44+
* @param roles - The roles to add
45+
*/
46+
public addDefaultRoles(...roles: RestOrArray<Snowflake>) {
47+
const normalizedValues = normalizeArray(roles);
48+
optionsLengthValidator.parse((this.data.default_values?.length ?? 0) + normalizedValues.length);
49+
this.data.default_values ??= [];
50+
51+
this.data.default_values.push(
52+
...normalizedValues.map((id) => ({
53+
id,
54+
type: SelectMenuDefaultValueType.Role as const,
55+
})),
56+
);
57+
58+
return this;
59+
}
60+
61+
/**
62+
* Sets default roles to this auto populated select menu.
63+
*
64+
* @param roles - The roles to set
65+
*/
66+
public setDefaultRoles(...roles: RestOrArray<Snowflake>) {
67+
const normalizedValues = normalizeArray(roles);
68+
optionsLengthValidator.parse(normalizedValues.length);
69+
70+
this.data.default_values = normalizedValues.map((id) => ({
71+
id,
72+
type: SelectMenuDefaultValueType.Role as const,
73+
}));
74+
75+
return this;
76+
}
3477
}

packages/builders/src/components/selectMenu/UserSelectMenu.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
import type { APIUserSelectComponent } from 'discord-api-types/v10';
2-
import { ComponentType } from 'discord-api-types/v10';
1+
import {
2+
type APIUserSelectComponent,
3+
type Snowflake,
4+
ComponentType,
5+
SelectMenuDefaultValueType,
6+
} from 'discord-api-types/v10';
7+
import { type RestOrArray, normalizeArray } from '../../util/normalizeArray.js';
8+
import { optionsLengthValidator } from '../Assertions.js';
39
import { BaseSelectMenuBuilder } from './BaseSelectMenu.js';
410

511
/**
@@ -31,4 +37,41 @@ export class UserSelectMenuBuilder extends BaseSelectMenuBuilder<APIUserSelectCo
3137
public constructor(data?: Partial<APIUserSelectComponent>) {
3238
super({ ...data, type: ComponentType.UserSelect });
3339
}
40+
41+
/**
42+
* Adds default users to this auto populated select menu.
43+
*
44+
* @param users - The users to add
45+
*/
46+
public addDefaultUsers(...users: RestOrArray<Snowflake>) {
47+
const normalizedValues = normalizeArray(users);
48+
optionsLengthValidator.parse((this.data.default_values?.length ?? 0) + normalizedValues.length);
49+
this.data.default_values ??= [];
50+
51+
this.data.default_values.push(
52+
...normalizedValues.map((id) => ({
53+
id,
54+
type: SelectMenuDefaultValueType.User as const,
55+
})),
56+
);
57+
58+
return this;
59+
}
60+
61+
/**
62+
* Sets default users to this auto populated select menu.
63+
*
64+
* @param users - The users to set
65+
*/
66+
public setDefaultUsers(...users: RestOrArray<Snowflake>) {
67+
const normalizedValues = normalizeArray(users);
68+
optionsLengthValidator.parse(normalizedValues.length);
69+
70+
this.data.default_values = normalizedValues.map((id) => ({
71+
id,
72+
type: SelectMenuDefaultValueType.User as const,
73+
}));
74+
75+
return this;
76+
}
3477
}

packages/discord.js/src/structures/ChatInputCommandInteraction.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const CommandInteraction = require('./CommandInteraction');
44
const CommandInteractionOptionResolver = require('./CommandInteractionOptionResolver');
5+
const { transformResolved } = require('../util/Util');
56

67
/**
78
* Represents a command interaction.
@@ -18,7 +19,7 @@ class ChatInputCommandInteraction extends CommandInteraction {
1819
this.options = new CommandInteractionOptionResolver(
1920
this.client,
2021
data.data.options?.map(option => this.transformOption(option, data.data.resolved)) ?? [],
21-
this.transformResolved(data.data.resolved ?? {}),
22+
transformResolved({ client: this.client, guild: this.guild, channel: this.channel }, data.data.resolved),
2223
);
2324
}
2425

packages/discord.js/src/structures/CommandInteraction.js

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use strict';
22

3-
const { Collection } = require('@discordjs/collection');
43
const Attachment = require('./Attachment');
54
const BaseInteraction = require('./BaseInteraction');
65
const InteractionWebhook = require('./InteractionWebhook');
@@ -91,62 +90,6 @@ class CommandInteraction extends BaseInteraction {
9190
* @property {Collection<Snowflake, Attachment>} [attachments] The resolved attachments
9291
*/
9392

94-
/**
95-
* Transforms the resolved received from the API.
96-
* @param {APIInteractionDataResolved} resolved The received resolved objects
97-
* @returns {CommandInteractionResolvedData}
98-
* @private
99-
*/
100-
transformResolved({ members, users, channels, roles, messages, attachments }) {
101-
const result = {};
102-
103-
if (members) {
104-
result.members = new Collection();
105-
for (const [id, member] of Object.entries(members)) {
106-
const user = users[id];
107-
result.members.set(id, this.guild?.members._add({ user, ...member }) ?? member);
108-
}
109-
}
110-
111-
if (users) {
112-
result.users = new Collection();
113-
for (const user of Object.values(users)) {
114-
result.users.set(user.id, this.client.users._add(user));
115-
}
116-
}
117-
118-
if (roles) {
119-
result.roles = new Collection();
120-
for (const role of Object.values(roles)) {
121-
result.roles.set(role.id, this.guild?.roles._add(role) ?? role);
122-
}
123-
}
124-
125-
if (channels) {
126-
result.channels = new Collection();
127-
for (const channel of Object.values(channels)) {
128-
result.channels.set(channel.id, this.client.channels._add(channel, this.guild) ?? channel);
129-
}
130-
}
131-
132-
if (messages) {
133-
result.messages = new Collection();
134-
for (const message of Object.values(messages)) {
135-
result.messages.set(message.id, this.channel?.messages?._add(message) ?? message);
136-
}
137-
}
138-
139-
if (attachments) {
140-
result.attachments = new Collection();
141-
for (const attachment of Object.values(attachments)) {
142-
const patched = new Attachment(attachment);
143-
result.attachments.set(attachment.id, patched);
144-
}
145-
}
146-
147-
return result;
148-
}
149-
15093
/**
15194
* Represents an option of a received command interaction.
15295
* @typedef {Object} CommandInteractionOption

packages/discord.js/src/structures/ContextMenuCommandInteraction.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const { lazy } = require('@discordjs/util');
44
const { ApplicationCommandOptionType } = require('discord-api-types/v10');
55
const CommandInteraction = require('./CommandInteraction');
66
const CommandInteractionOptionResolver = require('./CommandInteractionOptionResolver');
7+
const { transformResolved } = require('../util/Util');
78

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

@@ -21,7 +22,7 @@ class ContextMenuCommandInteraction extends CommandInteraction {
2122
this.options = new CommandInteractionOptionResolver(
2223
this.client,
2324
this.resolveContextMenuOptions(data.data),
24-
this.transformResolved(data.data.resolved),
25+
transformResolved({ client: this.client, guild: this.guild, channel: this.channel }, data.data.resolved),
2526
);
2627

2728
/**

0 commit comments

Comments
 (0)