chore(module.ts) Move Command Modules to different file, change context objs to class counterparts

This commit is contained in:
Jacob Nguyen
2022-03-07 23:49:38 -06:00
parent 707840bc76
commit 36831def0f
6 changed files with 52 additions and 54 deletions

View File

@@ -1,17 +1,18 @@
import type {
CommandInteraction,
Interaction,
Message
} from 'discord.js';
import { None, Option } from 'ts-results';
export class Context {
export default class Context {
private msg: Option<Message> = None;
private interac: Option<CommandInteraction> = None;
private interac: Option<Interaction> = None;
constructor(message : Option<Message>, interaction: Option<CommandInteraction> ) {
constructor(message : Option<Message>, interaction: Option<Interaction> ) {
this.msg = message;
this.interac = interaction
this.interac = interaction;
}
get messageUnchecked() {
return this.msg.unwrap();
}
@@ -25,3 +26,4 @@ export class Context {
return this.interac;
}
}

28
src/handler/module.ts Normal file
View File

@@ -0,0 +1,28 @@
import type { Visibility, possibleOutput, Arg } from '../types/handler';
import type { CommandType } from './sern';
import type Context from './context' ;
import type { Awaitable } from 'discord.js';
import type { Ok } from 'ts-results';
import type * as Utils from './utilities/preprocessors/args';
/**
* An object that gets imported and acts as a command.
* @typedef {object} Module<T=string>
* @property {string} desc
* @property {Visibility} visibility
* @property {CommandType} type
* @property {(eventParams : Context, args : Ok<T=string) => Awaitable<possibleOutput | void>)} execute
* @prop {(ctx: Context, args: Arg) => Utils.ArgType<T>} parse
*/
interface Module<T = string> {
alias: string[];
desc: string;
visibility: Visibility;
type: CommandType;
test: boolean;
execute: (eventParams: Context, args: Ok<T>) => Awaitable<possibleOutput | void>;
parse?: (ctx: Context, args: Arg) => Utils.ArgType<T>;
}
export default Module;

View File

@@ -1,16 +1,11 @@
import * as Files from './utilities/readFile';
import type * as Utils from './utilities/preprocessors/args';
import type {
possibleOutput,
Visibility,
Context,
Arg
} from '../types/handler';
import type {
ApplicationCommandOptionData,
Awaitable,
Client,
CommandInteraction,
Message
@@ -20,7 +15,8 @@ import { Ok, None, Some } from 'ts-results';
import { isNotFromBot, hasPrefix, fmt } from './utilities/messageHelpers';
import Logger, { sEvent } from './logger';
import { AllTrue } from './utilities/higherOrders';
import type Module from './module';
import Context from './context';
/**
* @class
*/
@@ -101,7 +97,7 @@ export class Handler {
if (name === undefined) return `Could not find ${interaction.commandName} command!`;
if (module.mod.type < CommandType.SLASH) return 'This is not a slash command';
const context = { message: None, interaction: Some(interaction) };
const context = new Context(None, Some(interaction));
const parsedArgs = module.mod.parse?.(context, ['slash', interaction.options]) ?? Ok('');
if (parsedArgs.err) return parsedArgs.val;
@@ -148,10 +144,7 @@ export class Handler {
return;
}
}
const context = {
message: Some(message),
interaction: None,
};
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;
@@ -296,25 +289,7 @@ export interface Wrapper {
readonly privateServers: { test: boolean; id: string }[];
}
/**
* An object that gets imported and acts as a command.
* @typedef {object} Module<T=string>
* @property {string} desc
* @property {Visibility} visibility
* @property {CommandType} type
* @property {(eventParams : Context, args : Ok<T=string>) => Awaitable<possibleOutput | void>)} execute
* @prop {(ctx: Context, args: Arg) => Utils.ArgType<T>} parse
*/
export interface Module<T = string> {
alias: string[];
desc: string;
visibility: Visibility;
type: CommandType;
test: boolean;
execute: (eventParams: Context, args: Ok<T>) => Awaitable<possibleOutput | void>;
parse?: (ctx: Context, args: Arg) => Utils.ArgType<T>;
}
/**
* @enum { number };

View File

@@ -212,7 +212,7 @@
function toTimeString<T extends string | number | symbol>(
unix: bigint | number,
units: Record<T, bigint>,
isFromNow: boolean = false,
isFromNow = false,
limit?: number
) {
if (typeof unix === 'number') unix = BigInt(unix);
@@ -255,7 +255,7 @@
const date = new Date(unix);
const timestamp = formatDate(date);
let ret = FrozenTimestampStyles[style];
for (let [key, value] of Object.entries(timestamp)) {
for (const [key, value] of Object.entries(timestamp)) {
ret = ret.split(`{${key}}`).join(value);
}
return ret;
@@ -361,7 +361,7 @@
static timestamp(
unix: number | Date | string,
format: TimestampStyles = TimestampStyles.BOTH_SHORT,
isSeconds: boolean = false
isSeconds = false
) {
if (typeof unix === 'string') unix = Number(unix);
if (unix instanceof Date) unix = unix.getTime();
@@ -375,7 +375,7 @@
static date(
unix: number | Date | string,
format: TimestampStyles = TimestampStyles.BOTH_SHORT,
isSeconds: boolean = false
isSeconds = false
) {
if (typeof unix === 'string') unix = Number(unix);
if (unix instanceof Date) unix = unix.getTime();
@@ -592,7 +592,7 @@
match<T extends DiscordRegexMatch>(
type: DiscordRegexNames,
onlyFirst: boolean = false
onlyFirst = false
): DiscordRegexPayload<T> {
const regex = DiscordRegex[type];
if (regex === undefined) {
@@ -698,7 +698,7 @@
static match(
raw: string,
what: DiscordRegexNames,
onlyFirst: boolean = false
onlyFirst = false
) {
return new this(raw).match(what, onlyFirst);
}

View File

@@ -1,11 +1,12 @@
import type { ApplicationCommandOptionData } from 'discord.js';
import type * as Sern from '../sern';
import type Module from '../module';
import { readdirSync, statSync } from 'fs';
import { basename, join } from 'path';
export type CommandVal = {
mod: Sern.Module<unknown> & { name : string };
mod: Module<unknown> & { name : string };
options: ApplicationCommandOptionData[];
};
@@ -32,20 +33,20 @@ export const fmtFileName = (n: string) => n.substring(0, n.length - 3);
/**
*
* @param {Sern.Handler} handler an instance of Sern.Handler
* @returns {Promise<{ name: string; mod: Sern.Module<unknown>; absPath: string; }[]>} data from command files
* @returns {Promise<{ name: string; mod: Module<unknown>; absPath: string; }[]>} data from command files
*/
export async function buildData(handler: Sern.Handler): Promise<
{
name: string;
mod: Sern.Module<unknown>;
mod: Module<unknown>;
absPath: string;
}[]
> {
const commandDir = handler.commandDir;
return Promise.all(
(await getCommands(commandDir)).map(async (absPath) => {
return { name: basename(absPath), mod: (await import(absPath)).default as Sern.Module<unknown>, absPath };
return { name: basename(absPath), mod: (await import(absPath)).default as Module<unknown>, absPath };
}),
);
}

View File

@@ -1,30 +1,22 @@
import type { Option } from 'ts-results';
import type {
CommandInteraction,
CommandInteractionOptionResolver,
Message,
MessagePayload,
MessageOptions,
} from 'discord.js';
import type * as Sern from '../handler/sern';
import type Module from '../handler/module';
export type Visibility = 'private' | 'public';
// Anything that can be sent in a `<TextChannel>#send` or `<CommandInteraction>#reply`
export type possibleOutput<T = string> = T | (MessagePayload & MessageOptions);
export type execute = Sern.Module<unknown>['execute'];
export type execute = Module<unknown>['execute'];
// Thanks @cursorsdottsx
export type ParseType<T> = {
[K in keyof T]: T[K] extends unknown ? [k: K, args: T[K]] : never;
}[keyof T];
// A Sern.Module['delegate'] will carry a Context Parameter
export type Context = {
message: Option<Message>;
interaction: Option<CommandInteraction>;
};
export type Arg = ParseType<{ text: string[]; slash: SlashOptions }>;