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: add support for autocomplete interactions #6672

Merged
merged 59 commits into from Oct 28, 2021
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
403f1b5
feat: add support for autocomplete interactions
OfficialSirH Sep 22, 2021
9a8d142
fix: redid some bits of the implementation
OfficialSirH Sep 22, 2021
dca6b71
types: autocomplete extends
OfficialSirH Sep 22, 2021
1e44487
fix: indentation and grammar
OfficialSirH Sep 22, 2021
d775631
fix: example for result method
OfficialSirH Sep 22, 2021
6edb155
types: readjust result to consistent typing
OfficialSirH Sep 22, 2021
fc9bd01
types: update options for result method
OfficialSirH Sep 22, 2021
32dadae
types: add missing types
OfficialSirH Sep 22, 2021
7aad008
fix: grammar and formatting
OfficialSirH Sep 22, 2021
4ad3d22
fix: transformCommand method allows autocomplete
OfficialSirH Sep 22, 2021
1e491c1
fix: result method's callback
OfficialSirH Sep 22, 2021
f93253c
fix: getFocused method return
OfficialSirH Sep 22, 2021
56cc153
types: replace unecessary type
OfficialSirH Sep 22, 2021
afa2859
fix: definitions and methods for autocomplete interaction
OfficialSirH Sep 23, 2021
162aad0
fix: inconsistencies and methods
OfficialSirH Sep 23, 2021
d59e411
fix: missing properties
OfficialSirH Sep 23, 2021
ba00b83
fix: necessary properties and types
OfficialSirH Sep 23, 2021
7353091
fix: export autocomplete interaction
OfficialSirH Sep 24, 2021
4d597c1
types: return never if non-autocomplete interaction uses focused getter
OfficialSirH Sep 25, 2021
98d92ca
fix: options equal function to compare with autocomplete
OfficialSirH Sep 27, 2021
689f461
feat: add support for autocomplete interactions
OfficialSirH Sep 22, 2021
a46bddc
fix: redid some bits of the implementation
OfficialSirH Sep 22, 2021
b876a35
types: autocomplete extends
OfficialSirH Sep 22, 2021
d9f3830
fix: indentation and grammar
OfficialSirH Sep 22, 2021
7a27aaa
fix: example for result method
OfficialSirH Sep 22, 2021
1d642b6
types: readjust result to consistent typing
OfficialSirH Sep 22, 2021
f4c8d24
types: update options for result method
OfficialSirH Sep 22, 2021
4f72943
types: add missing types
OfficialSirH Sep 22, 2021
9a59744
fix: grammar and formatting
OfficialSirH Sep 22, 2021
cc29956
fix: transformCommand method allows autocomplete
OfficialSirH Sep 22, 2021
02cb303
fix: result method's callback
OfficialSirH Sep 22, 2021
4cdd056
fix: getFocused method return
OfficialSirH Sep 22, 2021
b899cfd
types: replace unecessary type
OfficialSirH Sep 22, 2021
7d5d39c
fix: definitions and methods for autocomplete interaction
OfficialSirH Sep 23, 2021
1dc4efe
fix: inconsistencies and methods
OfficialSirH Sep 23, 2021
e0286e9
fix: missing properties
OfficialSirH Sep 23, 2021
8d8dd21
fix: necessary properties and types
OfficialSirH Sep 23, 2021
2f11b9f
fix: export autocomplete interaction
OfficialSirH Sep 24, 2021
5af0aa7
types: return never if non-autocomplete interaction uses focused getter
OfficialSirH Oct 3, 2021
3b0ee88
fix: options equal function to compare with autocomplete
OfficialSirH Sep 27, 2021
bf3d557
Merge branch 'main' of https://github.com/OfficialSirH/discord.js int…
OfficialSirH Oct 3, 2021
76d5479
fix: remove redundant channel jsdoc in classes
OfficialSirH Oct 3, 2021
18438d4
Merge branch 'main' of https://github.com/discordjs/discord.js into t…
OfficialSirH Oct 5, 2021
3bebf2e
Merge branch 'main' of https://github.com/discordjs/discord.js into t…
OfficialSirH Oct 12, 2021
86e4ea2
types: applied generic variable for all option resolver methods
OfficialSirH Oct 15, 2021
06ec092
Merge branch 'main' of https://github.com/discordjs/discord.js into t…
OfficialSirH Oct 17, 2021
5bdfb03
Merge branch 'main' of https://github.com/discordjs/discord.js into t…
OfficialSirH Oct 26, 2021
ab9e609
Merge branch 'main' of https://github.com/discordjs/discord.js into t…
OfficialSirH Oct 27, 2021
bcdc01d
types: apply CacheType generics to AutocompleteInteraction
OfficialSirH Oct 27, 2021
0cec4d8
types: omit option resolver methods from interactions that don't need it
OfficialSirH Oct 28, 2021
6e05904
types: unnecessary generic
OfficialSirH Oct 28, 2021
20769ea
Merge branch 'main' of https://github.com/OfficialSirH/discord.js int…
suneettipirneni Oct 28, 2021
f18d1e7
Merge branch 'main' of https://github.com/discordjs/discord.js into f…
suneettipirneni Oct 28, 2021
b9026f2
chore: rough commit
suneettipirneni Oct 28, 2021
0080acf
fix: type tests
suneettipirneni Oct 28, 2021
3b2d716
Revert "chore: rough commit"
suneettipirneni Oct 28, 2021
28d6ca6
Revert "Revert "chore: rough commit""
suneettipirneni Oct 28, 2021
cc479ab
fix: remove js file
suneettipirneni Oct 28, 2021
82140bd
Merge pull request #1 from suneettipirneni/feat/autocomplete
OfficialSirH Oct 28, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/client/actions/InteractionCreate.js
@@ -1,6 +1,7 @@
'use strict';

