From 4df491b2af43807e0c88369e105c4bbf33742bfa Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Tue, 11 Jun 2024 00:58:54 -0500 Subject: [PATCH 01/13] need to impl swap --- packages/ioc/package.json | 1 + packages/ioc/src/container.ts | 31 ++++++++++++++++++++------- packages/ioc/test/index.test.ts | 37 ++++++++++++++++++++++----------- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/packages/ioc/package.json b/packages/ioc/package.json index d3ee3bb..c0f40f4 100644 --- a/packages/ioc/package.json +++ b/packages/ioc/package.json @@ -5,6 +5,7 @@ "main": "dist/index.js", "scripts": { "test": "vitest --run", + "tdd": "vitest", "build": "tsc" }, "devDependencies": { diff --git a/packages/ioc/src/container.ts b/packages/ioc/src/container.ts index 8c86bd1..b1ed407 100644 --- a/packages/ioc/src/container.ts +++ b/packages/ioc/src/container.ts @@ -1,6 +1,9 @@ - +/** + * A semi-generic container that provides error handling, emitter, and module store. + * For the handler to operate correctly, The only user provided dependency needs to be @sern/client + */ function hasCallableMethod(obj: object, name: PropertyKey) { - // object will always be defined + //@ts-ignore return typeof obj[name] == 'function'; } /** @@ -21,17 +24,18 @@ export class Container { this.hooks.get(name)!.push(callback); } private registerHooks(hookname: string, insert: object) { + if(hasCallableMethod(insert, hookname)) { - console.log(hookname) //@ts-ignore - this.addHook(hookname, async () => await insert[hookname]()) + this.addHook(hookname, () => insert[hookname]()) } } + addSingleton(key: string, insert: object) { if(typeof insert !== 'object') { throw Error("Inserted object must be an object"); } - if(!this.__singletons.has(key)){ + if(!this.__singletons.has(key)) { this.registerHooks('init', insert) this.registerHooks('dispose', insert) this.__singletons.set(key, insert); @@ -40,8 +44,8 @@ export class Container { return false; } - addWiredSingleton(key: string, fn: (c: Container) => object) { - const insert = fn(this); + addWiredSingleton(key: string, fn: (c: Record) => object) { + const insert = fn(this.deps()); return this.addSingleton(key, insert); } @@ -70,5 +74,16 @@ export class Container { await hookFunction(); } } -} + swap(key: string, swp: object) { + if (typeof swp !== 'object') { + throw Error("Inserted object must be an object"); + } + + const existing = this.__singletons.get(key); + if (!existing) { + throw Error("No existing key to swap for " + key); + } + this.__singletons.set(key, swp); + } +} diff --git a/packages/ioc/test/index.test.ts b/packages/ioc/test/index.test.ts index 207f242..632cb1b 100644 --- a/packages/ioc/test/index.test.ts +++ b/packages/ioc/test/index.test.ts @@ -1,12 +1,17 @@ import { Container } from '../src/container'; -import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { describe, it, expect, beforeEach, vi, Mock } from 'vitest'; describe('CoreContainer Tests', () => { let coreContainer: Container; - + let singletonWInit: { init: Mock; value: string } beforeEach(() => { coreContainer = new Container({ autowire: false }); + singletonWInit = { + value: 'singletonWithInit', + init: vi.fn() + } + }); it('Adding and getting singletons', () => { @@ -99,22 +104,30 @@ describe('CoreContainer Tests', () => { expect(coreContainer.isReady()).toBe(true); }); it('Registering and executing hooks - init should be called once after ready', async () => { - let initCount = 0; - const singletonWithInit = { - value: 'singletonValueWithInit', - init: async () => { - initCount++; - } - }; - - coreContainer.addSingleton('singletonKeyWithInit', singletonWithInit); + coreContainer.addSingleton('singletonKeyWithInit', singletonWInit); // Call ready twice to ensure hooks are executed only once await coreContainer.ready(); await coreContainer.ready(); - expect(initCount).toBe(1); + expect(singletonWInit.init).toHaveBeenCalledOnce(); }); + it('should throw because not swapping anything', () => { + + expect(() => coreContainer.swap('singletonKeyWithInit', singletonWInit)).toThrow() + }) + it('should swap object with another', () => { + coreContainer.addSingleton('singleton', singletonWInit) + const singletonWithInit2 = { + value: 'singletonValueWithInit2', + init: vi.fn() + }; + coreContainer.swap('singleton', singletonWithInit2) + expect(coreContainer.get('singleton')).toBe(singletonWithInit2) + }) + it('should swap object, calling dispose hook', () => { + coreContainer.addSingleton('singleton', singletonWInit) + }) }) From f9508544df690d5f2cea37d017e2853595a45629 Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Tue, 11 Jun 2024 10:54:30 -0500 Subject: [PATCH 02/13] update docs for deps --- packages/localizer/index.mdx | 40 +++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/packages/localizer/index.mdx b/packages/localizer/index.mdx index eda90fa..dff7641 100644 --- a/packages/localizer/index.mdx +++ b/packages/localizer/index.mdx @@ -6,8 +6,6 @@ sidebar: --- -# @sern/localizer - A localization module for managing translations and providing localized content in your application. ## Installation @@ -16,21 +14,43 @@ A localization module for managing translations and providing localized content npm i @sern/localizer ``` + +import { Tabs, TabItem } from "@astrojs/starlight/components"; + + ## Usage **Initializing the Localizer** -```ts -import { makeDependencies } from '@sern/handler'; -import { Localization } from '@sern/localizer'; -await makeDependencies(({ add }) => { - add('localizer', Localization()); -}); -``` + + + ```ts {2} {6} + import { makeDependencies } from '@sern/handler'; + import { Localization } from '@sern/localizer'; + + await makeDependencies(({ add }) => { + // add other deps + add('localizer', Localization()); + }); + ``` + + + ```ts {5} + import type { Logging, CoreDependencies } from '@sern/handler' + import type { Localizer } from '@sern/localizer' + declare global { + interface Dependencies extends CoreDependencies { + localizer: Localizer; + } + } + export {} + ``` + + + This localizer is **FILE BASED**. Create the directory `assets/locals`. Each json file in here must be named after the `locale` -import { Tabs, TabItem } from "@astrojs/starlight/components"; From 01597c83dd0b85aba82831cd087c431ad56f9f46 Mon Sep 17 00:00:00 2001 From: EvolutionX <85353424+EvolutionX-10@users.noreply.github.com> Date: Wed, 12 Jun 2024 17:00:53 +0530 Subject: [PATCH 03/13] feat(ioc): impl dispose logic in swap method --- packages/ioc/src/container.ts | 10 +++++++ packages/ioc/test/index.test.ts | 51 ++++++++++++++++++++++++--------- 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/packages/ioc/src/container.ts b/packages/ioc/src/container.ts index b1ed407..d9b612c 100644 --- a/packages/ioc/src/container.ts +++ b/packages/ioc/src/container.ts @@ -82,8 +82,18 @@ export class Container { const existing = this.__singletons.get(key); if (!existing) { + // @jacoobes should we return false if no existing key? throw Error("No existing key to swap for " + key); } + // check if there's dispose hook, and call it + if (hasCallableMethod(existing, 'dispose')) { + this.disposeAll().then(() => {; + this.registerHooks('dispose', swp); + }); + } + this.__singletons.set(key, swp); + this.registerHooks('init', swp); + return true; } } diff --git a/packages/ioc/test/index.test.ts b/packages/ioc/test/index.test.ts index 632cb1b..0a60e16 100644 --- a/packages/ioc/test/index.test.ts +++ b/packages/ioc/test/index.test.ts @@ -5,13 +5,17 @@ import { describe, it, expect, beforeEach, vi, Mock } from 'vitest'; describe('CoreContainer Tests', () => { let coreContainer: Container; let singletonWInit: { init: Mock; value: string } + let singletonWDispose: { dispose: Mock; value: string } beforeEach(() => { coreContainer = new Container({ autowire: false }); singletonWInit = { value: 'singletonWithInit', init: vi.fn() - } - + }; + singletonWDispose = { + value: 'singletonWithDispose', + dispose: vi.fn() + } }); it('Adding and getting singletons', () => { @@ -34,6 +38,7 @@ describe('CoreContainer Tests', () => { const singleton = coreContainer.get('asyncSingletonKey'); expect(singleton).toEqual({ value: 'asyncSingletonValue' }); }) + it('Registering and executing hooks - init should be called once after ready', async () => { let initCount = 0; @@ -75,34 +80,40 @@ describe('CoreContainer Tests', () => { it('wired singleton', async () => { let fn = vi.fn() - const wiredSingletonFn = (container: Container) => { + const wiredSingletonFn = (container: unknown) => { return { value: 'wiredSingletonValue', init: fn }; }; const added = coreContainer.addWiredSingleton('wiredSingletonKey', wiredSingletonFn); expect(added).toBe(true); - const wiredSingleton = coreContainer.get('wiredSingletonKey'); + + const wiredSingleton = coreContainer.get>('wiredSingletonKey')!; expect(wiredSingleton).toEqual({ value: 'wiredSingletonValue', init: fn }); - await coreContainer.ready() - await coreContainer.ready() - //@ts-ignore + + await coreContainer.ready(); + await coreContainer.ready(); + expect(wiredSingleton.init).toHaveBeenCalledOnce(); }) it('dispose', async () => { let dfn = vi.fn() + let count = 0; const wiredSingletonFn = { value: 'wiredSingletonValue', dispose: dfn }; - coreContainer.addSingleton('sk', wiredSingletonFn); - + const added = coreContainer.addSingleton('sk', wiredSingletonFn); + expect(added).toBe(true); + + await coreContainer.disposeAll(); await coreContainer.disposeAll(); expect(dfn).toHaveBeenCalledOnce() }) - it('Checking if container is ready', async () => { + it('Checking if container is ready - async', async () => { expect(coreContainer.isReady()).toBe(false); await coreContainer.ready(); expect(coreContainer.isReady()).toBe(true); - }); + }); + it('Registering and executing hooks - init should be called once after ready', async () => { coreContainer.addSingleton('singletonKeyWithInit', singletonWInit); @@ -115,9 +126,9 @@ describe('CoreContainer Tests', () => { }); it('should throw because not swapping anything', () => { - expect(() => coreContainer.swap('singletonKeyWithInit', singletonWInit)).toThrow() }) + it('should swap object with another', () => { coreContainer.addSingleton('singleton', singletonWInit) const singletonWithInit2 = { @@ -125,9 +136,21 @@ describe('CoreContainer Tests', () => { init: vi.fn() }; coreContainer.swap('singleton', singletonWithInit2) - expect(coreContainer.get('singleton')).toBe(singletonWithInit2) + expect(coreContainer.get>('singleton')).toBe(singletonWithInit2) }) + it('should swap object, calling dispose hook', () => { - coreContainer.addSingleton('singleton', singletonWInit) + coreContainer.addSingleton('singleton', singletonWDispose); + const singletonWithDispose2 = { + value: 'singletonValueWithDispose2', + dispose: vi.fn() + }; + + const swapped = coreContainer.swap('singleton', singletonWithDispose2); + + expect(singletonWDispose.dispose).toHaveBeenCalledOnce(); + expect(coreContainer.get>('singleton')).toBe(singletonWithDispose2); + expect(singletonWithDispose2.dispose).not.toHaveBeenCalledOnce(); + expect(swapped).toBe(true); }) }) From 09ce86b67efba136ba8cf8681c7857fee962b83d Mon Sep 17 00:00:00 2001 From: EvolutionX <85353424+EvolutionX-10@users.noreply.github.com> Date: Thu, 13 Jun 2024 12:18:47 +0530 Subject: [PATCH 04/13] chore: well the book was obviously wrong. permalink: http://whatthecommit.com/3f3725962c1b9d44b824736db7579209 --- packages/ioc/package.json | 2 +- packages/ioc/src/container.ts | 12 +++++++----- packages/ioc/test/index.test.ts | 12 ++++++++++-- yarn.lock | 2 +- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/ioc/package.json b/packages/ioc/package.json index c0f40f4..3cb32bf 100644 --- a/packages/ioc/package.json +++ b/packages/ioc/package.json @@ -4,7 +4,7 @@ "description": "Dependency Injection system", "main": "dist/index.js", "scripts": { - "test": "vitest --run", + "test": "vitest --watch", "tdd": "vitest", "build": "tsc" }, diff --git a/packages/ioc/src/container.ts b/packages/ioc/src/container.ts index d9b612c..18a26f5 100644 --- a/packages/ioc/src/container.ts +++ b/packages/ioc/src/container.ts @@ -82,14 +82,16 @@ export class Container { const existing = this.__singletons.get(key); if (!existing) { - // @jacoobes should we return false if no existing key? - throw Error("No existing key to swap for " + key); + return false; } // check if there's dispose hook, and call it if (hasCallableMethod(existing, 'dispose')) { - this.disposeAll().then(() => {; - this.registerHooks('dispose', swp); - }); + existing.dispose(); + // get the index of the existing singleton, now delete the dispose hook at that index + const hookIndex = this.hooks.get('dispose')!.indexOf(existing.dispose); + if (hookIndex > -1) { + this.hooks.get('dispose')!.splice(hookIndex, 1); + } } this.__singletons.set(key, swp); diff --git a/packages/ioc/test/index.test.ts b/packages/ioc/test/index.test.ts index 0a60e16..6ab8a99 100644 --- a/packages/ioc/test/index.test.ts +++ b/packages/ioc/test/index.test.ts @@ -125,8 +125,9 @@ describe('CoreContainer Tests', () => { expect(singletonWInit.init).toHaveBeenCalledOnce(); }); - it('should throw because not swapping anything', () => { - expect(() => coreContainer.swap('singletonKeyWithInit', singletonWInit)).toThrow() + it('should be false because not swapping anything', () => { + const swap = coreContainer.swap('singletonKeyWithInit', singletonWInit); + expect(swap).toBe(false); }) it('should swap object with another', () => { @@ -146,11 +147,18 @@ describe('CoreContainer Tests', () => { dispose: vi.fn() }; + const singletonWithDispose3 = { + value: 'singletonValueWithDispose3', + dispose: vi.fn() + }; + + coreContainer.addSingleton('singletonWithDispose3', singletonWithDispose3); const swapped = coreContainer.swap('singleton', singletonWithDispose2); expect(singletonWDispose.dispose).toHaveBeenCalledOnce(); expect(coreContainer.get>('singleton')).toBe(singletonWithDispose2); expect(singletonWithDispose2.dispose).not.toHaveBeenCalledOnce(); + expect(singletonWithDispose3.dispose).not.toHaveBeenCalledOnce(); expect(swapped).toBe(true); }) }) diff --git a/yarn.lock b/yarn.lock index 7d2288b..cd6a09a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2278,7 +2278,7 @@ __metadata: "typescript@patch:typescript@^5.0.0#~builtin": version: 5.4.5 - resolution: "typescript@patch:typescript@npm%3A5.4.5#~builtin::version=5.4.5&hash=14eedb" + resolution: "typescript@patch:typescript@npm%3A5.4.5#~builtin::version=5.4.5&hash=f3b441" bin: tsc: bin/tsc tsserver: bin/tsserver From 2ffad764a3917b02e207b7c5b8a34b417e0c7d75 Mon Sep 17 00:00:00 2001 From: EvolutionX <85353424+EvolutionX-10@users.noreply.github.com> Date: Thu, 13 Jun 2024 12:19:33 +0530 Subject: [PATCH 05/13] chore: whatever will be, will be 8{ permalink: http://whatthecommit.com/aa55a9efae0bb2c02bfe019beb646460 --- packages/ioc/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ioc/package.json b/packages/ioc/package.json index 3cb32bf..c0f40f4 100644 --- a/packages/ioc/package.json +++ b/packages/ioc/package.json @@ -4,7 +4,7 @@ "description": "Dependency Injection system", "main": "dist/index.js", "scripts": { - "test": "vitest --watch", + "test": "vitest --run", "tdd": "vitest", "build": "tsc" }, From 0a13cd44188a0ca86a49e07e2acffd86abb323d8 Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Thu, 13 Jun 2024 10:59:40 -0500 Subject: [PATCH 06/13] finalize hook swap, actually delete from hook list --- packages/ioc/src/container.ts | 16 ++++++----- packages/ioc/test/index.test.ts | 51 +++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/packages/ioc/src/container.ts b/packages/ioc/src/container.ts index 18a26f5..05d8c3b 100644 --- a/packages/ioc/src/container.ts +++ b/packages/ioc/src/container.ts @@ -11,13 +11,14 @@ function hasCallableMethod(obj: object, name: PropertyKey) { */ export class Container { private __singletons = new Map(); - private hooks= new Map(); + //hooks are Maps of string -> object, where object is a reference to an object in __singletons + private hooks= new Map(); private finished_init = false; constructor(options: { autowire: boolean; path?: string }) { if(options.autowire) { /* noop */ } } - addHook(name: string, callback: Function) { + addHook(name: string, callback: object) { if (!this.hooks.has(name)) { this.hooks.set(name, []); } @@ -27,7 +28,7 @@ export class Container { if(hasCallableMethod(insert, hookname)) { //@ts-ignore - this.addHook(hookname, () => insert[hookname]()) + this.addHook(hookname, insert) } } @@ -68,10 +69,11 @@ export class Container { return Object.fromEntries(this.__singletons) as T } - async executeHooks(name: string) { + private async executeHooks(name: string) { const hookFunctions = this.hooks.get(name) || []; - for (const hookFunction of hookFunctions) { - await hookFunction(); + for (const hookObject of hookFunctions) { + //@ts-ignore .registerHooks verifies the hookObject hasCallableMethod + await hookObject[name](); } } @@ -88,7 +90,7 @@ export class Container { if (hasCallableMethod(existing, 'dispose')) { existing.dispose(); // get the index of the existing singleton, now delete the dispose hook at that index - const hookIndex = this.hooks.get('dispose')!.indexOf(existing.dispose); + const hookIndex = this.hooks.get('dispose')!.indexOf(existing); if (hookIndex > -1) { this.hooks.get('dispose')!.splice(hookIndex, 1); } diff --git a/packages/ioc/test/index.test.ts b/packages/ioc/test/index.test.ts index 6ab8a99..4cc8f1b 100644 --- a/packages/ioc/test/index.test.ts +++ b/packages/ioc/test/index.test.ts @@ -1,23 +1,30 @@ import { Container } from '../src/container'; -import { describe, it, expect, beforeEach, vi, Mock } from 'vitest'; +import { describe, it, expect, beforeEach, vi, Mock, afterEach } from 'vitest'; +class SingletonCheese { + dispose() { + return this.value + } + constructor(public value: string){} +} describe('CoreContainer Tests', () => { let coreContainer: Container; let singletonWInit: { init: Mock; value: string } - let singletonWDispose: { dispose: Mock; value: string } + let singletonWDispose: SingletonCheese beforeEach(() => { coreContainer = new Container({ autowire: false }); singletonWInit = { - value: 'singletonWithInit', - init: vi.fn() + value: 'singletonWithInit', + init: vi.fn() }; - singletonWDispose = { - value: 'singletonWithDispose', - dispose: vi.fn() - } + singletonWDispose = new SingletonCheese('singletonWithDispose') }); + afterEach(() => { + vi.clearAllMocks() + }) + it('Adding and getting singletons', () => { coreContainer.addSingleton('singletonKey', { value: 'singletonValue' }); const singleton = coreContainer.get('singletonKey'); @@ -125,11 +132,19 @@ describe('CoreContainer Tests', () => { expect(singletonWInit.init).toHaveBeenCalledOnce(); }); - it('should be false because not swapping anything', () => { + it('should return false because not swapping anything', () => { const swap = coreContainer.swap('singletonKeyWithInit', singletonWInit); expect(swap).toBe(false); }) - + it('should return true because not swapping anything', () => { + coreContainer.addSingleton('singletonKeyWithInit', singletonWInit); + const singletonWithInit2 = { + value: 'singletonValueWithInit2', + init: vi.fn() + }; + const swap = coreContainer.swap('singletonKeyWithInit', singletonWithInit2); + expect(swap).toBe(true); + }) it('should swap object with another', () => { coreContainer.addSingleton('singleton', singletonWInit) const singletonWithInit2 = { @@ -153,12 +168,24 @@ describe('CoreContainer Tests', () => { }; coreContainer.addSingleton('singletonWithDispose3', singletonWithDispose3); - const swapped = coreContainer.swap('singleton', singletonWithDispose2); + vi.spyOn(singletonWDispose, 'dispose') + coreContainer.swap('singleton', singletonWithDispose2); expect(singletonWDispose.dispose).toHaveBeenCalledOnce(); expect(coreContainer.get>('singleton')).toBe(singletonWithDispose2); expect(singletonWithDispose2.dispose).not.toHaveBeenCalledOnce(); expect(singletonWithDispose3.dispose).not.toHaveBeenCalledOnce(); - expect(swapped).toBe(true); + }) + it('should swap object, maintaining reference to `this`', () => { + coreContainer.addSingleton('singleton', singletonWDispose); + const singletonWithDispose2 = { + value: 'singletonValueWithDispose2', + dispose: vi.fn() + }; + const spiedDispose = vi.spyOn(singletonWDispose, 'dispose') + const swapped = coreContainer.swap('singleton', singletonWithDispose2); + expect(spiedDispose.mock.results[0].value).toEqual('singletonWithDispose'); + expect(coreContainer.get>('singleton')).toBe(singletonWithDispose2); + expect(singletonWithDispose2.dispose).not.toHaveBeenCalledOnce(); }) }) From dfe587e61bea0e6051388545d3f08eee3a6cdce1 Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Thu, 13 Jun 2024 11:02:14 -0500 Subject: [PATCH 07/13] finalize hook swap, actually delete from hook list --- packages/ioc/src/container.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/ioc/src/container.ts b/packages/ioc/src/container.ts index 05d8c3b..08f5a39 100644 --- a/packages/ioc/src/container.ts +++ b/packages/ioc/src/container.ts @@ -88,8 +88,12 @@ export class Container { } // check if there's dispose hook, and call it if (hasCallableMethod(existing, 'dispose')) { + //this should technically be awaited to ensure synchronicity of swap + // but i dont want to ruin the function signature of swap. existing.dispose(); // get the index of the existing singleton, now delete the dispose hook at that index + // .indexOf is safe because we only store singletons, and it should be a reference to + // the original object in this.__singletons const hookIndex = this.hooks.get('dispose')!.indexOf(existing); if (hookIndex > -1) { this.hooks.get('dispose')!.splice(hookIndex, 1); From 813857a1810fbdd85d39ee0ce5f920ce26aa16eb Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Thu, 13 Jun 2024 11:38:08 -0500 Subject: [PATCH 08/13] Update npm-publish.yml --- .github/workflows/npm-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index ccc7b82..31fc62d 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -29,11 +29,11 @@ jobs: - run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc - run: yarn set version classic working-directory: ./packages/${{ github.event.inputs.package }} + - run: yarn install --immutable - run: yarn build working-directory: ./packages/${{ github.event.inputs.package }} - run: yarn test working-directory: ./packages/${{ github.event.inputs.package }} - - run: yarn install --immutable - run: yarn publish env: NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} From 3f883d50e6233af12ec719b6c8135ba32ab7b635 Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Thu, 13 Jun 2024 11:48:36 -0500 Subject: [PATCH 09/13] add declaration:true --- packages/ioc/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ioc/tsconfig.json b/packages/ioc/tsconfig.json index b165ff8..5f9427b 100644 --- a/packages/ioc/tsconfig.json +++ b/packages/ioc/tsconfig.json @@ -49,7 +49,7 @@ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ // "declarationMap": true, /* Create sourcemaps for d.ts files. */ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ From 3b11dc574eae19bfea15c63ef5f48735b0d22487 Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Thu, 13 Jun 2024 11:55:11 -0500 Subject: [PATCH 10/13] Update package.json --- packages/ioc/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ioc/package.json b/packages/ioc/package.json index c0f40f4..f11e8b0 100644 --- a/packages/ioc/package.json +++ b/packages/ioc/package.json @@ -1,6 +1,6 @@ { "name": "@sern/ioc", - "version": "1.0.0", + "version": "1.0.1", "description": "Dependency Injection system", "main": "dist/index.js", "scripts": { From bc11d9922f3d2cab35fab3ad3d8fb4745f282d31 Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Thu, 13 Jun 2024 12:18:36 -0500 Subject: [PATCH 11/13] fix tsconfig for ioc --- .gitignore | 1 + packages/ioc/package.json | 2 +- packages/ioc/tsconfig.json | 7 ++++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 2d53da6..782f930 100644 --- a/.gitignore +++ b/.gitignore @@ -10,5 +10,6 @@ #.pnp.* node_modules/**/* packages/ioc/node_modules/* +packages/ioc/dist packages/poster/dts/discord.d.ts packages/**/node_modules diff --git a/packages/ioc/package.json b/packages/ioc/package.json index f11e8b0..c85d64b 100644 --- a/packages/ioc/package.json +++ b/packages/ioc/package.json @@ -1,6 +1,6 @@ { "name": "@sern/ioc", - "version": "1.0.1", + "version": "1.0.2", "description": "Dependency Injection system", "main": "dist/index.js", "scripts": { diff --git a/packages/ioc/tsconfig.json b/packages/ioc/tsconfig.json index 5f9427b..1208ce0 100644 --- a/packages/ioc/tsconfig.json +++ b/packages/ioc/tsconfig.json @@ -26,7 +26,7 @@ /* Modules */ "module": "ESNext", /* Specify what module code is generated. */ - // "rootDir": "./", /* Specify the root folder within your source files. */ + "rootDir": "./src", /* Specify the root folder within your source files. */ "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ @@ -52,7 +52,7 @@ "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ // "declarationMap": true, /* Create sourcemaps for d.ts files. */ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ "outDir": "./dist", /* Specify an output folder for all emitted files. */ @@ -105,5 +105,6 @@ /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } + }, + "include": ["./src", "./src/**/*.d.ts"] } From 7b69eebe9e77c2ef2295f1e0b1c898bb7916c0c1 Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Thu, 13 Jun 2024 13:08:54 -0500 Subject: [PATCH 12/13] rm redundant globalapis --- packages/ioc/package.json | 13 +++- packages/ioc/src/container.ts | 107 --------------------------------- packages/ioc/src/global.ts | 17 ++---- packages/ioc/src/index.ts | 109 +++++++++++++++++++++++++++++++++- 4 files changed, 125 insertions(+), 121 deletions(-) delete mode 100644 packages/ioc/src/container.ts diff --git a/packages/ioc/package.json b/packages/ioc/package.json index c85d64b..9d63bc6 100644 --- a/packages/ioc/package.json +++ b/packages/ioc/package.json @@ -1,8 +1,19 @@ { "name": "@sern/ioc", - "version": "1.0.2", + "version": "1.0.3", "description": "Dependency Injection system", "main": "dist/index.js", + "module": "./dist/index.js", + "exports": { + "." : { + "import": "./dist/index.js", + "require": "./dist/index.js" + }, + "./global": { + "import": "./dist/global.js", + "require": "./dist/global.js" + } + }, "scripts": { "test": "vitest --run", "tdd": "vitest", diff --git a/packages/ioc/src/container.ts b/packages/ioc/src/container.ts deleted file mode 100644 index 08f5a39..0000000 --- a/packages/ioc/src/container.ts +++ /dev/null @@ -1,107 +0,0 @@ -/** - * A semi-generic container that provides error handling, emitter, and module store. - * For the handler to operate correctly, The only user provided dependency needs to be @sern/client - */ -function hasCallableMethod(obj: object, name: PropertyKey) { - //@ts-ignore - return typeof obj[name] == 'function'; -} -/** - * A Depedency injection container capable of adding singletons, firing hooks, and managing IOC within an application - */ -export class Container { - private __singletons = new Map(); - //hooks are Maps of string -> object, where object is a reference to an object in __singletons - private hooks= new Map(); - private finished_init = false; - constructor(options: { autowire: boolean; path?: string }) { - if(options.autowire) { /* noop */ } - } - - addHook(name: string, callback: object) { - if (!this.hooks.has(name)) { - this.hooks.set(name, []); - } - this.hooks.get(name)!.push(callback); - } - private registerHooks(hookname: string, insert: object) { - - if(hasCallableMethod(insert, hookname)) { - //@ts-ignore - this.addHook(hookname, insert) - } - } - - addSingleton(key: string, insert: object) { - if(typeof insert !== 'object') { - throw Error("Inserted object must be an object"); - } - if(!this.__singletons.has(key)) { - this.registerHooks('init', insert) - this.registerHooks('dispose', insert) - this.__singletons.set(key, insert); - return true; - } - return false; - } - - addWiredSingleton(key: string, fn: (c: Record) => object) { - const insert = fn(this.deps()); - return this.addSingleton(key, insert); - } - - async disposeAll() { - await this.executeHooks('dispose'); - this.hooks.delete('dispose'); - } - - isReady() { return this.finished_init; } - hasKey(key: string) { return this.__singletons.has(key); } - get(key: PropertyKey) : T|undefined { return this.__singletons.get(key); } - - async ready() { - await this.executeHooks('init'); - this.hooks.delete('init'); - this.finished_init = true; - } - - deps>(): T { - return Object.fromEntries(this.__singletons) as T - } - - private async executeHooks(name: string) { - const hookFunctions = this.hooks.get(name) || []; - for (const hookObject of hookFunctions) { - //@ts-ignore .registerHooks verifies the hookObject hasCallableMethod - await hookObject[name](); - } - } - - swap(key: string, swp: object) { - if (typeof swp !== 'object') { - throw Error("Inserted object must be an object"); - } - - const existing = this.__singletons.get(key); - if (!existing) { - return false; - } - // check if there's dispose hook, and call it - if (hasCallableMethod(existing, 'dispose')) { - //this should technically be awaited to ensure synchronicity of swap - // but i dont want to ruin the function signature of swap. - existing.dispose(); - // get the index of the existing singleton, now delete the dispose hook at that index - // .indexOf is safe because we only store singletons, and it should be a reference to - // the original object in this.__singletons - const hookIndex = this.hooks.get('dispose')!.indexOf(existing); - if (hookIndex > -1) { - this.hooks.get('dispose')!.splice(hookIndex, 1); - } - } - - this.__singletons.set(key, swp); - this.registerHooks('init', swp); - return true; - } -} diff --git a/packages/ioc/src/global.ts b/packages/ioc/src/global.ts index 1f3d6d1..c140d84 100644 --- a/packages/ioc/src/global.ts +++ b/packages/ioc/src/global.ts @@ -1,4 +1,4 @@ -import { Container } from './container'; +import { Container } from './index'; //SIDE EFFECT: GLOBAL DI let containerSubject: Container; @@ -14,23 +14,18 @@ export async function __swap_container(c: Container) { containerSubject = c; } -/** - * Don't use this unless you know what you're doing. Destroys old containerSubject if it exists and disposes everything - * then it will swap - */ -export function __add_container(key: string, v: object) { - containerSubject.addSingleton(key, v); -} /** * Initiates the global api. * Once this is finished, the Service api and the other global api is available */ -export function __init_container(options: { +export async function __init_container(options: { autowire: boolean; path?: string | undefined; }) { containerSubject = new Container(options); + await containerSubject.ready() + return containerSubject } /** @@ -49,7 +44,7 @@ export function useContainerRaw() { /** * The Service api, retrieve from the globally init'ed container * Note: this method only works AFTER your container has been initiated - * @since 3.0.0 + * @since 1.0.0 * @example * ```ts * const client = Service('@sern/client'); @@ -65,7 +60,7 @@ export function Service(key: PropertyKey) { return dep; } /** - * @since 3.0.0 + * @since 1.0.0 * The plural version of {@link Service} * @returns array of dependencies, in the same order of keys provided */ diff --git a/packages/ioc/src/index.ts b/packages/ioc/src/index.ts index 920754c..08f5a39 100644 --- a/packages/ioc/src/index.ts +++ b/packages/ioc/src/index.ts @@ -1,2 +1,107 @@ -export { Service, Services, __init_container, __add_container } from './global'; -export { Container } from './container' +/** + * A semi-generic container that provides error handling, emitter, and module store. + * For the handler to operate correctly, The only user provided dependency needs to be @sern/client + */ +function hasCallableMethod(obj: object, name: PropertyKey) { + //@ts-ignore + return typeof obj[name] == 'function'; +} +/** + * A Depedency injection container capable of adding singletons, firing hooks, and managing IOC within an application + */ +export class Container { + private __singletons = new Map(); + //hooks are Maps of string -> object, where object is a reference to an object in __singletons + private hooks= new Map(); + private finished_init = false; + constructor(options: { autowire: boolean; path?: string }) { + if(options.autowire) { /* noop */ } + } + + addHook(name: string, callback: object) { + if (!this.hooks.has(name)) { + this.hooks.set(name, []); + } + this.hooks.get(name)!.push(callback); + } + private registerHooks(hookname: string, insert: object) { + + if(hasCallableMethod(insert, hookname)) { + //@ts-ignore + this.addHook(hookname, insert) + } + } + + addSingleton(key: string, insert: object) { + if(typeof insert !== 'object') { + throw Error("Inserted object must be an object"); + } + if(!this.__singletons.has(key)) { + this.registerHooks('init', insert) + this.registerHooks('dispose', insert) + this.__singletons.set(key, insert); + return true; + } + return false; + } + + addWiredSingleton(key: string, fn: (c: Record) => object) { + const insert = fn(this.deps()); + return this.addSingleton(key, insert); + } + + async disposeAll() { + await this.executeHooks('dispose'); + this.hooks.delete('dispose'); + } + + isReady() { return this.finished_init; } + hasKey(key: string) { return this.__singletons.has(key); } + get(key: PropertyKey) : T|undefined { return this.__singletons.get(key); } + + async ready() { + await this.executeHooks('init'); + this.hooks.delete('init'); + this.finished_init = true; + } + + deps>(): T { + return Object.fromEntries(this.__singletons) as T + } + + private async executeHooks(name: string) { + const hookFunctions = this.hooks.get(name) || []; + for (const hookObject of hookFunctions) { + //@ts-ignore .registerHooks verifies the hookObject hasCallableMethod + await hookObject[name](); + } + } + + swap(key: string, swp: object) { + if (typeof swp !== 'object') { + throw Error("Inserted object must be an object"); + } + + const existing = this.__singletons.get(key); + if (!existing) { + return false; + } + // check if there's dispose hook, and call it + if (hasCallableMethod(existing, 'dispose')) { + //this should technically be awaited to ensure synchronicity of swap + // but i dont want to ruin the function signature of swap. + existing.dispose(); + // get the index of the existing singleton, now delete the dispose hook at that index + // .indexOf is safe because we only store singletons, and it should be a reference to + // the original object in this.__singletons + const hookIndex = this.hooks.get('dispose')!.indexOf(existing); + if (hookIndex > -1) { + this.hooks.get('dispose')!.splice(hookIndex, 1); + } + } + + this.__singletons.set(key, swp); + this.registerHooks('init', swp); + return true; + } +} From da887deea6a43df2816a8814b2f5839699971e80 Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Thu, 13 Jun 2024 13:11:32 -0500 Subject: [PATCH 13/13] opops --- packages/ioc/test/index.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/ioc/test/index.test.ts b/packages/ioc/test/index.test.ts index 4cc8f1b..4921519 100644 --- a/packages/ioc/test/index.test.ts +++ b/packages/ioc/test/index.test.ts @@ -1,5 +1,4 @@ - -import { Container } from '../src/container'; +import { Container } from '../src'; import { describe, it, expect, beforeEach, vi, Mock, afterEach } from 'vitest'; class SingletonCheese {