From 878f67391b74bf1bc67ac4967dcd2e99afbe5b3f Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Sat, 18 Jun 2022 02:15:37 -0500 Subject: [PATCH] refactor: Cleaning up and adding docs --- .../events/userDefinedEventsHandling.ts | 125 ++++++++++++++++++ src/handler/sern.ts | 102 ++------------ 2 files changed, 139 insertions(+), 88 deletions(-) create mode 100644 src/handler/events/userDefinedEventsHandling.ts diff --git a/src/handler/events/userDefinedEventsHandling.ts b/src/handler/events/userDefinedEventsHandling.ts new file mode 100644 index 0000000..8a187f4 --- /dev/null +++ b/src/handler/events/userDefinedEventsHandling.ts @@ -0,0 +1,125 @@ +import { CommandType } from '../structures/enums'; +import { from, fromEvent, map, throwError } from 'rxjs'; +import { SernError } from '../structures/errors'; +import { buildData, ExternalEventEmitters } from '../utilities/readFile'; +import { controller } from '../sern'; +import type { DefinitelyDefined } from '../../types/handler'; +import type { Module } from '../structures/module'; +import type Wrapper from '../structures/wrapper'; +import type { EventModule } from '../structures/module'; +import * as Files from '../utilities/readFile'; +import { basename } from 'path'; +import { match } from 'ts-pattern'; +import { isDiscordEvent, isExternalEvent, isSernEvent } from '../utilities/predicates'; +import type { SpreadParams } from '../../types/handler'; +import { errTap } from './observableHandling'; + +export function processCommandPlugins$>( + { client, sernEmitter }: Wrapper, + { mod, absPath }: { mod: T; absPath: string }, +) { + if (mod.type === CommandType.Autocomplete) { + return throwError( + () => + SernError.NonValidModuleType + `. You cannot use command plugins and Autocomplete.`, + ); + } + if (mod.type === CommandType.External) { + mod.plugins.map(plug => ({ + ...plug, + name: plug?.name ?? 'Unnamed Plugin', + description: plug?.description ?? '...', + execute: plug.execute(ExternalEventEmitters.get(mod.emitter)!, mod, controller), + })); + } + if (mod.type === CommandType.Sern) { + mod.plugins.map(plug => ({ + ...plug, + name: plug?.name ?? 'Unnamed Plugin', + description: plug?.description ?? '...', + execute: plug.execute(sernEmitter!, mod, controller), + })); + } +} + +export function processEvents( + wrapper: Wrapper, + events: string | EventModule[] | (() => EventModule[]), +) { + const eventStream$ = eventObservable$(wrapper, events); + const normalize$ = eventStream$.pipe( + map(({ mod, absPath }) => { + return { + name: mod?.name ?? Files.fmtFileName(basename(absPath)), + description: mod?.description ?? '...', + ...mod, + }; + }), + ); + const processPlugins$ = normalize$.pipe(map(mod => mod)); //for now, until i figure out what to do with how plugins are registered + + const processAndLoadEvents$ = normalize$.pipe( + map(mod => { + return match(mod as EventModule) + .when(isSernEvent, m => { + if (wrapper.sernEmitter === undefined) { + return throwError(() => SernError.UndefinedSernEmitter); + } + return fromEvent( + wrapper.sernEmitter, + m.name!, + m.execute as SpreadParams, + ); + }) + .when(isDiscordEvent, m => + fromEvent( + wrapper.client, + mod.name!, + m.execute as SpreadParams, + ), + ) + .when(isExternalEvent, m => { + if (!ExternalEventEmitters.has(m.emitter)) { + throw Error( + SernError.UndefinedSernEmitter + + `Could not locate + a dependency ${m.emitter} to call this event listener`, + ); + } + return fromEvent(ExternalEventEmitters.get(m.emitter)!, m.name!, m.execute); + }) + .run(); + }), + ); +} + +function eventObservable$( + { sernEmitter }: Wrapper, + events: string | EventModule[] | (() => EventModule[]), +) { + return match(events) + .when(Array.isArray, (arr: EventModule[]) => { + return from(arr.map(self => ({ mod: self, absPath: __filename }))); + }) + .when( + e => typeof e === 'string', + (eventsDir: string) => { + return buildData(eventsDir).pipe( + errTap(reason => + sernEmitter?.emit('module.register', { + type: 'failure', + module: undefined, + reason, + }), + ), + ); + }, + ) + .when( + e => typeof e === 'function', + (evs: () => EventModule[]) => { + return from(evs().map(self => ({ mod: self, absPath: __filename }))); + }, + ) + .run(); +} diff --git a/src/handler/sern.ts b/src/handler/sern.ts index 16c0a8d..443a045 100644 --- a/src/handler/sern.ts +++ b/src/handler/sern.ts @@ -3,18 +3,15 @@ import { onReady } from './events/readyEvent'; import { onMessageCreate } from './events/messageEvent'; import { onInteractionCreate } from './events/interactionCreate'; import { Err, Ok } from 'ts-results'; -import { buildData, ExternalEventEmitters } from './utilities/readFile'; -import type { EventModule } from './structures/module'; -import { from, fromEvent, map, throwError } from 'rxjs'; -import { match } from 'ts-pattern'; -import { errTap } from './events/observableHandling'; -import { isDiscordEvent, isExternalEvent, isSernEvent } from './utilities/predicates'; -import { SernError } from './structures/errors'; -import type { SpreadParams } from '../types/handler'; -import * as Files from './utilities/readFile'; -import { basename } from 'path'; +import { ExternalEventEmitters } from './utilities/readFile'; import type { EventEmitter } from 'events'; +import { processEvents } from './events/userDefinedEventsHandling'; +/** + * + * @param wrapper options to pass into sern. + * Function to start the handler up. + */ export function init(wrapper: Wrapper) { const { events } = wrapper; if (events !== undefined) { @@ -25,6 +22,13 @@ export function init(wrapper: Wrapper) { onInteractionCreate(wrapper); } +/** + * + * @param emitter Any external event emitter. + * The object will be stored in a map, and then fetched by the name of the emitter provided. + * As there are infinite possibilities to adding external event emitters, + * Most types arent provided and are as narrow as possibly can. + */ export function addExternal(emitter: T) { if (ExternalEventEmitters.has(emitter.constructor.name)) { throw Error(`${emitter.constructor.name} already exists!`); @@ -32,84 +36,6 @@ export function addExternal(emitter: T) { ExternalEventEmitters.set(emitter.constructor.name, emitter); } -function processEvents(wrapper: Wrapper, events: string | EventModule[] | (() => EventModule[])) { - const eventStream = eventObservable$(wrapper, events); - const processPlugins$ = eventStream.pipe(map(mod => mod)); //for now, until i figure out what to do with how plugins are registered - const normalize$ = processPlugins$.pipe( - map(({ mod, absPath }) => { - return { - name: mod?.name ?? Files.fmtFileName(basename(absPath)), - description: mod?.description ?? '...', - ...mod, - }; - }), - ); - const processAndLoadEvents$ = normalize$.pipe( - map(mod => { - return match(mod as EventModule) - .when(isSernEvent, m => { - if (wrapper.sernEmitter === undefined) { - return throwError(() => SernError.UndefinedSernEmitter); - } - return fromEvent( - wrapper.sernEmitter, - m.name!, - m.execute as SpreadParams, - ); - }) - .when(isDiscordEvent, m => - fromEvent( - wrapper.client, - mod.name!, - m.execute as SpreadParams, - ), - ) - .when(isExternalEvent, m => { - if (!ExternalEventEmitters.has(m.emitter)) { - throw Error( - SernError.UndefinedSernEmitter + - `Could not locate - a dependency ${m.emitter} to call this event listener`, - ); - } - return fromEvent(ExternalEventEmitters.get(m.emitter)!, m.name!, m.execute); - }) - .run(); - }), - ); -} - -function eventObservable$( - { sernEmitter }: Wrapper, - events: string | EventModule[] | (() => EventModule[]), -) { - return match(events) - .when(Array.isArray, (arr: EventModule[]) => { - return from(arr.map(self => ({ mod: self, absPath: __filename }))); - }) - .when( - e => typeof e === 'string', - (eventsDir: string) => { - return buildData(eventsDir).pipe( - errTap(reason => - sernEmitter?.emit('module.register', { - type: 'failure', - module: undefined, - reason, - }), - ), - ); - }, - ) - .when( - e => typeof e === 'function', - (evs: () => EventModule[]) => { - return from(evs().map(self => ({ mod: self, absPath: __filename }))); - }, - ) - .run(); -} - export const controller = { next: () => Ok.EMPTY, stop: () => Err.EMPTY,