import { ApplicationCommandOptionType, type CommandInteractionOption, ComponentType, type Interaction, type ModalData, } from 'discord.js' const optionTypeToString: Record = { 1: 'Subcommand', 2: 'SubcommandGroup', 3: 'String', 4: 'Integer', 5: 'Boolean', 6: 'User', 7: 'Channel', 8: 'Role', 9: 'Mentionable', 10: 'Number', 11: 'Attachment', } /** * Format an interaction into a string, like: * @example * // Slash commands & autocomplete * /command [option1: value1] [option2: value2] * /command sub_command [focused*: value] * // Right click commands (message or user) * >command [Message (1233123123333): hello everybody my name is markiplier...] * >command [User (91298392100299): atorasuunva] * // Buttons/select menus/modals * [Button (custom-id)] * [SelectMenu (custom-id) [val1, val2, val3]] * [ModalSubmit (custom-id) [opt1: true] [opt2: val1, val2] [opt3: some text]] * @param interaction The interaction to format as a string * @returns The interaction as a string */ export function interactionToString(interaction: Interaction): string { if (interaction.isChatInputCommand() || interaction.isAutocomplete()) { const name = interaction.commandName const group = interaction.options.getSubcommandGroup(false) ?? '' const subcommand = interaction.options.getSubcommand(false) ?? '' const fGroup = group ? ` ${group}` : '' const fSubcommand = subcommand ? ` ${subcommand}` : '' const options = interaction.options.data.map(stringifyOption) return `/${name}${fGroup}${fSubcommand} ${options.join(' ')}` } if (interaction.isUserContextMenuCommand()) { return `>${interaction.commandName} [User] (${interaction.targetId}): ${interaction.targetUser.username}]` } if (interaction.isMessageContextMenuCommand()) { return `>${interaction.commandName} [Message] (${ interaction.targetId }): ${interaction.targetMessage.content.substring(0, 50)}` } if (interaction.isButton()) { return `[Button] (${interaction.customId})` } if (interaction.isAnySelectMenu()) { return `[SelectMenu] (${interaction.customId}) [${interaction.values.join(', ')}]` } if (interaction.isModalSubmit()) { // So far, only strings exist for modal submits const opts = interaction.fields.fields.map(formatModalData) return `[ModalSubmit] (${interaction.customId}) ${opts.join(' ')}` } return '[Unknown interaction type]' } function formatModalData(modalData: ModalData): string { switch (modalData.type) { case ComponentType.CheckboxGroup: { return `[${modalData.customId}: ${modalData.values.join(', ')}]` } case ComponentType.Checkbox: { return `[${modalData.customId}: ${modalData.value}]` } case ComponentType.FileUpload: { return `[${modalData.customId}: ${modalData.values.join(', ')}]` } case ComponentType.RadioGroup: { return `[${modalData.customId}: ${modalData.value}]` } case ComponentType.SelectMenu: { return `[${modalData.customId}: ${modalData.values.join(', ')}]` } case ComponentType.TextInput: { return `[${modalData.customId}: ${modalData.value}]` } default: { return `[${modalData.customId}: ${modalData.values.join(', ')}]` } } } function stringifyOption(opt: CommandInteractionOption): string { if (opt.type === ApplicationCommandOptionType.Subcommand) { return opt.options ? opt.options.map(stringifyOption).join(' ') : '' } if (opt.type === ApplicationCommandOptionType.SubcommandGroup) { return opt.options ? opt.options.map(stringifyOption).join(' ') : '' } return `[${opt.name}${opt.focused ? '*' : ''}<${optionTypeToString[opt.type]}>: ${opt.value}]` }