Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DI] Implement a plugin registry in ts-inject #12

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

78 changes: 78 additions & 0 deletions src/PluginRegistry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* A type representing a function that observes a plugin.
*
* @template PluginInterface - The interface that the plugin implements.
* @param plugin - The plugin instance that is being observed.
*/
export type PluginObserver<PluginInterface> = (plugin: PluginInterface) => void;

/**
* A registry for managing plugins and notifying observers about new plugins.
*
* This class allows you to register plugins and observe when new plugins are added.
* It maintains a list of plugins and notifies all registered observers whenever a new plugin is added.
*
* @template PluginInterface - The interface that all plugins must implement.
*
* @example
* // Define a plugin interface
* interface MyPlugin {
* doSomething(): void;
* }
*
* // Create a plugin registry for MyPlugin
* const registry = new PluginRegistry<MyPlugin>();
*
* // Define a plugin that implements MyPlugin
* const plugin: MyPlugin = {
* doSomething() {
* console.log('Plugin is doing something');
* }
* };
*
* // Define an observer
* const observer: PluginObserver<MyPlugin> = (plugin) => {
* console.log('New plugin registered:', plugin);
* };
*
* // Register the observer
* registry.observe(observer);
*
* // Register the plugin
* registry.register(plugin);
* // Output:
* // New plugin registered: { doSomething: [Function: doSomething] }
* // Plugin is doing something
*/
export class PluginRegistry<PluginInterface> {
private plugins: PluginInterface[] = [];
private observers: PluginObserver<PluginInterface>[] = [];

/**
* Registers a new plugin and notifies all observers about the new plugin.
*
* @param plugin - The plugin to be registered, which implements the PluginInterface.
*/
register(plugin: PluginInterface): void {
this.plugins.push(plugin);
this.observers.forEach((observer) => observer(plugin));
}

/**
* Registers an observer to the plugin registry.
*
* @param observer - The observer that will be called when a new plugin is registered.
*/
observe(observer: PluginObserver<PluginInterface>): void {
this.observers.push(observer);
}

/**
* Retrieves the list of registered plugins.
*
* @returns {PluginInterface[]} An array of plugins registered with the registry.
*/
getPlugins(): PluginInterface[] {
return this.plugins;
}
}
33 changes: 33 additions & 0 deletions src/__tests__/PluginRegistry.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { PluginRegistry } from "../PluginRegistry";

interface MockPluginInterface {
mockMethod(): void;
}

describe("PluginRegistry", () => {
let registry: PluginRegistry<MockPluginInterface>;
let plugin: MockPluginInterface;
let observer: jest.Mock;

beforeEach(() => {
registry = new PluginRegistry();
plugin = {
mockMethod: jest.fn(),
};
observer = jest.fn();
});

test("should register a plugin and notify observers", () => {
registry.observe(observer);
registry.register(plugin);

expect(observer).toHaveBeenCalledWith(plugin);
expect(observer).toHaveBeenCalledTimes(1);
});

test("should return the list of registered plugins", () => {
registry.register(plugin);

expect(registry.getPlugins()).toEqual([plugin]);
});
});