chore: change all file names to camel case

This commit is contained in:
Jacob Nguyen
2023-05-06 22:12:37 -05:00
parent bf6b99ff03
commit 8c28e00206
11 changed files with 132 additions and 156 deletions

View File

@@ -29,6 +29,7 @@ export async function defaultModuleLoader<T extends Module>(absPath: string): Mo
function checkIsProcessed<T extends Module>(m: T): asserts m is Processed<T> {
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}`);
}
export const fmtFileName = (n: string) => n.substring(0, n.length - 3);

View File

@@ -7,7 +7,7 @@ import { EventEmitter } from 'node:events';
import * as assert from 'node:assert';
import { concatMap, from, fromEvent, map, OperatorFunction, pipe } from 'rxjs';
import { arrayifySource, callPlugin } from '../../../core/operators';
import { createResultResolver } from '../observableHandling';
import { createResultResolver } from '../generic';
export function dispatchCommand(module: Processed<CommandModule>, createArgs: () => unknown[]) {
const args = createArgs();

View File

@@ -1,2 +1,2 @@
export * from './dispatchers';
export * from './provideArgs';
export * from './provide-args';

View File

@@ -5,13 +5,13 @@ import {
InteractionType,
Message,
} from 'discord.js';
import { Observable, filter, map } from 'rxjs';
import { EMPTY, Observable, concatMap, filter, from, map, of, throwError, tap } from 'rxjs';
import { CommandType, ModuleManager } from '../../core';
import { SernError } from '../../core/structures/errors';
import { filterMap } from '../../core/operators';
import { callPlugin, everyPluginOk, filterMap, filterMapTo } from '../../core/operators';
import { defaultModuleLoader } from '../../core/module-loading';
import { Processed } from '../../types/core';
import { BothCommand, CommandModule } from '../../types/module';
import { ImportPayload, Processed } from '../../types/core';
import { BothCommand, CommandModule, EventModule, Module } from '../../types/module';
import { contextArgs, dispatchAutocomplete, dispatchCommand, interactionArg } from './dispatchers';
import { isAutocomplete } from '../../core/predicates';
import { ObservableInput, pipe, switchMap } from 'rxjs';
@@ -23,6 +23,7 @@ import { AnyModule } from '../../types/module';
import { Err, Result } from 'ts-results-es';
import { Awaitable } from '../../types/handler';
import { fmt } from './messages';
import { ControlPlugin, VoidResult } from '../../types/plugin';
function createGenericHandler<Source, Narrowed extends Source, Output>(
source: Observable<Source>,
@@ -139,3 +140,112 @@ export function buildModules<T extends AnyModule>(
map(module => ({ module, absPath: module[sernMeta].fullPath })),
);
}
function hasPrefix(prefix: string, content: string) {
const prefixInContent = content.slice(0, prefix.length);
return prefixInContent.localeCompare(prefix, undefined, { sensitivity: 'accent' }) === 0;
}
/**
* Ignores messages from any person / bot except itself
* @param prefix
*/
export function isNonBot(prefix: string) {
return ({ author, content }: Message) => !author.bot && hasPrefix(prefix, content);
}
/**
* Wraps the task in a Result as a try / catch.
* if the task is ok, an event is emitted and the stream becomes empty
* if the task is an error, throw an error down the stream which will be handled by catchError
* @param emitter reference to SernEmitter that will emit a successful execution of module
* @param module the module that will be executed with task
* @param task the deferred execution which will be called
*/
export function executeModule(
emitter: SernEmitter,
{
module,
task,
}: {
module: Processed<Module>;
task: () => Awaitable<unknown>;
},
) {
return of(module).pipe(
//converting the task into a promise so rxjs can resolve the Awaitable properly
concatMap(() => Result.wrapAsync(async () => task())),
concatMap(result => {
if (result.ok) {
emitter.emit('module.activate', SernEmitter.success(module));
return EMPTY;
} else {
return throwError(() => SernEmitter.failure(module, result.val));
}
}),
);
}
/**
* A higher order function that
* - creates a stream of {@link VoidResult} { config.createStream }
* - any failures results to { config.onFailure } being called
* - if all results are ok, the stream is converted to { config.onSuccess }
* emit config.onSuccess Observable
* @param config
* @returns receiver function for flattening a stream of data
*/
export function createResultResolver<
T extends { execute: (...args: any[]) => any; onEvent: ControlPlugin[] },
Args extends { module: T; [key: string]: unknown },
Output,
>(config: {
onStop?: (module: T) => unknown;
onNext: (args: Args) => Output;
createStream: (args: Args) => Observable<VoidResult>;
}) {
return (args: Args) => {
const task$ = config.createStream(args);
return task$.pipe(
tap(result => {
result.err && config.onStop?.(args.module);
}),
everyPluginOk,
filterMapTo(() => config.onNext(args)),
);
};
}
/**
* Calls a module's init plugins and checks for Err. If so, call { onStop } and
* ignore the module
*/
export function callInitPlugins<
T extends Processed<CommandModule | EventModule>,
Args extends ImportPayload<T>,
>(config: { onStop?: (module: T) => unknown; onNext: (module: Args) => T }) {
return concatMap(
createResultResolver({
createStream: args => from(args.module.plugins).pipe(callPlugin(args)),
...config,
}),
);
}
/**
* Creates an executable task ( execute the command ) if all control plugins are successful
* @param onStop emits a failure response to the SernEmitter
*/
export function makeModuleExecutor<
M extends Processed<Module>,
Args extends { module: M; args: unknown[] },
>(onStop: (m: M) => unknown) {
const onNext = ({ args, module }: Args) => ({ task: () => module.execute(...args), module });
return concatMap(
createResultResolver({
onStop,
createStream: ({ args, module }) => from(module.onEvent).pipe(callPlugin(args)),
onNext,
}),
);
}

View File

@@ -1,23 +1,15 @@
import { Interaction } from 'discord.js';
import { catchError, concatMap, finalize, merge } from 'rxjs';
import { SernError } from '../../core/structures/errors';
import { executeModule, makeModuleExecutor } from './observableHandling';
import { ErrorHandling, handleError } from '../../core/contracts/errorHandling';
import { handleError } from '../../core/contracts/error-handling';
import { SernEmitter } from '../../core';
import { sharedObservable } from '../../core/operators';
import { useContainerRaw } from '../../core/dependencies';
import type { Logging, ModuleManager } from '../../core/contracts';
import type { EventEmitter } from 'node:events';
import { isAutocomplete, isCommand, isMessageComponent, isModal } from '../../core/predicates';
import { createInteractionHandler } from './generic';
import { createInteractionHandler, executeModule, makeModuleExecutor } from './generic';
import { DependencyList } from '../../types/core';
export function makeInteractionCreate([s, err, log, modules, client]: [
SernEmitter,
ErrorHandling,
Logging | undefined,
ModuleManager,
EventEmitter,
]) {
export function makeInteractionCreate([s, err, log, modules, client]: DependencyList ) {
const interactionStream$ = sharedObservable<Interaction>(client, 'interactionCreate');
const handle = createInteractionHandler<Interaction>(interactionStream$, modules);
const interactionHandler$ = merge(

View File

@@ -1,13 +1,13 @@
import { catchError, concatMap, EMPTY, finalize } from 'rxjs';
import { SernError } from '../../core/structures/errors';
import type { Message } from 'discord.js';
import { executeModule, ignoreNonBot, makeModuleExecutor } from './observableHandling';
import { ErrorHandling, handleError } from '../../core/contracts/errorHandling';
import { ErrorHandling, handleError } from '../../core/contracts/error-handling';
import type { Logging, ModuleManager } from '../../core/contracts';
import type { EventEmitter } from 'node:events';
import { SernEmitter, useContainerRaw } from '../../core';
import { sharedObservable } from '../../core/operators';
import { createMessageHandler } from './generic';
import { createMessageHandler, executeModule, isNonBot, makeModuleExecutor } from './generic';
import { DependencyList } from '../../types/core';
/**
* Removes the first character(s) _[depending on prefix length]_ of the message
@@ -24,13 +24,7 @@ export function fmt(msg: string, prefix: string): string[] {
}
export function makeMessageCreate(
[s, err, log, modules, client]: [
SernEmitter,
ErrorHandling,
Logging | undefined,
ModuleManager,
EventEmitter,
],
[s, err, log, modules, client]: DependencyList,
defaultPrefix: string | undefined,
) {
if (!defaultPrefix) {
@@ -39,7 +33,7 @@ export function makeMessageCreate(
}
const messageStream$ = sharedObservable<Message>(client, 'messageCreate');
const handler = createMessageHandler(messageStream$, defaultPrefix, modules);
const messageHandler = handler(ignoreNonBot(defaultPrefix) as (m: Message) => m is Message);
const messageHandler = handler(isNonBot(defaultPrefix) as (m: Message) => m is Message);
return messageHandler.pipe(
makeModuleExecutor(module => {
s.emit('module.activate', SernEmitter.failure(module, SernError.PluginFailure));

View File

@@ -1,117 +0,0 @@
import { concatMap, EMPTY, from, Observable, of, tap, throwError } from 'rxjs';
import { Result } from 'ts-results-es';
import type { CommandModule, EventModule, Module } from '../../types/module';
import { SernEmitter } from '../../core';
import { callPlugin, everyPluginOk, filterMapTo } from '../../core/operators';
import type { ImportPayload, Processed } from '../../types/core';
import type { ControlPlugin, VoidResult } from '../../types/plugin';
import { Awaitable } from '../../types/handler';
import { Message } from 'discord.js';
function hasPrefix(prefix: string, content: string) {
const prefixInContent = content.slice(0, prefix.length);
return prefixInContent.localeCompare(prefix, undefined, { sensitivity: 'accent' }) === 0;
}
/**
* Ignores messages from any person / bot except itself
* @param prefix
*/
export function ignoreNonBot(prefix: string) {
return ({ author, content }: Message) => !author.bot && hasPrefix(prefix, content);
}
/**
* Wraps the task in a Result as a try / catch.
* if the task is ok, an event is emitted and the stream becomes empty
* if the task is an error, throw an error down the stream which will be handled by catchError
* @param emitter reference to SernEmitter that will emit a successful execution of module
* @param module the module that will be executed with task
* @param task the deferred execution which will be called
*/
export function executeModule(
emitter: SernEmitter,
{
module,
task,
}: {
module: Processed<Module>;
task: () => Awaitable<unknown>;
},
) {
return of(module).pipe(
//converting the task into a promise so rxjs can resolve the Awaitable properly
concatMap(() => Result.wrapAsync(async () => task())),
concatMap(result => {
if (result.ok) {
emitter.emit('module.activate', SernEmitter.success(module));
return EMPTY;
} else {
return throwError(() => SernEmitter.failure(module, result.val));
}
}),
);
}
/**
* A higher order function that
* - creates a stream of {@link VoidResult} { config.createStream }
* - any failures results to { config.onFailure } being called
* - if all results are ok, the stream is converted to { config.onSuccess }
* emit config.onSuccess Observable
* @param config
* @returns receiver function for flattening a stream of data
*/
export function createResultResolver<
T extends { execute: (...args: any[]) => any; onEvent: ControlPlugin[] },
Args extends { module: T; [key: string]: unknown },
Output,
>(config: {
onStop?: (module: T) => unknown;
onNext: (args: Args) => Output;
createStream: (args: Args) => Observable<VoidResult>;
}) {
return (args: Args) => {
const task$ = config.createStream(args);
return task$.pipe(
tap(result => {
result.err && config.onStop?.(args.module);
}),
everyPluginOk,
filterMapTo(() => config.onNext(args)),
);
};
}
/**
* Calls a module's init plugins and checks for Err. If so, call { onStop } and
* ignore the module
*/
export function callInitPlugins<
T extends Processed<CommandModule | EventModule>,
Args extends ImportPayload<T>,
>(config: { onStop?: (module: T) => unknown; onNext: (module: Args) => T }) {
return concatMap(
createResultResolver({
createStream: args => from(args.module.plugins).pipe(callPlugin(args)),
...config,
}),
);
}
/**
* Creates an executable task ( execute the command ) if all control plugins are successful
* @param onStop emits a failure response to the SernEmitter
*/
export function makeModuleExecutor<
M extends Processed<Module>,
Args extends { module: M; args: unknown[] },
>(onStop: (m: M) => unknown) {
const onNext = ({ args, module }: Args) => ({ task: () => module.execute(...args), module });
return concatMap(
createResultResolver({
onStop,
createStream: ({ args, module }) => from(module.onEvent).pipe(callPlugin(args)),
onNext,
}),
);
}

View File

@@ -1,20 +1,17 @@
import { ObservableInput, fromEvent, take } from 'rxjs';
import { callInitPlugins } from './observableHandling';
import { CommandType } from '../../core/structures';
import { SernError } from '../../core/structures/errors';
import { Result } from 'ts-results-es';
import { ModuleManager } from '../../core/contracts';
import { SernEmitter, } from '../../core';
import { sernMeta } from '../../commands';
import { Processed, ServerlessDependencyList, WebsocketDependencyList } from '../../types/core';
import { Processed, DependencyList } from '../../types/core';
import { Module } from '../../types/module';
import * as assert from 'node:assert';
import { buildModules } from './generic';
import { buildModules, callInitPlugins } from './generic';
export function startReadyEvent(
[sEmitter, errorHandler, , moduleManager, client]:
| ServerlessDependencyList
| WebsocketDependencyList,
[sEmitter, errorHandler, , moduleManager, client]: DependencyList,
input: ObservableInput<string>,
) {
const ready$ = fromEvent(client!, 'ready').pipe(take(1));

View File

@@ -1,6 +1,5 @@
import { catchError, finalize, map, mergeAll, of } from 'rxjs';
import type { Dependencies, Processed, Wrapper } from '../../types/core';
import { callInitPlugins } from './observableHandling';
import type { CommandModule, EventModule } from '../../types/module';
import type { EventEmitter } from 'node:events';
import { SernEmitter } from '../../core';
@@ -8,9 +7,9 @@ import type { ErrorHandling, Logging } from '../../core/contracts';
import { EventType } from '../../core/structures';
import { SernError } from '../../core/structures/errors';
import { eventDispatcher } from './dispatchers';
import { handleError } from '../../core/contracts/errorHandling';
import { handleError } from '../../core/contracts/error-handling';
import { useContainerRaw } from '../../core/dependencies';
import { buildModules } from './generic';
import { buildModules, callInitPlugins } from './generic';
export function makeEventsHandler(
[s, err, log, client]: [SernEmitter, ErrorHandling, Logging | undefined, EventEmitter],

View File

@@ -1,4 +1,4 @@
import { makeEventsHandler } from './events/userDefined';
import { makeEventsHandler } from './events/user-defined';
import { makeInteractionCreate } from './events/interactions';
import { startReadyEvent } from './events/ready';
import { makeMessageCreate } from './events/messages';