@js-injection/service-provider 1.0.0-alpha.1

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.
@@ -0,0 +1,102 @@
1
+ import type { Class, IServiceProvider, MapToInstance, ServiceDefinitionMap, TypeMap } from './types.js';
2
+ export declare class ServiceProvider<T extends TypeMap> implements IServiceProvider<T> {
3
+ readonly name: string;
4
+ private definitions;
5
+ private parent?;
6
+ private readonly isAsyncScope;
7
+ private instances;
8
+ private resolving;
9
+ private path;
10
+ private disposed;
11
+ /**
12
+ * @param name The name of the service provider.
13
+ * @param definitions The service definitions map.
14
+ * @param parent The parent service provider, if any.
15
+ * @param isAsyncScope Whether this is an asynchronous scope.
16
+ */
17
+ constructor(name: string, definitions: ServiceDefinitionMap, parent?: ServiceProvider<T> | undefined, isAsyncScope?: boolean);
18
+ /**
19
+ * Creates a new scoped ServiceProvider.
20
+ * @param name The name of the scope.
21
+ * @example
22
+ * const scope = di.createScope('request-scope');
23
+ */
24
+ createScope(name?: string): IServiceProvider<T>;
25
+ /**
26
+ * Creates a new scoped ServiceProvider that supports asynchronous disposal.
27
+ * @param name The name of the scope.
28
+ * @example
29
+ * const scope = di.createAsyncScope('worker-scope');
30
+ */
31
+ createAsyncScope(name?: string): IServiceProvider<T>;
32
+ /**
33
+ * Resolves a service by its key.
34
+ * @param key The key to resolve.
35
+ * @example
36
+ * const logger = di.getService('Logger');
37
+ */
38
+ getService<K extends keyof T & (string | symbol)>(key: K): MapToInstance<T[K]>;
39
+ /**
40
+ * Resolves a service by its Class type.
41
+ * @param type The class type to resolve.
42
+ * @example
43
+ * const logger = di.getService(Logger);
44
+ */
45
+ getService<C extends Class>(type: C): InstanceType<C>;
46
+ /**
47
+ * Synchronously disposes of all resolved services.
48
+ * Throws AsyncDisposalError if this is an async scope or if any service disposal returns a Promise.
49
+ */
50
+ dispose(): void;
51
+ /**
52
+ * Asynchronously disposes of all resolved services.
53
+ */
54
+ disposeAsync(): Promise<void>;
55
+ /**
56
+ * Resolves a singleton value.
57
+ * @param uid The unique ID of the value.
58
+ * @param value The value to resolve.
59
+ */
60
+ private resolveValue;
61
+ /**
62
+ * Resolves an array of services.
63
+ * @param uid The unique ID of the service array.
64
+ * @param types The class types to resolve for the array.
65
+ */
66
+ private resolveArray;
67
+ /**
68
+ * Resolves a service via a factory.
69
+ * @param uid The unique ID of the service.
70
+ * @param factory The factory to use for resolution.
71
+ */
72
+ private resolveFactory;
73
+ /**
74
+ * Resolves a service via a function.
75
+ * @param uid The unique ID of the service.
76
+ * @param func The function to use for resolution.
77
+ * @param params The arguments for the function.
78
+ */
79
+ private resolveFunc;
80
+ /**
81
+ * Resolves a service via its class type.
82
+ * @param uid The unique ID of the service.
83
+ * @param type The class type to instantiate.
84
+ * @param params The constructor arguments.
85
+ */
86
+ private resolveClass;
87
+ /**
88
+ * Creates a proxy for the type map to allow resolving services by property access.
89
+ */
90
+ private createContainerProxy;
91
+ /**
92
+ * Gets the key for a given key or class type.
93
+ * @param keyOrType The key or class type.
94
+ */
95
+ private getKey;
96
+ /**
97
+ * Attempts to get the key for a given key or class type without throwing.
98
+ * @param keyOrType The key or class type.
99
+ */
100
+ private tryGetKey;
101
+ }
102
+ //# sourceMappingURL=service-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-provider.d.ts","sourceRoot":"","sources":["../../../src/service-provider.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,KAAK,EAGL,gBAAgB,EAChB,aAAa,EAEb,oBAAoB,EACpB,OAAO,EACR,MAAM,YAAY,CAAC;AAEpB,qBAAa,eAAe,CAAC,CAAC,SAAS,OAAO,CAAE,YAAW,gBAAgB,CAAC,CAAC,CAAC;aAa1D,IAAI,EAAE,MAAM;IAC5B,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,MAAM,CAAC;IACf,OAAO,CAAC,QAAQ,CAAC,YAAY;IAf/B,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,IAAI,CAA2B;IACvC,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;;;OAKG;gBAEe,IAAI,EAAE,MAAM,EACpB,WAAW,EAAE,oBAAoB,EACjC,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,YAAA,EAClB,YAAY,GAAE,OAAe;IAGhD;;;;;OAKG;IACH,WAAW,CAAC,IAAI,GAAE,MAAgB,GAAG,gBAAgB,CAAC,CAAC,CAAC;IAKxD;;;;;OAKG;IACH,gBAAgB,CAAC,IAAI,GAAE,MAAsB,GAAG,gBAAgB,CAAC,CAAC,CAAC;IAKnE;;;;;OAKG;IACH,UAAU,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9E;;;;;OAKG;IACH,UAAU,CAAC,CAAC,SAAS,KAAK,EAAE,IAAI,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;IAmDrD;;;OAGG;IACH,OAAO,IAAI,IAAI;IAyBf;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBnC;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAKpB;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAUpB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAOtB;;;;;OAKG;IACH,OAAO,CAAC,WAAW;IAanB;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IAapB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAS5B;;;OAGG;IACH,OAAO,CAAC,MAAM;IAYd;;;OAGG;IACH,OAAO,CAAC,SAAS;CA8BlB"}
@@ -0,0 +1,168 @@
1
+ export type Class = abstract new (...args: any[]) => any;
2
+ export type ConcreteClass<T extends Class = Class> = new (...args: any[]) => InstanceType<T>;
3
+ /**
4
+ * Maps a value from a TypeMap to its resolved instance type.
5
+ */
6
+ export type MapToInstance<T> = T extends abstract new (...args: any[]) => infer R ? R : (T extends (infer C)[] ? (C extends abstract new (...args: any[]) => infer R ? R[] : T) : T);
7
+ /**
8
+ * Represents an object that can be disposed synchronously.
9
+ */
10
+ export interface IDisposable {
11
+ dispose(): void;
12
+ }
13
+ /**
14
+ * Represents an object that can be disposed asynchronously.
15
+ */
16
+ export interface IAsyncDisposable {
17
+ disposeAsync(): Promise<void>;
18
+ }
19
+ /**
20
+ * Interface for the ServiceProvider to avoid circular dependencies in types.
21
+ */
22
+ export interface IServiceProvider<T extends TypeMap> {
23
+ /**
24
+ * The name of the service provider.
25
+ */
26
+ readonly name: string;
27
+ /**
28
+ * Synchronously disposes of all resolved services.
29
+ * Throws if any service requires asynchronous disposal.
30
+ */
31
+ dispose(): void;
32
+ /**
33
+ * Asynchronously disposes of all resolved services.
34
+ */
35
+ disposeAsync(): Promise<void>;
36
+ /**
37
+ * Creates a new scoped ServiceProvider.
38
+ */
39
+ createScope(): IServiceProvider<T>;
40
+ /**
41
+ * Creates a new scoped ServiceProvider that supports asynchronous disposal.
42
+ */
43
+ createAsyncScope(): IServiceProvider<T>;
44
+ /**
45
+ * Resolves a service by its key.
46
+ */
47
+ getService<K extends keyof T & (string | symbol)>(key: K): MapToInstance<T[K]>;
48
+ /**
49
+ * Resolves a service by its Class type.
50
+ */
51
+ getService<C extends Class>(type: C): InstanceType<C>;
52
+ /**
53
+ * Resolves a service by its key or its Class type.
54
+ */
55
+ getService<K extends keyof T & (string | symbol)>(keyOrType: K | T[K]): MapToInstance<T[K]>;
56
+ }
57
+ /**
58
+ * Maps all keys in a TypeMap to their resolved instance types.
59
+ */
60
+ export type ResolvedTypeMap<T extends TypeMap> = {
61
+ [K in keyof T & (string | symbol)]: MapToInstance<T[K]>;
62
+ };
63
+ /**
64
+ * A factory function that creates an instance of a service.
65
+ */
66
+ export type ImplementationFactory<T extends TypeMap, R> = (container: ResolvedTypeMap<T>, sp: IServiceProvider<T>) => R;
67
+ /**
68
+ * Resolves the arguments for a given function.
69
+ * Each argument can be its actual type or a key from the DI container.
70
+ */
71
+ export type FuncArgs<F extends (...args: any[]) => any, T extends TypeMap> = Parameters<F> extends infer P ? (P extends any[] ? {
72
+ [K in keyof P]: P[K] | FilterKeys<T, P[K]> | (P[K] extends abstract new (...args: any[]) => infer R ? FilterKeys<T, abstract new (...args: any[]) => R> : never);
73
+ } : never) : never;
74
+ /**
75
+ * Resolves the constructor arguments for a given class.
76
+ * Each argument can be its actual type or a key from the DI container.
77
+ */
78
+ export type ClassArgs<T extends Class, Keys extends (string | symbol)> = ConstructorParameters<T> extends infer P ? (P extends any[] ? {
79
+ [K in keyof P]: P[K] | Keys | Class;
80
+ } : never) : never;
81
+ /**
82
+ * Represents the lifetime of a service.
83
+ */
84
+ export type ServiceLifetime = 'singleton' | 'scoped';
85
+ /**
86
+ * A registration for a service created via a function.
87
+ */
88
+ export type FunctionRegistration<F extends (...args: any[]) => any, L extends ServiceLifetime, T extends TypeMap> = {
89
+ kind: 'function';
90
+ lifetime: L;
91
+ func: F;
92
+ params: FuncArgs<F, T>;
93
+ };
94
+ /**
95
+ * A registration for a service created via a factory.
96
+ */
97
+ export type FactoryRegistration<C extends Class, L extends ServiceLifetime> = {
98
+ kind: 'service';
99
+ lifetime: L;
100
+ type: C;
101
+ factory: ImplementationFactory<any, any>;
102
+ };
103
+ /**
104
+ * A registration for a service created via constructor injection.
105
+ */
106
+ export type ClassRegistration<C extends Class, L extends ServiceLifetime, Keys extends (string | symbol)> = {
107
+ kind: 'service';
108
+ lifetime: L;
109
+ type: C;
110
+ params: ClassArgs<C, Keys>;
111
+ };
112
+ /**
113
+ * A registration for an array of services (multiple implementations).
114
+ */
115
+ export type ArrayRegistration<C extends Class[], L extends ServiceLifetime> = {
116
+ kind: 'service';
117
+ lifetime: L;
118
+ type: C;
119
+ };
120
+ /**
121
+ * A registration for a constant value.
122
+ */
123
+ export type ValueRegistration<V, L extends ServiceLifetime> = {
124
+ kind: 'value';
125
+ lifetime: L;
126
+ value: V;
127
+ };
128
+ /**
129
+ * Internal runtime definition for a service or value.
130
+ */
131
+ export interface ServiceDefinition<T> {
132
+ kind: 'service' | 'value' | 'function';
133
+ lifetime: 'singleton' | 'scoped';
134
+ uid: string | symbol;
135
+ type?: T;
136
+ params?: any[];
137
+ factory?: T extends Class ? ImplementationFactory<any, any> : never;
138
+ value?: T;
139
+ func?: (...args: any[]) => any;
140
+ }
141
+ /**
142
+ * A record of all registered services and their internal definitions.
143
+ */
144
+ export type ServiceDefinitionMap = Record<string | symbol, ServiceDefinition<any>>;
145
+ /**
146
+ * A record mapping string keys to Class constructors, arrays of constructors, or values.
147
+ */
148
+ export type TypeMap = Record<string | symbol, any>;
149
+ /**
150
+ * Filters keys of M that match type V.
151
+ */
152
+ export type FilterKeys<M, V> = {
153
+ [K in keyof M]: M[K] extends V ? K : never;
154
+ }[keyof M] & (string | symbol);
155
+ /**
156
+ * Filters out keys from TypeMap that are primarily used for service registration.
157
+ */
158
+ export type FilterValueKeys<M extends TypeMap> = {
159
+ [K in keyof M]: M[K] extends abstract new (...args: any[]) => any ? never : (M[K] extends (abstract new (...args: any[]) => any)[] ? never : (M[K] extends (...args: any[]) => any ? never : K));
160
+ }[keyof M] & (string | symbol);
161
+ /**
162
+ * Filters keys of M that are functions, promises, or async functions.
163
+ * Excludes class constructors and promises that resolve to class constructors.
164
+ */
165
+ export type FilterFuncKeys<M extends TypeMap> = {
166
+ [K in keyof M]: (M[K] extends ((...args: any[]) => any) | Promise<any> ? ((M[K] extends Promise<infer R> ? R : M[K]) extends abstract new (...args: any[]) => any ? never : K) : never);
167
+ }[keyof M] & (string | symbol);
168
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,179 @@
1
+ # DI Service Provider Cheatsheet
2
+
3
+ Quick reference for the Type-Safe Dependency Injection container.
4
+
5
+ ## Table of Contents
6
+ 1. [Setup & TypeMap](#1-setup--typemap)
7
+ 2. [Class Registration](#2-class-registration)
8
+ 3. [Factory Registration](#3-factory-registration)
9
+ 4. [Function Registration](#4-function-registration)
10
+ 5. [Array Registration](#5-array-registration)
11
+ 6. [Value Registration](#6-value-registration)
12
+ 7. [Service Retrieval](#7-service-retrieval)
13
+ 8. [Scopes](#8-scopes)
14
+ 9. [Disposal](#9-disposal)
15
+
16
+ ---
17
+
18
+ ## 1. Setup & TypeMap
19
+ The `TypeMap` defines the contract of your container.
20
+
21
+ ```typescript
22
+ import { ServiceCollection } from '@js-injection/service-provider';
23
+
24
+ interface MyMap {
25
+ logger: ILogger;
26
+ database: Database;
27
+ userService: UserService;
28
+ apiClient: ApiClient;
29
+ config: Config;
30
+ plugins: Plugin[];
31
+ generateId: () => string;
32
+ }
33
+ ```
34
+
35
+ ---
36
+
37
+ ## 2. Class Registration
38
+ Standard constructor injection. Dependencies are automatically resolved.
39
+
40
+ ```typescript
41
+ class Logger implements ILogger {
42
+ log(msg: string) { console.log(msg); }
43
+ }
44
+
45
+ class UserService {
46
+ constructor(public logger: ILogger) {}
47
+ }
48
+
49
+ class ApiClient {
50
+ constructor(public logger: ILogger) {}
51
+ }
52
+
53
+ const sp = new ServiceCollection<MyMap>()
54
+ // Singleton (one instance global)
55
+ .addSingletonClass(Logger)
56
+ .addSingletonClass(UserService, Logger)
57
+ // Scoped (one instance per scope)
58
+ .addScopedClass(ApiClient)
59
+ // Build the service provider
60
+ .build();
61
+ ```
62
+
63
+ ---
64
+
65
+ ## 3. Factory Registration
66
+ Use factories for complex logic or when you need access to the container.
67
+
68
+ ```typescript
69
+ class Database {
70
+ constructor(public connectionString: string) {}
71
+ }
72
+
73
+ const sp = new ServiceCollection<MyMap>()
74
+ // Singleton Factory
75
+ .addSingletonFactory(Database, (container) => {
76
+ const connectionString = container.config.dbUrl;
77
+ return new Database(connectionString);
78
+ })
79
+ // Scoped Factory
80
+ .addScopedFactory('apiClient', (container, sp) => {
81
+ return new ApiClient(container.logger);
82
+ })
83
+ // Build the service provider
84
+ .build();
85
+ ```
86
+
87
+ ---
88
+
89
+ ## 4. Function Registration
90
+ Register a function as a service. Arguments are auto-injected.
91
+
92
+ ```typescript
93
+ function createIdGenerator(prefix: string) {
94
+ return () => `${prefix}-${Math.random()}`;
95
+ }
96
+
97
+ // Arguments can be literal values or other services
98
+ const sp = new ServiceCollection<MyMap>()
99
+ .addSingletonFunc('generateId', createIdGenerator, 'APP')
100
+ // Build the service provider
101
+ .build();
102
+ ```
103
+
104
+ ---
105
+
106
+ ## 5. Array Registration
107
+ Map multiple implementations to a single key. Returns an array.
108
+
109
+ ```typescript
110
+ interface Plugin { name: string; }
111
+ class AuthPlugin implements Plugin { name = 'auth'; }
112
+ class LogPlugin implements Plugin { name = 'log'; }
113
+
114
+ // Individual classes are auto-registered if needed
115
+ const sp = new ServiceCollection<MyMap>()
116
+ .addSingletonArray('plugins', AuthPlugin, LogPlugin)
117
+ // Build the service provider
118
+ .build();
119
+
120
+ // Retrieval
121
+ const plugins = sp.getService('plugins'); // [AuthPlugin, LogPlugin]
122
+ ```
123
+
124
+ ---
125
+
126
+ ## 6. Value Registration
127
+ Register constant values or configuration objects.
128
+
129
+ ```typescript
130
+ interface Config { dbUrl: string; }
131
+ const config: Config = { dbUrl: 'postgres://localhost:5432' };
132
+
133
+ const sp = new ServiceCollection<MyMap>()
134
+ .addSingletonValue('config', config)
135
+ // Build the service provider
136
+ .build();
137
+ ```
138
+
139
+ ---
140
+
141
+ ## 7. Service Retrieval
142
+ Resolve services from the built provider.
143
+
144
+ ```typescript
145
+ const sp = new ServiceCollection<MyMap>().build();
146
+
147
+ // 1. Resolve by Class (returns Implementation type)
148
+ const userService = sp.getService(UserService);
149
+
150
+ // 2. Resolve by Key (returns Interface type from TypeMap)
151
+ const logger = sp.getService('logger');
152
+ ```
153
+
154
+ ---
155
+
156
+ ## 8. Scopes
157
+ Create child containers for unit-of-work isolation.
158
+
159
+ ```typescript
160
+ // Standard Scope
161
+ const scope = sp.createScope();
162
+ const scopedSvc = scope.getService(ApiClient);
163
+
164
+ // Async Scope (supports async disposal)
165
+ const asyncScope = sp.createAsyncScope();
166
+ ```
167
+
168
+ ---
169
+
170
+ ## 9. Disposal
171
+ Clean up resources for `IDisposable` and `IAsyncDisposable` services.
172
+
173
+ ```typescript
174
+ // Synchronous (throws if any service is async)
175
+ sp.dispose();
176
+
177
+ // Asynchronous (recommended)
178
+ await sp.disposeAsync();
179
+ ```
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@js-injection/service-provider",
3
+ "version": "1.0.0-alpha.1",
4
+ "description": "",
5
+ "license": "ISC",
6
+ "author": "",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://gitlab.com/js-injection/service-provider.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://gitlab.com/js-injection/service-provider/issues"
13
+ },
14
+ "homepage": "https://gitlab.com/js-injection/service-provider#readme",
15
+ "engines": {
16
+ "node": ">=22"
17
+ },
18
+ "type": "module",
19
+ "types": "./dist/types/src/index.d.ts",
20
+ "main": "./dist/legacy.cjs",
21
+ "imports": {
22
+ "#src/*": "./out/src/*"
23
+ },
24
+ "exports": {
25
+ "import": "./dist/index.js",
26
+ "types": "./dist/types/src/index.d.ts",
27
+ "require": "./dist/legacy.cjs"
28
+ },
29
+ "devDependencies": {
30
+ "@types/mocha": "10.0.10",
31
+ "@types/node": "22.19.15",
32
+ "@types/source-map-support": "0.5.10",
33
+ "c8": "11.0.0",
34
+ "esbuild": "0.27.4",
35
+ "js-build-tasks": "1.0.0-rc.18",
36
+ "mocha": "11.7.5",
37
+ "mocha-ui-esm": "1.0.0-beta.17",
38
+ "rimraf": "6.1.3",
39
+ "source-map-support": "0.5.21",
40
+ "typescript": "5.9.3"
41
+ },
42
+ "scripts": {
43
+ "compile": "task",
44
+ "bundle": "task",
45
+ "test": "task",
46
+ "coverage": "task",
47
+ "start": "task compile bundle:smoke && node ./dist/test/smoke/async-func.js",
48
+ "prepublishOnly": "task"
49
+ }
50
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Thrown when a circular dependency is detected.
3
+ */
4
+ export class CircularDependencyError extends Error {
5
+ constructor(path: string) {
6
+ super(`Circular dependency detected: ${path}`);
7
+ this.name = 'CircularDependencyError';
8
+ }
9
+ }
10
+
11
+ /**
12
+ * Thrown when a service cannot be resolved.
13
+ */
14
+ export class ServiceNotFoundError extends Error {
15
+ constructor(identifier: string) {
16
+ super(`Service not registered for identifier: ${identifier}`);
17
+ this.name = 'ServiceNotFoundError';
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Thrown when a registration is invalid.
23
+ */
24
+ export class RegistrationError extends Error {
25
+ constructor(message: string) {
26
+ super(message);
27
+ this.name = 'RegistrationError';
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Thrown when a service provider has been disposed.
33
+ */
34
+ export class ServiceProviderDisposedError extends Error {
35
+ constructor() {
36
+ super('ServiceProvider has been disposed and cannot resolve services.');
37
+ this.name = 'ServiceProviderDisposedError';
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Thrown when a synchronous dispose is called on a scope containing services that require asynchronous disposal.
43
+ */
44
+ export class AsyncDisposalError extends Error {
45
+ constructor(serviceKey: string) {
46
+ super(`Service "${serviceKey}" requires asynchronous disposal but a synchronous dispose was called. Please use await disposeAsync() instead.`);
47
+ this.name = 'AsyncDisposalError';
48
+ }
49
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './errors.js';
2
+ export * from './service-collection.js';
3
+ export * from './service-provider.js';
4
+ export * from './types.js';
@@ -0,0 +1,17 @@
1
+ import type { Class } from './types.js';
2
+
3
+ const classKeyRegistry = new WeakMap<Class, symbol>();
4
+
5
+ /**
6
+ * Resolves a stable Symbol for a given class constructor.
7
+ * This is used to ensure that DI resolution remains stable even after minification.
8
+ * @param type The class constructor.
9
+ */
10
+ export function getStableKey(type: Class): symbol {
11
+ let key = classKeyRegistry.get(type);
12
+ if (!key) {
13
+ key = Symbol(type.name || 'AnonymousClass');
14
+ classKeyRegistry.set(type, key);
15
+ }
16
+ return key;
17
+ }