Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions packages/structures/src/applicationCommands/ApplicationCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { DiscordSnowflake } from '@sapphire/snowflake';
import type { APIApplicationCommand, ApplicationCommandType } from 'discord-api-types/v10';
import { Structure } from '../Structure.js';
import { kData } from '../utils/symbols.js';
import { isIdSet } from '../utils/type-guards.js';
import type { Partialize } from '../utils/types.js';

/**
* Represents any application command on Discord.
*
* @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`
* @remarks has substructure `User` which needs to be instantiated and stored by an extending class using it
* @remarks intentionally does not export `roles` so that extending classes can resolve `Snowflake[]` to `Role[]`
*/
export class ApplicationCommand<Omitted extends keyof APIApplicationCommand | '' = ''> extends Structure<
APIApplicationCommand,
Omitted
> {
/**
* The template used for removing data from the raw data stored for each application command
*/
public static override readonly DataTemplate: Partial<APIApplicationCommand> = {};

/**
* @param data - The raw data received from the API for the application command
*/
public constructor(data: Partialize<APIApplicationCommand, Omitted>) {
super(data);
}

/**
* Unique ID of command
*
* @remarks Valid option types: ALL
*/
public get id() {
return this[kData].id;
}

/**
* Type of command
*
* @remarks Valid option types: ALL
* @defaultValue {@link ApplicationCommandType.ChatInput}
*/
public get type() {
return this[kData].type;
}

/**
* Id of the parent application
*
* @remarks Valid option types: ALL
*/
public get applicationId() {
return this[kData].application_id;
}

/**
* Guild ID of the command, if not global
*
* @remarks Valid option types: ALL
*/
public get guildId() {
return this[kData].guild_id;
}

/**
* Name of the application, 1-32 characters
*
* @remarks Valid option types: ALL
* @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-naming}
*/
public get name() {
return this[kData].name;
}

/**
* Localization map for the `name` field.
*
* @remarks Values follow the same restrictions as `name`.
* @remarks Valid option types: ALL
* @see {@link https://discord.com/developers/docs/reference#locales}
*/
public get nameLocalizations() {
return this[kData].name_localizations;
}

/**
* Description for {@link ApplicationCommandType.ChatInput} commands, 1-100 characters.
* Empty string for {@link ApplicationCommandType.User} and {@link ApplicationCommandType.Message} commands.
*
* @remarks Valid option types: ALL
*/
public get description() {
return this[kData].description;
}

/**
* Localization map for the `description` field.
*
* @remarks Values follow the same restrictions as `description`.
* @remarks Valid option types: ALL
* @see {@link https://discord.com/developers/docs/reference#locales}
*/
public get descriptionLocalizations() {
return this[kData].description_localizations;
}

/**
* Set of permissions represented as a bit set
*
* @see {@link https://discord.com/developers/docs/topics/permissions}
*/
public get defaultMemberPermissions() {
return this[kData].default_member_permissions;
}

/**
* Whether the command is age-restricted (NSFW)
*
* @defaultValue `false`
* @see {@link https://discord.com/developers/docs/interactions/application-commands#agerestricted-commands}
*/
public get nsfw() {
return this[kData].nsfw;
}

/**
* The timestamp the command was created at
*/
public get createdTimestamp() {
return isIdSet(this.id) ? DiscordSnowflake.timestampFrom(this.id) : null;
}

/**
* The time the command was created at
*/
public get createdAt() {
const createdTimestamp = this.createdTimestamp;
return createdTimestamp ? new Date(createdTimestamp) : null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { APIApplicationCommandAttachmentOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
import type { Partialize } from '../../utils/types';
import { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase';

/**
* Represents an attachment option type for an application command.
*
* @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`
*/
export class ApplicationCommandOptionAttachment<
Omitted extends keyof APIApplicationCommandAttachmentOption,
> extends ApplicationCommandOptionBase<ApplicationCommandOptionType.Attachment, Omitted> {
/**
* The template used for removing data from the raw data stored for each application attachment option type.
*/
public static override readonly DataTemplate: Partial<APIApplicationCommandAttachmentOption> = {};

/**
* @param data - The raw data received from the API for the application command option
*/
public constructor(data: Partialize<APIApplicationCommandAttachmentOption, Omitted>) {
super(data);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import type { APIApplicationCommandOptionBase, ApplicationCommandOptionType } from 'discord-api-types/v10';
import { Structure } from '../../Structure.js';
import { kData } from '../../utils/symbols.js';
import type { Partialize } from '../../utils/types.js';

/**
* @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure}
* export type APIApplicationCommandBasicOption = APIApplicationCommandAttachmentOption | APIApplicationCommandBooleanOption | APIApplicationCommandChannelOption | APIApplicationCommandIntegerOption | APIApplicationCommandMentionableOption | APIApplicationCommandNumberOption | APIApplicationCommandRoleOption | APIApplicationCommandStringOption | APIApplicationCommandUserOption;
* /**
* @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure}
* export type APIApplicationCommandOption = APIApplicationCommandBasicOption | APIApplicationCommandSubcommandGroupOption | APIApplicationCommandSubcommandOption;
*/

export type ApplicationCommandOptionTypeType<Type extends ApplicationCommandOptionType> = Extract<
APIApplicationCommandOptionBase<Type>,
{ type: Type }
>;

/**
* Represents any application command option on Discord.
*
* @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`
* @remarks required options must be listed before optional options
*/
export abstract class ApplicationCommandOptionBase<
CommandOptionType extends ApplicationCommandOptionType,
Omitted extends keyof Omitted | '' = '',
> extends Structure<ApplicationCommandOptionTypeType<CommandOptionType>, Omitted> {
/**
* @param data - The raw data received from the API for the application command option
*/
public constructor(data: Partialize<ApplicationCommandOptionTypeType<CommandOptionType>, Omitted>) {
super(data);
}

/**
* Type of this option
*
* @remarks Valid option types: ALL
* @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-type}
*/
public get type() {
return this[kData].type;
}

/**
* 1-32 character name.
*
* @remarks Must be unique within an array of application command options.
* @remarks Valid option types: ALL
* @see {@link https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-naming}
*/
public get name() {
return this[kData].name;
}

/**
* Localization map for the `name` field.
*
* @remarks Values follow the same restrictions as `name`.
* @remarks Valid option types: ALL
* @see {@link https://discord.com/developers/docs/reference#locales}
*/
public get nameLocalizations() {
return this[kData].name_localizations;
}

/**
* 1-100 character description
*
* @remarks Valid option types: ALL
*/
public get description() {
return this[kData].description;
}

/**
* Localization map for the `description` field.
*
* @remarks Values follow the same restrictions as `description`.
* @remarks Valid option types: ALL
* @see {@link https://discord.com/developers/docs/reference#locales}
*/
public get descriptionLocalizations() {
return this[kData].description_localizations;
}

/**
* Whether the parameter is required or optional
*
* @remarks Valid option types: All except {@link ApplicationCommandOptionType.Subcommand | Subcommand}, {@link ApplicationCommandOptionType.SubcommandGroup | SubcommandGroup}
* @defaultValue `false`
*/
public get required() {
return this[kData].required;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { APIApplicationCommandBooleanOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
import type { Partialize } from '../../utils/types';
import { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase';

/**
* Represents a boolean option type for an application command.
*
* @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`
*/
export class ApplicationCommandOptionBoolean<
Omitted extends keyof APIApplicationCommandBooleanOption,
> extends ApplicationCommandOptionBase<ApplicationCommandOptionType.Boolean, Omitted> {
/**
* The template used for removing data from the raw data stored for each boolean application command option
*/
public static override readonly DataTemplate: Partial<APIApplicationCommandBooleanOption> = {};

/**
* @param data - The raw data received from the API for the boolean application command option
*/
public constructor(data: Partialize<APIApplicationCommandBooleanOption, Omitted>) {
super(data);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { APIApplicationCommandChannelOption, ApplicationCommandOptionAllowedChannelType, ApplicationCommandOptionType } from 'discord-api-types/v10';
import type { Partialize } from '../../utils/types';
import { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase';

/**
* Represents a channel option type for an application command.
*
* @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`
*/
export class ApplicationCommandOptionChannel<
Omitted extends keyof { channel_types?: ApplicationCommandOptionAllowedChannelType[] } & keyof APIApplicationCommandChannelOption,
> extends ApplicationCommandOptionBase<ApplicationCommandOptionType.Channel, Omitted> {
/**
* The template used for removing data from the raw data stored for each channel application command option
*/
public static override readonly DataTemplate: Partial<APIApplicationCommandChannelOption> = {};

/**
* @param data - The raw data received from the API for the channel application command option
*/
public constructor(data: Partialize<APIApplicationCommandChannelOption, Omitted>) {
super(data);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { APIApplicationCommandOptionChoice } from 'discord-api-types/v10';
import { Structure } from '../../Structure.js';
import { kData } from '../../utils/symbols.js';
import type { Partialize } from '../../utils/types.js';

/**
* Represents any application command option choice on Discord.
*
* @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`
* @remarks has substructure `User` which needs to be instantiated and stored by an extending class using it
*/
export class ApplicationCommandOptionChoice<
Omitted extends keyof APIApplicationCommandOptionChoice | '' = '',
> extends Structure<APIApplicationCommandOptionChoice, Omitted> {
/**
* The template used for removing data from the raw data stored for each application command option choice
*/
public static override readonly DataTemplate: Partial<APIApplicationCommandOptionChoice> = {};

/**
* @param data - The raw data received from the API for the application command option choice
*/
public constructor(data: Partialize<APIApplicationCommandOptionChoice, Omitted>) {
super(data);
}

/**
* 1-100 character choice name
*/
public get name() {
return this[kData].name;
}

/**
* Type of value depends on the option type that the choice belongs to
*/
public get value() {
return this[kData].value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { APIApplicationCommandIntegerOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
import type { Partialize } from '../../utils/types';
import { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase';

/**
* Represents an integer option type for an application command.
*
* @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`
*/
export class ApplicationCommandOptionInteger<
Omitted extends keyof APIApplicationCommandIntegerOption,
> extends ApplicationCommandOptionBase<ApplicationCommandOptionType.Integer, Omitted> {
/**
* The template used for removing data from the raw data stored for each integer application command option type.
*/
public static override readonly DataTemplate: Partial<APIApplicationCommandIntegerOption> = {};

/**
* @param data - The raw data received from the API for the integer option type
*/
public constructor(data: Partialize<APIApplicationCommandIntegerOption, Omitted>) {
super(data);
}
}
Loading
Loading