@joist/di
Version:
Dependency Injection for Vanilla JS classes
75 lines • 2.63 kB
JavaScript
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