add separate id for id processing

This commit is contained in:
Jacob Nguyen
2023-05-10 21:41:18 -05:00
parent 0256a38187
commit 57dfa09a73
5 changed files with 83 additions and 34 deletions

View File

@@ -1,6 +1,6 @@
import * as assert from "assert";
import { composeRoot, useContainer } from "./dependency-injection";
import { DependencyConfiguration, Dependencies } from "./types";
import { DependencyConfiguration } from "./types";
import { CoreContainer } from "../structures/container";
@@ -24,16 +24,13 @@ export function useContainerRaw() {
* @param conf a configuration for creating your project dependencies
*/
export async function makeDependencies<const T extends Dependencies>(
conf: DependencyConfiguration<T>,
conf: DependencyConfiguration,
) {
//Until there are more optional dependencies, just check if the logger exists
//SIDE EFFECT
containerSubject = new CoreContainer()
await composeRoot(conf);
await composeRoot(containerSubject, conf);
//SIDE EFFECT
containerSubject.ready();
return useContainer<T>();
}

View File

@@ -1,4 +1,4 @@
import type { CoreDependencies, Dependencies, DependencyConfiguration, MapDeps, IntoDependencies } from './types';
import type { DependencyConfiguration, MapDeps, IntoDependencies } from './types';
import { DefaultLogging } from '../structures';
import { SernError } from '../structures/errors';
import { useContainerRaw } from './base';
@@ -24,8 +24,7 @@ export function single<T>(cb: () => T) {
export function transient<T>(cb: () => () => T) {
return cb;
}
export function Service(key: string): unknown
export function Service(key: string) : unknown
export function Service<T extends keyof Dependencies>(key: T) {
return useContainerRaw().get(key)!
}
@@ -41,31 +40,35 @@ export function Services<const T extends (keyof Dependencies)[]>(...keys: [...T]
* Finally, update the containerSubject with the new container state
* @param conf
*/
export async function composeRoot<T extends Dependencies>(conf: DependencyConfiguration<T>) {
export async function composeRoot(
container: CoreContainer<Partial<Dependencies>>,
conf: DependencyConfiguration
) {
//container should have no client or logger yet.
const excludeLogger = conf.exclude?.has('@sern/logger');
const container = useContainerRaw();
if (!excludeLogger) {
const hasLogger = conf.exclude?.has('@sern/logger');
if (!hasLogger) {
container.upsert({
'@sern/logger': () => new DefaultLogging(),
});
}
//Build the container based on the callback provided by the user
const updatedContainer = await conf.build(container as CoreContainer<CoreDependencies>);
conf.build(container as CoreContainer<CoreDependencies>);
try {
updatedContainer.get('@sern/client');
container.get('@sern/client');
} catch {
throw new Error(SernError.MissingRequired + " No client was provided")
}
if (!excludeLogger) {
updatedContainer.get('@sern/logger')?.info({ message: 'All dependencies loaded successfully.' });
if (!hasLogger) {
container.get('@sern/logger')?.info({ message: 'All dependencies loaded successfully.' });
}
container.ready();
}
export function useContainer<const T extends Dependencies>() {
console.warn(`
Warning: using a container hook is not recommended.
Warning: using a container hook (useContainer) is not recommended.
Could lead to many unwanted side effects.
Use the new Service(s) api function instead.
`

16
src/core/ioc/ioc.d.ts vendored Normal file
View File

@@ -0,0 +1,16 @@
type Singleton<T> = () => T;
type Transient<T> = () => () => T;
interface CoreDependencies {
'@sern/logger'?: Singleton<import('../contracts/logging').Logging>;
'@sern/emitter': Singleton<import('../structures/sern-emitter').SernEmitter>;
'@sern/store': Singleton<import('../contracts/module-store').CoreModuleStore>;
'@sern/modules': Singleton<import('../contracts/module-manager').ModuleManager>;
'@sern/errors': Singleton<import('../contracts/error-handling').ErrorHandling>;
}
interface Dependencies extends CoreDependencies {
'@sern/client': Singleton<import('node:events').EventEmitter>;
}

View File

@@ -1,35 +1,22 @@
import { Container, UnpackFunction } from "iti";
import { Awaitable, ModuleStore } from "../../shared";
import { ErrorHandling, Logging, ModuleManager } from "../contracts";
import { SernEmitter } from "../";
import EventEmitter from "node:events";
export type Singleton<T> = () => T;
export type Transient<T> = () => () => T;
export interface CoreDependencies {
'@sern/logger'?: Singleton<Logging>;
'@sern/emitter': Singleton<SernEmitter>;
'@sern/store': Singleton<ModuleStore>;
'@sern/modules': Singleton<ModuleManager>;
'@sern/errors': Singleton<ErrorHandling>;
}
export interface Dependencies extends CoreDependencies {
'@sern/client': Singleton<EventEmitter>;
}
export type DependencyFromKey<T extends keyof Dependencies> = Dependencies[T];
export type IntoDependencies<Tuple extends [...any[]]> = {
[Index in keyof Tuple]: UnpackFunction<DependencyFromKey<Tuple[Index]>&{}>; //Unpack and make NonNullable
} & { length: Tuple['length'] };
export interface DependencyConfiguration<T extends Dependencies> {
export interface DependencyConfiguration {
//@deprecated. Loggers will always be included in the future
exclude?: Set<'@sern/logger'>;
build: (root: Container<CoreDependencies, {}>) => Awaitable<Container<T, {}>>;
build: (root: Container<CoreDependencies, {}>) => Container<Dependencies, {}>;
}
//To be removed in future

46
src/handler/id.ts Normal file
View File

@@ -0,0 +1,46 @@
import { Interaction, InteractionType } from "discord.js";
import { CommandType, EventType } from "../core";
/**
* 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.
*/
export function createId<T extends Interaction>(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`;
}
}
}
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|EventType) {
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
*/
export function uniqueId(t: CommandType|EventType) {
const am = (appBitField & t) !== 0 ? 'A' : 'C';
return am + apiType(t);
}