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

@@ -35,8 +35,9 @@
"author": "SernDevs",
"license": "MIT",
"dependencies": {
"@sern/ioc": "^1.0.3",
"@sern/ioc": "^1.0.4",
"callsites": "^3.1.0",
"deepmerge": "^4.3.1",
"node-cron": "^3.0.3",
"rxjs": "^7.8.0",
"ts-results-es": "^4.1.0"

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>;
}

View File

@@ -57,13 +57,8 @@ vi.mock('discord.js', async (importOriginal) => {
function createRandomPlugin (s: 'go', mut?: Partial<Module>) {
return CommandInitPlugin(({ module }) => {
if(mut) {
for(const [k,v] of Object.entries(mut)) {
module[k] = v
}
}
return s == 'go'
? controller.next()
? controller.next(mut)
: controller.stop()
})
}
@@ -103,16 +98,22 @@ describe('eventDispatcher standard', () => {
});
});
test ('mutate with init plugins', async () => {
test ('call init plugins', async () => {
const deps = mockDeps()
const plugins = createRandomPlugin('go', { name: "abc" })
const mod = createRandomModule([plugins])
console.log(mod)
const s = await callInitPlugins(mod, deps, false)
console.log(s)
expect("abc").equal(s.name)
})
test('init plugins replace array', async () => {
const deps = mockDeps()
const plugins = createRandomPlugin('go', { opts: [] })
const plugins2 = createRandomPlugin('go', { opts: ['a'] })
const mod = createRandomModule([plugins, plugins2])
const s = await callInitPlugins(mod, deps, false)
expect(['a']).deep.equal(s.opts)
})
test('call control plugin ', async () => {
const plugin = CommandControlPlugin<CommandType.Slash>((ctx,sdt) => {

View File

@@ -553,12 +553,13 @@ __metadata:
resolution: "@sern/handler@workspace:."
dependencies:
"@faker-js/faker": ^8.0.1
"@sern/ioc": ^1.0.3
"@sern/ioc": ^1.0.4
"@types/node": ^20.0.0
"@types/node-cron": ^3.0.11
"@typescript-eslint/eslint-plugin": 5.58.0
"@typescript-eslint/parser": 5.59.1
callsites: ^3.1.0
deepmerge: ^4.3.1
discord.js: ^14.x.x
eslint: 8.39.0
node-cron: ^3.0.3
@@ -569,10 +570,10 @@ __metadata:
languageName: unknown
linkType: soft
"@sern/ioc@npm:^1.0.3":
version: 1.0.3
resolution: "@sern/ioc@npm:1.0.3"
checksum: 2c640cabbf3927d923b57233e660be1d6d4da1cd376a4ba77b118fd9aa5ef81c465d287357a15a7cd7827306dd614c73bde68751978d2030c3a4877dcbb0d02d
"@sern/ioc@npm:^1.0.4":
version: 1.0.4
resolution: "@sern/ioc@npm:1.0.4"
checksum: 3d1a63099b3e8ff0d44bb73007b1d66c3f3b27cf7a193c2d9122e021cb72be1ced535ea98efaf72602f371a489177e3b144ed72da8d7de80887c0408ce79cce2
languageName: node
linkType: hard
@@ -1172,6 +1173,13 @@ __metadata:
languageName: node
linkType: hard
"deepmerge@npm:^4.3.1":
version: 4.3.1
resolution: "deepmerge@npm:4.3.1"
checksum: 2024c6a980a1b7128084170c4cf56b0fd58a63f2da1660dcfe977415f27b17dbe5888668b59d0b063753f3220719d5e400b7f113609489c90160bb9a5518d052
languageName: node
linkType: hard
"diff-sequences@npm:^29.6.3":
version: 29.6.3
resolution: "diff-sequences@npm:29.6.3"