@travetto/di 6.0.1 → 7.0.0-rc.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.
package/src/registry.ts DELETED
@@ -1,579 +0,0 @@
1
- import {
2
- Class, Runtime, asConstructable, castTo, classConstruct, describeFunction,
3
- asFull, castKey, TypedFunction, hasFunction, AppError
4
- } from '@travetto/runtime';
5
- import { MetadataRegistry, RootRegistry, ChangeEvent } from '@travetto/registry';
6
-
7
- import { Dependency, InjectableConfig, ClassTarget, InjectableFactoryConfig, PostConstructHandler } from './types.ts';
8
- import { InjectionError } from './error.ts';
9
-
10
- class AutoCreate { }
11
- type TargetId = string;
12
- type ClassId = string;
13
- export type Resolved<T> = { config: InjectableConfig<T>, qualifier: symbol, id: string };
14
-
15
- export type ResolutionType = 'strict' | 'loose' | 'any';
16
-
17
- const PrimaryCandidateSymbol = Symbol();
18
-
19
- const hasPostConstruct = hasFunction<{ postConstruct: () => Promise<unknown> }>('postConstruct');
20
- const hasPreDestroy = hasFunction<{ preDestroy: () => Promise<unknown> }>('preDestroy');
21
-
22
- /**
23
- * Dependency registry
24
- */
25
- class $DependencyRegistry extends MetadataRegistry<InjectableConfig> {
26
- pendingFinalize: Class[] = [];
27
-
28
- defaultSymbols = new Set<symbol>();
29
-
30
- instances = new Map<TargetId, Map<symbol, unknown>>();
31
- instancePromises = new Map<TargetId, Map<symbol, Promise<unknown>>>();
32
-
33
- factories = new Map<TargetId, Map<Class, InjectableConfig>>();
34
-
35
- targetToClass = new Map<TargetId, Map<symbol, string>>();
36
- classToTarget = new Map<ClassId, Map<symbol, TargetId>>();
37
-
38
- constructor() {
39
- super(RootRegistry);
40
- }
41
-
42
- /**
43
- * Resolve the target given a qualifier
44
- * @param target
45
- * @param qualifier
46
- */
47
- resolveTarget<T>(target: ClassTarget<T>, qualifier?: symbol, resolution?: ResolutionType): Resolved<T> {
48
- const qualifiers = this.targetToClass.get(target.Ⲑid) ?? new Map<symbol, string>();
49
-
50
- let cls: string | undefined;
51
-
52
- if (qualifier && qualifiers.has(qualifier)) {
53
- cls = qualifiers.get(qualifier);
54
- } else {
55
- const resolved = [...qualifiers.keys()];
56
- if (!qualifier) {
57
- // If primary found
58
- if (qualifiers.has(PrimaryCandidateSymbol)) {
59
- qualifier = PrimaryCandidateSymbol;
60
- } else {
61
- // If there is only one default symbol
62
- const filtered = resolved.filter(x => !!x).filter(x => this.defaultSymbols.has(x));
63
- if (filtered.length === 1) {
64
- qualifier = filtered[0];
65
- } else if (filtered.length > 1) {
66
- // If dealing with sub types, prioritize exact matches
67
- const exact = this
68
- .getCandidateTypes(castTo<Class>(target))
69
- .filter(x => x.class === target);
70
- if (exact.length === 1) {
71
- qualifier = exact[0].qualifier;
72
- } else {
73
- if (resolution === 'any') {
74
- qualifier = filtered[0];
75
- } else {
76
- throw new InjectionError('Dependency has multiple candidates', target, filtered);
77
- }
78
- }
79
- }
80
- }
81
- }
82
-
83
- if (!qualifier) {
84
- throw new InjectionError('Dependency not found', target);
85
- } else if (!qualifiers.has(qualifier)) {
86
- if (!this.defaultSymbols.has(qualifier) && resolution === 'loose') {
87
- console.debug('Unable to find specific dependency, falling back to general instance', { qualifier, target: target.Ⲑid });
88
- return this.resolveTarget(target);
89
- }
90
- throw new InjectionError('Dependency not found', target, [qualifier]);
91
- } else {
92
- cls = qualifiers.get(qualifier!)!;
93
- }
94
- }
95
-
96
- const config: InjectableConfig<T> = castTo(this.get(cls!));
97
- return {
98
- qualifier,
99
- config,
100
- id: (config.factory ? config.target : config.class).Ⲑid
101
- };
102
- }
103
-
104
- /**
105
- * Retrieve all dependencies
106
- */
107
- async fetchDependencies<T>(managed: InjectableConfig<T>, deps?: Dependency[], keys?: string[]): Promise<unknown[]> {
108
- if (!deps || !deps.length) {
109
- return [];
110
- }
111
-
112
- const promises = deps.map(async (x, i) => {
113
- try {
114
- return await this.getInstance(x.target, x.qualifier, x.resolution);
115
- } catch (err) {
116
- if (x.optional && err instanceof InjectionError && err.category === 'notfound') {
117
- return undefined;
118
- } else {
119
- if (err && err instanceof Error) {
120
- err.message = `${err.message} via=${managed.class.Ⲑid}[${keys?.[i] ?? 'constructor'}]`;
121
- }
122
- throw err;
123
- }
124
- }
125
- });
126
-
127
- return await Promise.all(promises);
128
- }
129
-
130
- /**
131
- * Resolve all field dependencies
132
- */
133
- async resolveFieldDependencies<T>(config: InjectableConfig<T>, instance: T): Promise<void> {
134
- const keys = Object.keys(config.dependencies.fields ?? {})
135
- .filter(k => instance[castKey<T>(k)] === undefined); // Filter out already set ones
136
-
137
- // And auto-wire
138
- if (keys.length) {
139
- const deps = await this.fetchDependencies(config, keys.map(x => config.dependencies.fields[x]), keys);
140
- for (let i = 0; i < keys.length; i++) {
141
- instance[castKey<T>(keys[i])] = castTo(deps[i]);
142
- }
143
- }
144
- }
145
-
146
- /**
147
- * Actually construct an instance while resolving the dependencies
148
- */
149
- async construct<T>(target: ClassTarget<T>, qualifier: symbol): Promise<T> {
150
- const managed = this.resolveTarget(target, qualifier).config;
151
-
152
- // Only fetch constructor values
153
- const consValues = await this.fetchDependencies(managed, managed.dependencies.cons);
154
-
155
- // Create instance
156
- const inst = managed.factory ?
157
- managed.factory(...consValues) :
158
- classConstruct(managed.class, consValues);
159
-
160
- // And auto-wire fields
161
- await this.resolveFieldDependencies(managed, inst);
162
-
163
- // If factory with field properties on the sub class
164
- if (managed.factory) {
165
- const resolved = this.get(asConstructable(inst).constructor);
166
-
167
- if (resolved) {
168
- await this.resolveFieldDependencies(resolved, inst);
169
- }
170
- }
171
-
172
- // Run post construct, if it wasn't passed in, otherwise it was already created
173
- if (hasPostConstruct(inst) && !consValues.includes(inst)) {
174
- await inst.postConstruct();
175
- }
176
-
177
- // Run post constructors
178
- for (const op of Object.values(managed.postConstruct)) {
179
- await op(inst);
180
- }
181
-
182
- return inst;
183
- }
184
-
185
- /**
186
- * Create the instance
187
- */
188
- async createInstance<T>(target: ClassTarget<T>, qualifier: symbol): Promise<T> {
189
- const classId = this.resolveTarget(target, qualifier).id;
190
-
191
- if (!this.instances.has(classId)) {
192
- this.instances.set(classId, new Map());
193
- this.instancePromises.set(classId, new Map());
194
- }
195
-
196
- if (this.instancePromises.get(classId)!.has(qualifier)) {
197
- return castTo(this.instancePromises.get(classId)!.get(qualifier));
198
- }
199
-
200
- const instancePromise = this.construct(target, qualifier);
201
- this.instancePromises.get(classId)!.set(qualifier, instancePromise);
202
- try {
203
- const instance = await instancePromise;
204
- this.instances.get(classId)!.set(qualifier, instance);
205
- return instance;
206
- } catch (err) {
207
- // Clear it out, don't save failed constructions
208
- this.instancePromises.get(classId)!.delete(qualifier);
209
- throw err;
210
- }
211
- }
212
-
213
- /**
214
- * Destroy an instance
215
- */
216
- destroyInstance(cls: Class, qualifier: symbol): void {
217
- const classId = cls.Ⲑid;
218
-
219
- const activeInstance = this.instances.get(classId)!.get(qualifier);
220
- if (hasPreDestroy(activeInstance)) {
221
- activeInstance.preDestroy();
222
- }
223
-
224
- this.defaultSymbols.delete(qualifier);
225
- this.instances.get(classId)!.delete(qualifier);
226
- this.instancePromises.get(classId)!.delete(qualifier);
227
- this.classToTarget.get(classId)!.delete(qualifier);
228
- console.debug('On uninstall', { id: classId, qualifier: qualifier.toString(), classId });
229
- }
230
-
231
- override async init(): Promise<void> {
232
- await super.init();
233
- if (Runtime.dynamic) {
234
- const { DependencyRegistration } = await import('../support/dynamic.injection.ts');
235
- DependencyRegistration.init(this);
236
- }
237
-
238
- await this.getCandidateInstances(AutoCreate);
239
- }
240
-
241
- /**
242
- * Handle initial installation for the entire registry
243
- */
244
- override initialInstall(): Class[] {
245
- const finalizing = this.pendingFinalize;
246
- this.pendingFinalize = [];
247
-
248
- for (const cls of finalizing) {
249
- this.install(cls, { type: 'added', curr: cls });
250
- }
251
-
252
- return [];
253
- }
254
-
255
- /**
256
- * Register a cls as pending
257
- */
258
- createPending(cls: Class): Partial<InjectableConfig> {
259
- if (!this.resolved) {
260
- this.pendingFinalize.push(cls);
261
- }
262
-
263
- return {
264
- class: cls,
265
- enabled: true,
266
- target: cls,
267
- interfaces: [],
268
- dependencies: {
269
- fields: {},
270
- cons: []
271
- },
272
- postConstruct: {}
273
- };
274
- }
275
-
276
- /**
277
- * Get an instance by type and qualifier
278
- */
279
- async getInstance<T>(target: ClassTarget<T>, qual?: symbol, resolution?: ResolutionType): Promise<T> {
280
- this.verifyInitialized();
281
-
282
- if (!target) {
283
- throw new AppError('Unable to get instance when target is undefined');
284
- }
285
-
286
- const { id: classId, qualifier } = this.resolveTarget(target, qual, resolution);
287
- if (!this.instances.has(classId) || !this.instances.get(classId)!.has(qualifier)) {
288
- await this.createInstance(target, qualifier); // Wait for proxy
289
- }
290
- return castTo(this.instances.get(classId)!.get(qualifier));
291
- }
292
-
293
- /**
294
- * Get all available candidate types for the target
295
- */
296
- getCandidateTypes<T>(target: Class<T>): InjectableConfig<T>[] {
297
- const qualifiers = this.targetToClass.get(target.Ⲑid)!;
298
- const uniqueQualifiers = qualifiers ? Array.from(new Set(qualifiers.values())) : [];
299
- return castTo(uniqueQualifiers.map(id => this.get(id)));
300
- }
301
-
302
- /**
303
- * Get candidate instances by target type, with an optional filter
304
- */
305
- getCandidateInstances<T>(target: Class<T>, predicate?: (cfg: InjectableConfig<T>) => boolean): Promise<T[]> {
306
- const inputs = this.getCandidateTypes<T>(target).filter(x => !predicate || predicate(x));
307
- return Promise.all(inputs.map(l => this.getInstance<T>(l.class, l.qualifier)));
308
- }
309
-
310
- /**
311
- * Register a constructor with dependencies
312
- */
313
- registerConstructor<T>(cls: Class<T>, dependencies?: Dependency[]): void {
314
- const conf = this.getOrCreatePending(cls);
315
- conf.dependencies!.cons = dependencies;
316
- }
317
-
318
- /**
319
- * Register a post construct handler
320
- */
321
- registerPostConstructHandler<T>(cls: Class<T>, name: string, handler: PostConstructHandler<T>): void {
322
- const conf = this.getOrCreatePending(cls);
323
- conf.postConstruct![name] = castTo(handler);
324
- }
325
-
326
- /**
327
- * Register a property as a dependency
328
- */
329
- registerProperty<T>(cls: Class<T>, field: string, dependency: Dependency): void {
330
- const conf = this.getOrCreatePending(cls);
331
- conf.dependencies!.fields[field] = dependency;
332
- }
333
-
334
- /**
335
- * Register a class
336
- */
337
- registerClass<T>(cls: Class<T>, pConfig: Partial<InjectableConfig<T>> = {}): void {
338
- const config = this.getOrCreatePending(pConfig.class ?? cls);
339
-
340
- config.enabled = pConfig.enabled ?? config.enabled;
341
- config.class = cls;
342
- config.qualifier = pConfig.qualifier ?? config.qualifier ?? Symbol.for(cls.Ⲑid);
343
- if (pConfig.interfaces) {
344
- (config.interfaces ??= []).push(...pConfig.interfaces);
345
- }
346
- if (pConfig.primary !== undefined) {
347
- config.primary = pConfig.primary;
348
- }
349
- if (pConfig.factory) {
350
- config.factory = pConfig.factory ?? config.factory;
351
- }
352
- if (pConfig.target) {
353
- config.target = pConfig.target;
354
- }
355
- if (pConfig.dependencies) {
356
- config.dependencies = {
357
- ...pConfig.dependencies,
358
- fields: {
359
- ...pConfig.dependencies.fields
360
- }
361
- };
362
- }
363
- if (pConfig.autoCreate) {
364
- (config.interfaces ??= []).push(AutoCreate);
365
- }
366
- }
367
-
368
- /**
369
- * Register a factory configuration
370
- */
371
- registerFactory(config: Omit<InjectableFactoryConfig, 'qualifier'> & {
372
- id: string;
373
- qualifier?: undefined | symbol;
374
- fn: TypedFunction;
375
- }): void {
376
- const finalConfig: Partial<InjectableConfig> = {};
377
-
378
- finalConfig.enabled = config.enabled ?? true;
379
- finalConfig.factory = config.fn;
380
- finalConfig.target = config.target;
381
- finalConfig.qualifier = config.qualifier;
382
- if (!finalConfig.qualifier) {
383
- finalConfig.qualifier = Symbol.for(config.id);
384
- }
385
- if (config.primary !== undefined) {
386
- finalConfig.primary = config.primary;
387
- }
388
-
389
- finalConfig.dependencies = { fields: {} };
390
-
391
- if (config.dependencies) {
392
- finalConfig.dependencies.cons = config.dependencies;
393
- }
394
-
395
- // Create mock cls for DI purposes
396
- const fnClass = class { static Ⲑid = config.id; };
397
-
398
- finalConfig.class = fnClass;
399
-
400
- this.registerClass(fnClass, finalConfig);
401
-
402
- const srcClassId = config.src.Ⲑid;
403
-
404
- if (!this.factories.has(srcClassId)) {
405
- this.factories.set(srcClassId, new Map());
406
- }
407
-
408
- this.factories.get(srcClassId)!.set(fnClass, asFull(finalConfig));
409
- }
410
-
411
- /**
412
- * On Install event
413
- */
414
- override onInstall<T>(cls: Class<T>, e: ChangeEvent<Class<T>>): void {
415
- super.onInstall(cls, e);
416
- const classId = cls.Ⲑid;
417
-
418
- // Install factories separate from classes
419
- if (this.factories.has(classId)) {
420
- for (const fact of this.factories.get(classId)!.keys()) {
421
- this.onInstall(fact, e);
422
- }
423
- }
424
- }
425
-
426
- /**
427
- * Handle installing a class
428
- */
429
- onInstallFinalize<T>(cls: Class<T>): InjectableConfig<T> {
430
- const classId = cls.Ⲑid;
431
-
432
- const config: InjectableConfig<T> = castTo(this.getOrCreatePending(cls));
433
-
434
- if (config.enabled !== undefined && !(typeof config.enabled === 'boolean' ? config.enabled : config.enabled())) {
435
- return config; // Do not setup if disabled
436
- }
437
-
438
- // Allow for the factory to fulfill the target
439
- let parentClass: Function = config.factory ? config.target : Object.getPrototypeOf(cls);
440
-
441
- if (config.factory) {
442
- while (describeFunction(Object.getPrototypeOf(parentClass))?.abstract) {
443
- parentClass = Object.getPrototypeOf(parentClass);
444
- }
445
- if (!this.targetToClass.has(classId)) {
446
- this.targetToClass.set(classId, new Map());
447
- }
448
- // Make explicitly discoverable as self
449
- this.targetToClass.get(classId)?.set(config.qualifier, classId);
450
- }
451
-
452
- const parentConfig = this.get(parentClass.Ⲑid);
453
-
454
- if (parentConfig) {
455
- config.dependencies.fields = {
456
- ...parentConfig.dependencies!.fields,
457
- ...config.dependencies.fields
458
- };
459
-
460
- // collect interfaces
461
- config.interfaces = [
462
- ...parentConfig.interfaces,
463
- ...config.interfaces
464
- ];
465
-
466
- config.postConstruct = {
467
- ...parentConfig.postConstruct,
468
- ...config.postConstruct
469
- };
470
-
471
- // Inherit cons deps if no constructor defined
472
- if (config.dependencies.cons === undefined) {
473
- config.dependencies.cons = parentConfig.dependencies.cons;
474
- }
475
- }
476
-
477
- if (describeFunction(cls)?.abstract) { // Skip out early, only needed to inherit
478
- return config;
479
- }
480
-
481
- if (!this.classToTarget.has(classId)) {
482
- this.classToTarget.set(classId, new Map());
483
- }
484
-
485
- const targetClassId = config.target.Ⲑid;
486
-
487
- if (!this.targetToClass.has(targetClassId)) {
488
- this.targetToClass.set(targetClassId, new Map());
489
- }
490
-
491
- if (config.qualifier === Symbol.for(classId)) {
492
- this.defaultSymbols.add(config.qualifier);
493
- }
494
-
495
- this.targetToClass.get(targetClassId)!.set(config.qualifier, classId);
496
- this.classToTarget.get(classId)!.set(config.qualifier, targetClassId);
497
-
498
- // If aliased
499
- for (const el of config.interfaces) {
500
- const elClassId = el.Ⲑid;
501
- if (!this.targetToClass.has(elClassId)) {
502
- this.targetToClass.set(elClassId, new Map());
503
- }
504
- this.targetToClass.get(elClassId)!.set(config.qualifier, classId);
505
- this.classToTarget.get(classId)!.set(Symbol.for(elClassId), elClassId);
506
-
507
- if (config.primary && (classId === targetClassId || config.factory)) {
508
- this.targetToClass.get(elClassId)!.set(PrimaryCandidateSymbol, classId);
509
- }
510
- }
511
-
512
- // If targeting self (default @Injectable behavior)
513
- if ((classId === targetClassId || config.factory) && (parentConfig || describeFunction(parentClass)?.abstract)) {
514
- const parentId = parentClass.Ⲑid;
515
-
516
- if (!this.targetToClass.has(parentId)) {
517
- this.targetToClass.set(parentId, new Map());
518
- }
519
-
520
- if (config.primary) {
521
- this.targetToClass.get(parentId)!.set(PrimaryCandidateSymbol, classId);
522
- }
523
-
524
- this.targetToClass.get(parentId)!.set(config.qualifier, classId);
525
- this.classToTarget.get(classId)!.set(config.qualifier, parentId);
526
- }
527
-
528
- if (config.primary) {
529
- if (!this.targetToClass.has(classId)) {
530
- this.targetToClass.set(classId, new Map());
531
- }
532
- this.targetToClass.get(classId)!.set(PrimaryCandidateSymbol, classId);
533
-
534
- if (config.factory) {
535
- this.targetToClass.get(targetClassId)!.set(PrimaryCandidateSymbol, classId);
536
- }
537
-
538
- // Register primary if only one interface provided and no parent config
539
- if (config.interfaces.length === 1 && !parentConfig) {
540
- const [primaryInterface] = config.interfaces;
541
- const primaryClassId = primaryInterface.Ⲑid;
542
- if (!this.targetToClass.has(primaryClassId)) {
543
- this.targetToClass.set(primaryClassId, new Map());
544
- }
545
- this.targetToClass.get(primaryClassId)!.set(PrimaryCandidateSymbol, classId);
546
- }
547
- }
548
-
549
- return config;
550
- }
551
-
552
- /**
553
- * Handle uninstalling a class
554
- */
555
- override onUninstallFinalize(cls: Class): void {
556
- const classId = cls.Ⲑid;
557
-
558
- if (!this.classToTarget.has(classId)) {
559
- return;
560
- }
561
-
562
- if (this.instances.has(classId)) {
563
- for (const qualifier of this.classToTarget.get(classId)!.keys()) {
564
- this.destroyInstance(cls, qualifier);
565
- }
566
- }
567
- }
568
-
569
- /**
570
- * Inject fields into instance
571
- */
572
- async injectFields<T extends { constructor: Class<T> }>(o: T, cls = o.constructor): Promise<void> {
573
- this.verifyInitialized();
574
- // Compute fields to be auto-wired
575
- return await this.resolveFieldDependencies(this.get(cls), o);
576
- }
577
- }
578
-
579
- export const DependencyRegistry = new $DependencyRegistry();
@@ -1,108 +0,0 @@
1
- import { Class, describeFunction } from '@travetto/runtime';
2
- import { RetargettingProxy } from '@travetto/registry';
3
-
4
- import type { DependencyRegistry, ResolutionType, Resolved } from '../src/registry.ts';
5
- import type { ClassTarget, InjectableConfig } from '../src/types.ts';
6
-
7
- /**
8
- * Wraps the Dependency Registry to support proxying instances
9
- */
10
- class $DynamicDependencyRegistry {
11
- #proxies = new Map<string, Map<symbol | undefined, RetargettingProxy<unknown>>>();
12
- #registry: typeof DependencyRegistry;
13
- #registryCreateInstance: <T>(target: ClassTarget<T>, qualifier: symbol) => Promise<T>;
14
- #registryResolveTarget: <T>(target: ClassTarget<T>, qualifier?: symbol, resolution?: ResolutionType) => Resolved<T>;
15
- #registryOnInstallFinalize: <T>(target: Class<T>) => InjectableConfig<T>;
16
- #registryDestroyInstance: <T>(target: Class<T>, qualifier: symbol) => void;
17
-
18
- /**
19
- * Proxy the created instance
20
- */
21
- proxyInstance<T>(target: ClassTarget<T>, qual: symbol | undefined, instance: T): T {
22
- const { qualifier, id: classId } = this.#registryResolveTarget(target, qual);
23
- let proxy: RetargettingProxy<unknown>;
24
-
25
- if (!this.#proxies.has(classId)) {
26
- this.#proxies.set(classId, new Map());
27
- }
28
-
29
- if (!this.#proxies.get(classId)!.has(qualifier)) {
30
- proxy = new RetargettingProxy<T>(instance);
31
- this.#proxies.get(classId)!.set(qualifier, proxy);
32
- if (this.#registry.trace) {
33
- console.debug('Registering proxy', { id: target.Ⲑid, qualifier: qualifier.toString() });
34
- }
35
- } else {
36
- proxy = this.#proxies.get(classId)!.get(qualifier)!;
37
- proxy.setTarget(instance);
38
- if (this.#registry.trace) {
39
- console.debug('Updating target', {
40
- id: target.Ⲑid, qualifier: qualifier.toString(), instanceType: target.name
41
- });
42
- }
43
- }
44
-
45
- return proxy.get<T>();
46
- }
47
-
48
- /**
49
- * Create instance and wrap in a proxy
50
- */
51
- async createInstance<T>(target: ClassTarget<T>, qualifier: symbol): Promise<T> {
52
- const instance = await this.#registryCreateInstance(target, qualifier);
53
- const classId = this.#registryResolveTarget(target, qualifier).id;
54
- // Reset as proxy instance
55
- const proxied = this.proxyInstance<T>(target, qualifier, instance);
56
- this.#registry['instances'].get(classId)!.set(qualifier, proxied);
57
- return proxied;
58
- }
59
-
60
- /**
61
- * Reload proxy if in watch mode
62
- */
63
- onInstallFinalize<T>(cls: Class<T>): InjectableConfig<T> {
64
- const config = this.#registryOnInstallFinalize(cls);
65
- // If already loaded, reload
66
- const classId = cls.Ⲑid;
67
-
68
- if (
69
- !describeFunction(cls)?.abstract &&
70
- this.#proxies.has(classId) &&
71
- this.#proxies.get(classId)!.has(config.qualifier)
72
- ) {
73
- console.debug('Reloading on next tick');
74
- // Timing matters due to create instance being asynchronous
75
- process.nextTick(() => this.createInstance(config.target, config.qualifier));
76
- }
77
-
78
- return config;
79
- }
80
-
81
- destroyInstance(cls: Class, qualifier: symbol): void {
82
- const classId = cls.Ⲑid;
83
- const proxy = this.#proxies.get(classId)?.get(qualifier);
84
- this.#registryDestroyInstance(cls, qualifier);
85
- if (proxy) {
86
- proxy.setTarget(null);
87
- }
88
- }
89
-
90
- register(registry: typeof DependencyRegistry): void {
91
- this.#registry = registry;
92
- this.#registryCreateInstance = registry.createInstance.bind(registry);
93
- this.#registryResolveTarget = registry.resolveTarget.bind(registry);
94
- this.#registryOnInstallFinalize = registry.onInstallFinalize.bind(registry);
95
- this.#registryDestroyInstance = registry.destroyInstance.bind(registry);
96
-
97
- this.#registry.createInstance = this.createInstance.bind(this);
98
- this.#registry.destroyInstance = this.destroyInstance.bind(this);
99
- this.#registry.onInstallFinalize = this.onInstallFinalize.bind(this);
100
- }
101
- }
102
-
103
- export const DependencyRegistration = {
104
- init(registry: typeof DependencyRegistry): void {
105
- const dynamic = new $DynamicDependencyRegistry();
106
- dynamic.register(registry);
107
- }
108
- };