Skip to content

Commit

Permalink
refactor: cleanup (#348)
Browse files Browse the repository at this point in the history
* some wip code

Co-authored-by: Jacob Nguyen <[email protected]>

* general idea

* style

* making shrimple truly optional

* got optional localizer working

* proposing api notation?

* prepare for localization map

* add localsFor

* merge some internals

* boss call

* add test for init functionality

* add documentation

* inline and cleanup

* feat: logging for experimental json loading

* loosen typings

* dev workflow and cleaning up comments

* cleaning up a bit more

* rename Localizer -> Localization

* more documentation, change dir for default localizer

* some tests

* "

* move stuff, refactor, deprecate

* yarnb

* Update index.ts

---------

Co-authored-by: Jacob Nguyen <[email protected]>
Co-authored-by: Jacob Nguyen <[email protected]>
Co-authored-by: jacob <[email protected]>
  • Loading branch information
4 people authored Feb 9, 2024
1 parent 5cad432 commit 45cbda7
Show file tree
Hide file tree
Showing 36 changed files with 311 additions and 272 deletions.
34 changes: 34 additions & 0 deletions .github/workflows/npm-publish-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Continuous Delivery

on:
push:
branches:
- main
paths:
- 'src/**'
- 'package.json'

jobs:
Publish:
name: Publishing Dev
runs-on: ubuntu-latest

steps:
- name: Check out Git repository
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3

- name: Set up Node.js
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3
with:
node-version: 18
registry-url: 'https://registry.npmjs.org'

- name: Install Node.js dependencies
run: npm i && npm run build:dev

- name: Publish to npm
run: |
npm version premajor --preid "dev.$(git rev-parse --verify --short HEAD)" --git-tag-version=false
npm publish --tag dev
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
"@typescript-eslint/eslint-plugin": "5.58.0",
"@typescript-eslint/parser": "5.59.1",
"discord.js": "^14.11.0",
"esbuild": "^0.17.0",
"eslint": "8.39.0",
"prettier": "2.8.8",
"tsup": "^6.7.0",
Expand Down Expand Up @@ -95,5 +94,8 @@
"type": "git",
"url": "git+https://github.com/sern-handler/handler.git"
},
"engines": {
"node": ">= 18.16.x"
},
"homepage": "https://sern.dev"
}
2 changes: 1 addition & 1 deletion src/core/_internal.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export * as Id from './id';
export * from './operators';
export * from './predicates';
export * as Files from './module-loading';
export * from './functions';
export type { VoidResult } from '../types/core-plugin';
export { SernError } from './structures/enums';
export { ModuleStore } from './structures/module-store';
export * as DefaultServices from './structures/services';
export { useContainerRaw } from './ioc/base'

9 changes: 0 additions & 9 deletions src/core/contracts/disposable.ts

This file was deleted.

2 changes: 2 additions & 0 deletions src/core/contracts/emitter.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//i deleted it, hmm so how should we allow users to enable localization?
// a
import type { AnyFunction } from '../../types/utility';

export interface Emitter {
Expand Down
2 changes: 0 additions & 2 deletions src/core/contracts/error-handling.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { CommandModule,Processed, EventModule } from "../../types/core-modules";

/**
* @since 2.0.0
*/
Expand Down
16 changes: 16 additions & 0 deletions src/core/contracts/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

/**
* Represents an initialization contract.
* Let dependencies implement this to initiate some logic.
*/
export interface Init {
init(): unknown;
}

/**
* Represents a Disposable contract.
* Let dependencies implement this to dispose and cleanup.
*/
export interface Disposable {
dispose(): unknown;
}
3 changes: 1 addition & 2 deletions src/core/contracts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ export * from './error-handling';
export * from './logging';
export * from './module-manager';
export * from './module-store';
export * from './init';
export * from './hooks';
export * from './emitter';
export * from './disposable'
9 changes: 0 additions & 9 deletions src/core/contracts/init.ts

This file was deleted.

46 changes: 43 additions & 3 deletions src/core/functions.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import { Err, Ok } from 'ts-results-es';
import { ApplicationCommandOptionType, AutocompleteInteraction } from 'discord.js';
import type { SernAutocompleteData, SernOptionsData } from '../types/core-modules';
import type { Module, SernAutocompleteData, SernOptionsData } from '../types/core-modules';
import type { AnyCommandPlugin, AnyEventPlugin, Plugin } from '../types/core-plugin';
import { PluginType } from './structures';
import type {
AnySelectMenuInteraction,
ButtonInteraction,
ChatInputCommandInteraction,
MessageContextMenuCommandInteraction,
ModalSubmitInteraction,
UserContextMenuCommandInteraction,
AutocompleteInteraction
} from 'discord.js';
import { ApplicationCommandOptionType, InteractionType } from 'discord.js'
import { PayloadType, PluginType } from './structures';
import assert from 'assert';
import { Payload } from '../types/utility';

//function wrappers for empty ok / err
export const ok = /* @__PURE__*/ () => Ok.EMPTY;
Expand Down Expand Up @@ -81,3 +91,33 @@ export function treeSearch(
}
}
}


