diff --git a/src/handler/events/readyEvent.ts b/src/handler/events/readyEvent.ts index 53404fc..92e942c 100644 --- a/src/handler/events/readyEvent.ts +++ b/src/handler/events/readyEvent.ts @@ -1,7 +1,9 @@ -import { concatMap, first, fromEvent, pipe, tap } from "rxjs"; +import { concatMap, first, from, fromEvent, map, pipe, tap } from "rxjs"; +import { basename } from 'path'; import * as Files from '../utilities/readFile'; import type Wrapper from '../structures/wrapper'; - +import type { Command } from "../structures/commands/command"; +import type { ApplicationCommandOptionData } from "discord.js"; export const onReady = ( wrapper : Wrapper ) => { const { client, init, commands, } = wrapper; fromEvent(client, 'ready') @@ -11,11 +13,24 @@ export const onReady = ( wrapper : Wrapper ) => { concatMap( pipe( () => Files.buildData(commands), + ( createCommandCache ) ) ), ) - .subscribe(); + .subscribe( () => console.log(Files.Commands)); } -async function createCommandCache( ) { +function setCommands ( { mod, absPath } : { mod : Command, absPath : string } ) { + const options = mod.options ?? [] as ApplicationCommandOptionData[]; + const name = mod.name ?? Files.fmtFileName(basename(absPath)); + + mod.alias?.forEach( n => Files.Alias.set( n, { mod, options } )); + + Files.Commands.set(name, { mod, options }); +} + +async function createCommandCache( + arr: Promise<{mod: Command, absPath: string}[]> + ) { + from(await arr).subscribe ( setCommands ); } diff --git a/src/handler/sern.ts b/src/handler/sern.ts index 8f9a4ca..c4cef72 100644 --- a/src/handler/sern.ts +++ b/src/handler/sern.ts @@ -1,4 +1,3 @@ -import * as Files from './utilities/readFile'; import type { DiscordEvent, possibleOutput, @@ -48,10 +47,9 @@ export class Handler { */ constructor(wrapper: Wrapper) { this.wrapper = wrapper; - this.client - - + } +/** .on('messageCreate', async (message: Message) => { const module = this.findModuleFrom(message); if (module === undefined) { @@ -86,12 +84,7 @@ export class Handler { }); } - /** - * - * @param {Files.CommandVal} module Command file information - * @param {CommandInteraction} interaction The Discord.js command interaction (DiscordJS#CommandInteraction)) - * @returns {possibleOutput | undefined} Takes return value and replies it, if possible input - */ + private async interactionResult( module: Files.CommandVal, @@ -109,13 +102,7 @@ export class Handler { return (module.mod.execute?.(context, parsedArgs) as possibleOutput | undefined); } - /** - * - * @param {Files.CommandVal} module Command file information - * @param {Message} message The message object - * @param {string} args Anything after the command - * @returns Takes return value and replies it, if possible input - */ + private async commandResult( module: Files.CommandVal, @@ -129,159 +116,22 @@ export class Handler { ); return; } - if (module.mod.visibility === 'private') { - const checkIsTestServer = this.privateServers.find(({ id }) => id === message.guildId!)?.test; - if (checkIsTestServer === undefined) { - this.defaultLogger.log( - sEvent.MISUSE_CMD, - message.guildId!, - `The text command ${module.mod.name} has private modifier but is not registered in private server config.` - ); - return; - } - if (checkIsTestServer !== module.mod.test) { - this.defaultLogger.log( - sEvent.MISUSE_CMD, - message.guildId!, - `The command ${module.mod.name} is only available on test servers.` - ); - return; - } - } const context = new Context ( Some(message), None ); const args = message.content.slice(this.prefix.length).trim().split(/s+/g); const parsedArgs = module.mod.parse?.(context, ['text', args]) ?? Ok(args); if (parsedArgs.err) return parsedArgs.val; return (module.mod.execute?.(context, parsedArgs) as possibleOutput | undefined); - } - - /** - * This function chains `Files.buildData` - * @param {{name: string, mod: Module, absPath: string}} modArr module information - */ - - private async registerModules( - modArr: { - name: string; - mod: Module; - absPath: string; - }[], - ) { - for await (const { name, mod, absPath } of modArr) { - const cmdName = Files.fmtFileName(name); - switch (mod.type) { - case 1: - Files.Commands.set(cmdName, { mod: { name: cmdName, ...mod }, options: [] }); - break; - case 2: - case 1 | 2: - { - const options = (await import(absPath)).options as ApplicationCommandOptionData[]; - Files.Commands.set(cmdName, { mod: { name: cmdName, ...mod }, options: options ?? [] }); - switch (mod.visibility) { - case 'private': { - // Reloading guild slash commands - await this.reloadSlash(cmdName, mod.desc, options); - } - case 'public': { - // Creating global commands - await this.client.application!.commands.create({ - name: cmdName, - description: mod.desc, - options, - }); - } - } - } - break; - default: - throw Error(`SernHandlerError: ${name} with ${mod.visibility} is not a valid module type.`); - } - - if (mod.alias.length > 0) { - for (const alias of mod.alias) { - Files.Alias.set(alias, { mod: { name: cmdName, ...mod }, options: [] }); - } - } - } - } - - /** - * - * @param {T extends Message | CommandInteraction} ctx name of possible command - * @returns {Files.CommandVal | undefined} - */ - - private findModuleFrom(ctx: T): Files.CommandVal | undefined { - const name = ctx.applicationId === null ? fmt(ctx as Message, this.prefix).shift()! : (ctx as CommandInteraction).commandName; - return Files.Commands.get(name) ?? Files.Alias.get(name); - } - - /** - * - * @param {string} cmdName name of command - * @param {string} description description of command - * @param {ApplicationCommandOptionData[]} options any options for the slash command - */ - - private async reloadSlash( - cmdName: string, - description: string, - options: ApplicationCommandOptionData[], - ): Promise { - for (const { id } of this.privateServers) { - const guild = await this.client.guilds.fetch(id); - guild.commands.create({ - name: cmdName, - description, - options, - }); - } - } - - /** - * @readonly - * @returns {string} The prefix used for legacy commands - */ - - get prefix(): string { - return this.wrapper.defaultPrefix; - } - - /** - * @readonly - * @returns {string} Directory of the commands folder - */ - - get commandDir(): string { - return this.wrapper.commands; - } - - /** - * @readonly - * @returns {Client} the discord.js client (DiscordJS#Client)); - */ - - get client(): Client { - return this.wrapper.client; - } - - /** - * @readonly - * @returns {{test: boolean, id: string}[]} Private server ID for testing or personal use - */ - - get privateServers(): { test: boolean; id: string }[] { - return this.wrapper.privateServers; - } -} + }; +*/ +} /** * @enum { number }; */ export enum CommandType { - TEXT = 1, - SLASH = 2, + TEXT = 0b0001, + SLASH = 0b0010, + BOTH = 0b0011 } diff --git a/src/handler/structures/commands/command.ts b/src/handler/structures/commands/command.ts index 068f4ed..85c049c 100644 --- a/src/handler/structures/commands/command.ts +++ b/src/handler/structures/commands/command.ts @@ -1,26 +1,44 @@ -import type { Awaitable } from "discord.js"; +import type { ApplicationCommandOptionData, Awaitable } from "discord.js"; import type { possibleOutput, Arg } from "../../../types/handler"; import Context from "../context"; import type * as Utils from '../../utilities/preprocessors/args'; import { None, Ok } from "ts-results"; -import type { CommandType } from "../../sern"; +import { CommandType } from "../../sern"; export abstract class Command { - protected name : string | undefined; + protected _name? : string | undefined; protected _ctx : Context = new Context( None, None ); - protected commandType : CommandType; - + protected _commandType : CommandType; + protected _options : ApplicationCommandOptionData[] | undefined; + protected _alias : string[] | undefined; protected constructor ( - name : string | undefined, - commandType : CommandType + commandType : CommandType, + options?: ApplicationCommandOptionData[], + alias? : string[], + name? : string | undefined ) { - this.name = name; - this.commandType = commandType; + this._name = name; + this._commandType = commandType; + switch ( commandType ) { + case CommandType.TEXT : { + this._alias = alias; + this._options = undefined; + } break; + case CommandType.SLASH : case CommandType.BOTH : { + this._alias = undefined + this._options = options; + } break; + + } } abstract execute ( args: Ok ) : Awaitable; - abstract parse? (args: Arg) : Utils.ArgType; - private set ctx ( context: Context ) { this._ctx = context; } + abstract parse? ( args: Arg ) : Utils.ArgType; + public set ctx ( context: Context ) { this._ctx = context; } + public get name () { return this._name; } + public get commandType () { return this._commandType; } + public get options() { return this._options; } + public get alias() { return this._alias } } diff --git a/src/handler/utilities/readFile.ts b/src/handler/utilities/readFile.ts index 4e11be1..adc4dfb 100644 --- a/src/handler/utilities/readFile.ts +++ b/src/handler/utilities/readFile.ts @@ -1,5 +1,4 @@ import type { ApplicationCommandOptionData } from 'discord.js'; -import type Module from '../structures/module'; import { readdirSync, statSync } from 'fs'; import { join } from 'path';