1- import type { CommandKit } from '../../CommandKit' ;
21import {
2+ ApplicationCommandType ,
33 AutocompleteInteraction ,
44 Awaitable ,
55 Collection ,
@@ -10,18 +10,20 @@ import {
1010 Message ,
1111 SlashCommandBuilder ,
1212} from 'discord.js' ;
13- import { Context } from '../commands/Context' ;
14- import { toFileURL } from '../../utils/resolve-file-url' ;
15- import { MessageCommandParser } from '../commands/MessageCommandParser' ;
16- import { CommandKitErrorCodes , isErrorType } from '../../utils/error-codes' ;
17- import { CommandRegistrar } from '../register/CommandRegistrar' ;
13+ import type { CommandKit } from '../../CommandKit' ;
1814import { AsyncFunction , GenericFunction } from '../../context/async-context' ;
1915import { Logger } from '../../logger/Logger' ;
20- import { Command , Middleware } from '../router ' ;
21- import { AppCommandRunner } from '../commands/AppCommandRunner ' ;
16+ import type { CommandData } from '../../types ' ;
17+ import colors from '../../utils/colors ' ;
2218import { COMMANDKIT_IS_DEV } from '../../utils/constants' ;
19+ import { CommandKitErrorCodes , isErrorType } from '../../utils/error-codes' ;
20+ import { toFileURL } from '../../utils/resolve-file-url' ;
2321import { rewriteCommandDeclaration } from '../../utils/types-package' ;
24- import colors from '../../utils/colors' ;
22+ import { AppCommandRunner } from '../commands/AppCommandRunner' ;
23+ import { Context } from '../commands/Context' ;
24+ import { MessageCommandParser } from '../commands/MessageCommandParser' ;
25+ import { CommandRegistrar } from '../register/CommandRegistrar' ;
26+ import { Command , Middleware } from '../router' ;
2527
2628/**
2729 * Function type for wrapping command execution with custom logic.
@@ -34,7 +36,7 @@ export type RunCommand = <T extends AsyncFunction>(fn: T) => T;
3436 * It can be used to define slash commands, context menu commands, and message commands.
3537 */
3638export interface AppCommandNative {
37- command : SlashCommandBuilder | Record < string , any > ;
39+ command : CommandData | Record < string , any > ;
3840 chatInput ?: ( ctx : Context ) => Awaitable < unknown > ;
3941 autocomplete ?: ( ctx : Context ) => Awaitable < unknown > ;
4042 message ?: ( ctx : Context ) => Awaitable < unknown > ;
@@ -127,6 +129,10 @@ const commandDataSchema = {
127129 userContextMenu : ( c : unknown ) => typeof c === 'function' ,
128130} ;
129131
132+ export type CommandDataSchema = typeof commandDataSchema ;
133+ export type CommandDataSchemaKey = keyof CommandDataSchema ;
134+ export type CommandDataSchemaValue = CommandDataSchema [ CommandDataSchemaKey ] ;
135+
130136/**
131137 * @private
132138 * @internal
@@ -674,29 +680,51 @@ export class AppCommandHandler {
674680 data : {
675681 command : {
676682 name : command . name ,
677- description : `${ command . name } commands ` ,
683+ description : `${ command . name } command ` ,
678684 type : 1 ,
679685 } ,
680686 } ,
681687 } ) ;
682688 return ;
683689 }
684690
685- const data = await import ( `${ toFileURL ( command . path ) } ?t=${ Date . now ( ) } ` ) ;
691+ const commandFileData = ( await import (
692+ `${ toFileURL ( command . path ) } ?t=${ Date . now ( ) } `
693+ ) ) as AppCommandNative ;
686694
687- if ( ! data . command ) {
695+ if ( ! commandFileData . command ) {
688696 throw new Error (
689697 `Invalid export for command ${ command . name } : no command definition found` ,
690698 ) ;
691699 }
692700
701+ if (
702+ ( ! commandFileData . command . type ||
703+ commandFileData . command . type === ApplicationCommandType . ChatInput ) &&
704+ ! commandFileData . command . description
705+ ) {
706+ commandFileData . command . description = `${ command . name } command` ;
707+ }
708+
693709 let handlerCount = 0 ;
694- for ( const [ key , validator ] of Object . entries ( commandDataSchema ) ) {
695- if ( key !== 'command' && data [ key ] ) handlerCount ++ ;
696- if ( data [ key ] && ! ( await validator ( data [ key ] ) ) ) {
697- throw new Error (
698- `Invalid export for command ${ command . name } : ${ key } does not match expected value` ,
699- ) ;
710+
711+ for ( const [ key , propValidator ] of Object . entries ( commandDataSchema ) as [
712+ CommandDataSchemaKey ,
713+ CommandDataSchemaValue ,
714+ ] [ ] ) {
715+ const exportedProp = commandFileData [ key ] ;
716+
717+ if ( exportedProp ) {
718+ if ( ! ( await propValidator ( exportedProp ) ) ) {
719+ throw new Error (
720+ `Invalid export for command ${ command . name } : ${ key } does not match expected value` ,
721+ ) ;
722+ }
723+
724+ if ( key !== 'command' ) {
725+ // command file includes a handler function (chatInput, message, etc)
726+ handlerCount ++ ;
727+ }
700728 }
701729 }
702730
@@ -706,7 +734,7 @@ export class AppCommandHandler {
706734 ) ;
707735 }
708736
709- let lastUpdated = data . command ;
737+ let lastUpdated = commandFileData . command ;
710738
711739 await this . commandkit . plugins . execute ( async ( ctx , plugin ) => {
712740 const res = await plugin . prepareCommand ( ctx , lastUpdated ) ;
@@ -718,9 +746,9 @@ export class AppCommandHandler {
718746
719747 this . loadedCommands . set ( id , {
720748 command,
721- guilds : data . guilds ,
749+ guilds : commandFileData . command . guilds ,
722750 data : {
723- ...data ,
751+ ...commandFileData ,
724752 command : 'toJSON' in lastUpdated ? lastUpdated . toJSON ( ) : lastUpdated ,
725753 } ,
726754 } ) ;
0 commit comments