@js-injection/service-provider 1.0.0-alpha.1 → 1.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/legacy.cjs +1 -1
- package/dist/legacy.cjs.map +1 -1
- package/dist/types/src/service-collection.d.ts +11 -11
- package/dist/types/src/types.d.ts +2 -2
- package/dist/types/src/types.d.ts.map +1 -1
- package/docs/CHEATSHEET.md +146 -109
- package/package.json +11 -4
- package/src/service-collection.ts +14 -14
- package/src/types.ts +2 -2
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var u=class extends Error{constructor(e){super(`Circular dependency detected: ${e}`),this.name="CircularDependencyError"}},p=class extends Error{constructor(e){super(`Service not registered for identifier: ${e}`),this.name="ServiceNotFoundError"}},l=class extends Error{constructor(e){super(e),this.name="RegistrationError"}},h=class extends Error{constructor(){super("ServiceProvider has been disposed and cannot resolve services."),this.name="ServiceProviderDisposedError"}},f=class extends Error{constructor(e){super(`Service "${e}" requires asynchronous disposal but a synchronous dispose was called. Please use await disposeAsync() instead.`),this.name="AsyncDisposalError"}};var v=new WeakMap;function c(y){let e=v.get(y);return e||(e=Symbol(y.name||"AnonymousClass"),v.set(y,e)),e}var m=class y{constructor(e,t,s,n=!1){this.name=e;this.definitions=t;this.parent=s;this.isAsyncScope=n}instances=new Map;resolving=new Set;path=[];disposed=!1;createScope(e="scope"){let t=this.parent||this;return new y(e,this.definitions,t,!1)}createAsyncScope(e="async-scope"){let t=this.parent||this;return new y(e,this.definitions,t,!0)}getService(e){if(this.disposed)throw new h;let t=this.getKey(e);if(this.parent&&this.definitions[t]?.lifetime==="singleton")return this.parent.getService(t);let s=this.definitions[t];if(!s){let i=typeof e=="string"||typeof e=="symbol"?String(e):e.name||String(e);throw new p(i)}let n=s.uid;if(this.instances.has(n))return this.instances.get(n);if(this.resolving.has(n)){let i=this.path.map(r=>typeof r=="symbol"?r.description||String(r):r).concat(typeof t=="symbol"?t.description||String(t):t).join(" -> ");throw new u(i)}this.resolving.add(n),this.path.push(t);try{return s.kind==="value"?this.resolveValue(n,s.value):Array.isArray(s.type)?this.resolveArray(n,s.type):s.kind==="function"&&s.func?this.resolveFunc(n,s.func,s.params):s.factory?this.resolveFactory(n,s.factory):this.resolveClass(n,s.type,s.params)}finally{this.resolving.delete(n),this.path.pop()}}dispose(){if(this.disposed)return;if(this.isAsyncScope)throw new f(this.name);this.disposed=!0;let e=Array.from(this.instances.entries()).reverse();for(let[t,s]of e)if(s&&typeof s.dispose=="function"){if(s.dispose()instanceof Promise)throw new f(typeof t=="symbol"&&t.description||String(t))}else if(s&&typeof s.disposeAsync=="function")throw new f(typeof t=="symbol"&&t.description||String(t));this.instances.clear()}async disposeAsync(){if(this.disposed)return;this.disposed=!0;let e=Array.from(this.instances.values()).reverse();for(let t of e)if(t&&typeof t.disposeAsync=="function")await t.disposeAsync();else if(t&&typeof t.dispose=="function"){let s=t.dispose();s instanceof Promise&&await s}this.instances.clear()}resolveValue(e,t){return this.instances.set(e,t),t}resolveArray(e,t){let s=t.map(n=>this.getService(n));return this.instances.set(e,s),s}resolveFactory(e,t){let s=this.createContainerProxy(),n=t(s,this);return this.instances.set(e,n),n}resolveFunc(e,t,s){let i=(s||[]).map(o=>{let a=this.tryGetKey(o);return a?this.getService(a):o}),r=t(...i);return this.instances.set(e,r),r}resolveClass(e,t,s){let i=(s||[]).map(o=>{let a=this.tryGetKey(o);return a?this.getService(a):o}),r=new t(...i);return this.instances.set(e,r),r}createContainerProxy(){return new Proxy({},{get:(e,t)=>{if(!(typeof t!="string"&&typeof t!="symbol"))return this.getService(t)}})}getKey(e){if(typeof e=="string"||typeof e=="symbol")return e;let t=this.tryGetKey(e);if(t)return t;let s=Array.isArray(e)?`[${e.map(n=>n.name).join(", ")}]`:e.name||String(e);throw new p(s)}tryGetKey(e){if(typeof e=="string"||typeof e=="symbol"){if(e in this.definitions)return e;if(typeof e=="string"){let t=Reflect.ownKeys(this.definitions).find(s=>{let n=this.definitions[s];return n.kind==="service"&&!Array.isArray(n.type)&&n.type?.name===e});if(t)return t}return}if(typeof e=="function"||Array.isArray(e)){let t=c(e);if(t in this.definitions)return t;let s=Reflect.ownKeys(this.definitions).find(n=>{let i=this.definitions[n];return i.kind==="service"&&i.type===e});if(s)return s}}};var K=class{definitions={};typeMap;constructor(){this.typeMap={}}addSingletonFactory(e,t){let s,n,i=!1;if(typeof e=="string"||typeof e=="symbol")s=e,n=this.typeMap[s],i=!0;else{let a=this.resolveKeyAndType(e);s=a.key,n=a.type}let r=i?s:c(n),o={kind:"service",lifetime:"singleton",uid:r,type:n,factory:t};return this.definitions[s]=o,s!==r&&(this.definitions[r]=o),this}addServiceProvider(e){return this.addSingletonFactory(e,(t,s)=>s)}addScopedFactory(e,t){let s,n,i=!1;if(typeof e=="string"||typeof e=="symbol")s=e,n=this.typeMap[s],i=!0;else{let a=this.resolveKeyAndType(e);s=a.key,n=a.type}let r=i?s:c(n),o={kind:"service",lifetime:"scoped",uid:r,type:n,factory:t};return this.definitions[s]=o,s!==r&&(this.definitions[r]=o),this}addSingletonClass(e,...t){let{key:s,type:n}=this.resolveKeyAndType(e),i=c(n),r={kind:"service",lifetime:"singleton",uid:i,type:n,params:t};return this.definitions[s]=r,this.definitions[i]=r,this}addScopedClass(e,...t){let{key:s,type:n}=this.resolveKeyAndType(e),i=c(n),r={kind:"service",lifetime:"scoped",uid:i,type:n,params:t};return this.definitions[s]=r,this.definitions[i]=r,this}addSingletonGroup(e,...t){let s={kind:"service",lifetime:"singleton",uid:e,type:t};this.typeMap[e]=t,this.definitions[e]=s;let n=t;for(let i of n){if(Reflect.ownKeys(this.typeMap).find(g=>this.typeMap[g]===i))continue;let o=i.name;if(!o)throw new l(`Class in group "${String(e)}" is missing a name and cannot be auto-registered.`);let a=c(i),d={kind:"service",lifetime:"singleton",uid:a,type:i,params:[]};this.typeMap[o]=i,this.definitions[o]=d,this.definitions[a]=d}return this}addScopedGroup(e,...t){let s={kind:"service",lifetime:"scoped",uid:e,type:t};this.typeMap[e]=t,this.definitions[e]=s;let n=t;for(let i of n){if(Reflect.ownKeys(this.typeMap).find(g=>this.typeMap[g]===i))continue;let o=i.name;if(!o)throw new l(`Class in group "${String(e)}" is missing a name and cannot be auto-registered.`);let a=c(i),d={kind:"service",lifetime:"scoped",uid:a,type:i,params:[]};this.typeMap[o]=i,this.definitions[o]=d,this.definitions[a]=d}return this}addSingletonFunc(e,t,...s){return this.definitions[e]={kind:"function",lifetime:"singleton",uid:e,func:t,params:s},this}addScopedFunc(e,t,...s){return this.definitions[e]={kind:"function",lifetime:"scoped",uid:e,func:t,params:s},this}addSingletonValue(e,t){return this.definitions[e]={kind:"value",lifetime:"singleton",uid:e,value:t},this}addScopedValue(e,t){return this.definitions[e]={kind:"value",lifetime:"scoped",uid:e,value:t},this}resolveKeyAndType(e){let t,s=Reflect.ownKeys(this.typeMap).find(n=>this.typeMap[n]===e);return s?t=s:(t=e.name||c(e),this.typeMap[t]=e),{key:t,type:e}}build(e="root"){for(let t of Reflect.ownKeys(this.definitions)){let s=this.definitions[t];if(!(s.kind!=="service"||!Array.isArray(s.type)))for(let n of s.type){let i=n.name,r=this.definitions[i];if(r&&r.params&&r.params.length===0&&n.length>0)throw new l(`Class "${i}" in group "${String(t)}" requires constructor arguments and must be registered independently using addSingletonClass or addScopedClass.`)}}return new m(e,this.definitions)}};export{f as AsyncDisposalError,u as CircularDependencyError,l as RegistrationError,K as ServiceCollection,p as ServiceNotFoundError,m as ServiceProvider,h as ServiceProviderDisposedError};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/errors.ts", "../src/registry.ts", "../src/service-provider.ts", "../src/service-collection.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Thrown when a circular dependency is detected.\n */\nexport class CircularDependencyError extends Error {\n constructor(path: string) {\n super(`Circular dependency detected: ${path}`);\n this.name = 'CircularDependencyError';\n }\n}\n\n/**\n * Thrown when a service cannot be resolved.\n */\nexport class ServiceNotFoundError extends Error {\n constructor(identifier: string) {\n super(`Service not registered for identifier: ${identifier}`);\n this.name = 'ServiceNotFoundError';\n }\n}\n\n/**\n * Thrown when a registration is invalid.\n */\nexport class RegistrationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'RegistrationError';\n }\n}\n\n/**\n * Thrown when a service provider has been disposed.\n */\nexport class ServiceProviderDisposedError extends Error {\n constructor() {\n super('ServiceProvider has been disposed and cannot resolve services.');\n this.name = 'ServiceProviderDisposedError';\n }\n}\n\n/**\n * Thrown when a synchronous dispose is called on a scope containing services that require asynchronous disposal.\n */\nexport class AsyncDisposalError extends Error {\n constructor(serviceKey: string) {\n super(`Service \"${serviceKey}\" requires asynchronous disposal but a synchronous dispose was called. Please use await disposeAsync() instead.`);\n this.name = 'AsyncDisposalError';\n }\n}\n", "import type { Class } from './types.js';\r\n\r\nconst classKeyRegistry = new WeakMap<Class, symbol>();\r\n\r\n/**\r\n * Resolves a stable Symbol for a given class constructor.\r\n * This is used to ensure that DI resolution remains stable even after minification.\r\n * @param type The class constructor.\r\n */\r\nexport function getStableKey(type: Class): symbol {\r\n let key = classKeyRegistry.get(type);\r\n if (!key) {\r\n key = Symbol(type.name || 'AnonymousClass');\r\n classKeyRegistry.set(type, key);\r\n }\r\n return key;\r\n}\r\n", "import {\n AsyncDisposalError,\n CircularDependencyError,\n ServiceNotFoundError,\n ServiceProviderDisposedError,\n} from './errors.js';\nimport { getStableKey } from './registry.js';\nimport type {\n Class,\n ConcreteClass,\n ImplementationFactory,\n IServiceProvider,\n MapToInstance,\n ResolvedTypeMap,\n ServiceDefinitionMap,\n TypeMap,\n} from './types.js';\n\nexport class ServiceProvider<T extends TypeMap> implements IServiceProvider<T> {\n private instances = new Map<string | symbol, any>();\n private resolving = new Set<string | symbol>();\n private path: (string | symbol)[] = [];\n private disposed = false;\n\n /**\n * @param name The name of the service provider.\n * @param definitions The service definitions map.\n * @param parent The parent service provider, if any.\n * @param isAsyncScope Whether this is an asynchronous scope.\n */\n constructor(\n public readonly name: string,\n private definitions: ServiceDefinitionMap,\n private parent?: ServiceProvider<T>,\n private readonly isAsyncScope: boolean = false\n ) { }\n\n /**\n * Creates a new scoped ServiceProvider.\n * @param name The name of the scope.\n * @example\n * const scope = di.createScope('request-scope');\n */\n createScope(name: string = 'scope'): IServiceProvider<T> {\n const root = this.parent || this;\n return new ServiceProvider<T>(name, this.definitions, root, false);\n }\n\n /**\n * Creates a new scoped ServiceProvider that supports asynchronous disposal.\n * @param name The name of the scope.\n * @example\n * const scope = di.createAsyncScope('worker-scope');\n */\n createAsyncScope(name: string = 'async-scope'): IServiceProvider<T> {\n const root = this.parent || this;\n return new ServiceProvider<T>(name, this.definitions, root, true);\n }\n\n /**\n * Resolves a service by its key.\n * @param key The key to resolve.\n * @example\n * const logger = di.getService('Logger');\n */\n getService<K extends keyof T & (string | symbol)>(key: K): MapToInstance<T[K]>;\n\n /**\n * Resolves a service by its Class type.\n * @param type The class type to resolve.\n * @example\n * const logger = di.getService(Logger);\n */\n getService<C extends Class>(type: C): InstanceType<C>;\n\n getService<K extends keyof T & (string | symbol)>(keyOrType: K | T[K]): MapToInstance<T[K]> {\n if (this.disposed) {\n throw new ServiceProviderDisposedError();\n }\n\n const key = this.getKey(keyOrType);\n\n if (this.parent && this.definitions[key]?.lifetime === 'singleton') {\n return this.parent.getService(key as any);\n }\n\n const item = this.definitions[key];\n if (!item) {\n const name = (typeof keyOrType === 'string' || typeof keyOrType === 'symbol')\n ? String(keyOrType)\n : (keyOrType as any).name || String(keyOrType);\n throw new ServiceNotFoundError(name);\n }\n\n const uid = item.uid;\n\n if (this.instances.has(uid)) {\n return this.instances.get(uid);\n }\n\n if (this.resolving.has(uid)) {\n const pathStr = this.path.map(k => (typeof k === 'symbol' ? k.description || String(k) : k)).concat(typeof key === 'symbol' ? key.description || String(key) : key).join(' -> ');\n throw new CircularDependencyError(pathStr);\n }\n\n this.resolving.add(uid);\n this.path.push(key);\n\n try {\n if (item.kind === 'value') return this.resolveValue(uid, item.value);\n\n if (Array.isArray(item.type)) return this.resolveArray(uid, item.type);\n\n if (item.kind === 'function' && item.func) return this.resolveFunc(uid, item.func, item.params);\n\n if (item.factory) return this.resolveFactory(uid, item.factory);\n\n return this.resolveClass(uid, item.type as Class, item.params);\n } finally {\n this.resolving.delete(uid);\n this.path.pop();\n }\n }\n\n /**\n * Synchronously disposes of all resolved services.\n * Throws AsyncDisposalError if this is an async scope or if any service disposal returns a Promise.\n */\n dispose(): void {\n if (this.disposed) return;\n\n if (this.isAsyncScope) {\n throw new AsyncDisposalError(this.name);\n }\n\n this.disposed = true;\n\n const entries = Array.from(this.instances.entries()).reverse();\n\n for (const [uid, inst] of entries) {\n if (inst && typeof inst.dispose === 'function') {\n const result = inst.dispose();\n if (result instanceof Promise) {\n throw new AsyncDisposalError(typeof uid === 'symbol' ? uid.description || String(uid) : String(uid));\n }\n } else if (inst && typeof inst.disposeAsync === 'function') {\n throw new AsyncDisposalError(typeof uid === 'symbol' ? uid.description || String(uid) : String(uid));\n }\n }\n\n this.instances.clear();\n }\n\n /**\n * Asynchronously disposes of all resolved services.\n */\n async disposeAsync(): Promise<void> {\n if (this.disposed) return;\n this.disposed = true;\n\n const entries = Array.from(this.instances.values()).reverse();\n\n for (const inst of entries) {\n if (inst && typeof inst.disposeAsync === 'function') {\n await inst.disposeAsync();\n } else if (inst && typeof inst.dispose === 'function') {\n const result = inst.dispose();\n if (result instanceof Promise) {\n await result;\n }\n }\n }\n\n this.instances.clear();\n }\n\n /**\n * Resolves a singleton value.\n * @param uid The unique ID of the value.\n * @param value The value to resolve.\n */\n private resolveValue(uid: string | symbol, value: any): any {\n this.instances.set(uid, value);\n return value;\n }\n\n /**\n * Resolves an array of services.\n * @param uid The unique ID of the service array.\n * @param types The class types to resolve for the array.\n */\n private resolveArray(uid: string | symbol, types: Class[]): any {\n const instances = types.map((cls) => {\n const inst = this.getService(cls);\n return inst;\n });\n\n this.instances.set(uid, instances);\n return instances;\n }\n\n /**\n * Resolves a service via a factory.\n * @param uid The unique ID of the service.\n * @param factory The factory to use for resolution.\n */\n private resolveFactory(uid: string | symbol, factory: ImplementationFactory<any, any>): any {\n const container = this.createContainerProxy();\n const result = factory(container, this);\n this.instances.set(uid, result);\n return result;\n }\n\n /**\n * Resolves a service via a function.\n * @param uid The unique ID of the service.\n * @param func The function to use for resolution.\n * @param params The arguments for the function.\n */\n private resolveFunc(uid: string | symbol, func: (...args: any[]) => any, params?: any[]): any {\n const rawParams = params || [];\n const resolvedParams = rawParams.map((param) => {\n const paramKey = this.tryGetKey(param);\n const inst = paramKey ? this.getService(paramKey) : param;\n return inst;\n });\n\n const result = func(...resolvedParams);\n this.instances.set(uid, result);\n return result;\n }\n\n /**\n * Resolves a service via its class type.\n * @param uid The unique ID of the service.\n * @param type The class type to instantiate.\n * @param params The constructor arguments.\n */\n private resolveClass(uid: string | symbol, type: Class, params?: any[]): any {\n const rawParams = params || [];\n const resolvedParams = rawParams.map((param) => {\n const paramKey = this.tryGetKey(param);\n const inst = paramKey ? this.getService(paramKey) : param;\n return inst;\n });\n\n const instance = new (type as ConcreteClass)(...resolvedParams);\n this.instances.set(uid, instance);\n return instance;\n }\n\n /**\n * Creates a proxy for the type map to allow resolving services by property access.\n */\n private createContainerProxy(): ResolvedTypeMap<T> {\n return new Proxy({} as ResolvedTypeMap<T>, {\n get: (_, prop) => {\n if (typeof prop !== 'string' && typeof prop !== 'symbol') return undefined;\n return this.getService(prop as any);\n }\n });\n }\n\n /**\n * Gets the key for a given key or class type.\n * @param keyOrType The key or class type.\n */\n private getKey<K extends keyof T & (string | symbol)>(keyOrType: K | T[K]): string | symbol {\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') return keyOrType;\n\n const key = this.tryGetKey(keyOrType);\n if (key) return key;\n\n const name = Array.isArray(keyOrType)\n ? `[${keyOrType.map((c: any) => (c as any).name).join(', ')}]`\n : (keyOrType as any).name || String(keyOrType);\n throw new ServiceNotFoundError(name);\n }\n\n /**\n * Attempts to get the key for a given key or class type without throwing.\n * @param keyOrType The key or class type.\n */\n private tryGetKey(keyOrType: any): string | symbol | undefined {\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') {\n if (keyOrType in this.definitions) return keyOrType;\n \n // Fallback for string names (backward compatibility)\n if (typeof keyOrType === 'string') {\n const entry = Reflect.ownKeys(this.definitions).find((k) => {\n const v = this.definitions[k as any];\n return v.kind === 'service' && !Array.isArray(v.type) && (v.type as any)?.name === keyOrType;\n });\n if (entry) return entry as string | symbol;\n }\n return undefined;\n }\n\n if (typeof keyOrType === 'function' || Array.isArray(keyOrType)) {\n // Check the stable registry first (minification proof)\n const stableKey = getStableKey(keyOrType as any);\n if (stableKey in this.definitions) return stableKey;\n\n // Fallback to searching by reference (for explicit symbols or non-auto registrations)\n const entry = Reflect.ownKeys(this.definitions).find((k) => {\n const v = this.definitions[k as any];\n return v.kind === 'service' && v.type === keyOrType;\n });\n if (entry) return entry as string | symbol;\n }\n\n return undefined;\n }\n}\n", "import {\n RegistrationError,\n} from './errors.js';\nimport { getStableKey } from './registry.js';\nimport { ServiceProvider } from './service-provider.js';\nimport type {\n Class,\n ClassArgs,\n FilterKeys,\n FilterValueKeys,\n FilterFuncKeys,\n FuncArgs,\n ImplementationFactory,\n MapToInstance,\n ServiceDefinitionMap,\n TypeMap,\n ServiceDefinition\n} from './types.js';\n\n/**\n * Fluent builder for service collections using a lookup map.\n */\nexport class ServiceCollection<T extends TypeMap> {\n private definitions: ServiceDefinitionMap = {};\n private typeMap: T;\n\n /**\n * Initializes a new instance of the ServiceCollection class.\n */\n constructor() {\n this.typeMap = {} as T;\n }\n\n /**\n * Adds a singleton service using a factory function.\n * Key is derived from the class.\n * @param type The class to register.\n * @param factory The factory function to create the service instance.\n * @example\n * .addSingletonFactory(UserRepo, (c) => new UserRepo(c.UserService))\n */\n addSingletonFactory<Key extends keyof T & (string | symbol), C extends Class>(\n type: C,\n factory: ImplementationFactory<T, InstanceType<C>>\n ): this;\n\n /**\n * Adds a singleton service using a factory function and a key.\n * @param key The key to register the service under.\n * @param factory The factory function to create the service instance.\n * @example\n * .addSingletonFactory(\"UserRepo\", (c) => new UserRepo(c.UserService))\n */\n addSingletonFactory<Key extends keyof T & (string | symbol)>(\n key: Key,\n factory: ImplementationFactory<T, MapToInstance<T[Key]>>\n ): this;\n\n addSingletonFactory<Key extends keyof T & (string | symbol)>(\n keyOrType: Key | Class,\n factory: ImplementationFactory<T, any>\n ): this {\n let key: string | symbol;\n let type: any;\n let isExplicitKey = false;\n\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') {\n key = keyOrType;\n type = this.typeMap[key];\n isExplicitKey = true;\n } else {\n const resolved = this.resolveKeyAndType<Key>(keyOrType as any);\n key = resolved.key;\n type = resolved.type;\n }\n\n const uid = isExplicitKey ? key : getStableKey(type);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid, type, factory };\n this.definitions[key] = def;\n if (key !== uid) this.definitions[uid] = def;\n\n return this;\n }\n\n /**\n * Registers the ServiceProvider itself as a service.\n * This allows services to depend on the ServiceProvider to resolve other services dynamically.\n * @param key The key to register the ServiceProvider under.\n * @example\n * .addServiceProvider(\"ServiceProvider\")\n */\n addServiceProvider<Key extends keyof T & (string | symbol)>(key: Key) {\n return this.addSingletonFactory(key as any, (_, sp) => sp)\n }\n\n /**\n * Adds a scoped service using a factory function.\n * Key is derived from the class.\n * @param type The class to register.\n * @param factory The factory function to create the service instance.\n * @example\n * .addScopedFactory(UserRepo, (c) => new UserRepo(c.UserService))\n */\n addScopedFactory<Key extends keyof T & (string | symbol), C extends Class>(\n type: C,\n factory: ImplementationFactory<T, InstanceType<C>>\n ): this;\n\n /**\n * Adds a scoped service using a factory function and a key.\n * @param key The key to register the service under.\n * @param factory The factory function to create the service instance.\n * @example\n * .addScopedFactory(\"UserRepo\", (c) => new UserRepo(c.UserService))\n */\n addScopedFactory<Key extends keyof T & (string | symbol)>(\n key: Key,\n factory: ImplementationFactory<T, MapToInstance<T[Key]>>\n ): this;\n\n addScopedFactory<Key extends keyof T & (string | symbol)>(\n keyOrType: Key | Class,\n factory: ImplementationFactory<T, any>\n ): this {\n let key: string | symbol;\n let type: any;\n let isExplicitKey = false;\n\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') {\n key = keyOrType;\n type = this.typeMap[key];\n isExplicitKey = true;\n } else {\n const resolved = this.resolveKeyAndType<Key>(keyOrType as any);\n key = resolved.key;\n type = resolved.type;\n }\n\n const uid = isExplicitKey ? key : getStableKey(type);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid, type, factory };\n this.definitions[key] = def;\n if (key !== uid) this.definitions[uid] = def;\n\n return this;\n }\n\n /**\n * Adds a singleton service using constructor injection.\n * Key is derived from the container map based on the Class.\n * @param type The class to register.\n * @param params The constructor arguments.\n * @example\n * .addSingletonClass(UserService, \"admin\", \"password\")\n */\n addSingletonClass<C extends Class>(\n type: C,\n ...params: ClassArgs<C, keyof T & (string | symbol)>\n ): this {\n const { key, type: typeRef } = this.resolveKeyAndType(type as any);\n const uid = getStableKey(typeRef);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid, type: typeRef, params };\n this.definitions[key] = def;\n this.definitions[uid] = def;\n return this;\n }\n\n /**\n * Adds a scoped service using constructor injection.\n * Key is derived from the container map based on the Class.\n * @param type The class to register.\n * @param params The constructor arguments.\n * @example\n * .addScopedClass(UserService, \"admin\", \"password\")\n */\n addScopedClass<C extends Class>(\n type: C,\n ...params: ClassArgs<C, keyof T & (string | symbol)>\n ): this {\n const { key, type: typeRef } = this.resolveKeyAndType(type as any);\n const uid = getStableKey(typeRef);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid, type: typeRef, params };\n this.definitions[key] = def;\n this.definitions[uid] = def;\n return this;\n }\n\n /**\n * Adds an array of singleton services.\n * Automatically registers individual classes if not already registered.\n * @param key The key for the service array.\n * @param types The classes to register in the array.\n * @example\n * .addSingletonArray(\"MessageCommand\", HelloCommand, ByeCommand)\n */\n addSingletonArray<\n Key extends FilterKeys<T, any[]>,\n C extends (new (...args: any[]) => MapToInstance<T[Key]>[number])[]\n >(\n key: Key,\n ...types: C\n ): this {\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid: key, type: types };\n (this.typeMap as any)[key] = types;\n this.definitions[key] = def;\n\n // Auto-register individual classes if not already registered\n const typeArray = types as Class[];\n for (const type of typeArray) {\n const foundKey = Reflect.ownKeys(this.typeMap).find(k => this.typeMap[k as any] === type);\n if (foundKey) continue;\n\n const name = type.name;\n if (!name) {\n throw new RegistrationError(`Class in array \"${String(key)}\" is missing a name and cannot be auto-registered.`);\n }\n\n const uid = getStableKey(type);\n const classDef: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid, type, params: [] };\n (this.typeMap as any)[name] = type;\n this.definitions[name] = classDef;\n this.definitions[uid] = classDef;\n }\n\n return this;\n }\n\n /**\n * Adds an array of scoped services.\n * Automatically registers individual classes as scoped if not already registered.\n * @param key The key for the service array.\n * @param types The classes to register in the array.\n * @example\n * .addScopedArray(\"MessageCommand\", HelloCommand, ByeCommand)\n */\n addScopedArray<\n Key extends FilterKeys<T, any[]>,\n C extends (new (...args: any[]) => MapToInstance<T[Key]>[number])[]\n >(\n key: Key,\n ...types: C\n ): this {\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid: key, type: types };\n (this.typeMap as any)[key] = types;\n this.definitions[key] = def;\n\n // Auto-register individual classes if not already registered\n const typeArray = types as Class[];\n for (const type of typeArray) {\n const foundKey = Reflect.ownKeys(this.typeMap).find(k => this.typeMap[k as any] === type);\n if (foundKey) continue;\n\n const name = type.name;\n if (!name) {\n throw new RegistrationError(`Class in array \"${String(key)}\" is missing a name and cannot be auto-registered.`);\n }\n\n const uid = getStableKey(type);\n const classDef: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid, type, params: [] };\n (this.typeMap as any)[name] = type;\n this.definitions[name] = classDef;\n this.definitions[uid] = classDef;\n }\n\n return this;\n }\n\n /**\n * Adds a singleton service using a function.\n * @param key The key for the service.\n * @param func The function to register.\n * @param params The function arguments.\n * @example\n * .addSingletonFunc(\"Logger\", createLogger, \"Config\")\n */\n addSingletonFunc<Key extends FilterFuncKeys<T>, F extends (...args: any[]) => T[Key]>(\n key: Key,\n func: F,\n ...params: FuncArgs<F, T>\n ): this {\n this.definitions[key] = { kind: 'function', lifetime: 'singleton', uid: key, func, params };\n return this;\n }\n\n /**\n * Adds a scoped service using a function.\n * @param key The key for the service.\n * @param func The function to register.\n * @param params The function arguments.\n * @example\n * .addScopedFunc(\"Logger\", createLogger, \"Config\")\n */\n addScopedFunc<Key extends FilterFuncKeys<T>, F extends (...args: any[]) => T[Key]>(\n key: Key,\n func: F,\n ...params: FuncArgs<F, T>\n ): this {\n this.definitions[key] = { kind: 'function', lifetime: 'scoped', uid: key, func, params };\n return this;\n }\n\n /**\n * Adds a singleton value.\n * @param key The key for the value.\n * @param value The value to register.\n * @example\n * .addSingletonValue(\"connectionString\", \"test connection string\")\n */\n addSingletonValue<Key extends FilterValueKeys<T>>(\n key: Key,\n value: T[Key]\n ): this {\n this.definitions[key] = { kind: 'value', lifetime: 'singleton', uid: key, value };\n return this;\n }\n\n /**\n * Adds a scoped value.\n * @param key The key for the value.\n * @param value The value to register.\n * @example\n * .addScopedValue(\"connectionString\", \"test connection string\")\n */\n addScopedValue<Key extends FilterValueKeys<T>>(\n key: Key,\n value: T[Key]\n ): this {\n this.definitions[key] = { kind: 'value', lifetime: 'scoped', uid: key, value };\n return this;\n }\n\n /**\n * Resolves the string key and Class reference for a given type.\n * If the type is already mapped in the TypeMap, the existing key is used.\n * Otherwise, it auto-registers the type using its class name as the key.\n * @param type The class reference to resolve.\n * @throws RegistrationError if the class name cannot be determined (e.g. anonymous class).\n * @example\n * const { key, type } = this.resolveKeyAndType(UserService);\n */\n private resolveKeyAndType<Key extends keyof T & (string | symbol)>(type: T[Key] & Class): { key: Key, type: T[Key] } {\n let key: Key;\n\n const foundKey = Reflect.ownKeys(this.typeMap).find(\n (k) => this.typeMap[k as any] === type\n );\n if (foundKey) {\n key = foundKey as Key;\n } else {\n // Auto-register using class name for backward compatibility\n key = (type.name || getStableKey(type)) as any as Key;\n (this.typeMap as any)[key] = type;\n }\n\n return { key, type };\n }\n\n /**\n * Builds the ServiceProvider.\n * @param name The name of the service provider.\n * @example\n * const di = new ServiceCollection<LocalMap>()\n * .addSingletonClass(MyService)\n * .build();\n */\n build(name: string = 'root'): ServiceProvider<T> {\n // Validate all registered services\n for (const key of Reflect.ownKeys(this.definitions)) {\n const item = this.definitions[key as any];\n if (item.kind !== 'service' || !Array.isArray(item.type)) continue;\n\n // This is an array of services\n for (const type of item.type as Class[]) {\n const name = type.name;\n const definitionsItem = this.definitions[name];\n\n // Check if this class was auto-registered (params is empty array) but requires arguments\n if (definitionsItem && definitionsItem.params && definitionsItem.params.length === 0 && type.length > 0) {\n throw new RegistrationError(`Class \"${name}\" in array \"${String(key)}\" requires constructor arguments and must be registered independently using addSingletonClass or addScopedClass.`);\n }\n }\n }\n\n return new ServiceProvider<T>(name, this.definitions);\n }\n}\n"],
|
|
4
|
+
"sourcesContent": ["/**\n * Thrown when a circular dependency is detected.\n */\nexport class CircularDependencyError extends Error {\n constructor(path: string) {\n super(`Circular dependency detected: ${path}`);\n this.name = 'CircularDependencyError';\n }\n}\n\n/**\n * Thrown when a service cannot be resolved.\n */\nexport class ServiceNotFoundError extends Error {\n constructor(identifier: string) {\n super(`Service not registered for identifier: ${identifier}`);\n this.name = 'ServiceNotFoundError';\n }\n}\n\n/**\n * Thrown when a registration is invalid.\n */\nexport class RegistrationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'RegistrationError';\n }\n}\n\n/**\n * Thrown when a service provider has been disposed.\n */\nexport class ServiceProviderDisposedError extends Error {\n constructor() {\n super('ServiceProvider has been disposed and cannot resolve services.');\n this.name = 'ServiceProviderDisposedError';\n }\n}\n\n/**\n * Thrown when a synchronous dispose is called on a scope containing services that require asynchronous disposal.\n */\nexport class AsyncDisposalError extends Error {\n constructor(serviceKey: string) {\n super(`Service \"${serviceKey}\" requires asynchronous disposal but a synchronous dispose was called. Please use await disposeAsync() instead.`);\n this.name = 'AsyncDisposalError';\n }\n}\n", "import type { Class } from './types.js';\r\n\r\nconst classKeyRegistry = new WeakMap<Class, symbol>();\r\n\r\n/**\r\n * Resolves a stable Symbol for a given class constructor.\r\n * This is used to ensure that DI resolution remains stable even after minification.\r\n * @param type The class constructor.\r\n */\r\nexport function getStableKey(type: Class): symbol {\r\n let key = classKeyRegistry.get(type);\r\n if (!key) {\r\n key = Symbol(type.name || 'AnonymousClass');\r\n classKeyRegistry.set(type, key);\r\n }\r\n return key;\r\n}\r\n", "import {\n AsyncDisposalError,\n CircularDependencyError,\n ServiceNotFoundError,\n ServiceProviderDisposedError,\n} from './errors.js';\nimport { getStableKey } from './registry.js';\nimport type {\n Class,\n ConcreteClass,\n ImplementationFactory,\n IServiceProvider,\n MapToInstance,\n ResolvedTypeMap,\n ServiceDefinitionMap,\n TypeMap,\n} from './types.js';\n\nexport class ServiceProvider<T extends TypeMap> implements IServiceProvider<T> {\n private instances = new Map<string | symbol, any>();\n private resolving = new Set<string | symbol>();\n private path: (string | symbol)[] = [];\n private disposed = false;\n\n /**\n * @param name The name of the service provider.\n * @param definitions The service definitions map.\n * @param parent The parent service provider, if any.\n * @param isAsyncScope Whether this is an asynchronous scope.\n */\n constructor(\n public readonly name: string,\n private definitions: ServiceDefinitionMap,\n private parent?: ServiceProvider<T>,\n private readonly isAsyncScope: boolean = false\n ) { }\n\n /**\n * Creates a new scoped ServiceProvider.\n * @param name The name of the scope.\n * @example\n * const scope = di.createScope('request-scope');\n */\n createScope(name: string = 'scope'): IServiceProvider<T> {\n const root = this.parent || this;\n return new ServiceProvider<T>(name, this.definitions, root, false);\n }\n\n /**\n * Creates a new scoped ServiceProvider that supports asynchronous disposal.\n * @param name The name of the scope.\n * @example\n * const scope = di.createAsyncScope('worker-scope');\n */\n createAsyncScope(name: string = 'async-scope'): IServiceProvider<T> {\n const root = this.parent || this;\n return new ServiceProvider<T>(name, this.definitions, root, true);\n }\n\n /**\n * Resolves a service by its key.\n * @param key The key to resolve.\n * @example\n * const logger = di.getService('Logger');\n */\n getService<K extends keyof T & (string | symbol)>(key: K): MapToInstance<T[K]>;\n\n /**\n * Resolves a service by its Class type.\n * @param type The class type to resolve.\n * @example\n * const logger = di.getService(Logger);\n */\n getService<C extends Class>(type: C): InstanceType<C>;\n\n getService<K extends keyof T & (string | symbol)>(keyOrType: K | T[K]): MapToInstance<T[K]> {\n if (this.disposed) {\n throw new ServiceProviderDisposedError();\n }\n\n const key = this.getKey(keyOrType);\n\n if (this.parent && this.definitions[key]?.lifetime === 'singleton') {\n return this.parent.getService(key as any);\n }\n\n const item = this.definitions[key];\n if (!item) {\n const name = (typeof keyOrType === 'string' || typeof keyOrType === 'symbol')\n ? String(keyOrType)\n : (keyOrType as any).name || String(keyOrType);\n throw new ServiceNotFoundError(name);\n }\n\n const uid = item.uid;\n\n if (this.instances.has(uid)) {\n return this.instances.get(uid);\n }\n\n if (this.resolving.has(uid)) {\n const pathStr = this.path.map(k => (typeof k === 'symbol' ? k.description || String(k) : k)).concat(typeof key === 'symbol' ? key.description || String(key) : key).join(' -> ');\n throw new CircularDependencyError(pathStr);\n }\n\n this.resolving.add(uid);\n this.path.push(key);\n\n try {\n if (item.kind === 'value') return this.resolveValue(uid, item.value);\n\n if (Array.isArray(item.type)) return this.resolveArray(uid, item.type);\n\n if (item.kind === 'function' && item.func) return this.resolveFunc(uid, item.func, item.params);\n\n if (item.factory) return this.resolveFactory(uid, item.factory);\n\n return this.resolveClass(uid, item.type as Class, item.params);\n } finally {\n this.resolving.delete(uid);\n this.path.pop();\n }\n }\n\n /**\n * Synchronously disposes of all resolved services.\n * Throws AsyncDisposalError if this is an async scope or if any service disposal returns a Promise.\n */\n dispose(): void {\n if (this.disposed) return;\n\n if (this.isAsyncScope) {\n throw new AsyncDisposalError(this.name);\n }\n\n this.disposed = true;\n\n const entries = Array.from(this.instances.entries()).reverse();\n\n for (const [uid, inst] of entries) {\n if (inst && typeof inst.dispose === 'function') {\n const result = inst.dispose();\n if (result instanceof Promise) {\n throw new AsyncDisposalError(typeof uid === 'symbol' ? uid.description || String(uid) : String(uid));\n }\n } else if (inst && typeof inst.disposeAsync === 'function') {\n throw new AsyncDisposalError(typeof uid === 'symbol' ? uid.description || String(uid) : String(uid));\n }\n }\n\n this.instances.clear();\n }\n\n /**\n * Asynchronously disposes of all resolved services.\n */\n async disposeAsync(): Promise<void> {\n if (this.disposed) return;\n this.disposed = true;\n\n const entries = Array.from(this.instances.values()).reverse();\n\n for (const inst of entries) {\n if (inst && typeof inst.disposeAsync === 'function') {\n await inst.disposeAsync();\n } else if (inst && typeof inst.dispose === 'function') {\n const result = inst.dispose();\n if (result instanceof Promise) {\n await result;\n }\n }\n }\n\n this.instances.clear();\n }\n\n /**\n * Resolves a singleton value.\n * @param uid The unique ID of the value.\n * @param value The value to resolve.\n */\n private resolveValue(uid: string | symbol, value: any): any {\n this.instances.set(uid, value);\n return value;\n }\n\n /**\n * Resolves an array of services.\n * @param uid The unique ID of the service array.\n * @param types The class types to resolve for the array.\n */\n private resolveArray(uid: string | symbol, types: Class[]): any {\n const instances = types.map((cls) => {\n const inst = this.getService(cls);\n return inst;\n });\n\n this.instances.set(uid, instances);\n return instances;\n }\n\n /**\n * Resolves a service via a factory.\n * @param uid The unique ID of the service.\n * @param factory The factory to use for resolution.\n */\n private resolveFactory(uid: string | symbol, factory: ImplementationFactory<any, any>): any {\n const container = this.createContainerProxy();\n const result = factory(container, this);\n this.instances.set(uid, result);\n return result;\n }\n\n /**\n * Resolves a service via a function.\n * @param uid The unique ID of the service.\n * @param func The function to use for resolution.\n * @param params The arguments for the function.\n */\n private resolveFunc(uid: string | symbol, func: (...args: any[]) => any, params?: any[]): any {\n const rawParams = params || [];\n const resolvedParams = rawParams.map((param) => {\n const paramKey = this.tryGetKey(param);\n const inst = paramKey ? this.getService(paramKey) : param;\n return inst;\n });\n\n const result = func(...resolvedParams);\n this.instances.set(uid, result);\n return result;\n }\n\n /**\n * Resolves a service via its class type.\n * @param uid The unique ID of the service.\n * @param type The class type to instantiate.\n * @param params The constructor arguments.\n */\n private resolveClass(uid: string | symbol, type: Class, params?: any[]): any {\n const rawParams = params || [];\n const resolvedParams = rawParams.map((param) => {\n const paramKey = this.tryGetKey(param);\n const inst = paramKey ? this.getService(paramKey) : param;\n return inst;\n });\n\n const instance = new (type as ConcreteClass)(...resolvedParams);\n this.instances.set(uid, instance);\n return instance;\n }\n\n /**\n * Creates a proxy for the type map to allow resolving services by property access.\n */\n private createContainerProxy(): ResolvedTypeMap<T> {\n return new Proxy({} as ResolvedTypeMap<T>, {\n get: (_, prop) => {\n if (typeof prop !== 'string' && typeof prop !== 'symbol') return undefined;\n return this.getService(prop as any);\n }\n });\n }\n\n /**\n * Gets the key for a given key or class type.\n * @param keyOrType The key or class type.\n */\n private getKey<K extends keyof T & (string | symbol)>(keyOrType: K | T[K]): string | symbol {\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') return keyOrType;\n\n const key = this.tryGetKey(keyOrType);\n if (key) return key;\n\n const name = Array.isArray(keyOrType)\n ? `[${keyOrType.map((c: any) => (c as any).name).join(', ')}]`\n : (keyOrType as any).name || String(keyOrType);\n throw new ServiceNotFoundError(name);\n }\n\n /**\n * Attempts to get the key for a given key or class type without throwing.\n * @param keyOrType The key or class type.\n */\n private tryGetKey(keyOrType: any): string | symbol | undefined {\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') {\n if (keyOrType in this.definitions) return keyOrType;\n \n // Fallback for string names (backward compatibility)\n if (typeof keyOrType === 'string') {\n const entry = Reflect.ownKeys(this.definitions).find((k) => {\n const v = this.definitions[k as any];\n return v.kind === 'service' && !Array.isArray(v.type) && (v.type as any)?.name === keyOrType;\n });\n if (entry) return entry as string | symbol;\n }\n return undefined;\n }\n\n if (typeof keyOrType === 'function' || Array.isArray(keyOrType)) {\n // Check the stable registry first (minification proof)\n const stableKey = getStableKey(keyOrType as any);\n if (stableKey in this.definitions) return stableKey;\n\n // Fallback to searching by reference (for explicit symbols or non-auto registrations)\n const entry = Reflect.ownKeys(this.definitions).find((k) => {\n const v = this.definitions[k as any];\n return v.kind === 'service' && v.type === keyOrType;\n });\n if (entry) return entry as string | symbol;\n }\n\n return undefined;\n }\n}\n", "import {\n RegistrationError,\n} from './errors.js';\nimport { getStableKey } from './registry.js';\nimport { ServiceProvider } from './service-provider.js';\nimport type {\n Class,\n ClassArgs,\n FilterKeys,\n FilterValueKeys,\n FilterFuncKeys,\n FuncArgs,\n ImplementationFactory,\n MapToInstance,\n ServiceDefinitionMap,\n TypeMap,\n ServiceDefinition\n} from './types.js';\n\n/**\n * Fluent builder for service collections using a lookup map.\n */\nexport class ServiceCollection<T extends TypeMap> {\n private definitions: ServiceDefinitionMap = {};\n private typeMap: T;\n\n /**\n * Initializes a new instance of the ServiceCollection class.\n */\n constructor() {\n this.typeMap = {} as T;\n }\n\n /**\n * Adds a singleton service using a factory function.\n * Key is derived from the class.\n * @param type The class to register.\n * @param factory The factory function to create the service instance.\n * @example\n * .addSingletonFactory(UserRepo, (c) => new UserRepo(c.UserService))\n */\n addSingletonFactory<Key extends keyof T & (string | symbol), C extends Class>(\n type: C,\n factory: ImplementationFactory<T, InstanceType<C>>\n ): this;\n\n /**\n * Adds a singleton service using a factory function and a key.\n * @param key The key to register the service under.\n * @param factory The factory function to create the service instance.\n * @example\n * .addSingletonFactory(\"UserRepo\", (c) => new UserRepo(c.UserService))\n */\n addSingletonFactory<Key extends keyof T & (string | symbol)>(\n key: Key,\n factory: ImplementationFactory<T, MapToInstance<T[Key]>>\n ): this;\n\n addSingletonFactory<Key extends keyof T & (string | symbol)>(\n keyOrType: Key | Class,\n factory: ImplementationFactory<T, any>\n ): this {\n let key: string | symbol;\n let type: any;\n let isExplicitKey = false;\n\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') {\n key = keyOrType;\n type = this.typeMap[key];\n isExplicitKey = true;\n } else {\n const resolved = this.resolveKeyAndType<Key>(keyOrType as any);\n key = resolved.key;\n type = resolved.type;\n }\n\n const uid = isExplicitKey ? key : getStableKey(type);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid, type, factory };\n this.definitions[key] = def;\n if (key !== uid) this.definitions[uid] = def;\n\n return this;\n }\n\n /**\n * Registers the ServiceProvider itself as a service.\n * This allows services to depend on the ServiceProvider to resolve other services dynamically.\n * @param key The key to register the ServiceProvider under.\n * @example\n * .addServiceProvider(\"ServiceProvider\")\n */\n addServiceProvider<Key extends keyof T & (string | symbol)>(key: Key) {\n return this.addSingletonFactory(key as any, (_, sp) => sp)\n }\n\n /**\n * Adds a scoped service using a factory function.\n * Key is derived from the class.\n * @param type The class to register.\n * @param factory The factory function to create the service instance.\n * @example\n * .addScopedFactory(UserRepo, (c) => new UserRepo(c.UserService))\n */\n addScopedFactory<Key extends keyof T & (string | symbol), C extends Class>(\n type: C,\n factory: ImplementationFactory<T, InstanceType<C>>\n ): this;\n\n /**\n * Adds a scoped service using a factory function and a key.\n * @param key The key to register the service under.\n * @param factory The factory function to create the service instance.\n * @example\n * .addScopedFactory(\"UserRepo\", (c) => new UserRepo(c.UserService))\n */\n addScopedFactory<Key extends keyof T & (string | symbol)>(\n key: Key,\n factory: ImplementationFactory<T, MapToInstance<T[Key]>>\n ): this;\n\n addScopedFactory<Key extends keyof T & (string | symbol)>(\n keyOrType: Key | Class,\n factory: ImplementationFactory<T, any>\n ): this {\n let key: string | symbol;\n let type: any;\n let isExplicitKey = false;\n\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') {\n key = keyOrType;\n type = this.typeMap[key];\n isExplicitKey = true;\n } else {\n const resolved = this.resolveKeyAndType<Key>(keyOrType as any);\n key = resolved.key;\n type = resolved.type;\n }\n\n const uid = isExplicitKey ? key : getStableKey(type);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid, type, factory };\n this.definitions[key] = def;\n if (key !== uid) this.definitions[uid] = def;\n\n return this;\n }\n\n /**\n * Adds a singleton service using constructor injection.\n * Key is derived from the container map based on the Class.\n * @param type The class to register.\n * @param params The constructor arguments.\n * @example\n * .addSingletonClass(UserService, \"admin\", \"password\")\n */\n addSingletonClass<C extends Class>(\n type: C,\n ...params: ClassArgs<C, keyof T & (string | symbol)>\n ): this {\n const { key, type: typeRef } = this.resolveKeyAndType(type as any);\n const uid = getStableKey(typeRef);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid, type: typeRef, params };\n this.definitions[key] = def;\n this.definitions[uid] = def;\n return this;\n }\n\n /**\n * Adds a scoped service using constructor injection.\n * Key is derived from the container map based on the Class.\n * @param type The class to register.\n * @param params The constructor arguments.\n * @example\n * .addScopedClass(UserService, \"admin\", \"password\")\n */\n addScopedClass<C extends Class>(\n type: C,\n ...params: ClassArgs<C, keyof T & (string | symbol)>\n ): this {\n const { key, type: typeRef } = this.resolveKeyAndType(type as any);\n const uid = getStableKey(typeRef);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid, type: typeRef, params };\n this.definitions[key] = def;\n this.definitions[uid] = def;\n return this;\n }\n\n /**\n * Adds a group (array) of singleton services.\n * Automatically registers individual classes as singletons if not already registered.\n * @param key The key for the service group.\n * @param types The classes to register in the group.\n * @example\n * .addSingletonGroup(\"MessageCommand\", HelloCommand, ByeCommand)\n */\n addSingletonGroup<\n Key extends FilterKeys<T, any[]>,\n C extends (new (...args: any[]) => MapToInstance<T[Key]>[number])[]\n >(\n key: Key,\n ...types: C\n ): this {\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid: key, type: types };\n (this.typeMap as any)[key] = types;\n this.definitions[key] = def;\n\n // Auto-register individual classes if not already registered\n const typeArray = types as Class[];\n for (const type of typeArray) {\n const foundKey = Reflect.ownKeys(this.typeMap).find(k => this.typeMap[k as any] === type);\n if (foundKey) continue;\n\n const name = type.name;\n if (!name) {\n throw new RegistrationError(`Class in group \"${String(key)}\" is missing a name and cannot be auto-registered.`);\n }\n\n const uid = getStableKey(type);\n const classDef: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid, type, params: [] };\n (this.typeMap as any)[name] = type;\n this.definitions[name] = classDef;\n this.definitions[uid] = classDef;\n }\n\n return this;\n }\n\n /**\n * Adds a group (array) of scoped services.\n * Automatically registers individual classes as scoped if not already registered.\n * @param key The key for the service group.\n * @param types The classes to register in the group.\n * @example\n * .addScopedGroup(\"MessageCommand\", HelloCommand, ByeCommand)\n */\n addScopedGroup<\n Key extends FilterKeys<T, any[]>,\n C extends (new (...args: any[]) => MapToInstance<T[Key]>[number])[]\n >(\n key: Key,\n ...types: C\n ): this {\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid: key, type: types };\n (this.typeMap as any)[key] = types;\n this.definitions[key] = def;\n\n // Auto-register individual classes if not already registered\n const typeArray = types as Class[];\n for (const type of typeArray) {\n const foundKey = Reflect.ownKeys(this.typeMap).find(k => this.typeMap[k as any] === type);\n if (foundKey) continue;\n\n const name = type.name;\n if (!name) {\n throw new RegistrationError(`Class in group \"${String(key)}\" is missing a name and cannot be auto-registered.`);\n }\n\n const uid = getStableKey(type);\n const classDef: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid, type, params: [] };\n (this.typeMap as any)[name] = type;\n this.definitions[name] = classDef;\n this.definitions[uid] = classDef;\n }\n\n return this;\n }\n\n /**\n * Adds a singleton service using a function.\n * @param key The key for the service.\n * @param func The function to register.\n * @param params The function arguments.\n * @example\n * .addSingletonFunc(\"Logger\", createLogger, \"Config\")\n */\n addSingletonFunc<Key extends FilterFuncKeys<T>, F extends (...args: any[]) => T[Key]>(\n key: Key,\n func: F,\n ...params: FuncArgs<F, T>\n ): this {\n this.definitions[key] = { kind: 'function', lifetime: 'singleton', uid: key, func, params };\n return this;\n }\n\n /**\n * Adds a scoped service using a function.\n * @param key The key for the service.\n * @param func The function to register.\n * @param params The function arguments.\n * @example\n * .addScopedFunc(\"Logger\", createLogger, \"Config\")\n */\n addScopedFunc<Key extends FilterFuncKeys<T>, F extends (...args: any[]) => T[Key]>(\n key: Key,\n func: F,\n ...params: FuncArgs<F, T>\n ): this {\n this.definitions[key] = { kind: 'function', lifetime: 'scoped', uid: key, func, params };\n return this;\n }\n\n /**\n * Adds a singleton value.\n * @param key The key for the value.\n * @param value The value to register.\n * @example\n * .addSingletonValue(\"connectionString\", \"test connection string\")\n */\n addSingletonValue<Key extends FilterValueKeys<T>>(\n key: Key,\n value: T[Key]\n ): this {\n this.definitions[key] = { kind: 'value', lifetime: 'singleton', uid: key, value };\n return this;\n }\n\n /**\n * Adds a scoped value.\n * @param key The key for the value.\n * @param value The value to register.\n * @example\n * .addScopedValue(\"connectionString\", \"test connection string\")\n */\n addScopedValue<Key extends FilterValueKeys<T>>(\n key: Key,\n value: T[Key]\n ): this {\n this.definitions[key] = { kind: 'value', lifetime: 'scoped', uid: key, value };\n return this;\n }\n\n /**\n * Resolves the string key and Class reference for a given type.\n * If the type is already mapped in the TypeMap, the existing key is used.\n * Otherwise, it auto-registers the type using its class name as the key.\n * @param type The class reference to resolve.\n * @throws RegistrationError if the class name cannot be determined (e.g. anonymous class).\n * @example\n * const { key, type } = this.resolveKeyAndType(UserService);\n */\n private resolveKeyAndType<Key extends keyof T & (string | symbol)>(type: T[Key] & Class): { key: Key, type: T[Key] } {\n let key: Key;\n\n const foundKey = Reflect.ownKeys(this.typeMap).find(\n (k) => this.typeMap[k as any] === type\n );\n if (foundKey) {\n key = foundKey as Key;\n } else {\n // Auto-register using class name for backward compatibility\n key = (type.name || getStableKey(type)) as any as Key;\n (this.typeMap as any)[key] = type;\n }\n\n return { key, type };\n }\n\n /**\n * Builds the ServiceProvider.\n * @param name The name of the service provider.\n * @example\n * const di = new ServiceCollection<LocalMap>()\n * .addSingletonClass(MyService)\n * .build();\n */\n build(name: string = 'root'): ServiceProvider<T> {\n // Validate all registered services\n for (const key of Reflect.ownKeys(this.definitions)) {\n const item = this.definitions[key as any];\n if (item.kind !== 'service' || !Array.isArray(item.type)) continue;\n\n // This is an array of services\n for (const type of item.type as Class[]) {\n const name = type.name;\n const definitionsItem = this.definitions[name];\n\n // Check if this class was auto-registered (params is empty array) but requires arguments\n if (definitionsItem && definitionsItem.params && definitionsItem.params.length === 0 && type.length > 0) {\n throw new RegistrationError(`Class \"${name}\" in group \"${String(key)}\" requires constructor arguments and must be registered independently using addSingletonClass or addScopedClass.`);\n }\n }\n }\n\n return new ServiceProvider<T>(name, this.definitions);\n }\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["CircularDependencyError", "path", "ServiceNotFoundError", "identifier", "RegistrationError", "message", "ServiceProviderDisposedError", "AsyncDisposalError", "serviceKey", "classKeyRegistry", "getStableKey", "type", "key", "ServiceProvider", "_ServiceProvider", "name", "definitions", "parent", "isAsyncScope", "root", "keyOrType", "ServiceProviderDisposedError", "key", "item", "ServiceNotFoundError", "uid", "pathStr", "k", "CircularDependencyError", "AsyncDisposalError", "entries", "inst", "result", "value", "types", "instances", "cls", "factory", "container", "func", "params", "resolvedParams", "param", "paramKey", "type", "instance", "_", "prop", "c", "entry", "v", "stableKey", "getStableKey", "ServiceCollection", "keyOrType", "factory", "key", "type", "isExplicitKey", "resolved", "uid", "getStableKey", "def", "_", "sp", "params", "typeRef", "types", "typeArray", "k", "name", "RegistrationError", "classDef", "func", "value", "foundKey", "item", "definitionsItem", "ServiceProvider"]
|
|
7
7
|
}
|
package/dist/legacy.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var v=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var T=Object.prototype.hasOwnProperty;var x=(o,e)=>{for(var t in e)v(o,t,{get:e[t],enumerable:!0})},w=(o,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of b(e))!T.call(o,n)&&n!==t&&v(o,n,{get:()=>e[n],enumerable:!(s=C(e,n))||s.enumerable});return o};var F=o=>w(v({},"__esModule",{value:!0}),o);var A={};x(A,{AsyncDisposalError:()=>f,CircularDependencyError:()=>
|
|
1
|
+
"use strict";var v=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var T=Object.prototype.hasOwnProperty;var x=(o,e)=>{for(var t in e)v(o,t,{get:e[t],enumerable:!0})},w=(o,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of b(e))!T.call(o,n)&&n!==t&&v(o,n,{get:()=>e[n],enumerable:!(s=C(e,n))||s.enumerable});return o};var F=o=>w(v({},"__esModule",{value:!0}),o);var A={};x(A,{AsyncDisposalError:()=>f,CircularDependencyError:()=>u,RegistrationError:()=>l,ServiceCollection:()=>K,ServiceNotFoundError:()=>p,ServiceProvider:()=>m,ServiceProviderDisposedError:()=>h});module.exports=F(A);var u=class extends Error{constructor(e){super(`Circular dependency detected: ${e}`),this.name="CircularDependencyError"}},p=class extends Error{constructor(e){super(`Service not registered for identifier: ${e}`),this.name="ServiceNotFoundError"}},l=class extends Error{constructor(e){super(e),this.name="RegistrationError"}},h=class extends Error{constructor(){super("ServiceProvider has been disposed and cannot resolve services."),this.name="ServiceProviderDisposedError"}},f=class extends Error{constructor(e){super(`Service "${e}" requires asynchronous disposal but a synchronous dispose was called. Please use await disposeAsync() instead.`),this.name="AsyncDisposalError"}};var S=new WeakMap;function c(o){let e=S.get(o);return e||(e=Symbol(o.name||"AnonymousClass"),S.set(o,e)),e}var m=class o{constructor(e,t,s,n=!1){this.name=e;this.definitions=t;this.parent=s;this.isAsyncScope=n}instances=new Map;resolving=new Set;path=[];disposed=!1;createScope(e="scope"){let t=this.parent||this;return new o(e,this.definitions,t,!1)}createAsyncScope(e="async-scope"){let t=this.parent||this;return new o(e,this.definitions,t,!0)}getService(e){if(this.disposed)throw new h;let t=this.getKey(e);if(this.parent&&this.definitions[t]?.lifetime==="singleton")return this.parent.getService(t);let s=this.definitions[t];if(!s){let i=typeof e=="string"||typeof e=="symbol"?String(e):e.name||String(e);throw new p(i)}let n=s.uid;if(this.instances.has(n))return this.instances.get(n);if(this.resolving.has(n)){let i=this.path.map(r=>typeof r=="symbol"?r.description||String(r):r).concat(typeof t=="symbol"?t.description||String(t):t).join(" -> ");throw new u(i)}this.resolving.add(n),this.path.push(t);try{return s.kind==="value"?this.resolveValue(n,s.value):Array.isArray(s.type)?this.resolveArray(n,s.type):s.kind==="function"&&s.func?this.resolveFunc(n,s.func,s.params):s.factory?this.resolveFactory(n,s.factory):this.resolveClass(n,s.type,s.params)}finally{this.resolving.delete(n),this.path.pop()}}dispose(){if(this.disposed)return;if(this.isAsyncScope)throw new f(this.name);this.disposed=!0;let e=Array.from(this.instances.entries()).reverse();for(let[t,s]of e)if(s&&typeof s.dispose=="function"){if(s.dispose()instanceof Promise)throw new f(typeof t=="symbol"&&t.description||String(t))}else if(s&&typeof s.disposeAsync=="function")throw new f(typeof t=="symbol"&&t.description||String(t));this.instances.clear()}async disposeAsync(){if(this.disposed)return;this.disposed=!0;let e=Array.from(this.instances.values()).reverse();for(let t of e)if(t&&typeof t.disposeAsync=="function")await t.disposeAsync();else if(t&&typeof t.dispose=="function"){let s=t.dispose();s instanceof Promise&&await s}this.instances.clear()}resolveValue(e,t){return this.instances.set(e,t),t}resolveArray(e,t){let s=t.map(n=>this.getService(n));return this.instances.set(e,s),s}resolveFactory(e,t){let s=this.createContainerProxy(),n=t(s,this);return this.instances.set(e,n),n}resolveFunc(e,t,s){let i=(s||[]).map(a=>{let y=this.tryGetKey(a);return y?this.getService(y):a}),r=t(...i);return this.instances.set(e,r),r}resolveClass(e,t,s){let i=(s||[]).map(a=>{let y=this.tryGetKey(a);return y?this.getService(y):a}),r=new t(...i);return this.instances.set(e,r),r}createContainerProxy(){return new Proxy({},{get:(e,t)=>{if(!(typeof t!="string"&&typeof t!="symbol"))return this.getService(t)}})}getKey(e){if(typeof e=="string"||typeof e=="symbol")return e;let t=this.tryGetKey(e);if(t)return t;let s=Array.isArray(e)?`[${e.map(n=>n.name).join(", ")}]`:e.name||String(e);throw new p(s)}tryGetKey(e){if(typeof e=="string"||typeof e=="symbol"){if(e in this.definitions)return e;if(typeof e=="string"){let t=Reflect.ownKeys(this.definitions).find(s=>{let n=this.definitions[s];return n.kind==="service"&&!Array.isArray(n.type)&&n.type?.name===e});if(t)return t}return}if(typeof e=="function"||Array.isArray(e)){let t=c(e);if(t in this.definitions)return t;let s=Reflect.ownKeys(this.definitions).find(n=>{let i=this.definitions[n];return i.kind==="service"&&i.type===e});if(s)return s}}};var K=class{definitions={};typeMap;constructor(){this.typeMap={}}addSingletonFactory(e,t){let s,n,i=!1;if(typeof e=="string"||typeof e=="symbol")s=e,n=this.typeMap[s],i=!0;else{let y=this.resolveKeyAndType(e);s=y.key,n=y.type}let r=i?s:c(n),a={kind:"service",lifetime:"singleton",uid:r,type:n,factory:t};return this.definitions[s]=a,s!==r&&(this.definitions[r]=a),this}addServiceProvider(e){return this.addSingletonFactory(e,(t,s)=>s)}addScopedFactory(e,t){let s,n,i=!1;if(typeof e=="string"||typeof e=="symbol")s=e,n=this.typeMap[s],i=!0;else{let y=this.resolveKeyAndType(e);s=y.key,n=y.type}let r=i?s:c(n),a={kind:"service",lifetime:"scoped",uid:r,type:n,factory:t};return this.definitions[s]=a,s!==r&&(this.definitions[r]=a),this}addSingletonClass(e,...t){let{key:s,type:n}=this.resolveKeyAndType(e),i=c(n),r={kind:"service",lifetime:"singleton",uid:i,type:n,params:t};return this.definitions[s]=r,this.definitions[i]=r,this}addScopedClass(e,...t){let{key:s,type:n}=this.resolveKeyAndType(e),i=c(n),r={kind:"service",lifetime:"scoped",uid:i,type:n,params:t};return this.definitions[s]=r,this.definitions[i]=r,this}addSingletonGroup(e,...t){let s={kind:"service",lifetime:"singleton",uid:e,type:t};this.typeMap[e]=t,this.definitions[e]=s;let n=t;for(let i of n){if(Reflect.ownKeys(this.typeMap).find(g=>this.typeMap[g]===i))continue;let a=i.name;if(!a)throw new l(`Class in group "${String(e)}" is missing a name and cannot be auto-registered.`);let y=c(i),d={kind:"service",lifetime:"singleton",uid:y,type:i,params:[]};this.typeMap[a]=i,this.definitions[a]=d,this.definitions[y]=d}return this}addScopedGroup(e,...t){let s={kind:"service",lifetime:"scoped",uid:e,type:t};this.typeMap[e]=t,this.definitions[e]=s;let n=t;for(let i of n){if(Reflect.ownKeys(this.typeMap).find(g=>this.typeMap[g]===i))continue;let a=i.name;if(!a)throw new l(`Class in group "${String(e)}" is missing a name and cannot be auto-registered.`);let y=c(i),d={kind:"service",lifetime:"scoped",uid:y,type:i,params:[]};this.typeMap[a]=i,this.definitions[a]=d,this.definitions[y]=d}return this}addSingletonFunc(e,t,...s){return this.definitions[e]={kind:"function",lifetime:"singleton",uid:e,func:t,params:s},this}addScopedFunc(e,t,...s){return this.definitions[e]={kind:"function",lifetime:"scoped",uid:e,func:t,params:s},this}addSingletonValue(e,t){return this.definitions[e]={kind:"value",lifetime:"singleton",uid:e,value:t},this}addScopedValue(e,t){return this.definitions[e]={kind:"value",lifetime:"scoped",uid:e,value:t},this}resolveKeyAndType(e){let t,s=Reflect.ownKeys(this.typeMap).find(n=>this.typeMap[n]===e);return s?t=s:(t=e.name||c(e),this.typeMap[t]=e),{key:t,type:e}}build(e="root"){for(let t of Reflect.ownKeys(this.definitions)){let s=this.definitions[t];if(!(s.kind!=="service"||!Array.isArray(s.type)))for(let n of s.type){let i=n.name,r=this.definitions[i];if(r&&r.params&&r.params.length===0&&n.length>0)throw new l(`Class "${i}" in group "${String(t)}" requires constructor arguments and must be registered independently using addSingletonClass or addScopedClass.`)}}return new m(e,this.definitions)}};0&&(module.exports={AsyncDisposalError,CircularDependencyError,RegistrationError,ServiceCollection,ServiceNotFoundError,ServiceProvider,ServiceProviderDisposedError});
|
|
2
2
|
//# sourceMappingURL=legacy.cjs.map
|
package/dist/legacy.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts", "../src/errors.ts", "../src/registry.ts", "../src/service-provider.ts", "../src/service-collection.ts"],
|
|
4
|
-
"sourcesContent": ["export * from './errors.js';\nexport * from './service-collection.js';\nexport * from './service-provider.js';\nexport * from './types.js';\n", "/**\n * Thrown when a circular dependency is detected.\n */\nexport class CircularDependencyError extends Error {\n constructor(path: string) {\n super(`Circular dependency detected: ${path}`);\n this.name = 'CircularDependencyError';\n }\n}\n\n/**\n * Thrown when a service cannot be resolved.\n */\nexport class ServiceNotFoundError extends Error {\n constructor(identifier: string) {\n super(`Service not registered for identifier: ${identifier}`);\n this.name = 'ServiceNotFoundError';\n }\n}\n\n/**\n * Thrown when a registration is invalid.\n */\nexport class RegistrationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'RegistrationError';\n }\n}\n\n/**\n * Thrown when a service provider has been disposed.\n */\nexport class ServiceProviderDisposedError extends Error {\n constructor() {\n super('ServiceProvider has been disposed and cannot resolve services.');\n this.name = 'ServiceProviderDisposedError';\n }\n}\n\n/**\n * Thrown when a synchronous dispose is called on a scope containing services that require asynchronous disposal.\n */\nexport class AsyncDisposalError extends Error {\n constructor(serviceKey: string) {\n super(`Service \"${serviceKey}\" requires asynchronous disposal but a synchronous dispose was called. Please use await disposeAsync() instead.`);\n this.name = 'AsyncDisposalError';\n }\n}\n", "import type { Class } from './types.js';\r\n\r\nconst classKeyRegistry = new WeakMap<Class, symbol>();\r\n\r\n/**\r\n * Resolves a stable Symbol for a given class constructor.\r\n * This is used to ensure that DI resolution remains stable even after minification.\r\n * @param type The class constructor.\r\n */\r\nexport function getStableKey(type: Class): symbol {\r\n let key = classKeyRegistry.get(type);\r\n if (!key) {\r\n key = Symbol(type.name || 'AnonymousClass');\r\n classKeyRegistry.set(type, key);\r\n }\r\n return key;\r\n}\r\n", "import {\n AsyncDisposalError,\n CircularDependencyError,\n ServiceNotFoundError,\n ServiceProviderDisposedError,\n} from './errors.js';\nimport { getStableKey } from './registry.js';\nimport type {\n Class,\n ConcreteClass,\n ImplementationFactory,\n IServiceProvider,\n MapToInstance,\n ResolvedTypeMap,\n ServiceDefinitionMap,\n TypeMap,\n} from './types.js';\n\nexport class ServiceProvider<T extends TypeMap> implements IServiceProvider<T> {\n private instances = new Map<string | symbol, any>();\n private resolving = new Set<string | symbol>();\n private path: (string | symbol)[] = [];\n private disposed = false;\n\n /**\n * @param name The name of the service provider.\n * @param definitions The service definitions map.\n * @param parent The parent service provider, if any.\n * @param isAsyncScope Whether this is an asynchronous scope.\n */\n constructor(\n public readonly name: string,\n private definitions: ServiceDefinitionMap,\n private parent?: ServiceProvider<T>,\n private readonly isAsyncScope: boolean = false\n ) { }\n\n /**\n * Creates a new scoped ServiceProvider.\n * @param name The name of the scope.\n * @example\n * const scope = di.createScope('request-scope');\n */\n createScope(name: string = 'scope'): IServiceProvider<T> {\n const root = this.parent || this;\n return new ServiceProvider<T>(name, this.definitions, root, false);\n }\n\n /**\n * Creates a new scoped ServiceProvider that supports asynchronous disposal.\n * @param name The name of the scope.\n * @example\n * const scope = di.createAsyncScope('worker-scope');\n */\n createAsyncScope(name: string = 'async-scope'): IServiceProvider<T> {\n const root = this.parent || this;\n return new ServiceProvider<T>(name, this.definitions, root, true);\n }\n\n /**\n * Resolves a service by its key.\n * @param key The key to resolve.\n * @example\n * const logger = di.getService('Logger');\n */\n getService<K extends keyof T & (string | symbol)>(key: K): MapToInstance<T[K]>;\n\n /**\n * Resolves a service by its Class type.\n * @param type The class type to resolve.\n * @example\n * const logger = di.getService(Logger);\n */\n getService<C extends Class>(type: C): InstanceType<C>;\n\n getService<K extends keyof T & (string | symbol)>(keyOrType: K | T[K]): MapToInstance<T[K]> {\n if (this.disposed) {\n throw new ServiceProviderDisposedError();\n }\n\n const key = this.getKey(keyOrType);\n\n if (this.parent && this.definitions[key]?.lifetime === 'singleton') {\n return this.parent.getService(key as any);\n }\n\n const item = this.definitions[key];\n if (!item) {\n const name = (typeof keyOrType === 'string' || typeof keyOrType === 'symbol')\n ? String(keyOrType)\n : (keyOrType as any).name || String(keyOrType);\n throw new ServiceNotFoundError(name);\n }\n\n const uid = item.uid;\n\n if (this.instances.has(uid)) {\n return this.instances.get(uid);\n }\n\n if (this.resolving.has(uid)) {\n const pathStr = this.path.map(k => (typeof k === 'symbol' ? k.description || String(k) : k)).concat(typeof key === 'symbol' ? key.description || String(key) : key).join(' -> ');\n throw new CircularDependencyError(pathStr);\n }\n\n this.resolving.add(uid);\n this.path.push(key);\n\n try {\n if (item.kind === 'value') return this.resolveValue(uid, item.value);\n\n if (Array.isArray(item.type)) return this.resolveArray(uid, item.type);\n\n if (item.kind === 'function' && item.func) return this.resolveFunc(uid, item.func, item.params);\n\n if (item.factory) return this.resolveFactory(uid, item.factory);\n\n return this.resolveClass(uid, item.type as Class, item.params);\n } finally {\n this.resolving.delete(uid);\n this.path.pop();\n }\n }\n\n /**\n * Synchronously disposes of all resolved services.\n * Throws AsyncDisposalError if this is an async scope or if any service disposal returns a Promise.\n */\n dispose(): void {\n if (this.disposed) return;\n\n if (this.isAsyncScope) {\n throw new AsyncDisposalError(this.name);\n }\n\n this.disposed = true;\n\n const entries = Array.from(this.instances.entries()).reverse();\n\n for (const [uid, inst] of entries) {\n if (inst && typeof inst.dispose === 'function') {\n const result = inst.dispose();\n if (result instanceof Promise) {\n throw new AsyncDisposalError(typeof uid === 'symbol' ? uid.description || String(uid) : String(uid));\n }\n } else if (inst && typeof inst.disposeAsync === 'function') {\n throw new AsyncDisposalError(typeof uid === 'symbol' ? uid.description || String(uid) : String(uid));\n }\n }\n\n this.instances.clear();\n }\n\n /**\n * Asynchronously disposes of all resolved services.\n */\n async disposeAsync(): Promise<void> {\n if (this.disposed) return;\n this.disposed = true;\n\n const entries = Array.from(this.instances.values()).reverse();\n\n for (const inst of entries) {\n if (inst && typeof inst.disposeAsync === 'function') {\n await inst.disposeAsync();\n } else if (inst && typeof inst.dispose === 'function') {\n const result = inst.dispose();\n if (result instanceof Promise) {\n await result;\n }\n }\n }\n\n this.instances.clear();\n }\n\n /**\n * Resolves a singleton value.\n * @param uid The unique ID of the value.\n * @param value The value to resolve.\n */\n private resolveValue(uid: string | symbol, value: any): any {\n this.instances.set(uid, value);\n return value;\n }\n\n /**\n * Resolves an array of services.\n * @param uid The unique ID of the service array.\n * @param types The class types to resolve for the array.\n */\n private resolveArray(uid: string | symbol, types: Class[]): any {\n const instances = types.map((cls) => {\n const inst = this.getService(cls);\n return inst;\n });\n\n this.instances.set(uid, instances);\n return instances;\n }\n\n /**\n * Resolves a service via a factory.\n * @param uid The unique ID of the service.\n * @param factory The factory to use for resolution.\n */\n private resolveFactory(uid: string | symbol, factory: ImplementationFactory<any, any>): any {\n const container = this.createContainerProxy();\n const result = factory(container, this);\n this.instances.set(uid, result);\n return result;\n }\n\n /**\n * Resolves a service via a function.\n * @param uid The unique ID of the service.\n * @param func The function to use for resolution.\n * @param params The arguments for the function.\n */\n private resolveFunc(uid: string | symbol, func: (...args: any[]) => any, params?: any[]): any {\n const rawParams = params || [];\n const resolvedParams = rawParams.map((param) => {\n const paramKey = this.tryGetKey(param);\n const inst = paramKey ? this.getService(paramKey) : param;\n return inst;\n });\n\n const result = func(...resolvedParams);\n this.instances.set(uid, result);\n return result;\n }\n\n /**\n * Resolves a service via its class type.\n * @param uid The unique ID of the service.\n * @param type The class type to instantiate.\n * @param params The constructor arguments.\n */\n private resolveClass(uid: string | symbol, type: Class, params?: any[]): any {\n const rawParams = params || [];\n const resolvedParams = rawParams.map((param) => {\n const paramKey = this.tryGetKey(param);\n const inst = paramKey ? this.getService(paramKey) : param;\n return inst;\n });\n\n const instance = new (type as ConcreteClass)(...resolvedParams);\n this.instances.set(uid, instance);\n return instance;\n }\n\n /**\n * Creates a proxy for the type map to allow resolving services by property access.\n */\n private createContainerProxy(): ResolvedTypeMap<T> {\n return new Proxy({} as ResolvedTypeMap<T>, {\n get: (_, prop) => {\n if (typeof prop !== 'string' && typeof prop !== 'symbol') return undefined;\n return this.getService(prop as any);\n }\n });\n }\n\n /**\n * Gets the key for a given key or class type.\n * @param keyOrType The key or class type.\n */\n private getKey<K extends keyof T & (string | symbol)>(keyOrType: K | T[K]): string | symbol {\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') return keyOrType;\n\n const key = this.tryGetKey(keyOrType);\n if (key) return key;\n\n const name = Array.isArray(keyOrType)\n ? `[${keyOrType.map((c: any) => (c as any).name).join(', ')}]`\n : (keyOrType as any).name || String(keyOrType);\n throw new ServiceNotFoundError(name);\n }\n\n /**\n * Attempts to get the key for a given key or class type without throwing.\n * @param keyOrType The key or class type.\n */\n private tryGetKey(keyOrType: any): string | symbol | undefined {\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') {\n if (keyOrType in this.definitions) return keyOrType;\n \n // Fallback for string names (backward compatibility)\n if (typeof keyOrType === 'string') {\n const entry = Reflect.ownKeys(this.definitions).find((k) => {\n const v = this.definitions[k as any];\n return v.kind === 'service' && !Array.isArray(v.type) && (v.type as any)?.name === keyOrType;\n });\n if (entry) return entry as string | symbol;\n }\n return undefined;\n }\n\n if (typeof keyOrType === 'function' || Array.isArray(keyOrType)) {\n // Check the stable registry first (minification proof)\n const stableKey = getStableKey(keyOrType as any);\n if (stableKey in this.definitions) return stableKey;\n\n // Fallback to searching by reference (for explicit symbols or non-auto registrations)\n const entry = Reflect.ownKeys(this.definitions).find((k) => {\n const v = this.definitions[k as any];\n return v.kind === 'service' && v.type === keyOrType;\n });\n if (entry) return entry as string | symbol;\n }\n\n return undefined;\n }\n}\n", "import {\n RegistrationError,\n} from './errors.js';\nimport { getStableKey } from './registry.js';\nimport { ServiceProvider } from './service-provider.js';\nimport type {\n Class,\n ClassArgs,\n FilterKeys,\n FilterValueKeys,\n FilterFuncKeys,\n FuncArgs,\n ImplementationFactory,\n MapToInstance,\n ServiceDefinitionMap,\n TypeMap,\n ServiceDefinition\n} from './types.js';\n\n/**\n * Fluent builder for service collections using a lookup map.\n */\nexport class ServiceCollection<T extends TypeMap> {\n private definitions: ServiceDefinitionMap = {};\n private typeMap: T;\n\n /**\n * Initializes a new instance of the ServiceCollection class.\n */\n constructor() {\n this.typeMap = {} as T;\n }\n\n /**\n * Adds a singleton service using a factory function.\n * Key is derived from the class.\n * @param type The class to register.\n * @param factory The factory function to create the service instance.\n * @example\n * .addSingletonFactory(UserRepo, (c) => new UserRepo(c.UserService))\n */\n addSingletonFactory<Key extends keyof T & (string | symbol), C extends Class>(\n type: C,\n factory: ImplementationFactory<T, InstanceType<C>>\n ): this;\n\n /**\n * Adds a singleton service using a factory function and a key.\n * @param key The key to register the service under.\n * @param factory The factory function to create the service instance.\n * @example\n * .addSingletonFactory(\"UserRepo\", (c) => new UserRepo(c.UserService))\n */\n addSingletonFactory<Key extends keyof T & (string | symbol)>(\n key: Key,\n factory: ImplementationFactory<T, MapToInstance<T[Key]>>\n ): this;\n\n addSingletonFactory<Key extends keyof T & (string | symbol)>(\n keyOrType: Key | Class,\n factory: ImplementationFactory<T, any>\n ): this {\n let key: string | symbol;\n let type: any;\n let isExplicitKey = false;\n\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') {\n key = keyOrType;\n type = this.typeMap[key];\n isExplicitKey = true;\n } else {\n const resolved = this.resolveKeyAndType<Key>(keyOrType as any);\n key = resolved.key;\n type = resolved.type;\n }\n\n const uid = isExplicitKey ? key : getStableKey(type);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid, type, factory };\n this.definitions[key] = def;\n if (key !== uid) this.definitions[uid] = def;\n\n return this;\n }\n\n /**\n * Registers the ServiceProvider itself as a service.\n * This allows services to depend on the ServiceProvider to resolve other services dynamically.\n * @param key The key to register the ServiceProvider under.\n * @example\n * .addServiceProvider(\"ServiceProvider\")\n */\n addServiceProvider<Key extends keyof T & (string | symbol)>(key: Key) {\n return this.addSingletonFactory(key as any, (_, sp) => sp)\n }\n\n /**\n * Adds a scoped service using a factory function.\n * Key is derived from the class.\n * @param type The class to register.\n * @param factory The factory function to create the service instance.\n * @example\n * .addScopedFactory(UserRepo, (c) => new UserRepo(c.UserService))\n */\n addScopedFactory<Key extends keyof T & (string | symbol), C extends Class>(\n type: C,\n factory: ImplementationFactory<T, InstanceType<C>>\n ): this;\n\n /**\n * Adds a scoped service using a factory function and a key.\n * @param key The key to register the service under.\n * @param factory The factory function to create the service instance.\n * @example\n * .addScopedFactory(\"UserRepo\", (c) => new UserRepo(c.UserService))\n */\n addScopedFactory<Key extends keyof T & (string | symbol)>(\n key: Key,\n factory: ImplementationFactory<T, MapToInstance<T[Key]>>\n ): this;\n\n addScopedFactory<Key extends keyof T & (string | symbol)>(\n keyOrType: Key | Class,\n factory: ImplementationFactory<T, any>\n ): this {\n let key: string | symbol;\n let type: any;\n let isExplicitKey = false;\n\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') {\n key = keyOrType;\n type = this.typeMap[key];\n isExplicitKey = true;\n } else {\n const resolved = this.resolveKeyAndType<Key>(keyOrType as any);\n key = resolved.key;\n type = resolved.type;\n }\n\n const uid = isExplicitKey ? key : getStableKey(type);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid, type, factory };\n this.definitions[key] = def;\n if (key !== uid) this.definitions[uid] = def;\n\n return this;\n }\n\n /**\n * Adds a singleton service using constructor injection.\n * Key is derived from the container map based on the Class.\n * @param type The class to register.\n * @param params The constructor arguments.\n * @example\n * .addSingletonClass(UserService, \"admin\", \"password\")\n */\n addSingletonClass<C extends Class>(\n type: C,\n ...params: ClassArgs<C, keyof T & (string | symbol)>\n ): this {\n const { key, type: typeRef } = this.resolveKeyAndType(type as any);\n const uid = getStableKey(typeRef);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid, type: typeRef, params };\n this.definitions[key] = def;\n this.definitions[uid] = def;\n return this;\n }\n\n /**\n * Adds a scoped service using constructor injection.\n * Key is derived from the container map based on the Class.\n * @param type The class to register.\n * @param params The constructor arguments.\n * @example\n * .addScopedClass(UserService, \"admin\", \"password\")\n */\n addScopedClass<C extends Class>(\n type: C,\n ...params: ClassArgs<C, keyof T & (string | symbol)>\n ): this {\n const { key, type: typeRef } = this.resolveKeyAndType(type as any);\n const uid = getStableKey(typeRef);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid, type: typeRef, params };\n this.definitions[key] = def;\n this.definitions[uid] = def;\n return this;\n }\n\n /**\n * Adds an array of singleton services.\n * Automatically registers individual classes if not already registered.\n * @param key The key for the service array.\n * @param types The classes to register in the array.\n * @example\n * .addSingletonArray(\"MessageCommand\", HelloCommand, ByeCommand)\n */\n addSingletonArray<\n Key extends FilterKeys<T, any[]>,\n C extends (new (...args: any[]) => MapToInstance<T[Key]>[number])[]\n >(\n key: Key,\n ...types: C\n ): this {\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid: key, type: types };\n (this.typeMap as any)[key] = types;\n this.definitions[key] = def;\n\n // Auto-register individual classes if not already registered\n const typeArray = types as Class[];\n for (const type of typeArray) {\n const foundKey = Reflect.ownKeys(this.typeMap).find(k => this.typeMap[k as any] === type);\n if (foundKey) continue;\n\n const name = type.name;\n if (!name) {\n throw new RegistrationError(`Class in array \"${String(key)}\" is missing a name and cannot be auto-registered.`);\n }\n\n const uid = getStableKey(type);\n const classDef: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid, type, params: [] };\n (this.typeMap as any)[name] = type;\n this.definitions[name] = classDef;\n this.definitions[uid] = classDef;\n }\n\n return this;\n }\n\n /**\n * Adds an array of scoped services.\n * Automatically registers individual classes as scoped if not already registered.\n * @param key The key for the service array.\n * @param types The classes to register in the array.\n * @example\n * .addScopedArray(\"MessageCommand\", HelloCommand, ByeCommand)\n */\n addScopedArray<\n Key extends FilterKeys<T, any[]>,\n C extends (new (...args: any[]) => MapToInstance<T[Key]>[number])[]\n >(\n key: Key,\n ...types: C\n ): this {\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid: key, type: types };\n (this.typeMap as any)[key] = types;\n this.definitions[key] = def;\n\n // Auto-register individual classes if not already registered\n const typeArray = types as Class[];\n for (const type of typeArray) {\n const foundKey = Reflect.ownKeys(this.typeMap).find(k => this.typeMap[k as any] === type);\n if (foundKey) continue;\n\n const name = type.name;\n if (!name) {\n throw new RegistrationError(`Class in array \"${String(key)}\" is missing a name and cannot be auto-registered.`);\n }\n\n const uid = getStableKey(type);\n const classDef: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid, type, params: [] };\n (this.typeMap as any)[name] = type;\n this.definitions[name] = classDef;\n this.definitions[uid] = classDef;\n }\n\n return this;\n }\n\n /**\n * Adds a singleton service using a function.\n * @param key The key for the service.\n * @param func The function to register.\n * @param params The function arguments.\n * @example\n * .addSingletonFunc(\"Logger\", createLogger, \"Config\")\n */\n addSingletonFunc<Key extends FilterFuncKeys<T>, F extends (...args: any[]) => T[Key]>(\n key: Key,\n func: F,\n ...params: FuncArgs<F, T>\n ): this {\n this.definitions[key] = { kind: 'function', lifetime: 'singleton', uid: key, func, params };\n return this;\n }\n\n /**\n * Adds a scoped service using a function.\n * @param key The key for the service.\n * @param func The function to register.\n * @param params The function arguments.\n * @example\n * .addScopedFunc(\"Logger\", createLogger, \"Config\")\n */\n addScopedFunc<Key extends FilterFuncKeys<T>, F extends (...args: any[]) => T[Key]>(\n key: Key,\n func: F,\n ...params: FuncArgs<F, T>\n ): this {\n this.definitions[key] = { kind: 'function', lifetime: 'scoped', uid: key, func, params };\n return this;\n }\n\n /**\n * Adds a singleton value.\n * @param key The key for the value.\n * @param value The value to register.\n * @example\n * .addSingletonValue(\"connectionString\", \"test connection string\")\n */\n addSingletonValue<Key extends FilterValueKeys<T>>(\n key: Key,\n value: T[Key]\n ): this {\n this.definitions[key] = { kind: 'value', lifetime: 'singleton', uid: key, value };\n return this;\n }\n\n /**\n * Adds a scoped value.\n * @param key The key for the value.\n * @param value The value to register.\n * @example\n * .addScopedValue(\"connectionString\", \"test connection string\")\n */\n addScopedValue<Key extends FilterValueKeys<T>>(\n key: Key,\n value: T[Key]\n ): this {\n this.definitions[key] = { kind: 'value', lifetime: 'scoped', uid: key, value };\n return this;\n }\n\n /**\n * Resolves the string key and Class reference for a given type.\n * If the type is already mapped in the TypeMap, the existing key is used.\n * Otherwise, it auto-registers the type using its class name as the key.\n * @param type The class reference to resolve.\n * @throws RegistrationError if the class name cannot be determined (e.g. anonymous class).\n * @example\n * const { key, type } = this.resolveKeyAndType(UserService);\n */\n private resolveKeyAndType<Key extends keyof T & (string | symbol)>(type: T[Key] & Class): { key: Key, type: T[Key] } {\n let key: Key;\n\n const foundKey = Reflect.ownKeys(this.typeMap).find(\n (k) => this.typeMap[k as any] === type\n );\n if (foundKey) {\n key = foundKey as Key;\n } else {\n // Auto-register using class name for backward compatibility\n key = (type.name || getStableKey(type)) as any as Key;\n (this.typeMap as any)[key] = type;\n }\n\n return { key, type };\n }\n\n /**\n * Builds the ServiceProvider.\n * @param name The name of the service provider.\n * @example\n * const di = new ServiceCollection<LocalMap>()\n * .addSingletonClass(MyService)\n * .build();\n */\n build(name: string = 'root'): ServiceProvider<T> {\n // Validate all registered services\n for (const key of Reflect.ownKeys(this.definitions)) {\n const item = this.definitions[key as any];\n if (item.kind !== 'service' || !Array.isArray(item.type)) continue;\n\n // This is an array of services\n for (const type of item.type as Class[]) {\n const name = type.name;\n const definitionsItem = this.definitions[name];\n\n // Check if this class was auto-registered (params is empty array) but requires arguments\n if (definitionsItem && definitionsItem.params && definitionsItem.params.length === 0 && type.length > 0) {\n throw new RegistrationError(`Class \"${name}\" in array \"${String(key)}\" requires constructor arguments and must be registered independently using addSingletonClass or addScopedClass.`);\n }\n }\n }\n\n return new ServiceProvider<T>(name, this.definitions);\n }\n}\n"],
|
|
4
|
+
"sourcesContent": ["export * from './errors.js';\nexport * from './service-collection.js';\nexport * from './service-provider.js';\nexport * from './types.js';\n", "/**\n * Thrown when a circular dependency is detected.\n */\nexport class CircularDependencyError extends Error {\n constructor(path: string) {\n super(`Circular dependency detected: ${path}`);\n this.name = 'CircularDependencyError';\n }\n}\n\n/**\n * Thrown when a service cannot be resolved.\n */\nexport class ServiceNotFoundError extends Error {\n constructor(identifier: string) {\n super(`Service not registered for identifier: ${identifier}`);\n this.name = 'ServiceNotFoundError';\n }\n}\n\n/**\n * Thrown when a registration is invalid.\n */\nexport class RegistrationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'RegistrationError';\n }\n}\n\n/**\n * Thrown when a service provider has been disposed.\n */\nexport class ServiceProviderDisposedError extends Error {\n constructor() {\n super('ServiceProvider has been disposed and cannot resolve services.');\n this.name = 'ServiceProviderDisposedError';\n }\n}\n\n/**\n * Thrown when a synchronous dispose is called on a scope containing services that require asynchronous disposal.\n */\nexport class AsyncDisposalError extends Error {\n constructor(serviceKey: string) {\n super(`Service \"${serviceKey}\" requires asynchronous disposal but a synchronous dispose was called. Please use await disposeAsync() instead.`);\n this.name = 'AsyncDisposalError';\n }\n}\n", "import type { Class } from './types.js';\r\n\r\nconst classKeyRegistry = new WeakMap<Class, symbol>();\r\n\r\n/**\r\n * Resolves a stable Symbol for a given class constructor.\r\n * This is used to ensure that DI resolution remains stable even after minification.\r\n * @param type The class constructor.\r\n */\r\nexport function getStableKey(type: Class): symbol {\r\n let key = classKeyRegistry.get(type);\r\n if (!key) {\r\n key = Symbol(type.name || 'AnonymousClass');\r\n classKeyRegistry.set(type, key);\r\n }\r\n return key;\r\n}\r\n", "import {\n AsyncDisposalError,\n CircularDependencyError,\n ServiceNotFoundError,\n ServiceProviderDisposedError,\n} from './errors.js';\nimport { getStableKey } from './registry.js';\nimport type {\n Class,\n ConcreteClass,\n ImplementationFactory,\n IServiceProvider,\n MapToInstance,\n ResolvedTypeMap,\n ServiceDefinitionMap,\n TypeMap,\n} from './types.js';\n\nexport class ServiceProvider<T extends TypeMap> implements IServiceProvider<T> {\n private instances = new Map<string | symbol, any>();\n private resolving = new Set<string | symbol>();\n private path: (string | symbol)[] = [];\n private disposed = false;\n\n /**\n * @param name The name of the service provider.\n * @param definitions The service definitions map.\n * @param parent The parent service provider, if any.\n * @param isAsyncScope Whether this is an asynchronous scope.\n */\n constructor(\n public readonly name: string,\n private definitions: ServiceDefinitionMap,\n private parent?: ServiceProvider<T>,\n private readonly isAsyncScope: boolean = false\n ) { }\n\n /**\n * Creates a new scoped ServiceProvider.\n * @param name The name of the scope.\n * @example\n * const scope = di.createScope('request-scope');\n */\n createScope(name: string = 'scope'): IServiceProvider<T> {\n const root = this.parent || this;\n return new ServiceProvider<T>(name, this.definitions, root, false);\n }\n\n /**\n * Creates a new scoped ServiceProvider that supports asynchronous disposal.\n * @param name The name of the scope.\n * @example\n * const scope = di.createAsyncScope('worker-scope');\n */\n createAsyncScope(name: string = 'async-scope'): IServiceProvider<T> {\n const root = this.parent || this;\n return new ServiceProvider<T>(name, this.definitions, root, true);\n }\n\n /**\n * Resolves a service by its key.\n * @param key The key to resolve.\n * @example\n * const logger = di.getService('Logger');\n */\n getService<K extends keyof T & (string | symbol)>(key: K): MapToInstance<T[K]>;\n\n /**\n * Resolves a service by its Class type.\n * @param type The class type to resolve.\n * @example\n * const logger = di.getService(Logger);\n */\n getService<C extends Class>(type: C): InstanceType<C>;\n\n getService<K extends keyof T & (string | symbol)>(keyOrType: K | T[K]): MapToInstance<T[K]> {\n if (this.disposed) {\n throw new ServiceProviderDisposedError();\n }\n\n const key = this.getKey(keyOrType);\n\n if (this.parent && this.definitions[key]?.lifetime === 'singleton') {\n return this.parent.getService(key as any);\n }\n\n const item = this.definitions[key];\n if (!item) {\n const name = (typeof keyOrType === 'string' || typeof keyOrType === 'symbol')\n ? String(keyOrType)\n : (keyOrType as any).name || String(keyOrType);\n throw new ServiceNotFoundError(name);\n }\n\n const uid = item.uid;\n\n if (this.instances.has(uid)) {\n return this.instances.get(uid);\n }\n\n if (this.resolving.has(uid)) {\n const pathStr = this.path.map(k => (typeof k === 'symbol' ? k.description || String(k) : k)).concat(typeof key === 'symbol' ? key.description || String(key) : key).join(' -> ');\n throw new CircularDependencyError(pathStr);\n }\n\n this.resolving.add(uid);\n this.path.push(key);\n\n try {\n if (item.kind === 'value') return this.resolveValue(uid, item.value);\n\n if (Array.isArray(item.type)) return this.resolveArray(uid, item.type);\n\n if (item.kind === 'function' && item.func) return this.resolveFunc(uid, item.func, item.params);\n\n if (item.factory) return this.resolveFactory(uid, item.factory);\n\n return this.resolveClass(uid, item.type as Class, item.params);\n } finally {\n this.resolving.delete(uid);\n this.path.pop();\n }\n }\n\n /**\n * Synchronously disposes of all resolved services.\n * Throws AsyncDisposalError if this is an async scope or if any service disposal returns a Promise.\n */\n dispose(): void {\n if (this.disposed) return;\n\n if (this.isAsyncScope) {\n throw new AsyncDisposalError(this.name);\n }\n\n this.disposed = true;\n\n const entries = Array.from(this.instances.entries()).reverse();\n\n for (const [uid, inst] of entries) {\n if (inst && typeof inst.dispose === 'function') {\n const result = inst.dispose();\n if (result instanceof Promise) {\n throw new AsyncDisposalError(typeof uid === 'symbol' ? uid.description || String(uid) : String(uid));\n }\n } else if (inst && typeof inst.disposeAsync === 'function') {\n throw new AsyncDisposalError(typeof uid === 'symbol' ? uid.description || String(uid) : String(uid));\n }\n }\n\n this.instances.clear();\n }\n\n /**\n * Asynchronously disposes of all resolved services.\n */\n async disposeAsync(): Promise<void> {\n if (this.disposed) return;\n this.disposed = true;\n\n const entries = Array.from(this.instances.values()).reverse();\n\n for (const inst of entries) {\n if (inst && typeof inst.disposeAsync === 'function') {\n await inst.disposeAsync();\n } else if (inst && typeof inst.dispose === 'function') {\n const result = inst.dispose();\n if (result instanceof Promise) {\n await result;\n }\n }\n }\n\n this.instances.clear();\n }\n\n /**\n * Resolves a singleton value.\n * @param uid The unique ID of the value.\n * @param value The value to resolve.\n */\n private resolveValue(uid: string | symbol, value: any): any {\n this.instances.set(uid, value);\n return value;\n }\n\n /**\n * Resolves an array of services.\n * @param uid The unique ID of the service array.\n * @param types The class types to resolve for the array.\n */\n private resolveArray(uid: string | symbol, types: Class[]): any {\n const instances = types.map((cls) => {\n const inst = this.getService(cls);\n return inst;\n });\n\n this.instances.set(uid, instances);\n return instances;\n }\n\n /**\n * Resolves a service via a factory.\n * @param uid The unique ID of the service.\n * @param factory The factory to use for resolution.\n */\n private resolveFactory(uid: string | symbol, factory: ImplementationFactory<any, any>): any {\n const container = this.createContainerProxy();\n const result = factory(container, this);\n this.instances.set(uid, result);\n return result;\n }\n\n /**\n * Resolves a service via a function.\n * @param uid The unique ID of the service.\n * @param func The function to use for resolution.\n * @param params The arguments for the function.\n */\n private resolveFunc(uid: string | symbol, func: (...args: any[]) => any, params?: any[]): any {\n const rawParams = params || [];\n const resolvedParams = rawParams.map((param) => {\n const paramKey = this.tryGetKey(param);\n const inst = paramKey ? this.getService(paramKey) : param;\n return inst;\n });\n\n const result = func(...resolvedParams);\n this.instances.set(uid, result);\n return result;\n }\n\n /**\n * Resolves a service via its class type.\n * @param uid The unique ID of the service.\n * @param type The class type to instantiate.\n * @param params The constructor arguments.\n */\n private resolveClass(uid: string | symbol, type: Class, params?: any[]): any {\n const rawParams = params || [];\n const resolvedParams = rawParams.map((param) => {\n const paramKey = this.tryGetKey(param);\n const inst = paramKey ? this.getService(paramKey) : param;\n return inst;\n });\n\n const instance = new (type as ConcreteClass)(...resolvedParams);\n this.instances.set(uid, instance);\n return instance;\n }\n\n /**\n * Creates a proxy for the type map to allow resolving services by property access.\n */\n private createContainerProxy(): ResolvedTypeMap<T> {\n return new Proxy({} as ResolvedTypeMap<T>, {\n get: (_, prop) => {\n if (typeof prop !== 'string' && typeof prop !== 'symbol') return undefined;\n return this.getService(prop as any);\n }\n });\n }\n\n /**\n * Gets the key for a given key or class type.\n * @param keyOrType The key or class type.\n */\n private getKey<K extends keyof T & (string | symbol)>(keyOrType: K | T[K]): string | symbol {\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') return keyOrType;\n\n const key = this.tryGetKey(keyOrType);\n if (key) return key;\n\n const name = Array.isArray(keyOrType)\n ? `[${keyOrType.map((c: any) => (c as any).name).join(', ')}]`\n : (keyOrType as any).name || String(keyOrType);\n throw new ServiceNotFoundError(name);\n }\n\n /**\n * Attempts to get the key for a given key or class type without throwing.\n * @param keyOrType The key or class type.\n */\n private tryGetKey(keyOrType: any): string | symbol | undefined {\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') {\n if (keyOrType in this.definitions) return keyOrType;\n \n // Fallback for string names (backward compatibility)\n if (typeof keyOrType === 'string') {\n const entry = Reflect.ownKeys(this.definitions).find((k) => {\n const v = this.definitions[k as any];\n return v.kind === 'service' && !Array.isArray(v.type) && (v.type as any)?.name === keyOrType;\n });\n if (entry) return entry as string | symbol;\n }\n return undefined;\n }\n\n if (typeof keyOrType === 'function' || Array.isArray(keyOrType)) {\n // Check the stable registry first (minification proof)\n const stableKey = getStableKey(keyOrType as any);\n if (stableKey in this.definitions) return stableKey;\n\n // Fallback to searching by reference (for explicit symbols or non-auto registrations)\n const entry = Reflect.ownKeys(this.definitions).find((k) => {\n const v = this.definitions[k as any];\n return v.kind === 'service' && v.type === keyOrType;\n });\n if (entry) return entry as string | symbol;\n }\n\n return undefined;\n }\n}\n", "import {\n RegistrationError,\n} from './errors.js';\nimport { getStableKey } from './registry.js';\nimport { ServiceProvider } from './service-provider.js';\nimport type {\n Class,\n ClassArgs,\n FilterKeys,\n FilterValueKeys,\n FilterFuncKeys,\n FuncArgs,\n ImplementationFactory,\n MapToInstance,\n ServiceDefinitionMap,\n TypeMap,\n ServiceDefinition\n} from './types.js';\n\n/**\n * Fluent builder for service collections using a lookup map.\n */\nexport class ServiceCollection<T extends TypeMap> {\n private definitions: ServiceDefinitionMap = {};\n private typeMap: T;\n\n /**\n * Initializes a new instance of the ServiceCollection class.\n */\n constructor() {\n this.typeMap = {} as T;\n }\n\n /**\n * Adds a singleton service using a factory function.\n * Key is derived from the class.\n * @param type The class to register.\n * @param factory The factory function to create the service instance.\n * @example\n * .addSingletonFactory(UserRepo, (c) => new UserRepo(c.UserService))\n */\n addSingletonFactory<Key extends keyof T & (string | symbol), C extends Class>(\n type: C,\n factory: ImplementationFactory<T, InstanceType<C>>\n ): this;\n\n /**\n * Adds a singleton service using a factory function and a key.\n * @param key The key to register the service under.\n * @param factory The factory function to create the service instance.\n * @example\n * .addSingletonFactory(\"UserRepo\", (c) => new UserRepo(c.UserService))\n */\n addSingletonFactory<Key extends keyof T & (string | symbol)>(\n key: Key,\n factory: ImplementationFactory<T, MapToInstance<T[Key]>>\n ): this;\n\n addSingletonFactory<Key extends keyof T & (string | symbol)>(\n keyOrType: Key | Class,\n factory: ImplementationFactory<T, any>\n ): this {\n let key: string | symbol;\n let type: any;\n let isExplicitKey = false;\n\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') {\n key = keyOrType;\n type = this.typeMap[key];\n isExplicitKey = true;\n } else {\n const resolved = this.resolveKeyAndType<Key>(keyOrType as any);\n key = resolved.key;\n type = resolved.type;\n }\n\n const uid = isExplicitKey ? key : getStableKey(type);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid, type, factory };\n this.definitions[key] = def;\n if (key !== uid) this.definitions[uid] = def;\n\n return this;\n }\n\n /**\n * Registers the ServiceProvider itself as a service.\n * This allows services to depend on the ServiceProvider to resolve other services dynamically.\n * @param key The key to register the ServiceProvider under.\n * @example\n * .addServiceProvider(\"ServiceProvider\")\n */\n addServiceProvider<Key extends keyof T & (string | symbol)>(key: Key) {\n return this.addSingletonFactory(key as any, (_, sp) => sp)\n }\n\n /**\n * Adds a scoped service using a factory function.\n * Key is derived from the class.\n * @param type The class to register.\n * @param factory The factory function to create the service instance.\n * @example\n * .addScopedFactory(UserRepo, (c) => new UserRepo(c.UserService))\n */\n addScopedFactory<Key extends keyof T & (string | symbol), C extends Class>(\n type: C,\n factory: ImplementationFactory<T, InstanceType<C>>\n ): this;\n\n /**\n * Adds a scoped service using a factory function and a key.\n * @param key The key to register the service under.\n * @param factory The factory function to create the service instance.\n * @example\n * .addScopedFactory(\"UserRepo\", (c) => new UserRepo(c.UserService))\n */\n addScopedFactory<Key extends keyof T & (string | symbol)>(\n key: Key,\n factory: ImplementationFactory<T, MapToInstance<T[Key]>>\n ): this;\n\n addScopedFactory<Key extends keyof T & (string | symbol)>(\n keyOrType: Key | Class,\n factory: ImplementationFactory<T, any>\n ): this {\n let key: string | symbol;\n let type: any;\n let isExplicitKey = false;\n\n if (typeof keyOrType === 'string' || typeof keyOrType === 'symbol') {\n key = keyOrType;\n type = this.typeMap[key];\n isExplicitKey = true;\n } else {\n const resolved = this.resolveKeyAndType<Key>(keyOrType as any);\n key = resolved.key;\n type = resolved.type;\n }\n\n const uid = isExplicitKey ? key : getStableKey(type);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid, type, factory };\n this.definitions[key] = def;\n if (key !== uid) this.definitions[uid] = def;\n\n return this;\n }\n\n /**\n * Adds a singleton service using constructor injection.\n * Key is derived from the container map based on the Class.\n * @param type The class to register.\n * @param params The constructor arguments.\n * @example\n * .addSingletonClass(UserService, \"admin\", \"password\")\n */\n addSingletonClass<C extends Class>(\n type: C,\n ...params: ClassArgs<C, keyof T & (string | symbol)>\n ): this {\n const { key, type: typeRef } = this.resolveKeyAndType(type as any);\n const uid = getStableKey(typeRef);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid, type: typeRef, params };\n this.definitions[key] = def;\n this.definitions[uid] = def;\n return this;\n }\n\n /**\n * Adds a scoped service using constructor injection.\n * Key is derived from the container map based on the Class.\n * @param type The class to register.\n * @param params The constructor arguments.\n * @example\n * .addScopedClass(UserService, \"admin\", \"password\")\n */\n addScopedClass<C extends Class>(\n type: C,\n ...params: ClassArgs<C, keyof T & (string | symbol)>\n ): this {\n const { key, type: typeRef } = this.resolveKeyAndType(type as any);\n const uid = getStableKey(typeRef);\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid, type: typeRef, params };\n this.definitions[key] = def;\n this.definitions[uid] = def;\n return this;\n }\n\n /**\n * Adds a group (array) of singleton services.\n * Automatically registers individual classes as singletons if not already registered.\n * @param key The key for the service group.\n * @param types The classes to register in the group.\n * @example\n * .addSingletonGroup(\"MessageCommand\", HelloCommand, ByeCommand)\n */\n addSingletonGroup<\n Key extends FilterKeys<T, any[]>,\n C extends (new (...args: any[]) => MapToInstance<T[Key]>[number])[]\n >(\n key: Key,\n ...types: C\n ): this {\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid: key, type: types };\n (this.typeMap as any)[key] = types;\n this.definitions[key] = def;\n\n // Auto-register individual classes if not already registered\n const typeArray = types as Class[];\n for (const type of typeArray) {\n const foundKey = Reflect.ownKeys(this.typeMap).find(k => this.typeMap[k as any] === type);\n if (foundKey) continue;\n\n const name = type.name;\n if (!name) {\n throw new RegistrationError(`Class in group \"${String(key)}\" is missing a name and cannot be auto-registered.`);\n }\n\n const uid = getStableKey(type);\n const classDef: ServiceDefinition<any> = { kind: 'service', lifetime: 'singleton', uid, type, params: [] };\n (this.typeMap as any)[name] = type;\n this.definitions[name] = classDef;\n this.definitions[uid] = classDef;\n }\n\n return this;\n }\n\n /**\n * Adds a group (array) of scoped services.\n * Automatically registers individual classes as scoped if not already registered.\n * @param key The key for the service group.\n * @param types The classes to register in the group.\n * @example\n * .addScopedGroup(\"MessageCommand\", HelloCommand, ByeCommand)\n */\n addScopedGroup<\n Key extends FilterKeys<T, any[]>,\n C extends (new (...args: any[]) => MapToInstance<T[Key]>[number])[]\n >(\n key: Key,\n ...types: C\n ): this {\n const def: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid: key, type: types };\n (this.typeMap as any)[key] = types;\n this.definitions[key] = def;\n\n // Auto-register individual classes if not already registered\n const typeArray = types as Class[];\n for (const type of typeArray) {\n const foundKey = Reflect.ownKeys(this.typeMap).find(k => this.typeMap[k as any] === type);\n if (foundKey) continue;\n\n const name = type.name;\n if (!name) {\n throw new RegistrationError(`Class in group \"${String(key)}\" is missing a name and cannot be auto-registered.`);\n }\n\n const uid = getStableKey(type);\n const classDef: ServiceDefinition<any> = { kind: 'service', lifetime: 'scoped', uid, type, params: [] };\n (this.typeMap as any)[name] = type;\n this.definitions[name] = classDef;\n this.definitions[uid] = classDef;\n }\n\n return this;\n }\n\n /**\n * Adds a singleton service using a function.\n * @param key The key for the service.\n * @param func The function to register.\n * @param params The function arguments.\n * @example\n * .addSingletonFunc(\"Logger\", createLogger, \"Config\")\n */\n addSingletonFunc<Key extends FilterFuncKeys<T>, F extends (...args: any[]) => T[Key]>(\n key: Key,\n func: F,\n ...params: FuncArgs<F, T>\n ): this {\n this.definitions[key] = { kind: 'function', lifetime: 'singleton', uid: key, func, params };\n return this;\n }\n\n /**\n * Adds a scoped service using a function.\n * @param key The key for the service.\n * @param func The function to register.\n * @param params The function arguments.\n * @example\n * .addScopedFunc(\"Logger\", createLogger, \"Config\")\n */\n addScopedFunc<Key extends FilterFuncKeys<T>, F extends (...args: any[]) => T[Key]>(\n key: Key,\n func: F,\n ...params: FuncArgs<F, T>\n ): this {\n this.definitions[key] = { kind: 'function', lifetime: 'scoped', uid: key, func, params };\n return this;\n }\n\n /**\n * Adds a singleton value.\n * @param key The key for the value.\n * @param value The value to register.\n * @example\n * .addSingletonValue(\"connectionString\", \"test connection string\")\n */\n addSingletonValue<Key extends FilterValueKeys<T>>(\n key: Key,\n value: T[Key]\n ): this {\n this.definitions[key] = { kind: 'value', lifetime: 'singleton', uid: key, value };\n return this;\n }\n\n /**\n * Adds a scoped value.\n * @param key The key for the value.\n * @param value The value to register.\n * @example\n * .addScopedValue(\"connectionString\", \"test connection string\")\n */\n addScopedValue<Key extends FilterValueKeys<T>>(\n key: Key,\n value: T[Key]\n ): this {\n this.definitions[key] = { kind: 'value', lifetime: 'scoped', uid: key, value };\n return this;\n }\n\n /**\n * Resolves the string key and Class reference for a given type.\n * If the type is already mapped in the TypeMap, the existing key is used.\n * Otherwise, it auto-registers the type using its class name as the key.\n * @param type The class reference to resolve.\n * @throws RegistrationError if the class name cannot be determined (e.g. anonymous class).\n * @example\n * const { key, type } = this.resolveKeyAndType(UserService);\n */\n private resolveKeyAndType<Key extends keyof T & (string | symbol)>(type: T[Key] & Class): { key: Key, type: T[Key] } {\n let key: Key;\n\n const foundKey = Reflect.ownKeys(this.typeMap).find(\n (k) => this.typeMap[k as any] === type\n );\n if (foundKey) {\n key = foundKey as Key;\n } else {\n // Auto-register using class name for backward compatibility\n key = (type.name || getStableKey(type)) as any as Key;\n (this.typeMap as any)[key] = type;\n }\n\n return { key, type };\n }\n\n /**\n * Builds the ServiceProvider.\n * @param name The name of the service provider.\n * @example\n * const di = new ServiceCollection<LocalMap>()\n * .addSingletonClass(MyService)\n * .build();\n */\n build(name: string = 'root'): ServiceProvider<T> {\n // Validate all registered services\n for (const key of Reflect.ownKeys(this.definitions)) {\n const item = this.definitions[key as any];\n if (item.kind !== 'service' || !Array.isArray(item.type)) continue;\n\n // This is an array of services\n for (const type of item.type as Class[]) {\n const name = type.name;\n const definitionsItem = this.definitions[name];\n\n // Check if this class was auto-registered (params is empty array) but requires arguments\n if (definitionsItem && definitionsItem.params && definitionsItem.params.length === 0 && type.length > 0) {\n throw new RegistrationError(`Class \"${name}\" in group \"${String(key)}\" requires constructor arguments and must be registered independently using addSingletonClass or addScopedClass.`);\n }\n }\n }\n\n return new ServiceProvider<T>(name, this.definitions);\n }\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["index_exports", "__export", "AsyncDisposalError", "CircularDependencyError", "RegistrationError", "ServiceCollection", "ServiceNotFoundError", "ServiceProvider", "ServiceProviderDisposedError", "__toCommonJS", "CircularDependencyError", "path", "ServiceNotFoundError", "identifier", "RegistrationError", "message", "ServiceProviderDisposedError", "AsyncDisposalError", "serviceKey", "classKeyRegistry", "getStableKey", "type", "key", "ServiceProvider", "_ServiceProvider", "name", "definitions", "parent", "isAsyncScope", "root", "keyOrType", "ServiceProviderDisposedError", "key", "item", "ServiceNotFoundError", "uid", "pathStr", "k", "CircularDependencyError", "AsyncDisposalError", "entries", "inst", "result", "value", "types", "instances", "cls", "factory", "container", "func", "params", "resolvedParams", "param", "paramKey", "type", "instance", "_", "prop", "c", "entry", "v", "stableKey", "getStableKey", "ServiceCollection", "keyOrType", "factory", "key", "type", "isExplicitKey", "resolved", "uid", "getStableKey", "def", "_", "sp", "params", "typeRef", "types", "typeArray", "k", "name", "RegistrationError", "classDef", "func", "value", "foundKey", "item", "definitionsItem", "ServiceProvider"]
|
|
7
7
|
}
|
|
@@ -71,23 +71,23 @@ export declare class ServiceCollection<T extends TypeMap> {
|
|
|
71
71
|
*/
|
|
72
72
|
addScopedClass<C extends Class>(type: C, ...params: ClassArgs<C, keyof T & (string | symbol)>): this;
|
|
73
73
|
/**
|
|
74
|
-
* Adds
|
|
75
|
-
* Automatically registers individual classes if not already registered.
|
|
76
|
-
* @param key The key for the service
|
|
77
|
-
* @param types The classes to register in the
|
|
74
|
+
* Adds a group (array) of singleton services.
|
|
75
|
+
* Automatically registers individual classes as singletons if not already registered.
|
|
76
|
+
* @param key The key for the service group.
|
|
77
|
+
* @param types The classes to register in the group.
|
|
78
78
|
* @example
|
|
79
|
-
* .
|
|
79
|
+
* .addSingletonGroup("MessageCommand", HelloCommand, ByeCommand)
|
|
80
80
|
*/
|
|
81
|
-
|
|
81
|
+
addSingletonGroup<Key extends FilterKeys<T, any[]>, C extends (new (...args: any[]) => MapToInstance<T[Key]>[number])[]>(key: Key, ...types: C): this;
|
|
82
82
|
/**
|
|
83
|
-
* Adds
|
|
83
|
+
* Adds a group (array) of scoped services.
|
|
84
84
|
* Automatically registers individual classes as scoped if not already registered.
|
|
85
|
-
* @param key The key for the service
|
|
86
|
-
* @param types The classes to register in the
|
|
85
|
+
* @param key The key for the service group.
|
|
86
|
+
* @param types The classes to register in the group.
|
|
87
87
|
* @example
|
|
88
|
-
* .
|
|
88
|
+
* .addScopedGroup("MessageCommand", HelloCommand, ByeCommand)
|
|
89
89
|
*/
|
|
90
|
-
|
|
90
|
+
addScopedGroup<Key extends FilterKeys<T, any[]>, C extends (new (...args: any[]) => MapToInstance<T[Key]>[number])[]>(key: Key, ...types: C): this;
|
|
91
91
|
/**
|
|
92
92
|
* Adds a singleton service using a function.
|
|
93
93
|
* @param key The key for the service.
|
|
@@ -36,11 +36,11 @@ export interface IServiceProvider<T extends TypeMap> {
|
|
|
36
36
|
/**
|
|
37
37
|
* Creates a new scoped ServiceProvider.
|
|
38
38
|
*/
|
|
39
|
-
createScope(): IServiceProvider<T>;
|
|
39
|
+
createScope(name?: string): IServiceProvider<T>;
|
|
40
40
|
/**
|
|
41
41
|
* Creates a new scoped ServiceProvider that supports asynchronous disposal.
|
|
42
42
|
*/
|
|
43
|
-
createAsyncScope(): IServiceProvider<T>;
|
|
43
|
+
createAsyncScope(name?: string): IServiceProvider<T>;
|
|
44
44
|
/**
|
|
45
45
|
* Resolves a service by its key.
|
|
46
46
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,GAAG,QAAQ,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;AAEzD,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,KAAK,GAAG,KAAK,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC;AAE7F;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,IACzB,CAAC,SAAS,QAAQ,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC,GAChD,CAAC,GACD,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GACpB,CAAC,CAAC,SAAS,QAAQ,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC,GACjD,CAAC,EAAE,GACH,CAAC,CAAC,GACJ,CAAC,CAAC,CAAC;AAET;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,OAAO;IACjD;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAC;IAEhB;;OAEG;IACH,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9B;;OAEG;IACH,WAAW,IAAI,gBAAgB,CAAC,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"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"}
|
package/docs/CHEATSHEET.md
CHANGED
|
@@ -3,177 +3,214 @@
|
|
|
3
3
|
Quick reference for the Type-Safe Dependency Injection container.
|
|
4
4
|
|
|
5
5
|
## Table of Contents
|
|
6
|
-
1. [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
1. [Core Concepts](#core-concepts)
|
|
7
|
+
- [The TypeMap](#1-the-typemap)
|
|
8
|
+
- [Working with Interfaces](#2-working-with-interfaces)
|
|
9
|
+
2. [Registration Examples](#registration-examples)
|
|
10
|
+
- [Class Registration](#class-registration)
|
|
11
|
+
- [Interface & Key Registration](#interface--key-registration)
|
|
12
|
+
- [Factory Registration (Sync & Async)](#factory-registration-sync--async)
|
|
13
|
+
- [Function Registration (Sync & Async)](#function-registration-sync--async)
|
|
14
|
+
- [Group Registration (Multiple Implementations)](#group-registration-multiple-implementations)
|
|
15
|
+
3. [Scopes & Lifecycle](#scopes--lifecycle)
|
|
16
|
+
- [Scoped Services](#scoped-services)
|
|
17
|
+
- [Disposal](#disposal)
|
|
15
18
|
|
|
16
19
|
---
|
|
17
20
|
|
|
18
|
-
##
|
|
19
|
-
The `TypeMap` defines the contract of your container.
|
|
21
|
+
## Core Concepts
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
### 1. The TypeMap
|
|
24
|
+
The `TypeMap` is the central contract for your container. It maps **keys** (strings or symbols) to their **resolved instance types**. This ensures full type safety when resolving services.
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
database: Database;
|
|
27
|
-
userService: UserService;
|
|
28
|
-
apiClient: ApiClient;
|
|
29
|
-
config: Config;
|
|
30
|
-
plugins: Plugin[];
|
|
31
|
-
generateId: () => string;
|
|
32
|
-
}
|
|
33
|
-
```
|
|
26
|
+
### 2. Working with Interfaces
|
|
27
|
+
In TypeScript, interfaces do not exist at runtime, so you cannot use them as keys directly. Instead, you map a **string/symbol key** to an **interface type** in the `TypeMap`, then register a **concrete class** to that key.
|
|
34
28
|
|
|
35
29
|
---
|
|
36
30
|
|
|
37
|
-
##
|
|
31
|
+
## Registration Examples
|
|
32
|
+
|
|
33
|
+
### Class Registration
|
|
38
34
|
Standard constructor injection. Dependencies are automatically resolved.
|
|
39
35
|
|
|
40
36
|
```typescript
|
|
41
|
-
|
|
42
|
-
log(msg: string) { console.log(msg); }
|
|
43
|
-
}
|
|
37
|
+
import { ServiceCollection } from '@js-injection/service-provider';
|
|
44
38
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
39
|
+
// 1. Define Services
|
|
40
|
+
class Logger { log(msg: string) { console.log(msg); } }
|
|
41
|
+
class UserService { constructor(public logger: Logger) {} }
|
|
48
42
|
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
// 2. Define TypeMap
|
|
44
|
+
interface MyMap {
|
|
45
|
+
Logger: Logger;
|
|
46
|
+
UserService: UserService;
|
|
51
47
|
}
|
|
52
48
|
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
// 3. Build & Resolve
|
|
50
|
+
const container = new ServiceCollection<MyMap>()
|
|
55
51
|
.addSingletonClass(Logger)
|
|
56
52
|
.addSingletonClass(UserService, Logger)
|
|
57
|
-
// Scoped (one instance per scope)
|
|
58
|
-
.addScopedClass(ApiClient)
|
|
59
|
-
// Build the service provider
|
|
60
53
|
.build();
|
|
54
|
+
|
|
55
|
+
const userService = container.getService(UserService);
|
|
61
56
|
```
|
|
62
57
|
|
|
63
|
-
|
|
58
|
+
### Interface & Key Registration
|
|
59
|
+
Mapping an interface to a concrete implementation using a string key.
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { ServiceCollection } from '@js-injection/service-provider';
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
// 1. Define Interface & Implementation
|
|
65
|
+
interface ILogger { log(msg: string): void; }
|
|
66
|
+
class ConsoleLogger implements ILogger { log(msg: string) { console.log(msg); } }
|
|
67
|
+
|
|
68
|
+
// 2. Define TypeMap (Key -> Interface)
|
|
69
|
+
interface MyMap {
|
|
70
|
+
logger: ILogger;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 3. Build & Resolve
|
|
74
|
+
const container = new ServiceCollection<MyMap>()
|
|
75
|
+
.addSingletonClass('logger', ConsoleLogger)
|
|
76
|
+
.build();
|
|
77
|
+
|
|
78
|
+
// Resolution Options:
|
|
79
|
+
|
|
80
|
+
// A. Resolve by Key (returns ILogger interface type)
|
|
81
|
+
const logger = container.getService('logger');
|
|
82
|
+
|
|
83
|
+
// B. Resolve by Concrete Class (returns ConsoleLogger instance type)
|
|
84
|
+
const consoleLogger = container.getService(ConsoleLogger);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Factory Registration (Sync & Async)
|
|
88
|
+
Use factories for complex logic or when you need dynamic resolution from the container.
|
|
67
89
|
|
|
68
90
|
```typescript
|
|
69
|
-
|
|
70
|
-
|
|
91
|
+
import { ServiceCollection } from '@js-injection/service-provider';
|
|
92
|
+
|
|
93
|
+
class Database { constructor(public url: string) {} }
|
|
94
|
+
|
|
95
|
+
interface MyMap {
|
|
96
|
+
db: Database;
|
|
97
|
+
asyncDb: Promise<Database>;
|
|
98
|
+
config: { url: string };
|
|
71
99
|
}
|
|
72
100
|
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
.
|
|
76
|
-
|
|
77
|
-
|
|
101
|
+
const container = new ServiceCollection<MyMap>()
|
|
102
|
+
.addSingletonValue('config', { url: 'postgres://localhost' })
|
|
103
|
+
// A. Synchronous Factory
|
|
104
|
+
.addSingletonFactory('db', (c) => new Database(c.config.url))
|
|
105
|
+
// B. Asynchronous Factory
|
|
106
|
+
.addSingletonFactory('asyncDb', async (c) => {
|
|
107
|
+
const db = new Database(c.config.url);
|
|
108
|
+
await db.connect(); // hypothetical async operation
|
|
109
|
+
return db;
|
|
78
110
|
})
|
|
79
|
-
// Scoped Factory
|
|
80
|
-
.addScopedFactory('apiClient', (container, sp) => {
|
|
81
|
-
return new ApiClient(container.logger);
|
|
82
|
-
})
|
|
83
|
-
// Build the service provider
|
|
84
111
|
.build();
|
|
85
|
-
```
|
|
86
112
|
|
|
87
|
-
|
|
113
|
+
const db = container.getService('db');
|
|
114
|
+
const asyncDb = await container.getService('asyncDb'); // Use 'await' for promises
|
|
115
|
+
```
|
|
88
116
|
|
|
89
|
-
|
|
90
|
-
Register a function as a service. Arguments are auto-injected.
|
|
117
|
+
### Function Registration (Sync & Async)
|
|
118
|
+
Register a plain function as a service. Arguments are auto-injected from the container.
|
|
91
119
|
|
|
92
120
|
```typescript
|
|
93
|
-
|
|
94
|
-
|
|
121
|
+
import { ServiceCollection } from '@js-injection/service-provider';
|
|
122
|
+
|
|
123
|
+
// 1. Define Functions
|
|
124
|
+
const createId = (prefix: string) => () => `${prefix}-${Math.random()}`;
|
|
125
|
+
const fetchConfig = async (url: string) => {
|
|
126
|
+
const res = await fetch(url);
|
|
127
|
+
return res.json();
|
|
95
128
|
}
|
|
96
129
|
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
130
|
+
// 2. Define TypeMap
|
|
131
|
+
interface MyMap {
|
|
132
|
+
generateId: () => string;
|
|
133
|
+
config: Promise<any>;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 3. Build & Resolve
|
|
137
|
+
const container = new ServiceCollection<MyMap>()
|
|
138
|
+
.addSingletonValue('configUrl', 'https://api.example.com/config')
|
|
139
|
+
.addSingletonFunc('generateId', createId, 'APP')
|
|
140
|
+
.addSingletonFunc('config', fetchConfig, 'configUrl')
|
|
101
141
|
.build();
|
|
102
|
-
```
|
|
103
142
|
|
|
104
|
-
|
|
143
|
+
const generateId = container.getService('generateId');
|
|
144
|
+
const config = await container.getService('config'); // Use 'await' for promises
|
|
145
|
+
```
|
|
105
146
|
|
|
106
|
-
|
|
107
|
-
Map multiple implementations to a single key.
|
|
147
|
+
### Group Registration (Multiple Implementations)
|
|
148
|
+
Map multiple implementations to a single key. Useful for plugins or middleware.
|
|
108
149
|
|
|
109
150
|
```typescript
|
|
151
|
+
import { ServiceCollection } from '@js-injection/service-provider';
|
|
152
|
+
|
|
110
153
|
interface Plugin { name: string; }
|
|
111
154
|
class AuthPlugin implements Plugin { name = 'auth'; }
|
|
112
155
|
class LogPlugin implements Plugin { name = 'log'; }
|
|
113
156
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
157
|
+
interface MyMap {
|
|
158
|
+
plugins: Plugin[];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const container = new ServiceCollection<MyMap>()
|
|
162
|
+
.addSingletonGroup('plugins', AuthPlugin, LogPlugin)
|
|
118
163
|
.build();
|
|
119
164
|
|
|
120
|
-
//
|
|
121
|
-
const plugins = sp.getService('plugins'); // [AuthPlugin, LogPlugin]
|
|
165
|
+
const plugins = container.getService('plugins'); // [AuthPlugin, LogPlugin]
|
|
122
166
|
```
|
|
123
167
|
|
|
124
168
|
---
|
|
125
169
|
|
|
126
|
-
##
|
|
127
|
-
Register constant values or configuration objects.
|
|
170
|
+
## Scopes & Lifecycle
|
|
128
171
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const config: Config = { dbUrl: 'postgres://localhost:5432' };
|
|
172
|
+
### Scoped Services
|
|
173
|
+
Scoped services are created once per scope (e.g., per web request).
|
|
132
174
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
// Build the service provider
|
|
136
|
-
.build();
|
|
137
|
-
```
|
|
175
|
+
```typescript
|
|
176
|
+
import { ServiceCollection } from '@js-injection/service-provider';
|
|
138
177
|
|
|
139
|
-
|
|
178
|
+
class RequestContext { id = Math.random(); }
|
|
140
179
|
|
|
141
|
-
|
|
142
|
-
|
|
180
|
+
interface MyMap {
|
|
181
|
+
ctx: RequestContext;
|
|
182
|
+
}
|
|
143
183
|
|
|
144
|
-
|
|
145
|
-
|
|
184
|
+
const root = new ServiceCollection<MyMap>()
|
|
185
|
+
.addScopedClass('ctx', RequestContext)
|
|
186
|
+
.build();
|
|
146
187
|
|
|
147
|
-
//
|
|
148
|
-
const
|
|
188
|
+
// Each scope gets its own instance
|
|
189
|
+
const scope1 = root.createScope();
|
|
190
|
+
const scope2 = root.createScope();
|
|
149
191
|
|
|
150
|
-
|
|
151
|
-
const
|
|
192
|
+
const ctx1 = scope1.getService('ctx');
|
|
193
|
+
const ctx2 = scope2.getService('ctx'); // ctx1 !== ctx2
|
|
152
194
|
```
|
|
153
195
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
## 8. Scopes
|
|
157
|
-
Create child containers for unit-of-work isolation.
|
|
196
|
+
### Disposal
|
|
197
|
+
Clean up resources by implementing `dispose()` or `disposeAsync()`.
|
|
158
198
|
|
|
159
199
|
```typescript
|
|
160
|
-
|
|
161
|
-
const scope = sp.createScope();
|
|
162
|
-
const scopedSvc = scope.getService(ApiClient);
|
|
200
|
+
import { ServiceCollection } from '@js-injection/service-provider';
|
|
163
201
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
202
|
+
class Database {
|
|
203
|
+
async disposeAsync() { /* close connections */ }
|
|
204
|
+
}
|
|
167
205
|
|
|
168
|
-
|
|
206
|
+
interface MyMap { db: Database; }
|
|
169
207
|
|
|
170
|
-
|
|
171
|
-
|
|
208
|
+
const container = new ServiceCollection<MyMap>()
|
|
209
|
+
.addSingletonClass(Database)
|
|
210
|
+
.build();
|
|
172
211
|
|
|
173
|
-
|
|
174
|
-
// Synchronous (throws if any service is async)
|
|
175
|
-
sp.dispose();
|
|
212
|
+
container.getService(Database);
|
|
176
213
|
|
|
177
|
-
//
|
|
178
|
-
await
|
|
214
|
+
// Asynchronously dispose of all resolved services
|
|
215
|
+
await container.disposeAsync();
|
|
179
216
|
```
|
package/package.json
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@js-injection/service-provider",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
4
|
-
"description": "",
|
|
3
|
+
"version": "1.0.0-alpha.2",
|
|
4
|
+
"description": "A lightweight, type-safe dependency injection container",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dependency-injection",
|
|
7
|
+
"di",
|
|
8
|
+
"ioc",
|
|
9
|
+
"service-provider"
|
|
10
|
+
],
|
|
5
11
|
"license": "ISC",
|
|
6
|
-
"author": "",
|
|
12
|
+
"author": "Peter Flannery",
|
|
7
13
|
"repository": {
|
|
8
14
|
"type": "git",
|
|
9
15
|
"url": "git+https://gitlab.com/js-injection/service-provider.git"
|
|
@@ -18,6 +24,7 @@
|
|
|
18
24
|
"type": "module",
|
|
19
25
|
"types": "./dist/types/src/index.d.ts",
|
|
20
26
|
"main": "./dist/legacy.cjs",
|
|
27
|
+
"module": "./dist/index.js",
|
|
21
28
|
"imports": {
|
|
22
29
|
"#src/*": "./out/src/*"
|
|
23
30
|
},
|
|
@@ -34,7 +41,7 @@
|
|
|
34
41
|
"esbuild": "0.27.4",
|
|
35
42
|
"js-build-tasks": "1.0.0-rc.18",
|
|
36
43
|
"mocha": "11.7.5",
|
|
37
|
-
"mocha-ui-esm": "1.0.0-beta.
|
|
44
|
+
"mocha-ui-esm": "1.0.0-beta.19",
|
|
38
45
|
"rimraf": "6.1.3",
|
|
39
46
|
"source-map-support": "0.5.21",
|
|
40
47
|
"typescript": "5.9.3"
|
|
@@ -185,14 +185,14 @@ export class ServiceCollection<T extends TypeMap> {
|
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
/**
|
|
188
|
-
* Adds
|
|
189
|
-
* Automatically registers individual classes if not already registered.
|
|
190
|
-
* @param key The key for the service
|
|
191
|
-
* @param types The classes to register in the
|
|
188
|
+
* Adds a group (array) of singleton services.
|
|
189
|
+
* Automatically registers individual classes as singletons if not already registered.
|
|
190
|
+
* @param key The key for the service group.
|
|
191
|
+
* @param types The classes to register in the group.
|
|
192
192
|
* @example
|
|
193
|
-
* .
|
|
193
|
+
* .addSingletonGroup("MessageCommand", HelloCommand, ByeCommand)
|
|
194
194
|
*/
|
|
195
|
-
|
|
195
|
+
addSingletonGroup<
|
|
196
196
|
Key extends FilterKeys<T, any[]>,
|
|
197
197
|
C extends (new (...args: any[]) => MapToInstance<T[Key]>[number])[]
|
|
198
198
|
>(
|
|
@@ -211,7 +211,7 @@ export class ServiceCollection<T extends TypeMap> {
|
|
|
211
211
|
|
|
212
212
|
const name = type.name;
|
|
213
213
|
if (!name) {
|
|
214
|
-
throw new RegistrationError(`Class in
|
|
214
|
+
throw new RegistrationError(`Class in group "${String(key)}" is missing a name and cannot be auto-registered.`);
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
const uid = getStableKey(type);
|
|
@@ -225,14 +225,14 @@ export class ServiceCollection<T extends TypeMap> {
|
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
/**
|
|
228
|
-
* Adds
|
|
228
|
+
* Adds a group (array) of scoped services.
|
|
229
229
|
* Automatically registers individual classes as scoped if not already registered.
|
|
230
|
-
* @param key The key for the service
|
|
231
|
-
* @param types The classes to register in the
|
|
230
|
+
* @param key The key for the service group.
|
|
231
|
+
* @param types The classes to register in the group.
|
|
232
232
|
* @example
|
|
233
|
-
* .
|
|
233
|
+
* .addScopedGroup("MessageCommand", HelloCommand, ByeCommand)
|
|
234
234
|
*/
|
|
235
|
-
|
|
235
|
+
addScopedGroup<
|
|
236
236
|
Key extends FilterKeys<T, any[]>,
|
|
237
237
|
C extends (new (...args: any[]) => MapToInstance<T[Key]>[number])[]
|
|
238
238
|
>(
|
|
@@ -251,7 +251,7 @@ export class ServiceCollection<T extends TypeMap> {
|
|
|
251
251
|
|
|
252
252
|
const name = type.name;
|
|
253
253
|
if (!name) {
|
|
254
|
-
throw new RegistrationError(`Class in
|
|
254
|
+
throw new RegistrationError(`Class in group "${String(key)}" is missing a name and cannot be auto-registered.`);
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
const uid = getStableKey(type);
|
|
@@ -375,7 +375,7 @@ export class ServiceCollection<T extends TypeMap> {
|
|
|
375
375
|
|
|
376
376
|
// Check if this class was auto-registered (params is empty array) but requires arguments
|
|
377
377
|
if (definitionsItem && definitionsItem.params && definitionsItem.params.length === 0 && type.length > 0) {
|
|
378
|
-
throw new RegistrationError(`Class "${name}" in
|
|
378
|
+
throw new RegistrationError(`Class "${name}" in group "${String(key)}" requires constructor arguments and must be registered independently using addSingletonClass or addScopedClass.`);
|
|
379
379
|
}
|
|
380
380
|
}
|
|
381
381
|
}
|
package/src/types.ts
CHANGED
|
@@ -51,12 +51,12 @@ export interface IServiceProvider<T extends TypeMap> {
|
|
|
51
51
|
/**
|
|
52
52
|
* Creates a new scoped ServiceProvider.
|
|
53
53
|
*/
|
|
54
|
-
createScope(): IServiceProvider<T>;
|
|
54
|
+
createScope(name?: string): IServiceProvider<T>;
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Creates a new scoped ServiceProvider that supports asynchronous disposal.
|
|
58
58
|
*/
|
|
59
|
-
createAsyncScope(): IServiceProvider<T>;
|
|
59
|
+
createAsyncScope(name?: string): IServiceProvider<T>;
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* Resolves a service by its key.
|