From b0399f95079e0cff7fa96edfc13259d0997a4f4b Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Tue, 2 Jan 2024 13:04:59 -0600 Subject: [PATCH] refactor: minor (#347) * some refactoring * accidental merge * refactor: ensure all asserts have error message to avoid cryptic messages * general refactoring * move controller to create-plugin --- src/core/create-plugins.ts | 10 +++++++ src/core/functions.ts | 2 +- src/core/id.ts | 1 + src/core/ioc/base.ts | 11 ++++++-- src/core/ioc/container.ts | 11 ++++---- src/core/module-loading.ts | 1 - src/core/modules.ts | 6 ++-- src/core/operators.ts | 15 ++++------ src/core/structures/command-error.ts | 41 ---------------------------- src/core/structures/context.ts | 2 +- src/core/structures/core-context.ts | 2 +- src/core/structures/index.ts | 1 - src/handlers/dispatchers.ts | 6 ++-- src/handlers/event-utils.ts | 25 ++++++++--------- src/handlers/interaction-event.ts | 3 +- src/handlers/message-event.ts | 3 +- src/handlers/presence.ts | 2 +- src/index.ts | 1 - src/sern.ts | 9 +----- 19 files changed, 54 insertions(+), 98 deletions(-) delete mode 100644 src/core/structures/command-error.ts diff --git a/src/core/create-plugins.ts b/src/core/create-plugins.ts index fd0399a8..7f1b8bfe 100644 --- a/src/core/create-plugins.ts +++ b/src/core/create-plugins.ts @@ -1,6 +1,7 @@ import { CommandType, EventType, PluginType } from './structures'; import type { Plugin, PluginResult, EventArgs, CommandArgs } from '../types/core-plugin'; import type { ClientEvents } from 'discord.js'; +import { err, ok } from './functions'; export function makePlugin( type: PluginType, @@ -60,3 +61,12 @@ export function DiscordEventControlPlugin( ) { return makePlugin(PluginType.Control, execute); } + +/** + * @since 1.0.0 + * The object passed into every plugin to control a command's behavior + */ +export const controller = { + next: ok, + stop: err, +}; diff --git a/src/core/functions.ts b/src/core/functions.ts index f3eacb35..f45bf8a8 100644 --- a/src/core/functions.ts +++ b/src/core/functions.ts @@ -61,7 +61,7 @@ export function treeSearch( const choice = iAutocomplete.options.getFocused(true); assert( 'command' in cur, - 'No command property found for autocomplete option', + 'No `command` property found for autocomplete option', ); if (subcommands.size > 0) { const parent = iAutocomplete.options.getSubcommand(); diff --git a/src/core/id.ts b/src/core/id.ts index b8975e73..fa4a33ba 100644 --- a/src/core/id.ts +++ b/src/core/id.ts @@ -42,6 +42,7 @@ export const CommandTypeDiscordApi = [ ComponentType.MentionableSelect, ComponentType.ChannelSelect, ]; + /* * Generates a number based on CommandType. * This corresponds to an ApplicationCommandType or ComponentType diff --git a/src/core/ioc/base.ts b/src/core/ioc/base.ts index eb5a024a..9de0c75f 100644 --- a/src/core/ioc/base.ts +++ b/src/core/ioc/base.ts @@ -5,6 +5,7 @@ import { CoreContainer } from './container'; import { Result } from 'ts-results-es' import { DefaultServices } from '../_internal'; import { AnyFunction } from '../../types/utility'; +import type { Logging } from '../contracts/logging'; //SIDE EFFECT: GLOBAL DI let containerSubject: CoreContainer>; @@ -22,6 +23,12 @@ export function useContainerRaw() { return containerSubject; } +export function disposeAll(logger: Logging|undefined) { + containerSubject + ?.disposeAll() + .then(() => logger?.info({ message: 'Cleaning container and crashing' })); +} + const dependencyBuilder = (container: any, excluded: string[]) => { type Insertable = | ((container: CoreContainer) => unknown ) @@ -82,16 +89,16 @@ export const insertLogger = (containerSubject: CoreContainer) => { } export async function makeDependencies (conf: ValidDependencyConfig) { - //Until there are more optional dependencies, just check if the logger exists - //SIDE EFFECT containerSubject = new CoreContainer(); if(typeof conf === 'function') { const excluded: string[] = []; conf(dependencyBuilder(containerSubject, excluded)); + if(!excluded.includes('@sern/logger') && !containerSubject.getTokens()['@sern/logger']) { insertLogger(containerSubject); } + containerSubject.ready(); } else { composeRoot(containerSubject, conf); diff --git a/src/core/ioc/container.ts b/src/core/ioc/container.ts index 73b2b40b..ff61173c 100644 --- a/src/core/ioc/container.ts +++ b/src/core/ioc/container.ts @@ -22,19 +22,18 @@ export class CoreContainer> extends Container) .add({ '@sern/errors': () => new DefaultServices.DefaultErrorHandling(), - '@sern/emitter': () => new SernEmitter(), - '@sern/store': () => new ModuleStore() }) + '@sern/emitter': () => new SernEmitter, + '@sern/store': () => new ModuleStore }) .add(ctx => { - return { - '@sern/modules': () => - new DefaultServices.DefaultModuleManager(ctx['@sern/store']), - }; + return { '@sern/modules': () => + new DefaultServices.DefaultModuleManager(ctx['@sern/store']) }; }); } isReady() { return this.ready$.closed; } + override async disposeAll() { const otherDisposables = Object diff --git a/src/core/module-loading.ts b/src/core/module-loading.ts index f45400b6..a7c6d36d 100644 --- a/src/core/module-loading.ts +++ b/src/core/module-loading.ts @@ -130,7 +130,6 @@ export function loadConfig(wrapper: Wrapper | 'file'): Wrapper { eventsPath = makePath('events'); console.log('Events path is set to', eventsPath); } - return { defaultPrefix: config.defaultPrefix, diff --git a/src/core/modules.ts b/src/core/modules.ts index 6ed89752..ccfbe561 100644 --- a/src/core/modules.ts +++ b/src/core/modules.ts @@ -93,9 +93,9 @@ export abstract class CommandExecutable { abstract type: Type; plugins: AnyEventPlugin[] = []; diff --git a/src/core/operators.ts b/src/core/operators.ts index 3953eac3..12743ab9 100644 --- a/src/core/operators.ts +++ b/src/core/operators.ts @@ -28,16 +28,15 @@ export function filterMapTo(item: () => V): OperatorFunction { return concatMap(shouldKeep => (shouldKeep ? of(item()) : EMPTY)); } +interface PluginExecutable { + execute: (...args: unknown[]) => PluginResult; +}; /** * Calls any plugin with {args}. * @param args if an array, its spread and plugin called. */ -export function callPlugin(args: unknown): OperatorFunction< - { - execute: (...args: unknown[]) => PluginResult; - }, - VoidResult -> { +export function callPlugin(args: unknown): OperatorFunction +{ return concatMap(async plugin => { if (Array.isArray(args)) { return plugin.execute(...args); @@ -79,8 +78,6 @@ export const filterTap = (onErr: (e: R) => void): OperatorFunction { - const payload = { - type: 'fail', - body: undefined, - log : undefined - } as Record - - return { - /** - * @param {'fail' | 'continue'} p a status to determine if the error will - * terminate your application or continue. Warning and - */ - status: (p: 'fail' | 'continue') => { - payload.type = p; - return payload; - }, - /** - * @param {keyof Logging} type Determine to log to logger[type]. - * @param {T} message the message to log - * - * Log this error with the logger. - */ - log: (type: keyof Logging, message: T) => { - payload.log = { type, message }; - return payload; - }, - reply: (bodyContent: ReplyOptions) => { - payload.body = bodyContent; - return payload; - } - }; -} diff --git a/src/core/structures/context.ts b/src/core/structures/context.ts index 32cd036d..6ceb7abc 100644 --- a/src/core/structures/context.ts +++ b/src/core/structures/context.ts @@ -114,7 +114,7 @@ export class Context extends CoreContext { if ('interaction' in wrappable) { return new Context(Ok(wrappable)); } - assert.ok(wrappable.isChatInputCommand()); + assert.ok(wrappable.isChatInputCommand(), "Context created with bad interaction."); return new Context(Err(wrappable)); } } diff --git a/src/core/structures/core-context.ts b/src/core/structures/core-context.ts index c2e483cc..acff87b2 100644 --- a/src/core/structures/core-context.ts +++ b/src/core/structures/core-context.ts @@ -7,7 +7,7 @@ import * as assert from 'node:assert'; */ export abstract class CoreContext { protected constructor(protected ctx: Either) { - assert.ok(typeof ctx === 'object' && ctx != null); + assert.ok(typeof ctx === 'object' && ctx != null, "Context was nonobject or null"); } get message(): M { return this.ctx.expect(SernError.MismatchEvent); diff --git a/src/core/structures/index.ts b/src/core/structures/index.ts index 2a0ea034..e3c08dcb 100644 --- a/src/core/structures/index.ts +++ b/src/core/structures/index.ts @@ -3,4 +3,3 @@ export * from './context'; export * from './sern-emitter'; export * from './services'; export * from './module-store'; -export * as CommandError from './command-error'; diff --git a/src/handlers/dispatchers.ts b/src/handlers/dispatchers.ts index cc1525e8..ad9549c8 100644 --- a/src/handlers/dispatchers.ts +++ b/src/handlers/dispatchers.ts @@ -12,6 +12,7 @@ import { createResultResolver } from './event-utils'; import { BaseInteraction, Message } from 'discord.js'; import { CommandType, Context } from '../core'; import type { AnyFunction, Args } from '../types/utility'; +import { inspect } from 'node:util' import type { CommandModule, Module, Processed } from '../types/core-modules'; //TODO: refactor dispatchers so that it implements a strategy for each different type of payload? @@ -75,10 +76,7 @@ export function createDispatcher(payload: { case CommandType.Both: { if (isAutocomplete(payload.event)) { const option = treeSearch(payload.event, payload.module.options); - assert.ok( - option, - Error(SernError.NotSupportedInteraction + ` There is no autocomplete tag for this option`), - ); + assert.ok(option, SernError.NotSupportedInteraction + ` There is no autocomplete tag for ` + inspect(payload.module)); const { command, name, parent } = option; return { diff --git a/src/handlers/event-utils.ts b/src/handlers/event-utils.ts index 5af439a9..ad75f520 100644 --- a/src/handlers/event-utils.ts +++ b/src/handlers/event-utils.ts @@ -21,17 +21,17 @@ import { handleError, SernError, VoidResult, - useContainerRaw, } from '../core/_internal'; import { Emitter, ErrorHandling, Logging, ModuleManager } from '../core'; import { contextArgs, createDispatcher } from './dispatchers'; import { ObservableInput, pipe } from 'rxjs'; import { SernEmitter } from '../core'; import { Err, Ok, Result } from 'ts-results-es'; -import type { AnyFunction, Awaitable } from '../types/utility'; +import type { Awaitable } from '../types/utility'; import type { ControlPlugin } from '../types/core-plugin'; import type { AnyModule, CommandModule, Module, Processed } from '../types/core-modules'; import type { ImportPayload } from '../types/core'; +import { disposeAll } from '../core/ioc/base'; function createGenericHandler( source: Observable, @@ -77,11 +77,10 @@ export function createInteractionHandler( } return Files .defaultModuleLoader>(fullPath) - .then(payload => - Ok(createDispatcher({ - module: payload.module, - event, - }))); + .then(payload => Ok(createDispatcher({ + module: payload.module, + event, + }))); }, ); } @@ -100,10 +99,9 @@ export function createMessageHandler( } return Files .defaultModuleLoader>(fullPath) - .then((payload)=> { + .then(payload => { const args = contextArgs(event, rest); return Ok({ args, ...payload }); - }); }); } @@ -172,6 +170,8 @@ export function executeModule( ); } + + /** * A higher order function that * - creates a stream of {@link VoidResult} { config.createStream } @@ -258,8 +258,5 @@ export const handleCrash = (err: ErrorHandling, log?: Logging) => log?.info({ message: 'A stream closed or reached end of lifetime', }); - useContainerRaw() - ?.disposeAll() - .then(() => log?.info({ message: 'Cleaning container and crashing' })); - }), - ); + disposeAll(log); + })); diff --git a/src/handlers/interaction-event.ts b/src/handlers/interaction-event.ts index a39e2807..f9b90e14 100644 --- a/src/handlers/interaction-event.ts +++ b/src/handlers/interaction-event.ts @@ -28,6 +28,5 @@ export function interactionHandler([emitter, err, log, modules, client]: Depende filterTap(e => emitter.emit('warning', SernEmitter.warning(e))), makeModuleExecutor(module => emitter.emit('module.activate', SernEmitter.failure(module, SernError.PluginFailure))), - mergeMap(payload => executeModule(emitter, log, err, payload)), - ); + mergeMap(payload => executeModule(emitter, log, err, payload))); } diff --git a/src/handlers/message-event.ts b/src/handlers/message-event.ts index bb548758..d234ca70 100644 --- a/src/handlers/message-event.ts +++ b/src/handlers/message-event.ts @@ -42,6 +42,5 @@ export function messageHandler( makeModuleExecutor(module => { emitter.emit('module.activate', SernEmitter.failure(module, SernError.PluginFailure)); }), - mergeMap(payload => executeModule(emitter, log, err, payload)), - ); + mergeMap(payload => executeModule(emitter, log, err, payload))); } diff --git a/src/handlers/presence.ts b/src/handlers/presence.ts index 4719e72d..38afa6e0 100644 --- a/src/handlers/presence.ts +++ b/src/handlers/presence.ts @@ -42,5 +42,5 @@ export const presenceHandler = (path: string, setPresence: SetPresence) => { //concatMap resolves the promise, and passes it to the next concatMap. concatMap(fn => parseConfig(fn())), // subscribe to the observable parseConfig yields, and set the presence. - concatMap(conf => conf.pipe(map(setPresence)))) + concatMap(conf => conf.pipe(map(setPresence)))); } diff --git a/src/index.ts b/src/index.ts index e72c2e26..dd9bec69 100644 --- a/src/index.ts +++ b/src/index.ts @@ -55,4 +55,3 @@ export * as Presence from './core/presences' export { useContainerRaw } from './core/_internal' -export { controller } from './sern'; diff --git a/src/sern.ts b/src/sern.ts index 9e29a5bb..d6fe0d59 100644 --- a/src/sern.ts +++ b/src/sern.ts @@ -66,11 +66,4 @@ function useDependencies() { ); } -/** - * @since 1.0.0 - * The object passed into every plugin to control a command's behavior - */ -export const controller = { - next: ok, - stop: err, -}; +