const Action = require('./Action');
const AutocompleteInteraction = require('../../structures/AutocompleteInteraction');
const ButtonInteraction = require('../../structures/ButtonInteraction');
const CommandInteraction = require('../../structures/CommandInteraction');
const ContextMenuInteraction = require('../../structures/ContextMenuInteraction');
Expand Down Expand Up @@ -51,6 +52,9 @@ class InteractionCreateAction extends Action {
return;
}
break;
case InteractionTypes.APPLICATION_COMMAND_AUTOCOMPLETE:
InteractionType = AutocompleteInteraction;
break;
default:
client.emit(Events.DEBUG, `[INTERACTION] Received interaction with unknown type: ${data.type}`);
return;
Expand Down
3 changes: 3 additions & 0 deletions src/structures/ApplicationCommand.js
Expand Up @@ -128,6 +128,7 @@ class ApplicationCommand extends Base {
* @property {ApplicationCommandOptionType|number} type The type of the option
* @property {string} name The name of the option
* @property {string} description The description of the option
* @property {boolean} [autocomplete] Whether the option is an autocomplete option
* @property {boolean} [required] Whether the option is required
* @property {ApplicationCommandOptionChoice[]} [choices] The choices of the option for the user to pick from
* @property {ApplicationCommandOptionData[]} [options] Additional options if this option is a subcommand (group)
Expand Down Expand Up @@ -275,6 +276,7 @@ class ApplicationCommand extends Base {
* @property {string} name The name of the option
* @property {string} description The description of the option
* @property {boolean} [required] Whether the option is required
* @property {boolean} [autocomplete] Whether the option is an autocomplete option
* @property {ApplicationCommandOptionChoice[]} [choices] The choices of the option for the user to pick from
* @property {ApplicationCommandOption[]} [options] Additional options if this option is a subcommand (group)
*/
Expand All @@ -301,6 +303,7 @@ class ApplicationCommand extends Base {
description: option.description,
required:
option.required ?? (stringType === 'SUB_COMMAND' || stringType === 'SUB_COMMAND_GROUP' ? undefined : false),
autocomplete: option.autocomplete,
choices: option.choices,
options: option.options?.map(o => this.transformOption(o, received)),
};
Expand Down
89 changes: 89 additions & 0 deletions src/structures/AutocompleteInteraction.js
@@ -0,0 +1,89 @@
'use strict';

const CommandInteractionOptionResolver = require('./CommandInteractionOptionResolver');
const Interaction = require('./Interaction');
const { InteractionResponseTypes, ApplicationCommandOptionTypes } = require('../util/Constants');

/**
* Represents an autocomplete interaction.
* @extends {Interaction}
OfficialSirH marked this conversation as resolved.
Show resolved Hide resolved
*/
class AutocompleteInteraction extends Interaction {
OfficialSirH marked this conversation as resolved.
Show resolved Hide resolved
constructor(client, data) {
super(client, data);

/**
* The options passed to the command
* @type {CommandInteractionOptionResolver}
*/
this.options = new CommandInteractionOptionResolver(
this.client,
data.data.options?.map(option => this.transformOption(option, data.data.resolved)) ?? [],
);
}

/**
* Transforms an option received from the API.
* @param {APIApplicationCommandOption} option The received option
* @param {APIInteractionDataResolved} resolved The resolved interaction data
* @returns {CommandInteractionOption}
* @private
*/
transformOption(option, resolved) {
const result = {
name: option.name,
type: ApplicationCommandOptionTypes[option.type],
};

if ('value' in option) result.value = option.value;
if ('options' in option) result.options = option.options.map(opt => this.transformOption(opt, resolved));
if ('focused' in option) result.focused = option.focused;

if (resolved) {
const user = resolved.users?.[option.value];
if (user) result.user = this.client.users._add(user);

const member = resolved.members?.[option.value];
if (member) result.member = this.guild?.members._add({ user, ...member }) ?? member;

const channel = resolved.channels?.[option.value];
if (channel) result.channel = this.client.channels._add(channel, this.guild) ?? channel;

const role = resolved.roles?.[option.value];
if (role) result.role = this.guild?.roles._add(role) ?? role;
}

return result;
}

/**
* Sends results for the autocomplete of this interaction.
* @param {ApplicationCommandOptionChoice[]} options The options for the autocomplete
* @returns {Promise<void>}
* @example
* // respond to autocomplete interaction
* interaction.sendResult([
* {
* name: 'Option 1',
* value: 'option1',
* },
* ])
* .then(console.log)
* .catch(console.error);
*/
async result(options) {
OfficialSirH marked this conversation as resolved.
Show resolved Hide resolved
if (this.replied) throw new Error('INTERACTION_ALREADY_REPLIED');

await this.client.api.interactions(this.id, this.token).callback.post({
data: {
type: InteractionResponseTypes.APPLICATION_COMMAND_AUTOCOMPLETE_RESULT,
data: {
choices: options,
},
},
});
this.replied = true;
}
}

module.exports = AutocompleteInteraction;
1 change: 1 addition & 0 deletions src/structures/BaseCommandInteraction.js
Expand Up @@ -138,6 +138,7 @@ class BaseCommandInteraction extends Interaction {
* @typedef {Object} CommandInteractionOption
* @property {string} name The name of the option
* @property {ApplicationCommandOptionType} type The type of the option
* @property {boolean} [autocomplete] Whether the option is an autocomplete option
* @property {string|number|boolean} [value] The value of the option
* @property {CommandInteractionOption[]} [options] Additional options if this option is a
* subcommand (group)
Expand Down
12 changes: 12 additions & 0 deletions src/structures/CommandInteractionOptionResolver.js
Expand Up @@ -239,6 +239,18 @@ class CommandInteractionOptionResolver {
const option = this._getTypedOption(name, '_MESSAGE', ['message'], required);
return option?.message ?? null;
}

/**
* Gets the focused option.
* @param {boolean} [getFull=false] Whether to throw an error if the option is not found
OfficialSirH marked this conversation as resolved.
Show resolved Hide resolved
* @returns {string|number|ApplicationCommandOptionChoice}
* The value of the option, or the whole option if getFull is true
*/
getFocused(getFull = false) {
const focusedOption = this._hoistedOptions.find(option => option.focused);
if (!focusedOption) throw new TypeError('AUTOCOMPLETE_INTERACTION_OPTION_NO_FOCUSED_OPTION');
OfficialSirH marked this conversation as resolved.
Show resolved Hide resolved
return getFull ? focusedOption : focusedOption.value;
}
}

module.exports = CommandInteractionOptionResolver;
8 changes: 8 additions & 0 deletions src/structures/Interaction.js
Expand Up @@ -129,6 +129,14 @@ class Interaction extends Base {
return InteractionTypes[this.type] === InteractionTypes.APPLICATION_COMMAND && typeof this.targetId !== 'undefined';
}

/**
* Indicates whether this interaction is an {@link AutocompleteInteraction}
* @returns {boolean}
*/
isAutocomplete() {
return InteractionTypes[this.type] === InteractionTypes.APPLICATION_COMMAND_AUTOCOMPLETE;
}

/**
* Indicates whether this interaction is a {@link MessageComponentInteraction}.
* @returns {boolean}
Expand Down
9 changes: 8 additions & 1 deletion src/util/Constants.js
Expand Up @@ -954,7 +954,13 @@ exports.ApplicationCommandPermissionTypes = createEnum([null, 'ROLE', 'USER']);
* @typedef {string} InteractionType
* @see {@link https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-type}
*/
exports.InteractionTypes = createEnum([null, 'PING', 'APPLICATION_COMMAND', 'MESSAGE_COMPONENT']);
exports.InteractionTypes = createEnum([
null,
'PING',
'APPLICATION_COMMAND',
'MESSAGE_COMPONENT',
'APPLICATION_COMMAND_AUTOCOMPLETE',
]);

/**
* The type of an interaction response:
Expand All @@ -975,6 +981,7 @@ exports.InteractionResponseTypes = createEnum([
'DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE',
'DEFERRED_MESSAGE_UPDATE',
'UPDATE_MESSAGE',
'APPLICATION_COMMAND_AUTOCOMPLETE_RESULT',
]);
/* eslint-enable max-len */

Expand Down
2 changes: 2 additions & 0 deletions typings/enums.d.ts
Expand Up @@ -66,12 +66,14 @@ export const enum InteractionResponseTypes {
DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE = 5,
DEFERRED_MESSAGE_UPDATE = 6,
UPDATE_MESSAGE = 7,
APPLICATION_COMMAND_AUTOCOMPLETE_RESULT = 8,
}

export const enum InteractionTypes {
PING = 1,
APPLICATION_COMMAND = 2,
MESSAGE_COMPONENT = 3,
APPLICATION_COMMAND_AUTOCOMPLETE = 4,
}

export const enum InviteTargetType {
Expand Down
12 changes: 12 additions & 0 deletions typings/index.d.ts
Expand Up @@ -557,6 +557,12 @@ export class CommandInteraction extends BaseCommandInteraction {
public options: CommandInteractionOptionResolver;
}

export class AutocompleteInteraction extends Interaction {
OfficialSirH marked this conversation as resolved.
Show resolved Hide resolved
OfficialSirH marked this conversation as resolved.
Show resolved Hide resolved
public options: CommandInteractionOptionResolver;
private transformOption(option: APIApplicationCommandOption, resolved: null): CommandInteractionOption;
public sendResult(options: ApplicationCommandOptionChoice[]): Promise<void>;
OfficialSirH marked this conversation as resolved.
Show resolved Hide resolved
}

export class CommandInteractionOptionResolver {
public constructor(client: Client, options: CommandInteractionOption[], resolved: CommandInteractionResolvedData);
public readonly client: Client;
Expand Down Expand Up @@ -611,6 +617,8 @@ export class CommandInteractionOptionResolver {
): NonNullable<CommandInteractionOption['member' | 'role' | 'user']> | null;
public getMessage(name: string, required: true): NonNullable<CommandInteractionOption['message']>;
public getMessage(name: string, required?: boolean): NonNullable<CommandInteractionOption['message']> | null;
public getFocused(getFull: true): ApplicationCommandOptionChoice;
public getFocused(getFull?: boolean): string | number;
}

export class ContextMenuInteraction extends BaseCommandInteraction {
Expand Down Expand Up @@ -1025,6 +1033,7 @@ export class Interaction extends Base {
public inGuild(): this is this & { guildId: Snowflake; member: GuildMember | APIInteractionGuildMember };
public isButton(): this is ButtonInteraction;
public isCommand(): this is CommandInteraction;
public isAutocomplete(): this is AutocompleteInteraction;
public isContextMenu(): this is ContextMenuInteraction;
public isMessageComponent(): this is MessageComponentInteraction;
public isSelectMenu(): this is SelectMenuInteraction;
Expand Down Expand Up @@ -3034,6 +3043,7 @@ export interface BaseApplicationCommandOptionsData {
name: string;
description: string;
required?: boolean;
autocomplete?: boolean;
}

export interface UserApplicationCommandData extends BaseApplicationCommandData {
Expand Down Expand Up @@ -3432,6 +3442,8 @@ export interface CommandInteractionOption {
name: string;
type: ApplicationCommandOptionType;
value?: string | number | boolean;
focused?: boolean;
autocomplete?: boolean;
options?: CommandInteractionOption[];
user?: User;
member?: GuildMember | APIInteractionDataResolvedGuildMember;
Expand Down