mirror of
https://github.com/sern-handler/handler
synced 2026-06-20 06:42:14 +00:00
style: Formatted 17 files & changes messageHelper util
This commit is contained in:
@@ -3,5 +3,5 @@
|
||||
"trailingComma": "all",
|
||||
"singleQuote": true,
|
||||
"printWidth": 120,
|
||||
"tabWidth": 4
|
||||
"tabWidth": 2
|
||||
}
|
||||
|
||||
69
package-lock.json
generated
69
package-lock.json
generated
@@ -26,7 +26,7 @@
|
||||
"cz-conventional-changelog": "^3.0.1",
|
||||
"jest": "^27.5.1",
|
||||
"standard-version": "^9.3.2",
|
||||
"typedoc": "^0.22.11",
|
||||
"typedoc": "^0.22.14",
|
||||
"typescript": "^4.5.5"
|
||||
}
|
||||
},
|
||||
@@ -8494,16 +8494,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typedoc": {
|
||||
"version": "0.22.11",
|
||||
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.11.tgz",
|
||||
"integrity": "sha512-pVr3hh6dkS3lPPaZz1fNpvcrqLdtEvXmXayN55czlamSgvEjh+57GUqfhAI1Xsuu/hNHUT1KNSx8LH2wBP/7SA==",
|
||||
"version": "0.22.14",
|
||||
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.14.tgz",
|
||||
"integrity": "sha512-tlf9wIcsrnQSjetStrnRutuy2RjZkG5PK2umwveZLTkuC2K9VywOZTdu2G19BdOPzGrhZjf9WK7pthXqnFQejg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"glob": "^7.2.0",
|
||||
"lunr": "^2.3.9",
|
||||
"marked": "^4.0.10",
|
||||
"minimatch": "^3.0.4",
|
||||
"shiki": "^0.10.0"
|
||||
"marked": "^4.0.12",
|
||||
"minimatch": "^5.0.1",
|
||||
"shiki": "^0.10.1"
|
||||
},
|
||||
"bin": {
|
||||
"typedoc": "bin/typedoc"
|
||||
@@ -8512,7 +8512,28 @@
|
||||
"node": ">= 12.10.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x"
|
||||
"typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x"
|
||||
}
|
||||
},
|
||||
"node_modules/typedoc/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typedoc/node_modules/minimatch": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
|
||||
"integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
@@ -15296,16 +15317,36 @@
|
||||
}
|
||||
},
|
||||
"typedoc": {
|
||||
"version": "0.22.11",
|
||||
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.11.tgz",
|
||||
"integrity": "sha512-pVr3hh6dkS3lPPaZz1fNpvcrqLdtEvXmXayN55czlamSgvEjh+57GUqfhAI1Xsuu/hNHUT1KNSx8LH2wBP/7SA==",
|
||||
"version": "0.22.14",
|
||||
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.14.tgz",
|
||||
"integrity": "sha512-tlf9wIcsrnQSjetStrnRutuy2RjZkG5PK2umwveZLTkuC2K9VywOZTdu2G19BdOPzGrhZjf9WK7pthXqnFQejg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "^7.2.0",
|
||||
"lunr": "^2.3.9",
|
||||
"marked": "^4.0.10",
|
||||
"minimatch": "^3.0.4",
|
||||
"shiki": "^0.10.0"
|
||||
"marked": "^4.0.12",
|
||||
"minimatch": "^5.0.1",
|
||||
"shiki": "^0.10.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
|
||||
"integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"scripts": {
|
||||
"compile": "tsc",
|
||||
"watch": "tsc -w",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
@@ -34,7 +34,7 @@
|
||||
"cz-conventional-changelog": "^3.0.1",
|
||||
"jest": "^27.5.1",
|
||||
"standard-version": "^9.3.2",
|
||||
"typedoc": "^0.22.11",
|
||||
"typedoc": "^0.22.14",
|
||||
"typescript": "^4.5.5"
|
||||
},
|
||||
"config": {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
|
||||
import type { Interaction } from 'discord.js';
|
||||
import type Wrapper from '../structures/wrapper';
|
||||
|
||||
import * as Files from '../utilities/readFile';
|
||||
import Context from '../structures/context';
|
||||
|
||||
import { fromEvent, Observable, of, concatMap } from 'rxjs';
|
||||
import { CommandType } from '../sern';
|
||||
import Context from '../structures/context';
|
||||
import type Wrapper from '../structures/wrapper';
|
||||
import * as Files from '../utilities/readFile';
|
||||
import { filterTap } from './observableHandling';
|
||||
import { filter } from 'rxjs';
|
||||
|
||||
|
||||
@@ -1,39 +1,43 @@
|
||||
import type { ChatInputCommandInteraction, Message } from 'discord.js';
|
||||
import { fromEvent, Observable, of, concatMap } from 'rxjs';
|
||||
import { CommandType } from '../sern';
|
||||
import Context from '../structures/context';
|
||||
import type { Message } from 'discord.js';
|
||||
import type Wrapper from '../structures/wrapper';
|
||||
import { fmt } from '../utilities/messageHelpers';
|
||||
|
||||
import { fromEvent, Observable, of, concatMap } from 'rxjs';
|
||||
|
||||
import Context from '../structures/context';
|
||||
import * as Files from '../utilities/readFile';
|
||||
|
||||
import { fmt } from '../utilities/messageHelpers';
|
||||
import { CommandType } from '../sern';
|
||||
import { filterTap, ignoreNonBot } from './observableHandling';
|
||||
|
||||
export const onMessageCreate = (wrapper : Wrapper) => {
|
||||
const { client, defaultPrefix } = wrapper;
|
||||
(<Observable<Message>> fromEvent( client, 'messageCreate'))
|
||||
.pipe (
|
||||
ignoreNonBot(defaultPrefix),
|
||||
concatMap ( m => {
|
||||
const [ prefix, ...data ] = fmt(m, defaultPrefix);
|
||||
export const onMessageCreate = (wrapper: Wrapper) => {
|
||||
const { client, defaultPrefix } = wrapper;
|
||||
|
||||
(<Observable<Message>>fromEvent(client, 'messageCreate'))
|
||||
.pipe(
|
||||
ignoreNonBot(defaultPrefix),
|
||||
concatMap(m => {
|
||||
const [prefix, ...data] = fmt({ msg: m, prefix: defaultPrefix });
|
||||
const posMod = Files.Commands.get(prefix) ?? Files.Alias.get(prefix);
|
||||
|
||||
return of( posMod )
|
||||
.pipe (
|
||||
filterTap(CommandType.TEXT, mod => {
|
||||
const ctx = Context.wrap(m);
|
||||
mod.execute(ctx, ['text', data]);
|
||||
})
|
||||
);
|
||||
})
|
||||
).subscribe ({
|
||||
error(e) {
|
||||
//log things
|
||||
throw e;
|
||||
},
|
||||
next(command) {
|
||||
//log on each command emitted
|
||||
console.log(command);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
return of(posMod)
|
||||
.pipe(
|
||||
filterTap(CommandType.TEXT, mod => {
|
||||
const ctx = Context.wrap(m);
|
||||
mod.execute(ctx, ['text', data]);
|
||||
})
|
||||
);
|
||||
})
|
||||
).subscribe({
|
||||
error(e) {
|
||||
// Log the errors
|
||||
|
||||
throw e;
|
||||
},
|
||||
next(command) {
|
||||
// Log on each command emitted
|
||||
|
||||
console.log(command);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,63 +1,65 @@
|
||||
import type { Awaitable, Message } from 'discord.js';
|
||||
|
||||
import type { CommandType } from '../sern';
|
||||
import type { Module } from '../structures/structxports';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import type { ModuleDefs } from '../structures/modules/commands/moduleHandler';
|
||||
import { SernError } from '../structures/errors';
|
||||
import { isNotFromBot, isNotFromDM } from '../utilities/messageHelpers';
|
||||
|
||||
export function match(mod: Module | undefined, type : CommandType) : boolean {
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { SernError } from '../structures/errors';
|
||||
import { isFromBot, isFromDM } from '../utilities/messageHelpers';
|
||||
|
||||
export function match(mod: Module | undefined, type: CommandType): boolean {
|
||||
return mod !== undefined && (mod.type & type) != 0;
|
||||
}
|
||||
export function filterTap<T extends keyof ModuleDefs>(
|
||||
cmdType : T,
|
||||
tap: (mod : ModuleDefs[T]) => Awaitable<void>
|
||||
cmdType: T,
|
||||
tap: (mod: ModuleDefs[T]) => Awaitable<void>
|
||||
) {
|
||||
return (src : Observable<Module|undefined>) =>
|
||||
new Observable<Module|undefined>( subscriber => {
|
||||
return src.subscribe({
|
||||
return (src: Observable<Module | undefined>) =>
|
||||
new Observable<Module | undefined>(subscriber => {
|
||||
return src.subscribe({
|
||||
next(modul) {
|
||||
if(match(modul, cmdType)) {
|
||||
const asModT = <ModuleDefs[T]> modul;
|
||||
tap(asModT);
|
||||
subscriber.next(asModT);
|
||||
if (match(modul, cmdType)) {
|
||||
const asModT = <ModuleDefs[T]>modul;
|
||||
tap(asModT);
|
||||
subscriber.next(asModT);
|
||||
} else {
|
||||
if (modul === undefined) {
|
||||
return throwError(() => SernError.UNDEFINED_MODULE);
|
||||
}
|
||||
return throwError(() => SernError.MISMATCH_MODULE_TYPE);
|
||||
if (modul === undefined) {
|
||||
return throwError(() => SernError.UNDEFINED_MODULE);
|
||||
}
|
||||
return throwError(() => SernError.MISMATCH_MODULE_TYPE);
|
||||
}
|
||||
},
|
||||
error: (e) => subscriber.error(e),
|
||||
error: (e) => subscriber.error(e),
|
||||
complete: () => subscriber.complete()
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function ignoreNonBot(prefix : string) {
|
||||
return (src : Observable<Message>) =>
|
||||
export function ignoreNonBot(prefix: string) {
|
||||
return (src: Observable<Message>) =>
|
||||
new Observable<Message>(subscriber => {
|
||||
return src.subscribe({
|
||||
next(m) {
|
||||
const passAll = [
|
||||
isNotFromDM,
|
||||
isNotFromBot,
|
||||
(m : Message) =>
|
||||
m.content
|
||||
.slice(0,prefix.length)
|
||||
.localeCompare(prefix,
|
||||
undefined, { sensitivity : 'accent' }
|
||||
) === 0
|
||||
].every( fn => fn(m));
|
||||
return src.subscribe({
|
||||
next(m) {
|
||||
const passAll = [
|
||||
!isFromDM,
|
||||
!isFromBot,
|
||||
(m: Message) =>
|
||||
m.content
|
||||
.slice(0, prefix.length)
|
||||
.localeCompare(prefix,
|
||||
undefined, { sensitivity: 'accent' }
|
||||
) === 0
|
||||
].every(fn => fn(m));
|
||||
|
||||
if (passAll) {
|
||||
subscriber.next(m);
|
||||
}
|
||||
},
|
||||
error: (e) => subscriber.error(e),
|
||||
complete: () => subscriber.complete()
|
||||
if (passAll) {
|
||||
subscriber.next(m);
|
||||
}
|
||||
},
|
||||
error: (e) => subscriber.error(e),
|
||||
complete: () => subscriber.complete()
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,61 +1,62 @@
|
||||
import { first, from, fromEvent } from 'rxjs';
|
||||
import { basename } from 'path';
|
||||
import * as Files from '../utilities/readFile';
|
||||
import type Wrapper from '../structures/wrapper';
|
||||
import type { Module } from '../structures/structxports';
|
||||
import type { HandlerCallback, ModuleHandlers, ModuleStates, ModuleType } from '../structures/modules/commands/moduleHandler';
|
||||
|
||||
import * as Files from '../utilities/readFile';
|
||||
import { first, from, fromEvent } from 'rxjs';
|
||||
import { basename } from 'path';
|
||||
import { CommandType } from '../sern';
|
||||
|
||||
export const onReady = ( wrapper : Wrapper ) => {
|
||||
export const onReady = (wrapper: Wrapper) => {
|
||||
const { client, init, commands } = wrapper;
|
||||
fromEvent(client, 'ready')
|
||||
.pipe(first())
|
||||
.subscribe(() => {
|
||||
init?.( wrapper );
|
||||
Files.buildData( commands )
|
||||
.then( createCommandCache );
|
||||
})
|
||||
.pipe(first())
|
||||
.subscribe(() => {
|
||||
init?.(wrapper);
|
||||
Files.buildData(commands)
|
||||
.then(createCommandCache);
|
||||
})
|
||||
};
|
||||
|
||||
// Refactor : ? Possibly repetitive and verbose.
|
||||
const handler = ( name : string ) =>
|
||||
({
|
||||
[CommandType.TEXT] : mod => {
|
||||
mod.alias.forEach ( a => Files.Alias.set(a,mod));
|
||||
Files.Commands.set( name, mod );
|
||||
},
|
||||
[CommandType.SLASH]: mod => {
|
||||
Files.Commands.set( name , mod);
|
||||
},
|
||||
[CommandType.BOTH] : mod => {
|
||||
Files.Commands.set ( name, mod);
|
||||
mod.alias.forEach (a => Files.Alias.set(a, mod));
|
||||
},
|
||||
[CommandType.MENU_USER] : mod => {
|
||||
Files.ContextMenuUser.set ( name, mod );
|
||||
},
|
||||
[CommandType.MENU_MSG] : mod => {
|
||||
Files.ContextMenuMsg.set (name, mod );
|
||||
},
|
||||
[CommandType.BUTTON] : mod => {
|
||||
Files.Buttons.set(name, mod);
|
||||
},
|
||||
[CommandType.MENU_SELECT] : mod => {
|
||||
Files.SelectMenus.set(name, mod);
|
||||
}
|
||||
const handler = (name: string) =>
|
||||
({
|
||||
[CommandType.TEXT]: mod => {
|
||||
mod.alias.forEach(a => Files.Alias.set(a, mod));
|
||||
Files.Commands.set(name, mod);
|
||||
},
|
||||
[CommandType.SLASH]: mod => {
|
||||
Files.Commands.set(name, mod);
|
||||
},
|
||||
[CommandType.BOTH]: mod => {
|
||||
Files.Commands.set(name, mod);
|
||||
mod.alias.forEach(a => Files.Alias.set(a, mod));
|
||||
},
|
||||
[CommandType.MENU_USER]: mod => {
|
||||
Files.ContextMenuUser.set(name, mod);
|
||||
},
|
||||
[CommandType.MENU_MSG]: mod => {
|
||||
Files.ContextMenuMsg.set(name, mod);
|
||||
},
|
||||
[CommandType.BUTTON]: mod => {
|
||||
Files.Buttons.set(name, mod);
|
||||
},
|
||||
[CommandType.MENU_SELECT]: mod => {
|
||||
Files.SelectMenus.set(name, mod);
|
||||
}
|
||||
|
||||
} as ModuleHandlers);
|
||||
} as ModuleHandlers);
|
||||
|
||||
const registerModules = <T extends ModuleType >(name : string, mod : ModuleStates[T]) =>
|
||||
(<HandlerCallback<T>> handler(name)[mod.type])(mod);
|
||||
const registerModules = <T extends ModuleType>(name: string, mod: ModuleStates[T]) =>
|
||||
(<HandlerCallback<T>>handler(name)[mod.type])(mod);
|
||||
|
||||
function setCommands ( { mod, absPath } : { mod : Module, absPath : string } ) {
|
||||
const name = mod.name ?? Files.fmtFileName(basename(absPath));
|
||||
registerModules(name, mod);
|
||||
function setCommands({ mod, absPath }: { mod: Module, absPath: string }) {
|
||||
const name = mod.name ?? Files.fmtFileName(basename(absPath));
|
||||
registerModules(name, mod);
|
||||
}
|
||||
|
||||
function createCommandCache(
|
||||
arr: {mod: Module, absPath: string}[]
|
||||
) {
|
||||
from(arr).subscribe ( setCommands );
|
||||
function createCommandCache(
|
||||
arr: { mod: Module, absPath: string }[]
|
||||
) {
|
||||
from(arr).subscribe(setCommands);
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
|
||||
export enum sEvent {
|
||||
GLOBAL_SLASH,
|
||||
LOCAL_SLASH,
|
||||
MISUSE_CMD,
|
||||
DM,
|
||||
CRASH,
|
||||
TEXT_CMD,
|
||||
GLOBAL_SLASH,
|
||||
LOCAL_SLASH,
|
||||
MISUSE_CMD,
|
||||
CRASH,
|
||||
TEXT_CMD,
|
||||
DM,
|
||||
}
|
||||
|
||||
export default class Logger {
|
||||
public clear() {
|
||||
console.clear();
|
||||
}
|
||||
public clear() {
|
||||
console.clear();
|
||||
}
|
||||
|
||||
public log<T extends sEvent>(e: T, guildId: string, message: string) {
|
||||
// add colored logging?
|
||||
console.log(`[${new Date().toISOString()}] [${sEvent[e]}] @ ${guildId} :: ${message}`);
|
||||
}
|
||||
public log<T extends sEvent>(e: T, guildId: string, message: string) {
|
||||
// TODO: Add colored logging
|
||||
console.log(`[${new Date().toISOString()}] [${sEvent[e]}] @ ${guildId} :: ${message}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utilizes console.table() to print out memory usage of current process.
|
||||
* Optional at startup.
|
||||
*/
|
||||
public tableRam() {
|
||||
console.table(
|
||||
Object.entries(process.memoryUsage())
|
||||
.map(([k, v]: [string, number]) => {
|
||||
return { [k]: `${(((Math.round(v) / 1024 / 1024) * 100) / 100).toFixed(2)} MBs` };
|
||||
})
|
||||
.reduce((r, c) => Object.assign(r, c), {}),
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Utilizes console.table() to print out memory usage of current process.
|
||||
* Optional at startup.
|
||||
*/
|
||||
|
||||
public tableRam() {
|
||||
console.table(
|
||||
Object.entries(process.memoryUsage())
|
||||
.map(([k, v]: [string, number]) => {
|
||||
return { [k]: `${(((Math.round(v) / 1024 / 1024) * 100) / 100).toFixed(2)} MBs` };
|
||||
})
|
||||
.reduce((r, c) => Object.assign(r, c), {}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +1,41 @@
|
||||
import type {
|
||||
DiscordEvent,
|
||||
} from '../types/handler';
|
||||
|
||||
import type {
|
||||
Client,
|
||||
} from 'discord.js';
|
||||
|
||||
import type { DiscordEvent, } from '../types/handler';
|
||||
import type { Client } from 'discord.js';
|
||||
import type Wrapper from './structures/wrapper';
|
||||
|
||||
import { fromEvent } from 'rxjs';
|
||||
import { SernError } from './structures/errors';
|
||||
import { onReady } from './events/readyEvent';
|
||||
import { onMessageCreate } from './events/messageEvent';
|
||||
import { onInteractionCreate } from './events/interactionCreate';
|
||||
|
||||
export function init( wrapper : Wrapper ) {
|
||||
const { events, client } = wrapper;
|
||||
if (events !== undefined) eventObserver(client, events);
|
||||
onReady( wrapper );
|
||||
onMessageCreate( wrapper );
|
||||
onInteractionCreate ( wrapper );
|
||||
export function init(wrapper: Wrapper) {
|
||||
const { events, client } = wrapper;
|
||||
if (events !== undefined) eventObserver(client, events);
|
||||
|
||||
onReady(wrapper);
|
||||
onMessageCreate(wrapper);
|
||||
onInteractionCreate(wrapper);
|
||||
}
|
||||
|
||||
function eventObserver(client: Client, events: DiscordEvent[] ) {
|
||||
events.forEach( ( [event, cb] ) => {
|
||||
if (event === 'ready') throw Error(SernError.RESERVED_EVENT);
|
||||
fromEvent(client, event, cb).subscribe();
|
||||
function eventObserver(client: Client, events: DiscordEvent[]) {
|
||||
events.forEach(([event, cb]) => {
|
||||
if (event === 'ready') throw Error(SernError.RESERVED_EVENT);
|
||||
fromEvent(client, event, cb).subscribe();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @enum { number };
|
||||
*/
|
||||
|
||||
export enum CommandType {
|
||||
TEXT = 0b000001,
|
||||
SLASH = 0b000010,
|
||||
MENU_USER = 0b000100,
|
||||
MENU_MSG = 0b001000,
|
||||
BUTTON = 0b010000,
|
||||
MENU_SELECT= 0b100000,
|
||||
BOTH = 0b000011,
|
||||
ANY = 0b111111
|
||||
TEXT = 0b000001,
|
||||
SLASH = 0b000010,
|
||||
MENU_USER = 0b000100,
|
||||
MENU_MSG = 0b001000,
|
||||
BUTTON = 0b010000,
|
||||
MENU_SELECT = 0b100000,
|
||||
BOTH = 0b000011,
|
||||
ANY = 0b111111,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,121 +1,108 @@
|
||||
import type {
|
||||
Awaitable,
|
||||
ChatInputCommandInteraction,
|
||||
Guild,
|
||||
GuildMember,
|
||||
Message,
|
||||
Snowflake,
|
||||
TextBasedChannel,
|
||||
User
|
||||
Awaitable,
|
||||
ChatInputCommandInteraction,
|
||||
Guild,
|
||||
GuildMember,
|
||||
Message,
|
||||
Snowflake,
|
||||
TextBasedChannel,
|
||||
User,
|
||||
} from 'discord.js';
|
||||
import { None, Option, Some } from 'ts-results';
|
||||
import type { Nullish } from '../../types/handler';
|
||||
|
||||
function firstSome<T>(...args : Option<T>[]) : Nullish<T> {
|
||||
for ( const op of args ) {
|
||||
if (op.some) return op.val;
|
||||
}
|
||||
return null;
|
||||
|
||||
function firstSome<T>(...args: Option<T>[]): Nullish<T> {
|
||||
for (const op of args) {
|
||||
if (op.some) return op.val;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export default class Context {
|
||||
private constructor(
|
||||
private oMsg: Option<Message> = None,
|
||||
private oInterac: Option<ChatInputCommandInteraction> = None,
|
||||
) {
|
||||
this.oMsg = oMsg;
|
||||
this.oInterac = oInterac;
|
||||
}
|
||||
static wrap(wrappable: ChatInputCommandInteraction | Message): Context {
|
||||
if ('token' in wrappable) {
|
||||
return new Context(None, Some(wrappable));
|
||||
}
|
||||
return new Context(Some(wrappable), None);
|
||||
}
|
||||
public isEmpty() {
|
||||
return this.oMsg.none && this.oInterac.none;
|
||||
}
|
||||
public get message() {
|
||||
return this.oMsg.unwrap();
|
||||
}
|
||||
public get interaction() {
|
||||
return this.oInterac.unwrap();
|
||||
}
|
||||
|
||||
private constructor(
|
||||
private oMsg: Option<Message> = None,
|
||||
private oInterac: Option<ChatInputCommandInteraction> = None
|
||||
) {
|
||||
this.oMsg = oMsg;
|
||||
this.oInterac = oInterac;
|
||||
}
|
||||
static wrap(
|
||||
wrappable: ChatInputCommandInteraction|Message
|
||||
) : Context {
|
||||
if ( 'token' in wrappable ) {
|
||||
return new Context( None, Some(wrappable));
|
||||
}
|
||||
return new Context(Some(wrappable), None);
|
||||
}
|
||||
public isEmpty() {
|
||||
return this.oMsg.none && this.oInterac.none;
|
||||
}
|
||||
public get message() {
|
||||
return this.oMsg.unwrap();
|
||||
}
|
||||
public get interaction() {
|
||||
return this.oInterac.unwrap();
|
||||
}
|
||||
public get id(): Snowflake {
|
||||
return firstSome(
|
||||
this.oInterac.map((i) => i.id),
|
||||
this.oMsg.map((m) => m.id),
|
||||
)!;
|
||||
}
|
||||
public get channel(): Nullish<TextBasedChannel> {
|
||||
return firstSome(
|
||||
this.oMsg.map((m) => m.channel),
|
||||
this.oInterac.map((i) => i.channel),
|
||||
);
|
||||
}
|
||||
public get user(): User {
|
||||
return firstSome(
|
||||
this.oMsg.map((m) => m.author),
|
||||
this.oInterac.map((i) => i.user),
|
||||
)!;
|
||||
}
|
||||
public get createdTimestamp(): number {
|
||||
return firstSome(
|
||||
this.oMsg.map((m) => m.createdTimestamp),
|
||||
this.oInterac.map((i) => i.createdTimestamp),
|
||||
)!;
|
||||
}
|
||||
|
||||
public get id() : Snowflake {
|
||||
return firstSome(
|
||||
this.oInterac.map( i => i.id),
|
||||
this.oMsg.map(m => m.id)
|
||||
)!;
|
||||
}
|
||||
public get channel() : Nullish<TextBasedChannel> {
|
||||
return firstSome(
|
||||
this.oMsg.map(m => m.channel),
|
||||
this.oInterac.map(i => i.channel)
|
||||
);
|
||||
}
|
||||
public get user(): User {
|
||||
return firstSome(
|
||||
this.oMsg.map(m => m.author),
|
||||
this.oInterac.map(i => i.user)
|
||||
)!;
|
||||
}
|
||||
public get createdTimestamp() : number {
|
||||
return firstSome(
|
||||
this.oMsg.map(m => m.createdTimestamp),
|
||||
this.oInterac.map(i => i.createdTimestamp)
|
||||
)!;
|
||||
}
|
||||
|
||||
public get guild() : Guild {
|
||||
return firstSome(
|
||||
this.oMsg.map(m => m.guild!),
|
||||
this.oInterac.map(i => i.guild)
|
||||
)!;
|
||||
}
|
||||
public get guildId() : Snowflake {
|
||||
return firstSome(
|
||||
this.oMsg.map(m => m.guildId),
|
||||
this.oInterac.map(i => i.guildId)
|
||||
)!;
|
||||
}
|
||||
public get member() : Nullish<GuildMember> {
|
||||
return firstSome(
|
||||
this.oMsg.andThen(m => Some(m.member!)),
|
||||
this.oInterac.andThen(i => i.inCachedGuild() ? Some(i.member) : None)
|
||||
);
|
||||
}
|
||||
/*
|
||||
* Returns the underlying Context but allows for doing other operations
|
||||
*/
|
||||
public onInteraction(
|
||||
onInteraction : ( interaction : ChatInputCommandInteraction ) => Awaitable<void>,
|
||||
): Context {
|
||||
this.oInterac.map(onInteraction);
|
||||
return this;
|
||||
}
|
||||
public onMessage(
|
||||
onMessage : ( message : Message ) => Awaitable<void>
|
||||
): Context {
|
||||
this.oMsg.map( onMessage );
|
||||
return this;
|
||||
}
|
||||
public takeInteractionValue<T>(
|
||||
extract : (interaction : ChatInputCommandInteraction) => T
|
||||
): Nullish<T> {
|
||||
if(this.oInterac.none) return null;
|
||||
return extract(this.oInterac.val);
|
||||
}
|
||||
public takeMessageValue<T>(
|
||||
extract : (message: Message) => T
|
||||
): Nullish<T> {
|
||||
if(this.oMsg.none) return null;
|
||||
return extract(this.oMsg.val);
|
||||
}
|
||||
|
||||
public get guild(): Guild {
|
||||
return firstSome(
|
||||
this.oMsg.map((m) => m.guild!),
|
||||
this.oInterac.map((i) => i.guild),
|
||||
)!;
|
||||
}
|
||||
public get guildId(): Snowflake {
|
||||
return firstSome(
|
||||
this.oMsg.map((m) => m.guildId),
|
||||
this.oInterac.map((i) => i.guildId),
|
||||
)!;
|
||||
}
|
||||
public get member(): Nullish<GuildMember> {
|
||||
return firstSome(
|
||||
this.oMsg.andThen((m) => Some(m.member!)),
|
||||
this.oInterac.andThen((i) => (i.inCachedGuild() ? Some(i.member) : None)),
|
||||
);
|
||||
}
|
||||
/*
|
||||
* Returns the underlying Context but allows for doing other operations
|
||||
*/
|
||||
public onInteraction(onInteraction: (interaction: ChatInputCommandInteraction) => Awaitable<void>): Context {
|
||||
this.oInterac.map(onInteraction);
|
||||
return this;
|
||||
}
|
||||
public onMessage(onMessage: (message: Message) => Awaitable<void>): Context {
|
||||
this.oMsg.map(onMessage);
|
||||
return this;
|
||||
}
|
||||
public takeInteractionValue<T>(extract: (interaction: ChatInputCommandInteraction) => T): Nullish<T> {
|
||||
if (this.oInterac.none) return null;
|
||||
return extract(this.oInterac.val);
|
||||
}
|
||||
public takeMessageValue<T>(extract: (message: Message) => T): Nullish<T> {
|
||||
if (this.oMsg.none) return null;
|
||||
return extract(this.oMsg.val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export enum SernError {
|
||||
RESERVED_EVENT = 'Cannot register the reserved ready event. Please use the init property.',
|
||||
NO_ALIAS = 'You cannot provide an array with elements to a slash command.',
|
||||
NOT_VALID_MOD_TYPE = 'Detected an unknown module type',
|
||||
UNDEFINED_MODULE = `A module could not be detected at`,
|
||||
MISMATCH_MODULE_TYPE = `A module type mismatched with event emitted!`
|
||||
RESERVED_EVENT = 'Cannot register the reserved ready event. Please use the init property.',
|
||||
NO_ALIAS = 'You cannot provide an array with elements to a slash command.',
|
||||
NOT_VALID_MOD_TYPE = 'Detected an unknown module type',
|
||||
UNDEFINED_MODULE = `A module could not be detected at`,
|
||||
MISMATCH_MODULE_TYPE = `A module type mismatched with event emitted!`,
|
||||
}
|
||||
|
||||
@@ -1,45 +1,51 @@
|
||||
import type { ApplicationCommandOptionData, Awaitable, ButtonInteraction, ContextMenuCommandInteraction, MessageContextMenuCommandInteraction, SelectMenuInteraction } from 'discord.js';
|
||||
import type {
|
||||
ApplicationCommandOptionData,
|
||||
Awaitable,
|
||||
ButtonInteraction,
|
||||
MessageContextMenuInteraction,
|
||||
ContextMenuInteraction,
|
||||
SelectMenuInteraction,
|
||||
} from 'discord.js';
|
||||
|
||||
import type { Override } from '../../../../types/handler';
|
||||
import type { CommandType } from '../../../sern';
|
||||
import type { BaseModule } from '../module';
|
||||
|
||||
//possible refactoring to interfaces and not types
|
||||
// Possible refactoring to interfaces and not types
|
||||
export type TextCommand = {
|
||||
type : CommandType.TEXT;
|
||||
alias : string[] | [],
|
||||
type: CommandType.TEXT;
|
||||
alias: string[] | [];
|
||||
} & BaseModule;
|
||||
|
||||
export type SlashCommand = {
|
||||
type : CommandType.SLASH;
|
||||
options : ApplicationCommandOptionData[] | [],
|
||||
} & BaseModule;
|
||||
type: CommandType.SLASH;
|
||||
options: ApplicationCommandOptionData[] | [];
|
||||
} & BaseModule;
|
||||
|
||||
export type BothCommand = {
|
||||
type : CommandType.BOTH;
|
||||
alias : string[] | [];
|
||||
options : ApplicationCommandOptionData[] | [],
|
||||
type: CommandType.BOTH;
|
||||
alias: string[] | [];
|
||||
options: ApplicationCommandOptionData[] | [];
|
||||
} & BaseModule;
|
||||
|
||||
export type ContextMenuUser = {
|
||||
type : CommandType.MENU_USER;
|
||||
} & Override<BaseModule, { execute : ( ctx: ContextMenuCommandInteraction ) => Awaitable<void> }>;
|
||||
type: CommandType.MENU_USER;
|
||||
} & Override<BaseModule, { execute: (ctx: ContextMenuInteraction) => Awaitable<void> }>;
|
||||
export type ContextMenuMsg = {
|
||||
type : CommandType.MENU_MSG;
|
||||
} & Override<BaseModule, { execute : ( ctx: MessageContextMenuCommandInteraction ) => Awaitable<void> }>;
|
||||
type: CommandType.MENU_MSG;
|
||||
} & Override<BaseModule, { execute: (ctx: MessageContextMenuInteraction) => Awaitable<void> }>;
|
||||
export type ButtonCommand = {
|
||||
type : CommandType.BUTTON;
|
||||
} & Override<BaseModule, { execute : (ctx :ButtonInteraction ) => Awaitable<void> }>;
|
||||
type: CommandType.BUTTON;
|
||||
} & Override<BaseModule, { execute: (ctx: ButtonInteraction) => Awaitable<void> }>;
|
||||
export type SelectMenuCommand = {
|
||||
type : CommandType.MENU_SELECT;
|
||||
} & Override<BaseModule, { execute : (ctx : SelectMenuInteraction ) => Awaitable<void> }>;
|
||||
type: CommandType.MENU_SELECT;
|
||||
} & Override<BaseModule, { execute: (ctx: SelectMenuInteraction) => Awaitable<void> }>;
|
||||
|
||||
|
||||
export type Module =
|
||||
TextCommand
|
||||
| SlashCommand
|
||||
| BothCommand
|
||||
| ContextMenuUser
|
||||
| ContextMenuMsg
|
||||
| ButtonCommand
|
||||
| SelectMenuCommand;
|
||||
|
||||
export type Module =
|
||||
| TextCommand
|
||||
| SlashCommand
|
||||
| BothCommand
|
||||
| ContextMenuUser
|
||||
| ContextMenuMsg
|
||||
| ButtonCommand
|
||||
| SelectMenuCommand;
|
||||
|
||||
@@ -1,24 +1,31 @@
|
||||
import { CommandType } from '../../../sern';
|
||||
import type { TextCommand, BothCommand, ButtonCommand, SlashCommand, ContextMenuMsg, ContextMenuUser, SelectMenuCommand } from './module';
|
||||
//https://stackoverflow.com/questions/64092736/alternative-to-switch-statement-for-typescript-discriminated-union
|
||||
import type {
|
||||
TextCommand,
|
||||
BothCommand,
|
||||
ButtonCommand,
|
||||
SlashCommand,
|
||||
ContextMenuMsg,
|
||||
ContextMenuUser,
|
||||
SelectMenuCommand,
|
||||
} from './module';
|
||||
|
||||
// https://stackoverflow.com/questions/64092736/alternative-to-switch-statement-for-typescript-discriminated-union
|
||||
// Explicit Module Definitions for mapping
|
||||
export type ModuleDefs = {
|
||||
[CommandType.TEXT] : TextCommand,
|
||||
[CommandType.SLASH] : SlashCommand,
|
||||
[CommandType.BOTH] : BothCommand,
|
||||
[CommandType.MENU_MSG] : ContextMenuMsg,
|
||||
[CommandType.MENU_USER] : ContextMenuUser,
|
||||
[CommandType.BUTTON] : ButtonCommand,
|
||||
[CommandType.MENU_SELECT] : SelectMenuCommand
|
||||
}
|
||||
[CommandType.TEXT]: TextCommand;
|
||||
[CommandType.SLASH]: SlashCommand;
|
||||
[CommandType.BOTH]: BothCommand;
|
||||
[CommandType.MENU_MSG]: ContextMenuMsg;
|
||||
[CommandType.MENU_USER]: ContextMenuUser;
|
||||
[CommandType.BUTTON]: ButtonCommand;
|
||||
[CommandType.MENU_SELECT]: SelectMenuCommand;
|
||||
};
|
||||
|
||||
//Keys of ModuleDefs
|
||||
export type ModuleType = keyof ModuleDefs;
|
||||
// The keys mapped to a constructed union with its type
|
||||
export type ModuleStates = { [ K in ModuleType ] : { type : K } & ModuleDefs[K] };
|
||||
// A handler callback that is called on each ModuleDef
|
||||
export type HandlerCallback<K extends ModuleType> = ( params : ModuleStates[K] ) => unknown;
|
||||
export type ModuleStates = { [K in ModuleType]: { type: K } & ModuleDefs[K] };
|
||||
// A handler callback that is called on each ModuleDef
|
||||
export type HandlerCallback<K extends ModuleType> = (params: ModuleStates[K]) => unknown;
|
||||
//An object that acts as the mapped object to handler
|
||||
export type ModuleHandlers = { [K in ModuleType] : HandlerCallback<K> };
|
||||
|
||||
export type ModuleHandlers = { [K in ModuleType]: HandlerCallback<K> };
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import type { Awaitable, ChatInputCommandInteraction, Interaction } from "discord.js";
|
||||
import type { Args } from "../../..";
|
||||
import type Context from "../context";
|
||||
import type { Awaitable, ChatInputCommandInteraction, Interaction } from 'discord.js';
|
||||
import type { Args } from '../../..';
|
||||
import type Context from '../context';
|
||||
|
||||
export interface BaseModule {
|
||||
name? : string;
|
||||
description : string;
|
||||
execute: (ctx: Context, args: Args) => Awaitable<void>;
|
||||
name?: string;
|
||||
description: string;
|
||||
execute: (ctx: Context, args: Args) => Awaitable<void>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,11 +2,4 @@ import Context from './context';
|
||||
import type { SlashCommand, TextCommand, BothCommand, Module } from '../structures/modules/commands/module';
|
||||
import type Wrapper from './wrapper';
|
||||
|
||||
export {
|
||||
Context,
|
||||
SlashCommand,
|
||||
TextCommand,
|
||||
BothCommand,
|
||||
Module,
|
||||
Wrapper
|
||||
};
|
||||
export { Context, SlashCommand, TextCommand, BothCommand, Module, Wrapper };
|
||||
|
||||
@@ -4,18 +4,19 @@ import type { DiscordEvent } from '../../types/handler';
|
||||
/**
|
||||
* An object to be passed into Sern.Handler constructor.
|
||||
* @typedef {object} Wrapper
|
||||
* @property {readonly Client} client
|
||||
* @property {readonly string} defaultPrefix
|
||||
* @property {readonly string} commands
|
||||
* @prop {(handler : Handler) => void)} init
|
||||
* @prop { readonly DiscordEvent[] } events
|
||||
* @property {readonly Client} Client
|
||||
* @property {readonly string} The default prefix
|
||||
* @property {readonly string} Commands
|
||||
* @prop {(handler: Handler) => void)} init
|
||||
* @prop { readonly DiscordEvent[] } Events
|
||||
*/
|
||||
|
||||
interface Wrapper {
|
||||
readonly client: Client;
|
||||
readonly defaultPrefix: string;
|
||||
readonly commands: string;
|
||||
init?: (handler: Wrapper) => void;
|
||||
readonly events? : DiscordEvent[];
|
||||
readonly client: Client;
|
||||
readonly defaultPrefix: string;
|
||||
readonly commands: string;
|
||||
init?: (handler: Wrapper) => void;
|
||||
readonly events?: DiscordEvent[];
|
||||
}
|
||||
|
||||
export default Wrapper;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,15 @@
|
||||
import { ChannelType, Message } from 'discord.js';
|
||||
import type { Message } from 'discord.js';
|
||||
|
||||
/**
|
||||
* Checks if the message sent in DMs.
|
||||
* @param message The message object
|
||||
* @returns `true` if message comes from DM, `false` otherwise
|
||||
* @example isNotFromDM(message) ? 'Not From DM' : 'from DM'
|
||||
*
|
||||
*/
|
||||
|
||||
export function isNotFromDM ( message: Message ) {
|
||||
return message.channel.type !== ChannelType.DM;
|
||||
export function isFromDM(message: Message): boolean {
|
||||
return message.channel.type == 'DM';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -16,25 +17,29 @@ export function isNotFromDM ( message: Message ) {
|
||||
* @param message The message to check
|
||||
* @returns `true` if the author of the message is a bot, `false` otherwise
|
||||
* @example
|
||||
* isBot(message) ? 'yes it is a bot' : 'no it is not a bot';
|
||||
* isFromBot(message) ? 'Sent by a bot' : 'Sent by a person'';
|
||||
*/
|
||||
export function isNotFromBot(message: Message) {
|
||||
return !message.author.bot;
|
||||
|
||||
export function isFromBot(message: Message): boolean {
|
||||
return !!message.author.bot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the message **starts** with the prefix
|
||||
* Checks if the message starts with the prefix
|
||||
* @param message The message to check
|
||||
* @param prefix The prefix to check for
|
||||
* @returns `true` if the message starts with the prefix, `false` otherwise
|
||||
* @example
|
||||
* hasPrefix(message, '!') ? 'yes it does' : 'no it does not';
|
||||
* hasPrefix(message, '!') ? 'Starts with prefix' : 'Not starts with prefix';
|
||||
*/
|
||||
export function hasPrefix(message: Message, prefix?: string) {
|
||||
return message.content.startsWith(prefix!);
|
||||
|
||||
export function hasPrefix(message: Message, prefix?: string): boolean {
|
||||
return message.content.startsWith(prefix!);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the first character(s) _[depending on prefix length]_ of the message
|
||||
* @param message The message to remove the prefix from
|
||||
* Removes the first character(s) _-depending on prefix length-_ of the message
|
||||
* @param msg The message to remove the prefix from
|
||||
* @param prefix The prefix to remove
|
||||
* @returns The message without the prefix
|
||||
* @example
|
||||
@@ -42,6 +47,7 @@ export function hasPrefix(message: Message, prefix?: string) {
|
||||
* console.log(fmt(message, '!'));
|
||||
* // [ 'ping' ]
|
||||
*/
|
||||
export function fmt(msg: Message, prefix: string): string[] {
|
||||
return msg.content.slice(prefix.length).trim().split(/\s+/g);
|
||||
|
||||
export function fmt({ msg, prefix }: { msg: Message; prefix: string; }): string[] {
|
||||
return msg.content.slice(prefix.length).trim().split(/\s+/g);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import type { Module } from '../structures/modules/commands/module';
|
||||
|
||||
import { readdirSync, statSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import type { Module } from '../structures/modules/commands/module';
|
||||
import { SernError } from '../structures/errors';
|
||||
|
||||
//We can look into lazily loading modules once everything is set
|
||||
// We can look into lazily loading modules once everything is set
|
||||
export const ContextMenuUser = new Map<string, Module>();
|
||||
export const ContextMenuMsg = new Map<string, Module>();
|
||||
export const Commands = new Map<string, Module>();
|
||||
@@ -11,8 +12,7 @@ export const Alias = new Map<string, Module>();
|
||||
export const Buttons = new Map<string, Module>();
|
||||
export const SelectMenus = new Map<string, Module>();
|
||||
|
||||
|
||||
// Courtesy @Townsy45
|
||||
// Thanks to @Townsy45
|
||||
function readPath(dir: string, arrayOfFiles: string[] = []): string[] {
|
||||
try {
|
||||
const files = readdirSync(dir);
|
||||
@@ -30,20 +30,20 @@ function readPath(dir: string, arrayOfFiles: string[] = []): string[] {
|
||||
export const fmtFileName = (n: string) => n.substring(0, n.length - 3);
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param {commandsDir} Relative path to commands directory
|
||||
* @returns {Promise<{ mod: Command; absPath: string; }[]>} data from command files
|
||||
*/
|
||||
|
||||
export async function buildData(commandDir: string ): Promise<
|
||||
export async function buildData(commandDir: string): Promise<
|
||||
{
|
||||
mod: Module;
|
||||
absPath: string;
|
||||
}[]
|
||||
> {
|
||||
return Promise.all(
|
||||
getCommands(commandDir).map( async (absPath) => {
|
||||
const mod = <Module> (await import(absPath)).module;
|
||||
getCommands(commandDir).map(async (absPath) => {
|
||||
const mod = <Module>(await import(absPath)).module;
|
||||
if (mod === undefined) throw Error(`${SernError.UNDEFINED_MODULE} ${absPath}`);
|
||||
return { mod, absPath };
|
||||
}),
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { hasPrefix, fmt, isNotFromBot } from '../src/handler/utilities/messageHelpers';
|
||||
describe('FUNCTIONS', () => {
|
||||
test('If hasPrefix is a function', () => {
|
||||
expect(typeof hasPrefix).toBe('function');
|
||||
});
|
||||
test('if fmt is a function', () => {
|
||||
expect(typeof fmt).toBe('function');
|
||||
});
|
||||
test('if isBot is a function', () => {
|
||||
expect(typeof isNotFromBot).toBe('function');
|
||||
});
|
||||
import { hasPrefix, fmt, isFromBot } from '../src/handler/utilities/messageHelpers';
|
||||
|
||||
describe('FUNCTIONS', () => {
|
||||
test('If hasPrefix is a function', () => {
|
||||
expect(typeof hasPrefix).toBe('function');
|
||||
});
|
||||
test('if fmt is a function', () => {
|
||||
expect(typeof fmt).toBe('function');
|
||||
});
|
||||
test('if isBot is a function', () => {
|
||||
expect(typeof isFromBot).toBe('function');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user