Skip to content

Commit

Permalink
initplugins inject deps, inconspicuos
Browse files Browse the repository at this point in the history
  • Loading branch information
jacoobes committed May 20, 2024
1 parent 15511a4 commit e0f6a4c
Show file tree
Hide file tree
Showing 11 changed files with 68 additions and 129 deletions.
25 changes: 2 additions & 23 deletions src/core/create-plugins.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { CommandType, EventType, PluginType } from './structures/enums';
import type { Plugin, PluginResult, EventArgs, CommandArgs, InitArgs } from '../types/core-plugin';
import type { ClientEvents } from 'discord.js';
import { CommandType, PluginType } from './structures/enums';
import type { Plugin, PluginResult, CommandArgs, InitArgs } from '../types/core-plugin';
import { err, ok } from './functions';

export function makePlugin<V extends unknown[]>(
Expand Down Expand Up @@ -31,27 +30,7 @@ export function CommandControlPlugin<I extends CommandType>(
) {
return makePlugin(PluginType.Control, execute);
}
/**
* @since 2.5.0
*/
export function EventControlPlugin<I extends EventType>(
execute: (...args: EventArgs<I>) => PluginResult,
) {
return makePlugin(PluginType.Control, execute);
}

/**
* @since 2.5.0
* @Experimental
* A specialized function for creating control plugins with discord.js ClientEvents.
* Will probably be moved one day!
*/
export function DiscordEventControlPlugin<T extends keyof ClientEvents>(
name: T,
execute: (...args: ClientEvents[T]) => PluginResult,
) {
return makePlugin(PluginType.Control, execute);
}

/**
* @since 1.0.0
Expand Down
44 changes: 19 additions & 25 deletions src/core/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,37 +46,31 @@ export function treeSearch(
while (_options.length > 0) {
const cur = _options.pop()!;
switch (cur.type) {
case ApplicationCommandOptionType.Subcommand:
{
case ApplicationCommandOptionType.Subcommand: {
subcommands.add(cur.name);
for (const option of cur.options ?? []) _options.push(option);
}
break;
case ApplicationCommandOptionType.SubcommandGroup:
{
} break;
case ApplicationCommandOptionType.SubcommandGroup: {
for (const command of cur.options ?? []) _options.push(command);
}
break;
default:
{
if ('autocomplete' in cur && cur.autocomplete) {
const choice = iAutocomplete.options.getFocused(true);
assert( 'command' in cur, 'No `command` property found for option ' + cur.name);
if (subcommands.size > 0) {
const parent = iAutocomplete.options.getSubcommand();
const parentAndOptionMatches =
subcommands.has(parent) && cur.name === choice.name;
if (parentAndOptionMatches) {
return { ...cur, parent };
}
} else {
if (cur.name === choice.name) {
return { ...cur, parent: undefined };
}
} break;
default: {
if ('autocomplete' in cur && cur.autocomplete) {
const choice = iAutocomplete.options.getFocused(true);
assert( 'command' in cur, 'No `command` property found for option ' + cur.name);
if (subcommands.size > 0) {
const parent = iAutocomplete.options.getSubcommand();
const parentAndOptionMatches =
subcommands.has(parent) && cur.name === choice.name;
if (parentAndOptionMatches) {
return { ...cur, parent };
}
} else {
if (cur.name === choice.name) {
return { ...cur, parent: undefined };
}
}
}
break;
} break;
}
}
}
Expand Down
10 changes: 2 additions & 8 deletions src/core/modules.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { ClientEvents } from 'discord.js';
import { EventType } from '../core/structures/enums';
import type { AnyEventPlugin, } from '../types/core-plugin';
import type {
InputCommand,
InputEvent,
Expand All @@ -21,18 +20,14 @@ export function commandModule(mod: InputCommand): Module {
plugins,
} as Module;
}

/**
* @since 1.0.0
* The wrapper function to define event modules for sern
* @param mod
*/
export function eventModule(mod: InputEvent): Module {
const [onEvent, plugins] = partitionPlugins(mod.plugins);
return {
...mod,
plugins,
onEvent,
} as Module;
return mod as Module;
}

/** Create event modules from discord.js client events,
Expand All @@ -43,7 +38,6 @@ export function eventModule(mod: InputEvent): Module {
*/
export function discordEvent<T extends keyof ClientEvents>(mod: {
name: T;
plugins?: AnyEventPlugin[];
execute: (...args: ClientEvents[T]) => Awaitable<unknown>;
}) {
return eventModule({ type: EventType.Discord, ...mod, });
Expand Down
23 changes: 11 additions & 12 deletions src/core/structures/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,26 @@ function fmt(msg: string, prefix?: string): string[] {
* Message and ChatInputCommandInteraction
*/
export class Context extends CoreContext<Message, ChatInputCommandInteraction> {
prefix: string|undefined;

get options() {
return this.interaction.options;
}

args() {
return {
message: <T = string[]>() => {
args(type: 'message'|'interaction', parser?: Function) {
switch(type) {
case 'message': {
const [, ...rest] = fmt(this.message.content, this.prefix);
return rest as T;
},
interaction: () => this.interaction.options
return rest;
};
case 'interaction': {
return this.interaction.options;
};
}
}

protected constructor(protected ctx: Result<Message, ChatInputCommandInteraction>, prefix?: string) {
protected constructor(protected ctx: Result<Message, ChatInputCommandInteraction>,
public prefix?: string) {
super(ctx);
this.prefix = prefix
}

public get id(): Snowflake {
Expand All @@ -52,9 +53,7 @@ export class Context extends CoreContext<Message, ChatInputCommandInteraction> {
}

public get channel() {
return safeUnwrap(this.ctx
.map(m => m.channel)
.mapErr(i => i.channel));
return safeUnwrap(this.ctx.map(m => m.channel).mapErr(i => i.channel));
}

public get channelId(): Snowflake {
Expand Down
31 changes: 20 additions & 11 deletions src/handlers/event-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import * as Id from '../core/id'
import type { Emitter } from '../core/interfaces';
import { PayloadType, SernError } from '../core/structures/enums'
import { Err, Ok, Result } from 'ts-results-es';
import type { UnpackedDependencies, VoidResult } from '../types/utility';
import type { UnpackedDependencies } from '../types/utility';
import type { CommandModule, Module, Processed } from '../types/core-modules';
import * as assert from 'node:assert';
import { Context } from '../core/structures/context';
Expand All @@ -36,15 +36,9 @@ interface ExecutePayload {

function intoPayload(module: Module, deps: Dependencies) {
return pipe(map(arrayifySource),
map(args => ({ module, args, deps })));
map(args => ({ module, args, deps })),
map(p => p.args));
}
const createResult = (deps: Dependencies) =>
createResultResolver<unknown[]>({
onNext: (p) => p.args,
onStop: (module) => {
//maybe do something when plugins fail?
}
});
/**
* Creates an observable from { source }
* @param module
Expand All @@ -60,7 +54,6 @@ export function eventDispatcher(deps: Dependencies, module: Module, source: unkn
//@ts-ignore
return fromEvent(source, module.name!)
.pipe(intoPayload(module, deps),
concatMap(createResult(deps)),
execute);
}

Expand Down Expand Up @@ -218,7 +211,23 @@ export function createResultResolver<Output>(config: {
}
};
};

export async function callInitPlugins(module: Module, deps: Dependencies, sEmitter?: Emitter) {
for(const plugin of module.plugins) {
const res = await plugin.execute({
module,
absPath: module.meta.absPath ,
updateModule: (partial: Partial<Module>) => {
module = { ...module, ...partial };
return module;
},
deps
});
if(res.isErr()) {
sEmitter?.emit('module.register', resultPayload(PayloadType.Failure, module, SernError.PluginFailure));
throw Error("Plugin failed with controller.stop()");
}
}
}
async function callPlugins({ args, module, deps }: ExecutePayload) {
let state = {};
for(const plugin of module.onEvent) {
Expand Down
2 changes: 1 addition & 1 deletion src/handlers/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function isNonBot(prefix: string) {

function hasPrefix(prefix: string, content: string) {
const prefixInContent = content.slice(0, prefix.length);
return (prefixInContent.localeCompare(prefix, undefined, { sensitivity: 'accent' }) === 0);
return prefixInContent.localeCompare(prefix, undefined, { sensitivity: 'accent' }) === 0;
}

export default function (
Expand Down
16 changes: 2 additions & 14 deletions src/handlers/ready.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PayloadType } from '..';
import { CommandType, SernError } from '../core/structures/enums';
import { Module } from '../types/core-modules';
import { UnpackedDependencies } from '../types/utility';
import { callInitPlugins } from './event-utils';

export default async function(dir: string, deps : UnpackedDependencies) {
const { '@sern/client': client,
Expand All @@ -23,20 +24,7 @@ export default async function(dir: string, deps : UnpackedDependencies) {
if(!validType) {
throw Error(`Found ${module.name} at ${module.meta.absPath}, which has incorrect \`type\``);
}
for(const plugin of module.plugins) {
const res = await plugin.execute({
module,
absPath: module.meta.absPath ,
updateModule: (partial: Partial<Module>) => {
module = { ...module, ...partial };
return module;
}
});
if(res.isErr()) {
sEmitter.emit('module.register', resultPayload(PayloadType.Failure, module, SernError.PluginFailure));
throw Error("Plugin failed with controller.stop()");
}
}
await callInitPlugins(module, deps, sEmitter);
// FREEZE! no more writing!!
commands.set(module.meta.id, Object.freeze(module));
sEmitter.emit('module.register', resultPayload(PayloadType.Success, module));
Expand Down
20 changes: 3 additions & 17 deletions src/handlers/user-defined-events.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { EventType, PayloadType, SernError } from '../core/structures/enums';
import { eventDispatcher, handleCrash } from './event-utils'
import { EventType, SernError } from '../core/structures/enums';
import { callInitPlugins, eventDispatcher, handleCrash } from './event-utils'
import { EventModule, Module } from '../types/core-modules';
import * as Files from '../core/module-loading'
import type { UnpackedDependencies } from '../types/utility';
import { resultPayload } from '../core/functions';
import { from, map, mergeAll } from 'rxjs';

const intoDispatcher = (deps: UnpackedDependencies) =>
Expand All @@ -29,20 +28,7 @@ export default async function(deps: UnpackedDependencies, eventDir: string) {
const eventModules: EventModule[] = [];
for await (const path of Files.readRecursive(eventDir)) {
let { module } = await Files.importModule<Module>(path);
for(const plugin of module.plugins) {
const res = await plugin.execute({
module,
absPath: module.meta.absPath,
updateModule: (partial: Partial<Module>) => {
module = { ...module, ...partial };
return module;
}
});
if(res.isErr()) {
deps['@sern/emitter'].emit('module.register', resultPayload(PayloadType.Failure, module, SernError.PluginFailure));
throw Error("Plugin failed with controller.stop()");
}
}
await callInitPlugins(module, deps)
eventModules.push(module as EventModule);
}
from(eventModules)
Expand Down
3 changes: 1 addition & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ export type {
InitPlugin,
ControlPlugin,
Plugin,
AnyEventPlugin,
AnyCommandPlugin,
AnyPlugin,
} from './types/core-plugin';


Expand Down
6 changes: 3 additions & 3 deletions src/types/core-modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type {
} from 'discord.js';
import type { CommandType, EventType } from '../core/structures/enums';
import { Context } from '../core/structures/context'
import { AnyCommandPlugin, AnyEventPlugin, ControlPlugin, InitPlugin } from './core-plugin';
import { AnyPlugin, ControlPlugin, InitPlugin } from './core-plugin';
import { Awaitable, SernEventsMapping } from './utility';

type ToBeDecided = {
Expand Down Expand Up @@ -193,12 +193,12 @@ type EventModulesNoPlugins = {
};

export type InputEvent = {
[T in EventType]: EventModulesNoPlugins[T] & { plugins?: AnyEventPlugin[] };
[T in EventType]: EventModulesNoPlugins[T];
}[EventType];

export type InputCommand = {
[T in CommandType]: CommandModuleNoPlugins[T] & {
plugins?: AnyCommandPlugin[];
plugins?: AnyPlugin[];
};
}[CommandType];

Expand Down
17 changes: 4 additions & 13 deletions src/types/core-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@ import type {
Module,
Processed,
} from './core-modules';
import type { Awaitable, Payload } from './utility';
import type { CommandType, EventType, PluginType } from '../core/structures/enums'
import type { Awaitable } from './utility';
import type { CommandType, PluginType } from '../core/structures/enums'
import type { Context } from '../core/structures/context'
import type {
ButtonInteraction,
ChannelSelectMenuInteraction,
ClientEvents,
MentionableSelectMenuInteraction,
MessageContextMenuCommandInteraction,
ModalSubmitInteraction,
Expand All @@ -37,6 +36,7 @@ export type PluginResult = Awaitable<Result<unknown, unknown>>;
export interface InitArgs<T extends Processed<Module> = Processed<Module>> {
module: T;
absPath: string;
deps: Dependencies
updateModule: (module: Partial<T>) => T
}
export interface Controller {
Expand All @@ -57,11 +57,9 @@ export interface ControlPlugin<Args extends any[] = any[]> {
execute: (...args: Args) => PluginResult;
}

export type AnyCommandPlugin = ControlPlugin | InitPlugin<[InitArgs<Processed<Module>>]>;
export type AnyEventPlugin = ControlPlugin | InitPlugin<[InitArgs<Processed<Module>>]>;
export type AnyPlugin = ControlPlugin | InitPlugin<[InitArgs<Processed<Module>>]>;

export type CommandArgs<I extends CommandType = CommandType > = CommandArgsMatrix[I]
export type EventArgs<I extends EventType = EventType> = EventArgsMatrix[I]

interface CommandArgsMatrix {
[CommandType.Text]: [Context];
Expand All @@ -77,10 +75,3 @@ interface CommandArgsMatrix {
[CommandType.UserSelect]: [UserSelectMenuInteraction];
[CommandType.Modal]: [ModalSubmitInteraction];
}

interface EventArgsMatrix {
[EventType.Discord]: ClientEvents[keyof ClientEvents];
[EventType.Sern]: [Payload];
[EventType.External]: unknown[];
[EventType.Cron]: unknown[];
}

0 comments on commit e0f6a4c

Please sign in to comment.