import { GuildChannel , GuildMember , Role , User } from 'discord.js' ; import { Except } from 'type-fest' ; import { Command } from '../command' ; import { addOption , getParamType } from '../reflection' ; import { OptionConfig , OptionMetadataTypes } from '../types' ; import { is } from '../util' ; param name param config returns export function forced ( name , config ) { return option ( name , { ... config , force : true , } ) ; } param name param config returns export function option ( name , config ) { return ( target , property , index ) => { if ( property !== 'run' ) { throw new Error ( `The @option() decorator can only be used on the .run method. You used it on ${ property . toString ( ) }` ) ; } if ( ! ( target instanceof Command ) ) { throw new Error ( `You can only use @option() on a class extending Command! You used ${ target . constructor . name }` ) ; } if ( config . type === 'MENTIONABLE' && ! config . force ) { throw new TypeError ( 'You have manually set the type to MENTIONABLE, but force mode is not on! This will cause errors.' ) ; } const type = getParamType ( target , index ) ; let chosenType ; switch ( true ) { case config . force : { if ( ! config . type ) { throw new Error ( 'Cannot use force mode without specifying a type' ) ; } chosenType = config . type ; break ; } case type === Object : { throw new Error ( 'Type cannot be inferred! You may need to enable force mode and specify the type manually.' ) ; } case type === String : { chosenType = 'STRING' ; break ; } case type === Boolean : { chosenType = 'BOOLEAN' ; break ; } case type === Number : { if ( ! config . type ) { throw new TypeError ( 'You must specify a type for numbers in the config!' ) ; } if ( ! is ( config . type , [ 'NUMBER' , 'INTEGER' ] ) ) { throw new TypeError ( `Number type must be either NUMBER or INTEGER. Received ${ config . type }` ) ; } chosenType = config . type ; break ; } case type === Role : { chosenType = 'ROLE' ; break ; } case type === User || type === GuildMember : { chosenType = 'USER' ; break ; } case type instanceof GuildChannel . constructor : { chosenType = 'CHANNEL' ; break ; } default : { throw new TypeError ( 'Unsupported data type.' ) ; } } if ( config . type && chosenType !== config . type && ! config . force ) { throw new TypeError ( `Type mismatch. Found ${ config . type } in the config, but inferred ${ chosenType }! Enable force mode in if this was a mistake.` ) ; } addOption ( target , { name , index , config : { ... config , type : chosenType , } , } ) ; } ; }