mirror of
https://github.com/sern-handler/tools
synced 2026-06-06 01:16:59 +00:00
finalize hook swap, actually delete from hook list
This commit is contained in:
@@ -11,13 +11,14 @@ function hasCallableMethod(obj: object, name: PropertyKey) {
|
||||
*/
|
||||
export class Container {
|
||||
private __singletons = new Map<PropertyKey, any>();
|
||||
private hooks= new Map<string, Function[]>();
|
||||
//hooks are Maps of string -> object, where object is a reference to an object in __singletons
|
||||
private hooks= new Map<string, object[]>();
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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<any, any>; value: string }
|
||||
let singletonWDispose: { dispose: Mock<any, any>; 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<Record<string, unknown>>('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<Record<string, unknown>>('singleton')).toBe(singletonWithDispose2);
|
||||
expect(singletonWithDispose2.dispose).not.toHaveBeenCalledOnce();
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user