mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-20 05:23:31 +01:00
refactor: make builders types great again (#10026)
* refactor: make builders types great again * fix: subcommands only type --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
@@ -49,9 +49,11 @@ export * from './interactions/slashCommands/options/user.js';
|
|||||||
export * from './interactions/slashCommands/mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';
|
export * from './interactions/slashCommands/mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';
|
||||||
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionBase.js';
|
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionBase.js';
|
||||||
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionChannelTypesMixin.js';
|
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionChannelTypesMixin.js';
|
||||||
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.js';
|
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionWithAutocompleteMixin.js';
|
||||||
|
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionWithChoicesMixin.js';
|
||||||
export * from './interactions/slashCommands/mixins/NameAndDescription.js';
|
export * from './interactions/slashCommands/mixins/NameAndDescription.js';
|
||||||
export * from './interactions/slashCommands/mixins/SharedSlashCommandOptions.js';
|
export * from './interactions/slashCommands/mixins/SharedSlashCommandOptions.js';
|
||||||
|
export * from './interactions/slashCommands/mixins/SharedSubcommands.js';
|
||||||
|
|
||||||
export * as ContextMenuCommandAssertions from './interactions/contextMenuCommands/Assertions.js';
|
export * as ContextMenuCommandAssertions from './interactions/contextMenuCommands/Assertions.js';
|
||||||
export * from './interactions/contextMenuCommands/ContextMenuCommandBuilder.js';
|
export * from './interactions/contextMenuCommands/ContextMenuCommandBuilder.js';
|
||||||
|
|||||||
@@ -1,28 +1,13 @@
|
|||||||
import type {
|
import type { APIApplicationCommandOption, LocalizationMap, Permissions } from 'discord-api-types/v10';
|
||||||
APIApplicationCommandOption,
|
|
||||||
LocalizationMap,
|
|
||||||
Permissions,
|
|
||||||
RESTPostAPIChatInputApplicationCommandsJSONBody,
|
|
||||||
} from 'discord-api-types/v10';
|
|
||||||
import { mix } from 'ts-mixer';
|
import { mix } from 'ts-mixer';
|
||||||
import {
|
|
||||||
assertReturnOfBuilder,
|
|
||||||
validateDefaultMemberPermissions,
|
|
||||||
validateDefaultPermission,
|
|
||||||
validateLocalizationMap,
|
|
||||||
validateDMPermission,
|
|
||||||
validateMaxOptionsLength,
|
|
||||||
validateRequiredParameters,
|
|
||||||
validateNSFW,
|
|
||||||
} from './Assertions.js';
|
|
||||||
import { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from './SlashCommandSubcommands.js';
|
|
||||||
import { SharedNameAndDescription } from './mixins/NameAndDescription.js';
|
import { SharedNameAndDescription } from './mixins/NameAndDescription.js';
|
||||||
import { SharedSlashCommandOptions } from './mixins/SharedSlashCommandOptions.js';
|
import { SharedSlashCommandOptions } from './mixins/SharedSlashCommandOptions.js';
|
||||||
|
import { SharedSlashCommandSubcommands } from './mixins/SharedSubcommands.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A builder that creates API-compatible JSON data for slash commands.
|
* A builder that creates API-compatible JSON data for slash commands.
|
||||||
*/
|
*/
|
||||||
@mix(SharedSlashCommandOptions, SharedNameAndDescription)
|
@mix(SharedSlashCommandOptions, SharedNameAndDescription, SharedSlashCommandSubcommands)
|
||||||
export class SlashCommandBuilder {
|
export class SlashCommandBuilder {
|
||||||
/**
|
/**
|
||||||
* The name of this command.
|
* The name of this command.
|
||||||
@@ -52,7 +37,7 @@ export class SlashCommandBuilder {
|
|||||||
/**
|
/**
|
||||||
* Whether this command is enabled by default when the application is added to a guild.
|
* Whether this command is enabled by default when the application is added to a guild.
|
||||||
*
|
*
|
||||||
* @deprecated Use {@link ContextMenuCommandBuilder.setDefaultMemberPermissions} or {@link ContextMenuCommandBuilder.setDMPermission} instead.
|
* @deprecated Use {@link SharedSlashCommandSubcommands.setDefaultMemberPermissions} or {@link SharedSlashCommandSubcommands.setDMPermission} instead.
|
||||||
*/
|
*/
|
||||||
public readonly default_permission: boolean | undefined = undefined;
|
public readonly default_permission: boolean | undefined = undefined;
|
||||||
|
|
||||||
@@ -73,158 +58,27 @@ export class SlashCommandBuilder {
|
|||||||
* Whether this command is NSFW.
|
* Whether this command is NSFW.
|
||||||
*/
|
*/
|
||||||
public readonly nsfw: boolean | undefined = undefined;
|
public readonly nsfw: boolean | undefined = undefined;
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether the command is enabled by default when the application is added to a guild.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* If set to `false`, you will have to later `PUT` the permissions for this command.
|
|
||||||
* @param value - Whether or not to enable this command by default
|
|
||||||
* @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}
|
|
||||||
* @deprecated Use {@link SlashCommandBuilder.setDefaultMemberPermissions} or {@link SlashCommandBuilder.setDMPermission} instead.
|
|
||||||
*/
|
|
||||||
public setDefaultPermission(value: boolean) {
|
|
||||||
// Assert the value matches the conditions
|
|
||||||
validateDefaultPermission(value);
|
|
||||||
|
|
||||||
Reflect.set(this, 'default_permission', value);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the default permissions a member should have in order to run the command.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* You can set this to `'0'` to disable the command by default.
|
|
||||||
* @param permissions - The permissions bit field to set
|
|
||||||
* @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}
|
|
||||||
*/
|
|
||||||
public setDefaultMemberPermissions(permissions: Permissions | bigint | number | null | undefined) {
|
|
||||||
// Assert the value and parse it
|
|
||||||
const permissionValue = validateDefaultMemberPermissions(permissions);
|
|
||||||
|
|
||||||
Reflect.set(this, 'default_member_permissions', permissionValue);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets if the command is available in direct messages with the application.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* By default, commands are visible. This method is only for global commands.
|
|
||||||
* @param enabled - Whether the command should be enabled in direct messages
|
|
||||||
* @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}
|
|
||||||
*/
|
|
||||||
public setDMPermission(enabled: boolean | null | undefined) {
|
|
||||||
// Assert the value matches the conditions
|
|
||||||
validateDMPermission(enabled);
|
|
||||||
|
|
||||||
Reflect.set(this, 'dm_permission', enabled);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether this command is NSFW.
|
|
||||||
*
|
|
||||||
* @param nsfw - Whether this command is NSFW
|
|
||||||
*/
|
|
||||||
public setNSFW(nsfw = true) {
|
|
||||||
// Assert the value matches the conditions
|
|
||||||
validateNSFW(nsfw);
|
|
||||||
Reflect.set(this, 'nsfw', nsfw);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new subcommand group to this command.
|
|
||||||
*
|
|
||||||
* @param input - A function that returns a subcommand group builder or an already built builder
|
|
||||||
*/
|
|
||||||
public addSubcommandGroup(
|
|
||||||
input:
|
|
||||||
| SlashCommandSubcommandGroupBuilder
|
|
||||||
| ((subcommandGroup: SlashCommandSubcommandGroupBuilder) => SlashCommandSubcommandGroupBuilder),
|
|
||||||
): SlashCommandSubcommandsOnlyBuilder {
|
|
||||||
const { options } = this;
|
|
||||||
|
|
||||||
// First, assert options conditions - we cannot have more than 25 options
|
|
||||||
validateMaxOptionsLength(options);
|
|
||||||
|
|
||||||
// Get the final result
|
|
||||||
const result = typeof input === 'function' ? input(new SlashCommandSubcommandGroupBuilder()) : input;
|
|
||||||
|
|
||||||
assertReturnOfBuilder(result, SlashCommandSubcommandGroupBuilder);
|
|
||||||
|
|
||||||
// Push it
|
|
||||||
options.push(result);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new subcommand to this command.
|
|
||||||
*
|
|
||||||
* @param input - A function that returns a subcommand builder or an already built builder
|
|
||||||
*/
|
|
||||||
public addSubcommand(
|
|
||||||
input:
|
|
||||||
| SlashCommandSubcommandBuilder
|
|
||||||
| ((subcommandGroup: SlashCommandSubcommandBuilder) => SlashCommandSubcommandBuilder),
|
|
||||||
): SlashCommandSubcommandsOnlyBuilder {
|
|
||||||
const { options } = this;
|
|
||||||
|
|
||||||
// First, assert options conditions - we cannot have more than 25 options
|
|
||||||
validateMaxOptionsLength(options);
|
|
||||||
|
|
||||||
// Get the final result
|
|
||||||
const result = typeof input === 'function' ? input(new SlashCommandSubcommandBuilder()) : input;
|
|
||||||
|
|
||||||
assertReturnOfBuilder(result, SlashCommandSubcommandBuilder);
|
|
||||||
|
|
||||||
// Push it
|
|
||||||
options.push(result);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes this builder to API-compatible JSON data.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* This method runs validations on the data before serializing it.
|
|
||||||
* As such, it may throw an error if the data is invalid.
|
|
||||||
*/
|
|
||||||
public toJSON(): RESTPostAPIChatInputApplicationCommandsJSONBody {
|
|
||||||
validateRequiredParameters(this.name, this.description, this.options);
|
|
||||||
|
|
||||||
validateLocalizationMap(this.name_localizations);
|
|
||||||
validateLocalizationMap(this.description_localizations);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...this,
|
|
||||||
options: this.options.map((option) => option.toJSON()),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SlashCommandBuilder extends SharedNameAndDescription, SharedSlashCommandOptions {}
|
export interface SlashCommandBuilder
|
||||||
|
extends SharedNameAndDescription,
|
||||||
|
SharedSlashCommandOptions<SlashCommandOptionsOnlyBuilder>,
|
||||||
|
SharedSlashCommandSubcommands<SlashCommandSubcommandsOnlyBuilder> {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface specifically for slash command subcommands.
|
* An interface specifically for slash command subcommands.
|
||||||
*/
|
*/
|
||||||
export interface SlashCommandSubcommandsOnlyBuilder
|
export interface SlashCommandSubcommandsOnlyBuilder
|
||||||
extends Omit<SlashCommandBuilder, Exclude<keyof SharedSlashCommandOptions, 'options'>> {}
|
extends SharedNameAndDescription,
|
||||||
|
SharedSlashCommandSubcommands<SlashCommandSubcommandsOnlyBuilder> {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface specifically for slash command options.
|
* An interface specifically for slash command options.
|
||||||
*/
|
*/
|
||||||
export interface SlashCommandOptionsOnlyBuilder
|
export interface SlashCommandOptionsOnlyBuilder
|
||||||
extends SharedNameAndDescription,
|
extends SharedNameAndDescription,
|
||||||
SharedSlashCommandOptions,
|
SharedSlashCommandOptions<SlashCommandOptionsOnlyBuilder>,
|
||||||
Pick<SlashCommandBuilder, 'toJSON'> {}
|
ToAPIApplicationCommandOptions {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface that ensures the `toJSON()` call will return something
|
* An interface that ensures the `toJSON()` call will return something
|
||||||
|
|||||||
@@ -126,4 +126,6 @@ export class SlashCommandSubcommandBuilder implements ToAPIApplicationCommandOpt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SlashCommandSubcommandBuilder extends SharedNameAndDescription, SharedSlashCommandOptions<false> {}
|
export interface SlashCommandSubcommandBuilder
|
||||||
|
extends SharedNameAndDescription,
|
||||||
|
SharedSlashCommandOptions<SlashCommandSubcommandBuilder> {}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { s } from '@sapphire/shapeshift';
|
||||||
|
import type { ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||||
|
|
||||||
|
const booleanPredicate = s.boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This mixin holds choices and autocomplete symbols used for options.
|
||||||
|
*/
|
||||||
|
export class ApplicationCommandOptionWithAutocompleteMixin {
|
||||||
|
/**
|
||||||
|
* Whether this option utilizes autocomplete.
|
||||||
|
*/
|
||||||
|
public readonly autocomplete?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of this option.
|
||||||
|
*
|
||||||
|
* @privateRemarks Since this is present and this is a mixin, this is needed.
|
||||||
|
*/
|
||||||
|
public readonly type!: ApplicationCommandOptionType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this option uses autocomplete.
|
||||||
|
*
|
||||||
|
* @param autocomplete - Whether this option should use autocomplete
|
||||||
|
*/
|
||||||
|
public setAutocomplete(autocomplete: boolean): this {
|
||||||
|
// Assert that you actually passed a boolean
|
||||||
|
booleanPredicate.parse(autocomplete);
|
||||||
|
|
||||||
|
if (autocomplete && 'choices' in this && Array.isArray(this.choices) && this.choices.length > 0) {
|
||||||
|
throw new RangeError('Autocomplete and choices are mutually exclusive to each other.');
|
||||||
|
}
|
||||||
|
|
||||||
|
Reflect.set(this, 'autocomplete', autocomplete);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,22 +9,16 @@ const choicesPredicate = s.object({
|
|||||||
name_localizations: localizationMapPredicate,
|
name_localizations: localizationMapPredicate,
|
||||||
value: s.union(stringPredicate, numberPredicate),
|
value: s.union(stringPredicate, numberPredicate),
|
||||||
}).array;
|
}).array;
|
||||||
const booleanPredicate = s.boolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This mixin holds choices and autocomplete symbols used for options.
|
* This mixin holds choices and autocomplete symbols used for options.
|
||||||
*/
|
*/
|
||||||
export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin<ChoiceType extends number | string> {
|
export class ApplicationCommandOptionWithChoicesMixin<ChoiceType extends number | string> {
|
||||||
/**
|
/**
|
||||||
* The choices of this option.
|
* The choices of this option.
|
||||||
*/
|
*/
|
||||||
public readonly choices?: APIApplicationCommandOptionChoice<ChoiceType>[];
|
public readonly choices?: APIApplicationCommandOptionChoice<ChoiceType>[];
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether this option utilizes autocomplete.
|
|
||||||
*/
|
|
||||||
public readonly autocomplete?: boolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of this option.
|
* The type of this option.
|
||||||
*
|
*
|
||||||
@@ -38,7 +32,7 @@ export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin<ChoiceType
|
|||||||
* @param choices - The choices to add
|
* @param choices - The choices to add
|
||||||
*/
|
*/
|
||||||
public addChoices(...choices: APIApplicationCommandOptionChoice<ChoiceType>[]): this {
|
public addChoices(...choices: APIApplicationCommandOptionChoice<ChoiceType>[]): this {
|
||||||
if (choices.length > 0 && this.autocomplete) {
|
if (choices.length > 0 && 'autocomplete' in this && this.autocomplete) {
|
||||||
throw new RangeError('Autocomplete and choices are mutually exclusive to each other.');
|
throw new RangeError('Autocomplete and choices are mutually exclusive to each other.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +64,7 @@ export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin<ChoiceType
|
|||||||
* @param choices - The choices to set
|
* @param choices - The choices to set
|
||||||
*/
|
*/
|
||||||
public setChoices<Input extends APIApplicationCommandOptionChoice<ChoiceType>[]>(...choices: Input): this {
|
public setChoices<Input extends APIApplicationCommandOptionChoice<ChoiceType>[]>(...choices: Input): this {
|
||||||
if (choices.length > 0 && this.autocomplete) {
|
if (choices.length > 0 && 'autocomplete' in this && this.autocomplete) {
|
||||||
throw new RangeError('Autocomplete and choices are mutually exclusive to each other.');
|
throw new RangeError('Autocomplete and choices are mutually exclusive to each other.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,22 +75,4 @@ export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin<ChoiceType
|
|||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether this option uses autocomplete.
|
|
||||||
*
|
|
||||||
* @param autocomplete - Whether this option should use autocomplete
|
|
||||||
*/
|
|
||||||
public setAutocomplete(autocomplete: boolean): this {
|
|
||||||
// Assert that you actually passed a boolean
|
|
||||||
booleanPredicate.parse(autocomplete);
|
|
||||||
|
|
||||||
if (autocomplete && Array.isArray(this.choices) && this.choices.length > 0) {
|
|
||||||
throw new RangeError('Autocomplete and choices are mutually exclusive to each other.');
|
|
||||||
}
|
|
||||||
|
|
||||||
Reflect.set(this, 'autocomplete', autocomplete);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -14,9 +14,11 @@ import type { ApplicationCommandOptionBase } from './ApplicationCommandOptionBas
|
|||||||
/**
|
/**
|
||||||
* This mixin holds symbols that can be shared in slash command options.
|
* This mixin holds symbols that can be shared in slash command options.
|
||||||
*
|
*
|
||||||
* @typeParam ShouldOmitSubcommandFunctions - Whether to omit subcommand functions.
|
* @typeParam TypeAfterAddingOptions - The type this class should return after adding an option.
|
||||||
*/
|
*/
|
||||||
export class SharedSlashCommandOptions<ShouldOmitSubcommandFunctions = true> {
|
export class SharedSlashCommandOptions<
|
||||||
|
TypeAfterAddingOptions extends SharedSlashCommandOptions<TypeAfterAddingOptions>,
|
||||||
|
> {
|
||||||
public readonly options!: ToAPIApplicationCommandOptions[];
|
public readonly options!: ToAPIApplicationCommandOptions[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,16 +89,7 @@ export class SharedSlashCommandOptions<ShouldOmitSubcommandFunctions = true> {
|
|||||||
* @param input - A function that returns an option builder or an already built builder
|
* @param input - A function that returns an option builder or an already built builder
|
||||||
*/
|
*/
|
||||||
public addStringOption(
|
public addStringOption(
|
||||||
input:
|
input: SlashCommandStringOption | ((builder: SlashCommandStringOption) => SlashCommandStringOption),
|
||||||
| Omit<SlashCommandStringOption, 'addChoices'>
|
|
||||||
| Omit<SlashCommandStringOption, 'setAutocomplete'>
|
|
||||||
| SlashCommandStringOption
|
|
||||||
| ((
|
|
||||||
builder: SlashCommandStringOption,
|
|
||||||
) =>
|
|
||||||
| Omit<SlashCommandStringOption, 'addChoices'>
|
|
||||||
| Omit<SlashCommandStringOption, 'setAutocomplete'>
|
|
||||||
| SlashCommandStringOption),
|
|
||||||
) {
|
) {
|
||||||
return this._sharedAddOptionMethod(input, SlashCommandStringOption);
|
return this._sharedAddOptionMethod(input, SlashCommandStringOption);
|
||||||
}
|
}
|
||||||
@@ -107,16 +100,7 @@ export class SharedSlashCommandOptions<ShouldOmitSubcommandFunctions = true> {
|
|||||||
* @param input - A function that returns an option builder or an already built builder
|
* @param input - A function that returns an option builder or an already built builder
|
||||||
*/
|
*/
|
||||||
public addIntegerOption(
|
public addIntegerOption(
|
||||||
input:
|
input: SlashCommandIntegerOption | ((builder: SlashCommandIntegerOption) => SlashCommandIntegerOption),
|
||||||
| Omit<SlashCommandIntegerOption, 'addChoices'>
|
|
||||||
| Omit<SlashCommandIntegerOption, 'setAutocomplete'>
|
|
||||||
| SlashCommandIntegerOption
|
|
||||||
| ((
|
|
||||||
builder: SlashCommandIntegerOption,
|
|
||||||
) =>
|
|
||||||
| Omit<SlashCommandIntegerOption, 'addChoices'>
|
|
||||||
| Omit<SlashCommandIntegerOption, 'setAutocomplete'>
|
|
||||||
| SlashCommandIntegerOption),
|
|
||||||
) {
|
) {
|
||||||
return this._sharedAddOptionMethod(input, SlashCommandIntegerOption);
|
return this._sharedAddOptionMethod(input, SlashCommandIntegerOption);
|
||||||
}
|
}
|
||||||
@@ -127,16 +111,7 @@ export class SharedSlashCommandOptions<ShouldOmitSubcommandFunctions = true> {
|
|||||||
* @param input - A function that returns an option builder or an already built builder
|
* @param input - A function that returns an option builder or an already built builder
|
||||||
*/
|
*/
|
||||||
public addNumberOption(
|
public addNumberOption(
|
||||||
input:
|
input: SlashCommandNumberOption | ((builder: SlashCommandNumberOption) => SlashCommandNumberOption),
|
||||||
| Omit<SlashCommandNumberOption, 'addChoices'>
|
|
||||||
| Omit<SlashCommandNumberOption, 'setAutocomplete'>
|
|
||||||
| SlashCommandNumberOption
|
|
||||||
| ((
|
|
||||||
builder: SlashCommandNumberOption,
|
|
||||||
) =>
|
|
||||||
| Omit<SlashCommandNumberOption, 'addChoices'>
|
|
||||||
| Omit<SlashCommandNumberOption, 'setAutocomplete'>
|
|
||||||
| SlashCommandNumberOption),
|
|
||||||
) {
|
) {
|
||||||
return this._sharedAddOptionMethod(input, SlashCommandNumberOption);
|
return this._sharedAddOptionMethod(input, SlashCommandNumberOption);
|
||||||
}
|
}
|
||||||
@@ -149,15 +124,9 @@ export class SharedSlashCommandOptions<ShouldOmitSubcommandFunctions = true> {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
private _sharedAddOptionMethod<OptionBuilder extends ApplicationCommandOptionBase>(
|
private _sharedAddOptionMethod<OptionBuilder extends ApplicationCommandOptionBase>(
|
||||||
input:
|
input: OptionBuilder | ((builder: OptionBuilder) => OptionBuilder),
|
||||||
| Omit<OptionBuilder, 'addChoices'>
|
|
||||||
| Omit<OptionBuilder, 'setAutocomplete'>
|
|
||||||
| OptionBuilder
|
|
||||||
| ((
|
|
||||||
builder: OptionBuilder,
|
|
||||||
) => Omit<OptionBuilder, 'addChoices'> | Omit<OptionBuilder, 'setAutocomplete'> | OptionBuilder),
|
|
||||||
Instance: new () => OptionBuilder,
|
Instance: new () => OptionBuilder,
|
||||||
): ShouldOmitSubcommandFunctions extends true ? Omit<this, 'addSubcommand' | 'addSubcommandGroup'> : this {
|
): TypeAfterAddingOptions {
|
||||||
const { options } = this;
|
const { options } = this;
|
||||||
|
|
||||||
// First, assert options conditions - we cannot have more than 25 options
|
// First, assert options conditions - we cannot have more than 25 options
|
||||||
@@ -171,6 +140,6 @@ export class SharedSlashCommandOptions<ShouldOmitSubcommandFunctions = true> {
|
|||||||
// Push it
|
// Push it
|
||||||
options.push(result);
|
options.push(result);
|
||||||
|
|
||||||
return this;
|
return this as unknown as TypeAfterAddingOptions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
import type {
|
||||||
|
LocalizationMap,
|
||||||
|
Permissions,
|
||||||
|
RESTPostAPIChatInputApplicationCommandsJSONBody,
|
||||||
|
} from 'discord-api-types/v10';
|
||||||
|
import {
|
||||||
|
assertReturnOfBuilder,
|
||||||
|
validateDMPermission,
|
||||||
|
validateDefaultMemberPermissions,
|
||||||
|
validateDefaultPermission,
|
||||||
|
validateLocalizationMap,
|
||||||
|
validateMaxOptionsLength,
|
||||||
|
validateNSFW,
|
||||||
|
validateRequiredParameters,
|
||||||
|
} from '../Assertions.js';
|
||||||
|
import type { ToAPIApplicationCommandOptions } from '../SlashCommandBuilder.js';
|
||||||
|
import { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from '../SlashCommandSubcommands.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This mixin holds symbols that can be shared in slash subcommands.
|
||||||
|
*
|
||||||
|
* @typeParam TypeAfterAddingSubcommands - The type this class should return after adding a subcommand or subcommand group.
|
||||||
|
*/
|
||||||
|
export class SharedSlashCommandSubcommands<
|
||||||
|
TypeAfterAddingSubcommands extends SharedSlashCommandSubcommands<TypeAfterAddingSubcommands>,
|
||||||
|
> {
|
||||||
|
public readonly name: string = undefined!;
|
||||||
|
|
||||||
|
public readonly name_localizations?: LocalizationMap;
|
||||||
|
|
||||||
|
public readonly description: string = undefined!;
|
||||||
|
|
||||||
|
public readonly description_localizations?: LocalizationMap;
|
||||||
|
|
||||||
|
public readonly options: ToAPIApplicationCommandOptions[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the command is enabled by default when the application is added to a guild.
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* If set to `false`, you will have to later `PUT` the permissions for this command.
|
||||||
|
* @param value - Whether or not to enable this command by default
|
||||||
|
* @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}
|
||||||
|
* @deprecated Use {@link SharedSlashCommandSubcommands.setDefaultMemberPermissions} or {@link SharedSlashCommandSubcommands.setDMPermission} instead.
|
||||||
|
*/
|
||||||
|
public setDefaultPermission(value: boolean) {
|
||||||
|
// Assert the value matches the conditions
|
||||||
|
validateDefaultPermission(value);
|
||||||
|
|
||||||
|
Reflect.set(this, 'default_permission', value);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the default permissions a member should have in order to run the command.
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* You can set this to `'0'` to disable the command by default.
|
||||||
|
* @param permissions - The permissions bit field to set
|
||||||
|
* @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}
|
||||||
|
*/
|
||||||
|
public setDefaultMemberPermissions(permissions: Permissions | bigint | number | null | undefined) {
|
||||||
|
// Assert the value and parse it
|
||||||
|
const permissionValue = validateDefaultMemberPermissions(permissions);
|
||||||
|
|
||||||
|
Reflect.set(this, 'default_member_permissions', permissionValue);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if the command is available in direct messages with the application.
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* By default, commands are visible. This method is only for global commands.
|
||||||
|
* @param enabled - Whether the command should be enabled in direct messages
|
||||||
|
* @see {@link https://discord.com/developers/docs/interactions/application-commands#permissions}
|
||||||
|
*/
|
||||||
|
public setDMPermission(enabled: boolean | null | undefined) {
|
||||||
|
// Assert the value matches the conditions
|
||||||
|
validateDMPermission(enabled);
|
||||||
|
|
||||||
|
Reflect.set(this, 'dm_permission', enabled);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this command is NSFW.
|
||||||
|
*
|
||||||
|
* @param nsfw - Whether this command is NSFW
|
||||||
|
*/
|
||||||
|
public setNSFW(nsfw = true) {
|
||||||
|
// Assert the value matches the conditions
|
||||||
|
validateNSFW(nsfw);
|
||||||
|
Reflect.set(this, 'nsfw', nsfw);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new subcommand group to this command.
|
||||||
|
*
|
||||||
|
* @param input - A function that returns a subcommand group builder or an already built builder
|
||||||
|
*/
|
||||||
|
public addSubcommandGroup(
|
||||||
|
input:
|
||||||
|
| SlashCommandSubcommandGroupBuilder
|
||||||
|
| ((subcommandGroup: SlashCommandSubcommandGroupBuilder) => SlashCommandSubcommandGroupBuilder),
|
||||||
|
): TypeAfterAddingSubcommands {
|
||||||
|
const { options } = this;
|
||||||
|
|
||||||
|
// First, assert options conditions - we cannot have more than 25 options
|
||||||
|
validateMaxOptionsLength(options);
|
||||||
|
|
||||||
|
// Get the final result
|
||||||
|
const result = typeof input === 'function' ? input(new SlashCommandSubcommandGroupBuilder()) : input;
|
||||||
|
|
||||||
|
assertReturnOfBuilder(result, SlashCommandSubcommandGroupBuilder);
|
||||||
|
|
||||||
|
// Push it
|
||||||
|
options.push(result);
|
||||||
|
|
||||||
|
return this as unknown as TypeAfterAddingSubcommands;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new subcommand to this command.
|
||||||
|
*
|
||||||
|
* @param input - A function that returns a subcommand builder or an already built builder
|
||||||
|
*/
|
||||||
|
public addSubcommand(
|
||||||
|
input:
|
||||||
|
| SlashCommandSubcommandBuilder
|
||||||
|
| ((subcommandGroup: SlashCommandSubcommandBuilder) => SlashCommandSubcommandBuilder),
|
||||||
|
): TypeAfterAddingSubcommands {
|
||||||
|
const { options } = this;
|
||||||
|
|
||||||
|
// First, assert options conditions - we cannot have more than 25 options
|
||||||
|
validateMaxOptionsLength(options);
|
||||||
|
|
||||||
|
// Get the final result
|
||||||
|
const result = typeof input === 'function' ? input(new SlashCommandSubcommandBuilder()) : input;
|
||||||
|
|
||||||
|
assertReturnOfBuilder(result, SlashCommandSubcommandBuilder);
|
||||||
|
|
||||||
|
// Push it
|
||||||
|
options.push(result);
|
||||||
|
|
||||||
|
return this as unknown as TypeAfterAddingSubcommands;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes this builder to API-compatible JSON data.
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* This method runs validations on the data before serializing it.
|
||||||
|
* As such, it may throw an error if the data is invalid.
|
||||||
|
*/
|
||||||
|
public toJSON(): RESTPostAPIChatInputApplicationCommandsJSONBody {
|
||||||
|
validateRequiredParameters(this.name, this.description, this.options);
|
||||||
|
|
||||||
|
validateLocalizationMap(this.name_localizations);
|
||||||
|
validateLocalizationMap(this.description_localizations);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...this,
|
||||||
|
options: this.options.map((option) => option.toJSON()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,14 +3,19 @@ import { ApplicationCommandOptionType, type APIApplicationCommandIntegerOption }
|
|||||||
import { mix } from 'ts-mixer';
|
import { mix } from 'ts-mixer';
|
||||||
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';
|
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';
|
||||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
||||||
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.js';
|
import { ApplicationCommandOptionWithAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithAutocompleteMixin.js';
|
||||||
|
import { ApplicationCommandOptionWithChoicesMixin } from '../mixins/ApplicationCommandOptionWithChoicesMixin.js';
|
||||||
|
|
||||||
const numberValidator = s.number.int;
|
const numberValidator = s.number.int;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A slash command integer option.
|
* A slash command integer option.
|
||||||
*/
|
*/
|
||||||
@mix(ApplicationCommandNumericOptionMinMaxValueMixin, ApplicationCommandOptionWithChoicesAndAutocompleteMixin)
|
@mix(
|
||||||
|
ApplicationCommandNumericOptionMinMaxValueMixin,
|
||||||
|
ApplicationCommandOptionWithAutocompleteMixin,
|
||||||
|
ApplicationCommandOptionWithChoicesMixin,
|
||||||
|
)
|
||||||
export class SlashCommandIntegerOption
|
export class SlashCommandIntegerOption
|
||||||
extends ApplicationCommandOptionBase
|
extends ApplicationCommandOptionBase
|
||||||
implements ApplicationCommandNumericOptionMinMaxValueMixin
|
implements ApplicationCommandNumericOptionMinMaxValueMixin
|
||||||
@@ -58,4 +63,5 @@ export class SlashCommandIntegerOption
|
|||||||
|
|
||||||
export interface SlashCommandIntegerOption
|
export interface SlashCommandIntegerOption
|
||||||
extends ApplicationCommandNumericOptionMinMaxValueMixin,
|
extends ApplicationCommandNumericOptionMinMaxValueMixin,
|
||||||
ApplicationCommandOptionWithChoicesAndAutocompleteMixin<number> {}
|
ApplicationCommandOptionWithChoicesMixin<number>,
|
||||||
|
ApplicationCommandOptionWithAutocompleteMixin {}
|
||||||
|
|||||||
@@ -3,14 +3,19 @@ import { ApplicationCommandOptionType, type APIApplicationCommandNumberOption }
|
|||||||
import { mix } from 'ts-mixer';
|
import { mix } from 'ts-mixer';
|
||||||
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';
|
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';
|
||||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
||||||
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.js';
|
import { ApplicationCommandOptionWithAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithAutocompleteMixin.js';
|
||||||
|
import { ApplicationCommandOptionWithChoicesMixin } from '../mixins/ApplicationCommandOptionWithChoicesMixin.js';
|
||||||
|
|
||||||
const numberValidator = s.number;
|
const numberValidator = s.number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A slash command number option.
|
* A slash command number option.
|
||||||
*/
|
*/
|
||||||
@mix(ApplicationCommandNumericOptionMinMaxValueMixin, ApplicationCommandOptionWithChoicesAndAutocompleteMixin)
|
@mix(
|
||||||
|
ApplicationCommandNumericOptionMinMaxValueMixin,
|
||||||
|
ApplicationCommandOptionWithAutocompleteMixin,
|
||||||
|
ApplicationCommandOptionWithChoicesMixin,
|
||||||
|
)
|
||||||
export class SlashCommandNumberOption
|
export class SlashCommandNumberOption
|
||||||
extends ApplicationCommandOptionBase
|
extends ApplicationCommandOptionBase
|
||||||
implements ApplicationCommandNumericOptionMinMaxValueMixin
|
implements ApplicationCommandNumericOptionMinMaxValueMixin
|
||||||
@@ -58,4 +63,5 @@ export class SlashCommandNumberOption
|
|||||||
|
|
||||||
export interface SlashCommandNumberOption
|
export interface SlashCommandNumberOption
|
||||||
extends ApplicationCommandNumericOptionMinMaxValueMixin,
|
extends ApplicationCommandNumericOptionMinMaxValueMixin,
|
||||||
ApplicationCommandOptionWithChoicesAndAutocompleteMixin<number> {}
|
ApplicationCommandOptionWithChoicesMixin<number>,
|
||||||
|
ApplicationCommandOptionWithAutocompleteMixin {}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import { s } from '@sapphire/shapeshift';
|
|||||||
import { ApplicationCommandOptionType, type APIApplicationCommandStringOption } from 'discord-api-types/v10';
|
import { ApplicationCommandOptionType, type APIApplicationCommandStringOption } from 'discord-api-types/v10';
|
||||||
import { mix } from 'ts-mixer';
|
import { mix } from 'ts-mixer';
|
||||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
||||||
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.js';
|
import { ApplicationCommandOptionWithAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithAutocompleteMixin.js';
|
||||||
|
import { ApplicationCommandOptionWithChoicesMixin } from '../mixins/ApplicationCommandOptionWithChoicesMixin.js';
|
||||||
|
|
||||||
const minLengthValidator = s.number.greaterThanOrEqual(0).lessThanOrEqual(6_000);
|
const minLengthValidator = s.number.greaterThanOrEqual(0).lessThanOrEqual(6_000);
|
||||||
const maxLengthValidator = s.number.greaterThanOrEqual(1).lessThanOrEqual(6_000);
|
const maxLengthValidator = s.number.greaterThanOrEqual(1).lessThanOrEqual(6_000);
|
||||||
@@ -10,7 +11,7 @@ const maxLengthValidator = s.number.greaterThanOrEqual(1).lessThanOrEqual(6_000)
|
|||||||
/**
|
/**
|
||||||
* A slash command string option.
|
* A slash command string option.
|
||||||
*/
|
*/
|
||||||
@mix(ApplicationCommandOptionWithChoicesAndAutocompleteMixin)
|
@mix(ApplicationCommandOptionWithAutocompleteMixin, ApplicationCommandOptionWithChoicesMixin)
|
||||||
export class SlashCommandStringOption extends ApplicationCommandOptionBase {
|
export class SlashCommandStringOption extends ApplicationCommandOptionBase {
|
||||||
/**
|
/**
|
||||||
* The type of this option.
|
* The type of this option.
|
||||||
@@ -67,4 +68,6 @@ export class SlashCommandStringOption extends ApplicationCommandOptionBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SlashCommandStringOption extends ApplicationCommandOptionWithChoicesAndAutocompleteMixin<string> {}
|
export interface SlashCommandStringOption
|
||||||
|
extends ApplicationCommandOptionWithChoicesMixin<string>,
|
||||||
|
ApplicationCommandOptionWithAutocompleteMixin {}
|
||||||
|
|||||||
@@ -37,22 +37,22 @@ export interface IconData {
|
|||||||
/**
|
/**
|
||||||
* Represents the author data of an embed.
|
* Represents the author data of an embed.
|
||||||
*/
|
*/
|
||||||
export type EmbedAuthorData = IconData & Omit<APIEmbedAuthor, 'icon_url' | 'proxy_icon_url'>;
|
export interface EmbedAuthorData extends IconData, Omit<APIEmbedAuthor, 'icon_url' | 'proxy_icon_url'> {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the author options of an embed.
|
* Represents the author options of an embed.
|
||||||
*/
|
*/
|
||||||
export type EmbedAuthorOptions = Omit<EmbedAuthorData, 'proxyIconURL'>;
|
export interface EmbedAuthorOptions extends Omit<EmbedAuthorData, 'proxyIconURL'> {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the footer data of an embed.
|
* Represents the footer data of an embed.
|
||||||
*/
|
*/
|
||||||
export type EmbedFooterData = IconData & Omit<APIEmbedFooter, 'icon_url' | 'proxy_icon_url'>;
|
export interface EmbedFooterData extends IconData, Omit<APIEmbedFooter, 'icon_url' | 'proxy_icon_url'> {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the footer options of an embed.
|
* Represents the footer options of an embed.
|
||||||
*/
|
*/
|
||||||
export type EmbedFooterOptions = Omit<EmbedFooterData, 'proxyIconURL'>;
|
export interface EmbedFooterOptions extends Omit<EmbedFooterData, 'proxyIconURL'> {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the image data of an embed.
|
* Represents the image data of an embed.
|
||||||
@@ -170,7 +170,7 @@ export class EmbedBuilder {
|
|||||||
* You can set a maximum of 25 fields.
|
* You can set a maximum of 25 fields.
|
||||||
* @param fields - The fields to set
|
* @param fields - The fields to set
|
||||||
*/
|
*/
|
||||||
public setFields(...fields: RestOrArray<APIEmbedField>) {
|
public setFields(...fields: RestOrArray<APIEmbedField>): this {
|
||||||
this.spliceFields(0, this.data.fields?.length ?? 0, ...normalizeArray(fields));
|
this.spliceFields(0, this.data.fields?.length ?? 0, ...normalizeArray(fields));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user