mirror of
https://github.com/discordeno/discordeno.git
synced 2026-09-17 08:47:22 +00:00
fix(bot)!: Split DiscordSelectComponent into specific select components (#4690)
* refactor(bot)!: setup desired properties for all transformers SetupDesiredProps when is given an object that does not corrispond to a transformer object that supports desired properties will behave like TransformProperty on the entire object as when it tries to get the properties for said object it will find `never` as the props and for `IsKeyDesired` a props of `never` means that all props are desired. * Use Equals helper, clean up a bit the code * Explicit the IsKeyDesired TProps never behavior * fix(bot): Bug with return type in functions * fix(bot)!: Split DiscordSelectComponent into specific select components And add missing resolved property from the responses, since this now correctly transformers the responses, resolved has to be added. The reverse transformer does not transform resolved as it requires a bunch of others, such as a user, role, message reverse transformers etc. * Apply suggestions from code review Co-authored-by: Awesome Stickz <awesome@stickz.dev>
This commit is contained in:
@@ -354,6 +354,7 @@ export function createDesiredPropertiesObject<T extends RecursivePartial<Transfo
|
||||
size: defaultValue,
|
||||
component: defaultValue,
|
||||
values: defaultValue,
|
||||
resolved: defaultValue,
|
||||
...desiredProperties.component,
|
||||
},
|
||||
forumTag: {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import {
|
||||
type DiscordActionRow,
|
||||
type DiscordButtonComponent,
|
||||
type DiscordChannelSelectComponent,
|
||||
type DiscordChannelSelectInteractionResponseFromModal,
|
||||
type DiscordContainerComponent,
|
||||
type DiscordFileComponent,
|
||||
type DiscordFileUploadComponent,
|
||||
@@ -9,18 +11,24 @@ import {
|
||||
type DiscordLabelInteractionResponse,
|
||||
type DiscordMediaGalleryComponent,
|
||||
type DiscordMediaGalleryItem,
|
||||
type DiscordMentionableSelectComponent,
|
||||
type DiscordMentionableSelectInteractionResponseFromModal,
|
||||
type DiscordMessageComponent,
|
||||
type DiscordMessageComponentFromModalInteractionResponse,
|
||||
type DiscordRoleSelectComponent,
|
||||
type DiscordRoleSelectInteractionResponseFromModal,
|
||||
type DiscordSectionComponent,
|
||||
type DiscordSelectMenuComponent,
|
||||
type DiscordSeparatorComponent,
|
||||
type DiscordStringSelectInteractionResponse,
|
||||
type DiscordStringSelectComponent,
|
||||
type DiscordStringSelectInteractionResponseFromModal,
|
||||
type DiscordTextDisplayComponent,
|
||||
type DiscordTextDisplayInteractionResponse,
|
||||
type DiscordTextInputComponent,
|
||||
type DiscordTextInputInteractionResponse,
|
||||
type DiscordThumbnailComponent,
|
||||
type DiscordUnfurledMediaItem,
|
||||
type DiscordUserSelectComponent,
|
||||
type DiscordUserSelectInteractionResponseFromModal,
|
||||
MessageComponentTypes,
|
||||
} from '@discordeno/types';
|
||||
import type { Bot } from '../bot.js';
|
||||
@@ -45,11 +53,19 @@ export function transformComponent(bot: Bot, payload: DiscordMessageComponent |
|
||||
component = transformInputTextComponent(bot, payload);
|
||||
break;
|
||||
case MessageComponentTypes.StringSelect:
|
||||
component = transformStringSelectMenuComponent(bot, payload);
|
||||
break;
|
||||
case MessageComponentTypes.UserSelect:
|
||||
component = transformUserSelectMenuComponent(bot, payload);
|
||||
break;
|
||||
case MessageComponentTypes.RoleSelect:
|
||||
component = transformRoleSelectMenuComponent(bot, payload);
|
||||
break;
|
||||
case MessageComponentTypes.MentionableSelect:
|
||||
component = transformMentionableSelectMenuComponent(bot, payload);
|
||||
break;
|
||||
case MessageComponentTypes.ChannelSelect:
|
||||
component = transformSelectMenuComponent(bot, payload);
|
||||
component = transformChannelSelectMenuComponent(bot, payload);
|
||||
break;
|
||||
case MessageComponentTypes.Section:
|
||||
component = transformSectionComponent(bot, payload);
|
||||
@@ -170,7 +186,7 @@ function transformInputTextComponent(bot: Bot, payload: DiscordTextInputComponen
|
||||
return input;
|
||||
}
|
||||
|
||||
function transformSelectMenuComponent(bot: Bot, payload: DiscordSelectMenuComponent | DiscordStringSelectInteractionResponse) {
|
||||
function transformStringSelectMenuComponent(bot: Bot, payload: DiscordStringSelectComponent | DiscordStringSelectInteractionResponseFromModal) {
|
||||
const props = bot.transformers.desiredProperties.component;
|
||||
const select = {} as SetupDesiredProps<Component, TransformersDesiredProperties, DesiredPropertiesBehavior>;
|
||||
|
||||
@@ -185,12 +201,6 @@ function transformSelectMenuComponent(bot: Bot, payload: DiscordSelectMenuCompon
|
||||
if (props.placeholder && payload.placeholder) select.placeholder = payload.placeholder;
|
||||
if (props.minValues && payload.min_values) select.minValues = payload.min_values;
|
||||
if (props.maxValues && payload.max_values) select.maxValues = payload.max_values;
|
||||
if (props.defaultValues && payload.default_values)
|
||||
select.defaultValues = payload.default_values.map((defaultValue) => ({
|
||||
id: bot.transformers.snowflake(defaultValue.id),
|
||||
type: defaultValue.type,
|
||||
}));
|
||||
if (props.channelTypes && payload.channel_types) select.channelTypes = payload.channel_types;
|
||||
if (props.options && payload.options)
|
||||
select.options = payload.options.map((option) => ({
|
||||
label: option.label,
|
||||
@@ -211,6 +221,118 @@ function transformSelectMenuComponent(bot: Bot, payload: DiscordSelectMenuCompon
|
||||
return select;
|
||||
}
|
||||
|
||||
function transformUserSelectMenuComponent(bot: Bot, payload: DiscordUserSelectComponent | DiscordUserSelectInteractionResponseFromModal) {
|
||||
const props = bot.transformers.desiredProperties.component;
|
||||
const select = {} as SetupDesiredProps<Component, TransformersDesiredProperties, DesiredPropertiesBehavior>;
|
||||
|
||||
if (props.type && payload.type) select.type = payload.type;
|
||||
if (props.id && payload.id) select.id = payload.id;
|
||||
if (props.customId && payload.custom_id) select.customId = payload.custom_id;
|
||||
|
||||
// Check if this is the user select response
|
||||
if ('values' in payload) {
|
||||
if (props.values && payload.values) select.values = payload.values;
|
||||
if (props.resolved && payload.resolved) select.resolved = bot.transformers.interactionDataResolved(bot, payload.resolved);
|
||||
} else {
|
||||
if (props.placeholder && payload.placeholder) select.placeholder = payload.placeholder;
|
||||
if (props.minValues && payload.min_values) select.minValues = payload.min_values;
|
||||
if (props.maxValues && payload.max_values) select.maxValues = payload.max_values;
|
||||
if (props.defaultValues && payload.default_values)
|
||||
select.defaultValues = payload.default_values.map((defaultValue) => ({
|
||||
id: bot.transformers.snowflake(defaultValue.id),
|
||||
type: defaultValue.type,
|
||||
}));
|
||||
if (props.disabled && payload.disabled) select.disabled = payload.disabled;
|
||||
}
|
||||
|
||||
return select;
|
||||
}
|
||||
|
||||
function transformRoleSelectMenuComponent(bot: Bot, payload: DiscordRoleSelectComponent | DiscordRoleSelectInteractionResponseFromModal) {
|
||||
const props = bot.transformers.desiredProperties.component;
|
||||
const select = {} as SetupDesiredProps<Component, TransformersDesiredProperties, DesiredPropertiesBehavior>;
|
||||
|
||||
if (props.type && payload.type) select.type = payload.type;
|
||||
if (props.id && payload.id) select.id = payload.id;
|
||||
if (props.customId && payload.custom_id) select.customId = payload.custom_id;
|
||||
|
||||
// Check if this is the role select response
|
||||
if ('values' in payload) {
|
||||
if (props.values && payload.values) select.values = payload.values;
|
||||
if (props.resolved && payload.resolved) select.resolved = bot.transformers.interactionDataResolved(bot, payload.resolved);
|
||||
} else {
|
||||
if (props.placeholder && payload.placeholder) select.placeholder = payload.placeholder;
|
||||
if (props.minValues && payload.min_values) select.minValues = payload.min_values;
|
||||
if (props.maxValues && payload.max_values) select.maxValues = payload.max_values;
|
||||
if (props.defaultValues && payload.default_values)
|
||||
select.defaultValues = payload.default_values.map((defaultValue) => ({
|
||||
id: bot.transformers.snowflake(defaultValue.id),
|
||||
type: defaultValue.type,
|
||||
}));
|
||||
if (props.disabled && payload.disabled) select.disabled = payload.disabled;
|
||||
}
|
||||
|
||||
return select;
|
||||
}
|
||||
|
||||
function transformMentionableSelectMenuComponent(
|
||||
bot: Bot,
|
||||
payload: DiscordMentionableSelectComponent | DiscordMentionableSelectInteractionResponseFromModal,
|
||||
) {
|
||||
const props = bot.transformers.desiredProperties.component;
|
||||
const select = {} as SetupDesiredProps<Component, TransformersDesiredProperties, DesiredPropertiesBehavior>;
|
||||
|
||||
if (props.type && payload.type) select.type = payload.type;
|
||||
if (props.id && payload.id) select.id = payload.id;
|
||||
if (props.customId && payload.custom_id) select.customId = payload.custom_id;
|
||||
|
||||
// Check if this is the mentionable select response
|
||||
if ('values' in payload) {
|
||||
if (props.values && payload.values) select.values = payload.values;
|
||||
if (props.resolved && payload.resolved) select.resolved = bot.transformers.interactionDataResolved(bot, payload.resolved);
|
||||
} else {
|
||||
if (props.placeholder && payload.placeholder) select.placeholder = payload.placeholder;
|
||||
if (props.minValues && payload.min_values) select.minValues = payload.min_values;
|
||||
if (props.maxValues && payload.max_values) select.maxValues = payload.max_values;
|
||||
if (props.defaultValues && payload.default_values)
|
||||
select.defaultValues = payload.default_values.map((defaultValue) => ({
|
||||
id: bot.transformers.snowflake(defaultValue.id),
|
||||
type: defaultValue.type,
|
||||
}));
|
||||
if (props.disabled && payload.disabled) select.disabled = payload.disabled;
|
||||
}
|
||||
|
||||
return select;
|
||||
}
|
||||
|
||||
function transformChannelSelectMenuComponent(bot: Bot, payload: DiscordChannelSelectComponent | DiscordChannelSelectInteractionResponseFromModal) {
|
||||
const props = bot.transformers.desiredProperties.component;
|
||||
const select = {} as SetupDesiredProps<Component, TransformersDesiredProperties, DesiredPropertiesBehavior>;
|
||||
|
||||
if (props.type && payload.type) select.type = payload.type;
|
||||
if (props.id && payload.id) select.id = payload.id;
|
||||
if (props.customId && payload.custom_id) select.customId = payload.custom_id;
|
||||
|
||||
// Check if this is the channel select response
|
||||
if ('values' in payload) {
|
||||
if (props.values && payload.values) select.values = payload.values;
|
||||
if (props.resolved && payload.resolved) select.resolved = bot.transformers.interactionDataResolved(bot, payload.resolved);
|
||||
} else {
|
||||
if (props.placeholder && payload.placeholder) select.placeholder = payload.placeholder;
|
||||
if (props.minValues && payload.min_values) select.minValues = payload.min_values;
|
||||
if (props.maxValues && payload.max_values) select.maxValues = payload.max_values;
|
||||
if (props.defaultValues && payload.default_values)
|
||||
select.defaultValues = payload.default_values.map((defaultValue) => ({
|
||||
id: bot.transformers.snowflake(defaultValue.id),
|
||||
type: defaultValue.type,
|
||||
}));
|
||||
if (props.channelTypes && payload.channel_types) select.channelTypes = payload.channel_types;
|
||||
if (props.disabled && payload.disabled) select.disabled = payload.disabled;
|
||||
}
|
||||
|
||||
return select;
|
||||
}
|
||||
|
||||
function transformSectionComponent(bot: Bot, payload: DiscordSectionComponent) {
|
||||
const props = bot.transformers.desiredProperties.component;
|
||||
const section = {} as SetupDesiredProps<Component, TransformersDesiredProperties, DesiredPropertiesBehavior>;
|
||||
@@ -303,9 +425,9 @@ function transformLabelComponent(bot: Bot, payload: DiscordLabelComponent | Disc
|
||||
return label;
|
||||
}
|
||||
|
||||
function transformFileUploadComponent(bot: Bot, payload: DiscordFileUploadComponent | DiscordFileUploadInteractionResponse): Component {
|
||||
function transformFileUploadComponent(bot: Bot, payload: DiscordFileUploadComponent | DiscordFileUploadInteractionResponse) {
|
||||
const props = bot.transformers.desiredProperties.component;
|
||||
const fileUpload = {} as Component;
|
||||
const fileUpload = {} as SetupDesiredProps<Component, TransformersDesiredProperties, DesiredPropertiesBehavior>;
|
||||
|
||||
if (props.type && payload.type) fileUpload.type = payload.type;
|
||||
if (props.id && payload.id) fileUpload.id = payload.id;
|
||||
|
||||
@@ -2,22 +2,30 @@ import {
|
||||
type ButtonStyles,
|
||||
type DiscordActionRow,
|
||||
type DiscordButtonComponent,
|
||||
type DiscordChannelSelectComponent,
|
||||
type DiscordChannelSelectInteractionResponseFromModal,
|
||||
type DiscordContainerComponent,
|
||||
type DiscordFileComponent,
|
||||
type DiscordFileUploadComponent,
|
||||
type DiscordLabelComponent,
|
||||
type DiscordMediaGalleryComponent,
|
||||
type DiscordMediaGalleryItem,
|
||||
type DiscordMentionableSelectComponent,
|
||||
type DiscordMentionableSelectInteractionResponseFromModal,
|
||||
type DiscordMessageComponent,
|
||||
type DiscordMessageComponentFromModalInteractionResponse,
|
||||
type DiscordRoleSelectComponent,
|
||||
type DiscordRoleSelectInteractionResponseFromModal,
|
||||
type DiscordSectionComponent,
|
||||
type DiscordSelectMenuComponent,
|
||||
type DiscordStringSelectComponent,
|
||||
type DiscordStringSelectInteractionResponseFromModal,
|
||||
type DiscordTextDisplayComponent,
|
||||
type DiscordTextInputComponent,
|
||||
type DiscordTextInputInteractionResponse,
|
||||
type DiscordThumbnailComponent,
|
||||
type DiscordUnfurledMediaItem,
|
||||
type DiscordUserSelectComponent,
|
||||
type DiscordUserSelectInteractionResponseFromModal,
|
||||
MessageComponentTypes,
|
||||
type TextStyles,
|
||||
} from '@discordeno/types';
|
||||
@@ -39,11 +47,15 @@ export function transformComponentToDiscordComponent(
|
||||
case MessageComponentTypes.TextInput:
|
||||
return transformInputTextComponent(bot, payload);
|
||||
case MessageComponentTypes.StringSelect:
|
||||
case MessageComponentTypes.ChannelSelect:
|
||||
case MessageComponentTypes.RoleSelect:
|
||||
return transformStringSelectMenuComponent(bot, payload);
|
||||
case MessageComponentTypes.UserSelect:
|
||||
return transformUserSelectMenuComponent(bot, payload);
|
||||
case MessageComponentTypes.RoleSelect:
|
||||
return transformRoleSelectMenuComponent(bot, payload);
|
||||
case MessageComponentTypes.MentionableSelect:
|
||||
return transformSelectMenuComponent(bot, payload);
|
||||
return transformMentionableSelectMenuComponent(bot, payload);
|
||||
case MessageComponentTypes.ChannelSelect:
|
||||
return transformChannelSelectMenuComponent(bot, payload);
|
||||
case MessageComponentTypes.Section:
|
||||
return transformSectionComponent(bot, payload);
|
||||
case MessageComponentTypes.File:
|
||||
@@ -139,25 +151,23 @@ function transformInputTextComponent(_bot: Bot, payload: Component): DiscordText
|
||||
};
|
||||
}
|
||||
|
||||
function transformSelectMenuComponent(bot: Bot, payload: Component): DiscordSelectMenuComponent | DiscordStringSelectInteractionResponseFromModal {
|
||||
function transformStringSelectMenuComponent(
|
||||
bot: Bot,
|
||||
payload: Component,
|
||||
): DiscordStringSelectComponent | DiscordStringSelectInteractionResponseFromModal {
|
||||
if (payload.values) {
|
||||
return {
|
||||
type: MessageComponentTypes.StringSelect,
|
||||
values: payload.values,
|
||||
custom_id: payload.customId!,
|
||||
id: payload.id!,
|
||||
};
|
||||
} satisfies DiscordStringSelectInteractionResponseFromModal;
|
||||
}
|
||||
|
||||
return {
|
||||
type: payload.type as DiscordSelectMenuComponent['type'],
|
||||
type: MessageComponentTypes.StringSelect,
|
||||
id: payload.id,
|
||||
custom_id: payload.customId!,
|
||||
channel_types: payload.channelTypes,
|
||||
default_values: payload.defaultValues?.map((defaultValue) => ({
|
||||
id: bot.transformers.reverse.snowflake(defaultValue.id),
|
||||
type: defaultValue.type,
|
||||
})),
|
||||
disabled: payload.disabled,
|
||||
max_values: payload.maxValues,
|
||||
min_values: payload.minValues,
|
||||
@@ -173,10 +183,117 @@ function transformSelectMenuComponent(bot: Bot, payload: Component): DiscordSele
|
||||
}
|
||||
: undefined,
|
||||
default: option.default,
|
||||
})),
|
||||
}))!,
|
||||
placeholder: payload.placeholder,
|
||||
required: payload.required,
|
||||
};
|
||||
} satisfies DiscordStringSelectComponent;
|
||||
}
|
||||
|
||||
function transformUserSelectMenuComponent(bot: Bot, payload: Component): DiscordUserSelectComponent | DiscordUserSelectInteractionResponseFromModal {
|
||||
if (payload.values) {
|
||||
return {
|
||||
type: MessageComponentTypes.UserSelect,
|
||||
values: payload.values,
|
||||
custom_id: payload.customId!,
|
||||
id: payload.id!,
|
||||
// TODO: Add resolved reverse transformer
|
||||
resolved: {},
|
||||
} satisfies DiscordUserSelectInteractionResponseFromModal;
|
||||
}
|
||||
|
||||
return {
|
||||
type: MessageComponentTypes.UserSelect,
|
||||
id: payload.id,
|
||||
custom_id: payload.customId!,
|
||||
disabled: payload.disabled,
|
||||
max_values: payload.maxValues,
|
||||
min_values: payload.minValues,
|
||||
placeholder: payload.placeholder,
|
||||
default_values: payload.defaultValues?.map((value) => ({ id: bot.transformers.reverse.snowflake(value.id), type: value.type })),
|
||||
required: payload.required,
|
||||
} satisfies DiscordUserSelectComponent;
|
||||
}
|
||||
|
||||
function transformRoleSelectMenuComponent(bot: Bot, payload: Component): DiscordRoleSelectComponent | DiscordRoleSelectInteractionResponseFromModal {
|
||||
if (payload.values) {
|
||||
return {
|
||||
type: MessageComponentTypes.RoleSelect,
|
||||
values: payload.values,
|
||||
custom_id: payload.customId!,
|
||||
id: payload.id!,
|
||||
// TODO: Add resolved reverse transformer
|
||||
resolved: {},
|
||||
} satisfies DiscordRoleSelectInteractionResponseFromModal;
|
||||
}
|
||||
|
||||
return {
|
||||
type: MessageComponentTypes.RoleSelect,
|
||||
id: payload.id,
|
||||
custom_id: payload.customId!,
|
||||
disabled: payload.disabled,
|
||||
max_values: payload.maxValues,
|
||||
min_values: payload.minValues,
|
||||
placeholder: payload.placeholder,
|
||||
default_values: payload.defaultValues?.map((value) => ({ id: bot.transformers.reverse.snowflake(value.id), type: value.type })),
|
||||
required: payload.required,
|
||||
} satisfies DiscordRoleSelectComponent;
|
||||
}
|
||||
|
||||
function transformMentionableSelectMenuComponent(
|
||||
bot: Bot,
|
||||
payload: Component,
|
||||
): DiscordMentionableSelectComponent | DiscordMentionableSelectInteractionResponseFromModal {
|
||||
if (payload.values) {
|
||||
return {
|
||||
type: MessageComponentTypes.MentionableSelect,
|
||||
values: payload.values,
|
||||
custom_id: payload.customId!,
|
||||
id: payload.id!,
|
||||
// TODO: Add resolved reverse transformer
|
||||
resolved: {},
|
||||
} satisfies DiscordMentionableSelectInteractionResponseFromModal;
|
||||
}
|
||||
|
||||
return {
|
||||
type: MessageComponentTypes.MentionableSelect,
|
||||
id: payload.id,
|
||||
custom_id: payload.customId!,
|
||||
disabled: payload.disabled,
|
||||
max_values: payload.maxValues,
|
||||
min_values: payload.minValues,
|
||||
placeholder: payload.placeholder,
|
||||
default_values: payload.defaultValues?.map((value) => ({ id: bot.transformers.reverse.snowflake(value.id), type: value.type })),
|
||||
required: payload.required,
|
||||
} satisfies DiscordMentionableSelectComponent;
|
||||
}
|
||||
|
||||
function transformChannelSelectMenuComponent(
|
||||
bot: Bot,
|
||||
payload: Component,
|
||||
): DiscordChannelSelectComponent | DiscordChannelSelectInteractionResponseFromModal {
|
||||
if (payload.values) {
|
||||
return {
|
||||
type: MessageComponentTypes.ChannelSelect,
|
||||
values: payload.values,
|
||||
custom_id: payload.customId!,
|
||||
id: payload.id!,
|
||||
// TODO: Add resolved reverse transformer
|
||||
resolved: {},
|
||||
} satisfies DiscordChannelSelectInteractionResponseFromModal;
|
||||
}
|
||||
|
||||
return {
|
||||
type: MessageComponentTypes.ChannelSelect,
|
||||
id: payload.id,
|
||||
custom_id: payload.customId!,
|
||||
disabled: payload.disabled,
|
||||
max_values: payload.maxValues,
|
||||
min_values: payload.minValues,
|
||||
default_values: payload.defaultValues?.map((value) => ({ id: bot.transformers.reverse.snowflake(value.id), type: value.type })),
|
||||
placeholder: payload.placeholder,
|
||||
required: payload.required,
|
||||
channel_types: payload.channelTypes,
|
||||
} satisfies DiscordChannelSelectComponent;
|
||||
}
|
||||
|
||||
function transformSectionComponent(bot: Bot, payload: Component): DiscordSectionComponent {
|
||||
|
||||
@@ -599,7 +599,7 @@ export interface Component {
|
||||
/** a list of child components */
|
||||
components?: Component[];
|
||||
/** List of default values for auto-populated select menu components; number of default values must be in the range defined by min_values and max_values */
|
||||
defaultValues?: DiscordComponentDefaultValue[];
|
||||
defaultValues?: ComponentDefaultValue[];
|
||||
/** Identifier for a purchasable SKU, only available when using premium-style buttons */
|
||||
skuId?: bigint;
|
||||
/** Optional identifier for component */
|
||||
@@ -632,6 +632,8 @@ export interface Component {
|
||||
component?: Component;
|
||||
/** The text of the selected options */
|
||||
values?: string[];
|
||||
/** Resolved entities from selected options */
|
||||
resolved?: InteractionDataResolved;
|
||||
}
|
||||
|
||||
export interface UnfurledMediaItem {
|
||||
@@ -658,7 +660,7 @@ export interface MediaGalleryItem {
|
||||
spoiler?: boolean;
|
||||
}
|
||||
|
||||
export interface DiscordComponentDefaultValue {
|
||||
export interface ComponentDefaultValue {
|
||||
/** ID of a user, role, or channel */
|
||||
id: bigint;
|
||||
/** Type of value that id represents. */
|
||||
|
||||
Reference in New Issue
Block a user