From 5e878cc97b7d8fd740ea304f02b6ecd0e0832744 Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Wed, 10 May 2023 21:57:55 -0500 Subject: [PATCH] chore: progress of globalizing dependencies type --- src/core/index.ts | 3 +- src/core/module-loading.ts | 23 +++++++------- src/handler/commands.ts | 42 +++++--------------------- src/handler/events/generic.ts | 48 +++++++++++++----------------- src/handler/events/interactions.ts | 1 + src/handler/events/ready.ts | 4 +-- src/handler/events/user-defined.ts | 2 +- src/handler/types.ts | 1 + src/index.ts | 1 + src/shared.ts | 2 -- tsup.config.js | 4 +-- 11 files changed, 49 insertions(+), 82 deletions(-) diff --git a/src/core/index.ts b/src/core/index.ts index 1900d05..c78d226 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -23,7 +23,8 @@ export type { CommandModuleDefs, EventModuleDefs, BaseOptions, - SernAutocompleteData + SernAutocompleteData, + SernOptionsData } from './types/modules'; export type { Controller, diff --git a/src/core/module-loading.ts b/src/core/module-loading.ts index bcdd102..2a0fa8b 100644 --- a/src/core/module-loading.ts +++ b/src/core/module-loading.ts @@ -1,14 +1,13 @@ import { SernError } from './structures/errors'; import { type Result, Err, Ok } from 'ts-results-es'; import { Module } from './types/modules'; -import * as assert from 'node:assert'; -import util from 'node:util'; import { type Observable, from, mergeMap, ObservableInput } from 'rxjs'; import { readdir, stat } from 'fs/promises'; import { basename, join, resolve } from 'path'; -import { Processed } from '../handler/types'; - -export type ModuleResult = Promise, SernError>>; +import { ImportPayload } from '../handler/types'; +import * as assert from 'node:assert' +import { sernMeta } from '../handler/commands'; +export type ModuleResult = Promise, SernError>>; export async function importModule(absPath: string) { /// #if MODE === 'esm' @@ -18,19 +17,17 @@ export async function importModule(absPath: string) { /// #endif } export async function defaultModuleLoader(absPath: string): ModuleResult { - // prettier-ignore const module = await importModule(absPath); if (module === undefined) { return Err(SernError.UndefinedModule); } - checkIsProcessed(module); - return Ok(module); + + assert.ok(module.type > 0 && module.type < 1<<10, "Found a module that does not have a valid type"); + assert.ok(module[sernMeta], "Found a module that isn't marked with sernMeta"); + + return Ok({ module, absPath }); } -function checkIsProcessed(m: T): asserts m is Processed { - assert.ok(m.name !== undefined, `name is not defined for ${util.format(m)}`); - assert.ok(m.description !== undefined, `description is not defined for ${util.format(m)}`); -} export const fmtFileName = (n: string) => n.substring(0, n.length - 3); @@ -42,7 +39,7 @@ export const fmtFileName = (n: string) => n.substring(0, n.length - 3); */ export function buildModuleStream( input: ObservableInput, -): Observable, SernError>> { +): Observable, SernError>> { return from(input).pipe(mergeMap(defaultModuleLoader)); } diff --git a/src/handler/commands.ts b/src/handler/commands.ts index ba1a3c2..3259033 100644 --- a/src/handler/commands.ts +++ b/src/handler/commands.ts @@ -1,32 +1,12 @@ import { ClientEvents } from 'discord.js'; -import { CommandType, EventType, PluginType } from '../core/structures'; +import { EventType, PluginType } from '../core/structures'; import { AnyEventPlugin, Plugin } from '../core/types/plugins'; import { CommandModule, EventModule, InputCommand, InputEvent } from '../core/types/modules'; import { partition } from '../core/functions'; -import { filename, filePath } from '../core/module-loading'; import { Awaitable } from '../shared'; export const sernMeta = Symbol('@sern/meta'); -const appBitField = 0b000000011111; -/* - * Generates a number based on CommandType. - * This corresponds to an ApplicationCommandType or ComponentType - * TextCommands are 0 as they aren't either or. - */ -function apiType(t: CommandType) { - if (t === CommandType.Both || t === CommandType.Modal) return 1; - const log = Math.log2(t); - return (appBitField & t) !== 0 ? log : log - 2; -} - -/* - * Generates an id based on CommandType. - * A is for any ApplicationCommand. C is for any ComponentCommand - * Then, another number generated by apiType function is appended - */ -function uniqueId(t: CommandType) { - const am = (appBitField & t) !== 0 ? 'A' : 'C'; - return am + apiType(t); -} +export const UNREGISTERED = "meow meow meow"; +export const EMPTY_PATH = "purr purr purr"; /** * @since 1.0.0 The wrapper function to define command modules for sern * @param mod @@ -36,18 +16,14 @@ export function commandModule(mod: InputCommand): CommandModule { mod.plugins ?? [], el => (el as Plugin).type === PluginType.Control, ); - const fullPath = filePath(); - const name = mod.name ?? filename(fullPath); return { ...mod, - description: mod.description ?? '...', - name, onEvent, plugins, [sernMeta]: { - id: `${name}__${uniqueId(mod.type)}`, - fullPath, - }, + id: UNREGISTERED, + fullPath: EMPTY_PATH + } } as CommandModule; } /** @@ -60,14 +36,12 @@ export function eventModule(mod: InputEvent): EventModule { mod.plugins ?? [], el => (el as Plugin).type === PluginType.Control, ); - const fullPath = filePath(); return { - name: mod.name ?? filename(fullPath), onEvent, plugins, [sernMeta]: { - id: 'no-id', - fullPath, + id: UNREGISTERED, + fullPath: EMPTY_PATH }, ...mod, } as EventModule; diff --git a/src/handler/events/generic.ts b/src/handler/events/generic.ts index db1513d..de41c29 100644 --- a/src/handler/events/generic.ts +++ b/src/handler/events/generic.ts @@ -3,8 +3,8 @@ import { InteractionType, Message, } from 'discord.js'; -import { EMPTY, Observable, concatMap, filter, from, map, of, throwError, tap } from 'rxjs'; -import { ModuleManager } from '../../core'; +import { EMPTY, Observable, concatMap, filter, from, of, throwError, tap, MonoTypeOperatorFunction } from 'rxjs'; +import { CommandType, EventType, ModuleManager } from '../../core'; import { SernError } from '../../core/structures/errors'; import { callPlugin, everyPluginOk, filterMap, filterMapTo } from '../../core/operators'; import { defaultModuleLoader } from '../../core/module-loading'; @@ -20,6 +20,7 @@ import { fmt } from './messages'; import { ControlPlugin, VoidResult } from '../../core/types/plugins'; import { ImportPayload, Processed } from '../types'; import { Awaitable } from '../../shared'; +import { createId, uniqueId } from '../id'; function createGenericHandler( source: Observable, @@ -44,8 +45,8 @@ export function createInteractionHandler( const fullPath = mg.get(createId(event as unknown as Interaction)); if (!fullPath) return Err(SernError.UndefinedModule + ' No full path found in module store'); - return defaultModuleLoader(fullPath).then(res => - res.map(module => createDispatcher({ module, event })), + return defaultModuleLoader>(fullPath).then(res => + res.map(payload => createDispatcher({ module: payload.module, event })), ); }, ); @@ -58,39 +59,32 @@ export function createMessageHandler( ) { return createGenericHandler(source, event => { const [prefix, ...rest] = fmt(event.content, defaultPrefix); - const fullPath = mg.get(`${prefix}__A0`); + const fullPath = mg.get(`${prefix}_A0`); if (fullPath === undefined) { return Err(SernError.UndefinedModule + ' No full path found in module store'); } - return defaultModuleLoader(fullPath) + return defaultModuleLoader>(fullPath) .then(result => { const args = contextArgs(event, rest); - return result.map(module => dispatchMessage(module, args)) + return result.map(payload => dispatchMessage(payload.module, args)) }) }); } /** - * Creates a unique ID for a given interaction object. - * @param event The interaction object for which to create an ID. - * @returns A unique string ID based on the type and properties of the interaction object. - */ -function createId(event: T) { - switch (event.type) { - case InteractionType.MessageComponent: { - return `${event.customId}__C${event.componentType}`; - } - case InteractionType.ApplicationCommand: - case InteractionType.ApplicationCommandAutocomplete: { - return `${event.commandName}__A${event.commandType}`; - } - case InteractionType.ModalSubmit: { - return `${event.customId}__C1`; - } + * IMPURE SIDE EFFECT + * This function assigns remaining, incomplete data to each imported module. + */ +function assignDefaults(): MonoTypeOperatorFunction> { + return tap( + ({ module, absPath }) => { + module.name ??= Files.filename(absPath); + module.description ??= "..."; + module[sernMeta].fullPath = absPath; + module[sernMeta].id = `${module.name}_${uniqueId(module.type)}` } + ) } - - export function buildModules( input: ObservableInput, sernEmitter: SernEmitter, @@ -100,7 +94,7 @@ export function buildModules( errTap(error => { sernEmitter.emit('module.register', SernEmitter.failure(undefined, error)); }), - map(module => ({ module, absPath: module[sernMeta].fullPath })), + assignDefaults() ); } @@ -184,7 +178,7 @@ export function createResultResolver< * ignore the module */ export function callInitPlugins< - T extends Processed, + T extends Processed, Args extends ImportPayload, >(config: { onStop?: (module: T) => unknown; onNext: (module: Args) => T }) { return concatMap( diff --git a/src/handler/events/interactions.ts b/src/handler/events/interactions.ts index a03d9a6..610bd0e 100644 --- a/src/handler/events/interactions.ts +++ b/src/handler/events/interactions.ts @@ -26,3 +26,4 @@ export function makeInteractionHandler([emitter,,, modules, client]: DependencyL concatMap(payload => executeModule(emitter, payload)), ); } + diff --git a/src/handler/events/ready.ts b/src/handler/events/ready.ts index 6ccff7b..271e864 100644 --- a/src/handler/events/ready.ts +++ b/src/handler/events/ready.ts @@ -16,7 +16,7 @@ export function startReadyEvent( const ready$ = fromEvent(client!, 'ready').pipe(take(1)); return ready$ .pipe( - buildModules(allPaths, sEmitter), + buildModules>(allPaths, sEmitter), callInitPlugins({ onStop: module => { sEmitter.emit('module.register', SernEmitter.failure(module, SernError.PluginFailure)); @@ -43,7 +43,7 @@ function registerModule>( if (module.type === CommandType.Both || module.type === CommandType.Text ) { - module.alias?.forEach(a => manager.set(`${a}__A0`, fullPath)); + module.alias?.forEach(a => manager.set(`${a}_A0`, fullPath)); } return Result.wrap(() => manager.set(id, fullPath)); } diff --git a/src/handler/events/user-defined.ts b/src/handler/events/user-defined.ts index 5892985..437aec3 100644 --- a/src/handler/events/user-defined.ts +++ b/src/handler/events/user-defined.ts @@ -33,7 +33,7 @@ export function makeEventsHandler( }; of(null) .pipe( - buildModules(allPaths, emitter), + buildModules>(allPaths, emitter), callInitPlugins({ onStop: module => emitter.emit('module.register', SernEmitter.failure(module, SernError.PluginFailure)), diff --git a/src/handler/types.ts b/src/handler/types.ts index 9919359..eda3d83 100644 --- a/src/handler/types.ts +++ b/src/handler/types.ts @@ -20,4 +20,5 @@ export interface InitArgs> { export interface ImportPayload { module: T; absPath: string; + [key: string]: unknown } diff --git a/src/index.ts b/src/index.ts index 5b7dda1..61624f7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,4 +2,5 @@ export * as Sern from './handler/sern'; export * from './core'; export { commandModule, eventModule, discordEvent } from './handler/commands' export { controller } from './handler/sern'; +export type { Wrapper, Args } from './shared' diff --git a/src/shared.ts b/src/shared.ts index f05e8b9..6e89a12 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -4,7 +4,6 @@ import type { MessageReplyOptions, } from 'discord.js'; import { PayloadType } from './core'; -import { Dependencies } from './core/ioc/types'; import { AnyModule } from './core/types/modules'; export type ReplyOptions = @@ -27,7 +26,6 @@ export interface SernEventsMapping { export type Awaitable = PromiseLike | T; -export type ModuleStore = Map; export type Deprecated = [never, Message]; diff --git a/tsup.config.js b/tsup.config.js index e1d7160..6806f4e 100644 --- a/tsup.config.js +++ b/tsup.config.js @@ -54,9 +54,9 @@ export default defineConfig([ }, { dts: { - only: true + only: true, + entry: 'src/index.ts' }, - entry: ['src/index.ts'], outDir: 'dist' } ]);