interface InteractionTypable {
type: InteractionType;
}
//discord.js pls fix ur typings or i will >:(
type AnyMessageComponentInteraction = AnySelectMenuInteraction | ButtonInteraction;
type AnyCommandInteraction =
| ChatInputCommandInteraction
| MessageContextMenuCommandInteraction
| UserContextMenuCommandInteraction;

export function isMessageComponent(i: InteractionTypable): i is AnyMessageComponentInteraction {
return i.type === InteractionType.MessageComponent;
}
export function isCommand(i: InteractionTypable): i is AnyCommandInteraction {
return i.type === InteractionType.ApplicationCommand;
}
export function isAutocomplete(i: InteractionTypable): i is AutocompleteInteraction {
return i.type === InteractionType.ApplicationCommandAutocomplete;
}

export function isModal(i: InteractionTypable): i is ModalSubmitInteraction {
return i.type === InteractionType.ModalSubmit;
}

export function resultPayload<T extends PayloadType>
(type: T, module?: Module, reason?: unknown) {
return { type, module, reason } as Payload & { type : T };
}
63 changes: 45 additions & 18 deletions src/core/ioc/base.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import * as assert from 'assert';
import { composeRoot, useContainer } from './dependency-injection';
import type { DependencyConfiguration } from '../../types/ioc';
import { useContainer } from './dependency-injection';
import type { CoreDependencies, DependencyConfiguration } from '../../types/ioc';
import { CoreContainer } from './container';
import { Result } from 'ts-results-es'
import { Result } from 'ts-results-es';
import { DefaultServices } from '../_internal';
import { AnyFunction } from '../../types/utility';
import type { Logging } from '../contracts/logging';

//SIDE EFFECT: GLOBAL DI
let containerSubject: CoreContainer<Partial<Dependencies>>;

Expand All @@ -29,19 +30,18 @@ export function disposeAll(logger: Logging|undefined) {
.then(() => logger?.info({ message: 'Cleaning container and crashing' }));
}

