diff --git a/package-lock.json b/package-lock.json index 8647a1367c2e..bf463116201b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@types/ws": "^8.2.0", "discord-api-types": "^0.24.0", "node-fetch": "^2.6.1", + "type-fest": "^2.5.3", "ws": "^8.2.3" }, "devDependencies": { @@ -5861,20 +5862,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/fstream": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", @@ -6454,6 +6441,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globals/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globby": { "version": "11.0.4", "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", @@ -9727,17 +9726,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ow/node_modules/type-fest": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.5.2.tgz", - "integrity": "sha512-WMbytmAs5PUTqwGJRE+WoRrD2S0bYFtHX8k4Y/1l18CG5kqA3keJud9pPQ/r30FE9n8XRFCXF9BbccHIZzRYJw==", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -11368,6 +11356,7 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", + "deprecated": "This version of tar is no longer supported, and will not receive security updates. Please upgrade asap.", "dev": true, "dependencies": { "block-stream": "*", @@ -12044,12 +12033,11 @@ } }, "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.6.0.tgz", + "integrity": "sha512-XN1FDGGtaSDA6CFsCW5iolTQqFsnJ+ZF6JqSz0SqXoh4F8GY0xqUv5RYnTilpmL+sOH8OH4FX8tf9YyAPM2LDA==", "engines": { - "node": ">=10" + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -17193,13 +17181,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, "fstream": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", @@ -17647,6 +17628,14 @@ "dev": true, "requires": { "type-fest": "^0.20.2" + }, + "dependencies": { + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } } }, "globby": { @@ -20147,11 +20136,6 @@ "requires": { "is-obj": "^2.0.0" } - }, - "type-fest": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.5.2.tgz", - "integrity": "sha512-WMbytmAs5PUTqwGJRE+WoRrD2S0bYFtHX8k4Y/1l18CG5kqA3keJud9pPQ/r30FE9n8XRFCXF9BbccHIZzRYJw==" } } }, @@ -21930,10 +21914,9 @@ "dev": true }, "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.6.0.tgz", + "integrity": "sha512-XN1FDGGtaSDA6CFsCW5iolTQqFsnJ+ZF6JqSz0SqXoh4F8GY0xqUv5RYnTilpmL+sOH8OH4FX8tf9YyAPM2LDA==" }, "typedarray": { "version": "0.0.6", diff --git a/package.json b/package.json index 1a73c0053135..6ba8da221f33 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "@types/ws": "^8.2.0", "discord-api-types": "^0.24.0", "node-fetch": "^2.6.1", + "type-fest": "^2.5.3", "ws": "^8.2.3" }, "devDependencies": { diff --git a/tslint.json b/tslint.json index d66f7bdf3b60..151105a8b488 100644 --- a/tslint.json +++ b/tslint.json @@ -24,6 +24,7 @@ "array-type": [true, "array"], "one-line": false, "no-any-union": false, - "void-return": false + "void-return": false, + "unified-signatures": false } } diff --git a/typings/index.d.ts b/typings/index.d.ts index 66128dba8ec1..caf703c903c3 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -45,6 +45,7 @@ import { APIUser, GatewayVoiceServerUpdateDispatchData, GatewayVoiceStateUpdateDispatchData, + RESTPatchAPIApplicationCommandJSONBody, RESTPostAPIApplicationCommandsJSONBody, Snowflake, } from 'discord-api-types/v9'; @@ -137,6 +138,7 @@ import { RawWidgetData, RawWidgetMemberData, } from './rawDataTypes'; +import type { CamelCasedPropertiesDeep } from 'type-fest'; //#region Classes @@ -213,7 +215,7 @@ export class ApplicationCommand extends Base { public readonly manager: ApplicationCommandManager; public id: Snowflake; public name: string; - public options: ApplicationCommandOption[]; + public options: Camelize[]; public permissions: ApplicationCommandPermissionsManager< PermissionsFetchType, PermissionsFetchType, @@ -224,23 +226,29 @@ export class ApplicationCommand extends Base { public type: ApplicationCommandType; public version: Snowflake; public delete(): Promise>; + /** @deprecated use `edit(Camelize)` instead */ public edit(data: ApplicationCommandData): Promise>; + public edit( + data: Camelize, + ): Promise>; public equals( - command: ApplicationCommand | ApplicationCommandData | RawApplicationCommandData, + command: ApplicationCommand | Camelize | RawApplicationCommandData, enforceOptionorder?: boolean, ): boolean; public static optionsEqual( - existing: ApplicationCommandOption[], - options: ApplicationCommandOption[] | ApplicationCommandOptionData[] | APIApplicationCommandOption[], + existing: Camelize[], + options: Camelize[] | APIApplicationCommandOption[], enforceOptionorder?: boolean, ): boolean; private static _optionEquals( - existing: ApplicationCommandOption, - options: ApplicationCommandOption | ApplicationCommandOptionData | APIApplicationCommandOption, + existing: Camelize[], + options: Camelize[] | APIApplicationCommandOption, enforceOptionorder?: boolean, ): boolean; - private static transformOption(option: ApplicationCommandOptionData, received?: boolean): unknown; - private static transformCommand(command: ApplicationCommandData): RESTPostAPIApplicationCommandsJSONBody; + private static transformOption(option: Camelize, received?: boolean): unknown; + private static transformCommand( + command: Camelize, + ): RESTPostAPIApplicationCommandsJSONBody; private static isAPICommandData(command: object): command is RESTPostAPIApplicationCommandsJSONBody; } @@ -2336,10 +2344,8 @@ export class WebhookClient extends WebhookMixin(BaseClient) { options: string | MessagePayload | WebhookEditMessageOptions, ): Promise; public fetchMessage(message: Snowflake, options?: WebhookFetchMessageOptions): Promise; - /* tslint:disable:unified-signatures */ /** @deprecated */ public fetchMessage(message: Snowflake, cache?: boolean): Promise; - /* tslint:enable:unified-signatures */ public send(options: string | MessagePayload | WebhookMessageOptions): Promise; } @@ -2640,7 +2646,9 @@ export abstract class CachedManager extends DataManager + | RESTPostAPIApplicationCommandsJSONBody; export class ApplicationCommandManager< ApplicationCommandScope = ApplicationCommand<{ guild: GuildResolvable }>, @@ -2656,7 +2664,18 @@ export class ApplicationCommandManager< null >; private commandPath({ id, guildId }: { id?: Snowflake; guildId?: Snowflake }): unknown; + /** @deprecated use `create(ApplicationCommandDataResolvable)` instead */ + public create( + command: ApplicationCommandData | RESTPostAPIApplicationCommandsJSONBody, + ): Promise; + /** @deprecated use `create(ApplicationCommandDataResolvable, Snowflake)` instead */ + public create( + command: ApplicationCommandData | RESTPostAPIApplicationCommandsJSONBody, + guildId: Snowflake, + ): Promise; public create(command: ApplicationCommandDataResolvable, guildId?: Snowflake): Promise; + /** @deprecated use `delete(ApplicationCommandDataResolvable, Snowflake?)` instead */ + public delete(command: ApplicationCommandData, guildId?: Snowflake): Promise; public delete(command: ApplicationCommandResolvable, guildId?: Snowflake): Promise; public edit( command: ApplicationCommandResolvable, @@ -2677,13 +2696,20 @@ export class ApplicationCommandManager< id?: Snowflake, options?: FetchApplicationCommandOptions, ): Promise>; + /** @deprecated Use `set(ApplicationCommandResolvable)` instead */ + public set(commands: ApplicationCommandData[]): Promise>; + /** @deprecated Use `set(ApplicationCommandResolvable, Snowflake)` instead */ + public set( + commands: ApplicationCommandData[], + guildId: Snowflake, + ): Promise>; public set(commands: ApplicationCommandDataResolvable[]): Promise>; public set( commands: ApplicationCommandDataResolvable[], guildId: Snowflake, ): Promise>; private static transformCommand( - command: ApplicationCommandData, + command: Camelize, ): Omit; } @@ -2748,7 +2774,9 @@ export class GuildApplicationCommandManager extends ApplicationCommandManager); public guild: Guild; public create(command: ApplicationCommandDataResolvable): Promise; - public delete(command: ApplicationCommandResolvable): Promise; + /** @deprecated use `delete(ApplicationCommandDataResolvable, Snowflake?)` instead */ + public delete(command: ApplicationCommandData, guildId?: Snowflake): Promise; + public delete(command: ApplicationCommandResolvable, guildId?: Snowflake): Promise; public edit( command: ApplicationCommandResolvable, data: ApplicationCommandDataResolvable, @@ -2756,6 +2784,8 @@ export class GuildApplicationCommandManager extends ApplicationCommandManager; public fetch(options: BaseFetchOptions): Promise>; public fetch(id?: undefined, options?: BaseFetchOptions): Promise>; + /** @deprecated Use `set(ApplicationCommandResolvable)` instead */ + public set(commands: ApplicationCommandData[]): Promise>; public set(commands: ApplicationCommandDataResolvable[]): Promise>; } @@ -3074,10 +3104,8 @@ export interface PartialWebhookFields { options: string | MessagePayload | WebhookEditMessageOptions, ): Promise; fetchMessage(message: Snowflake | '@original', options?: WebhookFetchMessageOptions): Promise; - /* tslint:disable:unified-signatures */ /** @deprecated */ fetchMessage(message: Snowflake | '@original', cache?: boolean): Promise; - /* tslint:enable:unified-signatures */ send(options: string | MessagePayload | WebhookMessageOptions): Promise; } @@ -3343,6 +3371,7 @@ export interface ChatInputApplicationCommandData extends BaseApplicationCommandD options?: ApplicationCommandOptionData[]; } +/** @deprecated use `Camelize` instead */ export type ApplicationCommandData = | UserApplicationCommandData | MessageApplicationCommandData @@ -3430,6 +3459,10 @@ export interface ApplicationCommandNonOptions extends BaseApplicationCommandOpti type: Exclude; } +// Type alias since the lib name is very long. +export type Camelize = CamelCasedPropertiesDeep; + +/** @deprecated Use `Camelize` instead. */ export type ApplicationCommandOptionData = | ApplicationCommandSubGroupData | ApplicationCommandNonOptionsData @@ -3439,6 +3472,7 @@ export type ApplicationCommandOptionData = | ApplicationCommandNumericOptionData | ApplicationCommandSubCommandData; +/** @deprecated use `Camelize` instead */ export type ApplicationCommandOption = | ApplicationCommandSubGroup | ApplicationCommandNonOptions diff --git a/typings/index.test-d.ts b/typings/index.test-d.ts index 9eb72d8e9bfd..cbaf73061d12 100644 --- a/typings/index.test-d.ts +++ b/typings/index.test-d.ts @@ -1,5 +1,4 @@ -import type { ChildProcess } from 'child_process'; -import type { +import { APIInteractionGuildMember, APIMessage, APIPartialChannel, @@ -7,15 +6,21 @@ import type { APIInteractionDataResolvedGuildMember, APIInteractionDataResolvedChannel, APIRole, + ChannelType, + ApplicationCommandOptionType, + APIApplicationCommand, + APIApplicationCommandOption, + APIApplicationCommandSubCommandOptions, } from 'discord-api-types/v9'; +import type { ChildProcess } from 'node:child_process'; import { ApplicationCommand, - ApplicationCommandData, + ApplicationCommandChannelOptionData, + ApplicationCommandChoicesData, ApplicationCommandManager, - ApplicationCommandOptionData, + ApplicationCommandNonOptionsData, ApplicationCommandResolvable, ApplicationCommandSubCommandData, - ApplicationCommandSubGroupData, BaseCommandInteraction, ButtonInteraction, CacheType, @@ -28,7 +33,6 @@ import { CommandInteraction, CommandInteractionOption, CommandInteractionOptionResolver, - CommandOptionNonChoiceResolvableType, Constants, ContextMenuInteraction, DMChannel, @@ -77,6 +81,9 @@ import { User, VoiceChannel, Shard, + Camelize, + ApplicationCommandAutocompleteOption, + ApplicationCommandNumericOptionData, WebSocketShard, Collector, } from '.'; @@ -686,6 +693,20 @@ client.login('absolutely-valid-token'); // Test client conditional types client.on('ready', client => { expectType>(client); + + // Test camelized post command data. + client.application.commands.create({ + name: 'Foo', + description: 'Bar', + options: [ + { + name: 'test', + description: 'test', + type: ApplicationCommandOptionType.Channel, + channelTypes: [ChannelType.GuildCategory], + }, + ], + }); }); declare const loggedInClient: Client; @@ -783,7 +804,7 @@ expectType<1>(Constants.Status.CONNECTING); expectType<0>(Constants.Opcodes.DISPATCH); expectType<2>(Constants.ClientApplicationAssetTypes.BIG); -declare const applicationCommandData: ApplicationCommandData; +declare const applicationCommandData: Camelize; declare const applicationCommandResolvable: ApplicationCommandResolvable; declare const applicationCommandManager: ApplicationCommandManager; { @@ -805,22 +826,29 @@ declare const applicationCommandManager: ApplicationCommandManager; ); } -declare const applicationNonChoiceOptionData: ApplicationCommandOptionData & { - type: CommandOptionNonChoiceResolvableType; -}; +declare const applicationSubGroupCommandData: Camelize; { - // Options aren't allowed on this command type. - - // @ts-expect-error - applicationNonChoiceOptionData.choices; + expectType( + applicationSubGroupCommandData.type, + ); + expectAssignable(applicationSubGroupCommandData.options); } -declare const applicationSubGroupCommandData: ApplicationCommandSubGroupData; +declare const applicationSubCommandData: ApplicationCommandSubCommandData; { - expectType<'SUB_COMMAND_GROUP' | ApplicationCommandOptionTypes.SUB_COMMAND_GROUP>( - applicationSubGroupCommandData.type, - ); - expectType(applicationSubGroupCommandData.options); + expectType<'SUB_COMMAND' | ApplicationCommandOptionTypes.SUB_COMMAND>(applicationSubCommandData.type); + + // Check that only subcommands can have no subcommand or subcommand group sub-options. + expectType< + | ( + | ApplicationCommandChoicesData + | ApplicationCommandNonOptionsData + | ApplicationCommandChannelOptionData + | ApplicationCommandAutocompleteOption + | ApplicationCommandNumericOptionData + )[] + | undefined + >(applicationSubCommandData.options); } declare const guildApplicationCommandManager: GuildApplicationCommandManager;