UNPKG

@joist/di

Version:

Dependency Injection for Vanilla JS classes

75 lines 2.63 kB
import { callLifecycle } from "./lifecycle.js"; import { readInjector, readMetadata } from "./metadata.js"; import { StaticToken, } from "./provider.js"; export const INJECTOR = Symbol("JOIST_INJECTOR"); export class ProviderMap extends Map { } export class Injector { #instances = new WeakMap(); name; parent; providers; constructor(opts) { this.parent = opts?.parent; this.providers = new ProviderMap(opts?.providers); } injectAll(token, collection = []) { collection.push(this.inject(token, { skipParent: true })); if (this.parent) { return this.parent.injectAll(token, collection); } return collection; } inject(token, opts) { if (this.#instances.has(token)) { const instance = this.#instances.get(token); const metadata = readMetadata(token); const injector = readInjector(instance); if (metadata) { callLifecycle(instance, injector ?? this, metadata.onInjected); } return instance; } const provider = this.providers.get(token); if (provider) { if ("use" in provider) { return this.#createAndCache(token, () => new provider.use()); } if ("factory" in provider) { return this.#createAndCache(token, provider.factory); } throw new Error(`Provider for ${token.name} found but is missing either 'use' or 'factory'`); } if (this.parent && !opts?.skipParent) { return this.parent.inject(token); } if (token instanceof StaticToken) { if (!token.factory) { throw new Error(`Provider not found for "${token.name}"`); } return this.#createAndCache(token, token.factory); } return this.#createAndCache(token, () => new token()); } clear() { this.#instances = new WeakMap(); } #createAndCache(token, factory) { const instance = factory(this); this.#instances.set(token, instance); const injector = readInjector(instance); if (!injector) { return instance; } if (injector !== this) { injector.parent = this; } const metadata = readMetadata(token); if (metadata) { callLifecycle(instance ?? this, injector, metadata.onCreated); callLifecycle(instance ?? this, injector, metadata.onInjected); } return instance; } } //# sourceMappingURL=injector.js.map