update locals api, docs, tests

This commit is contained in:
Jacob Nguyen
2024-06-14 20:27:23 -05:00
parent 2f778f4dc2
commit 90f5ea7bda
10 changed files with 90 additions and 43 deletions

View File

@@ -14,11 +14,10 @@ import type { Awaitable } from '../types/utility';
*/
export function commandModule(mod: InputCommand): Module {
const [onEvent, plugins] = partitionPlugins(mod.plugins);
return {
...mod,
onEvent,
plugins,
} as Module;
return { ...mod,
onEvent,
plugins,
locals: {} } as Module;
}
/**
@@ -29,7 +28,9 @@ export function commandModule(mod: InputCommand): Module {
export function eventModule(mod: InputEvent): Module {
const [onEvent, plugins] = partitionPlugins(mod.plugins);
if(onEvent.length !== 0) throw Error("Event modules cannot have ControlPlugins");
return { ...mod, plugins } as Module;
return { ...mod,
plugins,
locals: {} } as Module;
}
/** Create event modules from discord.js client events,

View File

@@ -17,6 +17,7 @@ import { CommandType } from '../core/structures/enums'
import { inspect } from 'node:util'
import { disposeAll } from '../core/ioc';
import { resultPayload, isAutocomplete, treeSearch, fmt } from '../core/functions'
import merge from 'deepmerge'
function handleError<C>(crashHandler: ErrorHandling, emitter: Emitter, logging?: Logging) {
return (pload: unknown, caught: Observable<C>) => {
@@ -213,25 +214,26 @@ export function createResultResolver<Output>(config: {
};
};
export async function callInitPlugins(module: Module, deps: Dependencies, emit?: boolean) {
let _module = module;
function isObject(item: unknown) {
return (item && typeof item === 'object' && !Array.isArray(item));
}
//_module is frozen, preventing from mutations
export async function callInitPlugins(_module: Module, deps: Dependencies, emit?: boolean) {
let module = _module;
const emitter = deps['@sern/emitter'];
for(const plugin of _module.plugins ?? []) {
const res = await plugin.execute({
module: _module,
absPath: _module.meta.absPath,
deps
});
if (!res) throw Error("Plugin did not return anything. " + inspect(plugin, false, Infinity, true));
if(res.isErr()) {
for(const plugin of module.plugins ?? []) {
const result = await plugin.execute({ module, absPath: module.meta.absPath, deps });
if (!result) throw Error("Plugin did not return anything. " + inspect(plugin, false, Infinity, true));
if(result.isErr()) {
if(emit) {
emitter?.emit('module.register',
resultPayload('failure', module, res.error ?? SernError.PluginFailure));
resultPayload('failure', module, result.error ?? SernError.PluginFailure));
}
throw Error(res.error ?? SernError.PluginFailure);
throw Error(result.error ?? SernError.PluginFailure);
}
}
return _module
return module
}
async function callPlugins({ args, module, deps, params }: ExecutePayload) {
@@ -241,8 +243,8 @@ async function callPlugins({ args, module, deps, params }: ExecutePayload) {
if(result.isErr()) {
return result;
}
if(typeof result.value === 'object' && result.value !== null) {
state = { ...state, ...result.value, };
if(isObject(result.value)) {
state = merge(state, result.value!);
}
}
return Ok(state);

View File

@@ -23,8 +23,8 @@ export default async function(dir: string, deps : UnpackedDependencies) {
if(!validType) {
throw Error(`Found ${module.name} at ${module.meta.absPath}, which has incorrect \`type\``);
}
const resultModule = await callInitPlugins(module, deps, true);
// FREEZE! no more writing!!
const resultModule = await callInitPlugins(module, deps, true); // FREEZE! no more writing!!
commands.set(resultModule.meta.id, Object.freeze(resultModule));
sEmitter.emit('module.register', resultPayload('success', resultModule));
}

View File

@@ -18,7 +18,7 @@ import type {
} from 'discord.js';
import type { CommandType, EventType } from '../core/structures/enums';
import { Context } from '../core/structures/context'
import { AnyPlugin, ControlPlugin, InitPlugin } from './core-plugin';
import { ControlPlugin, InitPlugin, Plugin } from './core-plugin';
import { Awaitable, SernEventsMapping } from './utility';
//state, deps, type (very original)
@@ -41,6 +41,7 @@ export interface Module {
id: string;
absPath: string;
}
locals: Record<string,unknown>
execute(...args: any[]): Awaitable<any>;
}
@@ -191,10 +192,10 @@ export interface SernAutocompleteData
}
type CommandModuleNoPlugins = {
[T in CommandType]: Omit<CommandModuleDefs[T], 'plugins' | 'onEvent' | 'meta'>;
[T in CommandType]: Omit<CommandModuleDefs[T], 'plugins' | 'onEvent' | 'meta' | 'locals'>;
};
type EventModulesNoPlugins = {
[T in EventType]: Omit<EventModuleDefs[T], 'plugins' | 'onEvent' | 'meta'> ;
[T in EventType]: Omit<EventModuleDefs[T], 'plugins' | 'onEvent' | 'meta' | 'locals'> ;
};
export type InputEvent = {
@@ -206,7 +207,7 @@ export type InputEvent = {
export type InputCommand = {
[T in CommandType]: CommandModuleNoPlugins[T] & {
plugins?: AnyPlugin[];
plugins?: Plugin[];
};
}[CommandType];

View File

@@ -33,7 +33,6 @@ import type {
} from 'discord.js';
export type PluginResult = Awaitable<Result<Record<string,unknown>|undefined, string|undefined>>;
export interface InitArgs<T extends Processed<Module> = Processed<Module>> {
module: T;
absPath: string;
@@ -46,6 +45,7 @@ export interface Plugin<Args extends any[] = any[]> {
export interface InitPlugin<Args extends any[] = any[]> extends Plugin<Args> {
type: PluginType.Init;
execute: (...args: Args) => PluginResult;
}
export interface ControlPlugin<Args extends any[] = any[]> extends Plugin<Args> {
type: PluginType.Control;

View File

@@ -7,6 +7,21 @@
import { CoreDependencies } from './ioc';
declare global {
/**
* discord.js client.
* '@sern/client': Client
* sern emitter listens to events that happen throughout
* the handler. some include module.register, module.activate.
* '@sern/emitter': Contracts.Emitter;
* An error handler which is the final step before
* the sern process actually crashes.
'@sern/errors': Contracts.ErrorHandling;
* Optional logger. Performs ... logging
* '@sern/logger'?: Contracts.Logging;
* Readonly module store. sern stores these
* by module.meta.id -> Module
* '@sern/modules': Map<string, Module>;
*/
interface Dependencies extends CoreDependencies {}
}

View File

@@ -6,10 +6,28 @@ import { Module } from './core-modules';
export interface CoreDependencies {
/**
* discord.js client.
*/
'@sern/client': Client;
/**
* sern emitter listens to events that happen throughout
* the handler. some include module.register, module.activate.
*/
'@sern/emitter': Contracts.Emitter;
/**
* An error handler which is the final step before
* the sern process actually crashes.
*/
'@sern/errors': Contracts.ErrorHandling;
/**
* Optional logger. Performs ... logging
*/
'@sern/logger'?: Contracts.Logging;
/**
* Readonly module store. sern stores these
* by module.meta.id -> Module
*/
'@sern/modules': Map<string, Module>;
}