const dependencyBuilder = (container: any, excluded: string[]) => {
const dependencyBuilder = (container: any, excluded: string[] ) => {
type Insertable =
| ((container: CoreContainer<Dependencies>) => unknown )
| Record<PropertyKey, unknown>
| object
return {
/**
* Insert a dependency into your container.
* Supply the correct key and dependency
*/
add(key: keyof Dependencies, v: Insertable) {
Result
.wrap(() => container.add({ [key]: v}))
.expect("Failed to add " + key);
Result.wrap(() => container.add({ [key]: v}))
.expect("Failed to add " + key);
},
/**
* Exclude any dependencies from being added.
Expand All @@ -50,15 +50,15 @@ const dependencyBuilder = (container: any, excluded: string[]) => {
exclude(...keys: (keyof Dependencies)[]) {
keys.forEach(key => excluded.push(key));
},

/**
* @param key the key of the dependency
* @param v The dependency to swap out.
* Swap out a preexisting dependency.
*/
swap(key: keyof Dependencies, v: Insertable) {
Result
.wrap(() => container.upsert({ [key]: v }))
.expect("Failed to update " + key);
Result.wrap(() => container.upsert({ [key]: v }))
.expect("Failed to update " + key);
},
/**
* @param key the key of the dependency
Expand All @@ -70,9 +70,8 @@ const dependencyBuilder = (container: any, excluded: string[]) => {
* Swap out a preexisting dependency.
*/
addDisposer(key: keyof Dependencies, cleanup: AnyFunction) {
Result
.wrap(() => container.addDisposer({ [key] : cleanup }))
.expect("Failed to addDisposer for" + key);
Result.wrap(() => container.addDisposer({ [key] : cleanup }))
.expect("Failed to addDisposer for" + key);
}
};
};
Expand All @@ -87,15 +86,45 @@ export const insertLogger = (containerSubject: CoreContainer<any>) => {
containerSubject
.upsert({'@sern/logger': () => new DefaultServices.DefaultLogging});
}


/**
* Given the user's conf, check for any excluded/included dependency keys.
* Then, call conf.build to get the rest of the users' dependencies.
* Finally, update the containerSubject with the new container state
* @param conf
*/
function composeRoot(
container: CoreContainer<Partial<Dependencies>>,
conf: DependencyConfiguration,
) {
//container should have no client or logger yet.
const hasLogger = conf.exclude?.has('@sern/logger');
if (!hasLogger) {
insertLogger(container);
}
//Build the container based on the callback provided by the user
conf.build(container as CoreContainer<Omit<CoreDependencies, '@sern/client'>>);

if (!hasLogger) {
container.get('@sern/logger')?.info({ message: 'All dependencies loaded successfully.' });
}

container.ready();
}

export async function makeDependencies<const T extends Dependencies>
(conf: ValidDependencyConfig) {
containerSubject = new CoreContainer();
if(typeof conf === 'function') {
const excluded: string[] = [];
conf(dependencyBuilder(containerSubject, excluded));

const includeLogger =
!excluded.includes('@sern/logger')
&& !containerSubject.getTokens()['@sern/logger'];

if(!excluded.includes('@sern/logger')
&& !containerSubject.getTokens()['@sern/logger']) {
if(includeLogger) {
insertLogger(containerSubject);
}

Expand All @@ -107,5 +136,3 @@ export async function makeDependencies<const T extends Dependencies>
return useContainer<T>();
}



26 changes: 17 additions & 9 deletions src/core/ioc/container.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Container } from 'iti';
import { Disposable, SernEmitter } from '../';
import { Disposable } from '../';
import * as assert from 'node:assert';
import { Subject } from 'rxjs';
import { DefaultServices, ModuleStore } from '../_internal';
import * as Hooks from './hooks'
import * as Hooks from './hooks';
import { EventEmitter } from 'node:events';


/**
Expand All @@ -17,12 +18,13 @@ export class CoreContainer<T extends Partial<Dependencies>> extends Container<T,
assert.ok(!this.isReady(), 'Listening for dispose & init should occur prior to sern being ready.');

const { unsubscribe } = Hooks.createInitListener(this);

this.ready$
.subscribe({ complete: unsubscribe });

(this as Container<{}, {}>)
.add({ '@sern/errors': () => new DefaultServices.DefaultErrorHandling(),
'@sern/emitter': () => new SernEmitter,
.add({ '@sern/errors': () => new DefaultServices.DefaultErrorHandling,
'@sern/emitter': () => new EventEmitter({ captureRejections: true }),
'@sern/store': () => new ModuleStore })
.add(ctx => {
return { '@sern/modules': () =>
Expand All @@ -33,19 +35,25 @@ export class CoreContainer<T extends Partial<Dependencies>> extends Container<T,
isReady() {
return this.ready$.closed;
}

hasKey(key: string): boolean {
return Boolean((this as Container<any,any>)._context[key]);
}

override async disposeAll() {

const otherDisposables = Object
.entries(this._context)
.flatMap(([key, value]) =>
'dispose' in value ? [key] : []);

for(const key of otherDisposables) {
otherDisposables.forEach(key => {
//possible source of bug: dispose is a property.
this.addDisposer({ [key]: (dep: Disposable) => dep.dispose() } as never);
}
await super.disposeAll()
})
await super.disposeAll();
}



ready() {
this.ready$.complete();
this.ready$.unsubscribe();
Expand Down
Loading

0 comments on commit 45cbda7

Please sign in to comment.