@travetto/di 7.0.0-rc.1 → 7.0.0-rc.3
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/README.md +5 -5
- package/package.json +3 -3
- package/src/decorator.ts +12 -12
- package/src/registry/registry-adapter.ts +15 -16
- package/src/registry/registry-index.ts +47 -94
- package/src/registry/registry-resolver.ts +9 -7
- package/src/types.ts +3 -3
package/README.md
CHANGED
|
@@ -135,7 +135,7 @@ The [@Inject](https://github.com/travetto/travetto/tree/main/module/di/src/decor
|
|
|
135
135
|
**Code: Example Injectable with dependencies as Inject fields**
|
|
136
136
|
```typescript
|
|
137
137
|
import { Injectable, Inject } from '@travetto/di';
|
|
138
|
-
import { DependentService } from './
|
|
138
|
+
import { DependentService } from './dependency.ts';
|
|
139
139
|
|
|
140
140
|
@Injectable()
|
|
141
141
|
class CustomService {
|
|
@@ -153,15 +153,15 @@ The [@Injectable](https://github.com/travetto/travetto/tree/main/module/di/src/d
|
|
|
153
153
|
**Code: Example Injectable with dependencies in constructor**
|
|
154
154
|
```typescript
|
|
155
155
|
import { Injectable } from '@travetto/di';
|
|
156
|
-
import { DependentService } from './
|
|
156
|
+
import { DependentService } from './dependency.ts';
|
|
157
157
|
|
|
158
158
|
@Injectable()
|
|
159
159
|
class CustomService {
|
|
160
160
|
|
|
161
161
|
dependentService: DependentService;
|
|
162
162
|
|
|
163
|
-
constructor(
|
|
164
|
-
this.dependentService =
|
|
163
|
+
constructor(service: DependentService) {
|
|
164
|
+
this.dependentService = service;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
async coolOperation() {
|
|
@@ -176,7 +176,7 @@ Via [@InjectableFactory](https://github.com/travetto/travetto/tree/main/module/d
|
|
|
176
176
|
```typescript
|
|
177
177
|
import { InjectableFactory } from '@travetto/di';
|
|
178
178
|
|
|
179
|
-
import { DependentService, CustomService } from './
|
|
179
|
+
import { DependentService, CustomService } from './dependency.ts';
|
|
180
180
|
|
|
181
181
|
class Config {
|
|
182
182
|
@InjectableFactory()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/di",
|
|
3
|
-
"version": "7.0.0-rc.
|
|
3
|
+
"version": "7.0.0-rc.3",
|
|
4
4
|
"description": "Dependency registration/management and injection support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ast-transformations",
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"directory": "module/di"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@travetto/registry": "^7.0.0-rc.
|
|
30
|
+
"@travetto/registry": "^7.0.0-rc.3"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@travetto/transformer": "^7.0.0-rc.
|
|
33
|
+
"@travetto/transformer": "^7.0.0-rc.3"
|
|
34
34
|
},
|
|
35
35
|
"peerDependenciesMeta": {
|
|
36
36
|
"@travetto/transformer": {
|
package/src/decorator.ts
CHANGED
|
@@ -4,17 +4,17 @@ import { CONSTRUCTOR_PROPERTY } from '@travetto/schema';
|
|
|
4
4
|
import { InjectableCandidate, ResolutionType } from './types.ts';
|
|
5
5
|
import { DependencyRegistryIndex } from './registry/registry-index.ts';
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
typeof
|
|
7
|
+
const fromInput = <T extends { qualifier?: symbol }>(input?: T | symbol): T =>
|
|
8
|
+
typeof input === 'symbol' ? castTo({ qualifier: input }) : (input ?? castTo<T>({}));
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Indicate that a class is able to be injected
|
|
12
12
|
* @augments `@travetto/schema:Schema`
|
|
13
13
|
* @kind decorator
|
|
14
14
|
*/
|
|
15
|
-
export function Injectable(
|
|
15
|
+
export function Injectable(input?: Partial<InjectableCandidate> | symbol) {
|
|
16
16
|
return <T extends Class>(cls: T): void => {
|
|
17
|
-
DependencyRegistryIndex.getForRegister(cls).registerClass(
|
|
17
|
+
DependencyRegistryIndex.getForRegister(cls).registerClass(fromInput(input));
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -26,15 +26,15 @@ export type InjectConfig = { qualifier?: symbol, resolution?: ResolutionType };
|
|
|
26
26
|
* @augments `@travetto/schema:Input`
|
|
27
27
|
* @kind decorator
|
|
28
28
|
*/
|
|
29
|
-
export function Inject(
|
|
30
|
-
return (instanceOrCls: Class | ClassInstance, property?: string
|
|
31
|
-
const
|
|
29
|
+
export function Inject(input?: InjectConfig | symbol) {
|
|
30
|
+
return (instanceOrCls: Class | ClassInstance, property?: string, idx?: number | PropertyDescriptor): void => {
|
|
31
|
+
const config = fromInput(input);
|
|
32
32
|
const cls = getClass(instanceOrCls);
|
|
33
33
|
const propertyKey = property ?? CONSTRUCTOR_PROPERTY;
|
|
34
34
|
if (typeof idx !== 'number') {
|
|
35
|
-
DependencyRegistryIndex.registerFieldMetadata(cls, propertyKey,
|
|
35
|
+
DependencyRegistryIndex.registerFieldMetadata(cls, propertyKey, config);
|
|
36
36
|
} else {
|
|
37
|
-
DependencyRegistryIndex.registerParameterMetadata(cls, propertyKey, idx,
|
|
37
|
+
DependencyRegistryIndex.registerParameterMetadata(cls, propertyKey, idx, config);
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
}
|
|
@@ -44,9 +44,9 @@ export function Inject(config?: InjectConfig | symbol) {
|
|
|
44
44
|
* @augments `@travetto/schema:Method`
|
|
45
45
|
* @kind decorator
|
|
46
46
|
*/
|
|
47
|
-
export function InjectableFactory(
|
|
48
|
-
return <T extends Class>(cls: T, property: string
|
|
49
|
-
DependencyRegistryIndex.getForRegister(cls).registerFactory(property,
|
|
47
|
+
export function InjectableFactory(input?: Partial<InjectableCandidate> | symbol) {
|
|
48
|
+
return <T extends Class>(cls: T, property: string, descriptor: TypedPropertyDescriptor<(...args: Any[]) => Any>): void => {
|
|
49
|
+
DependencyRegistryIndex.getForRegister(cls).registerFactory(property, fromInput(input), {
|
|
50
50
|
factory: (...params: unknown[]) => descriptor.value!.apply(cls, params),
|
|
51
51
|
});
|
|
52
52
|
};
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { RegistryAdapter } from '@travetto/registry';
|
|
2
|
-
import { Class, classConstruct, describeFunction,
|
|
2
|
+
import { Class, classConstruct, describeFunction, safeAssign } from '@travetto/runtime';
|
|
3
3
|
import { CONSTRUCTOR_PROPERTY, SchemaRegistryIndex } from '@travetto/schema';
|
|
4
4
|
|
|
5
5
|
import { InjectableConfig, getDefaultQualifier, InjectableCandidate } from '../types';
|
|
6
6
|
|
|
7
|
-
function combineInjectableCandidates<T extends InjectableCandidate>(base: T, ...
|
|
8
|
-
for (const
|
|
9
|
-
safeAssign(base,
|
|
7
|
+
function combineInjectableCandidates<T extends InjectableCandidate>(base: T, ...overrides: Partial<T>[]): typeof base {
|
|
8
|
+
for (const override of overrides) {
|
|
9
|
+
safeAssign(base, override);
|
|
10
10
|
}
|
|
11
11
|
return base;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
function combineClasses<T extends InjectableConfig>(base: T, ...
|
|
15
|
-
for (const
|
|
14
|
+
function combineClasses<T extends InjectableConfig>(base: T, ...overrides: Partial<T>[]): typeof base {
|
|
15
|
+
for (const override of overrides) {
|
|
16
16
|
Object.assign(base, {
|
|
17
17
|
...base,
|
|
18
|
-
...
|
|
18
|
+
...override,
|
|
19
19
|
candidates: {
|
|
20
20
|
...base.candidates,
|
|
21
|
-
...
|
|
21
|
+
...override.candidates,
|
|
22
22
|
}
|
|
23
23
|
});
|
|
24
24
|
}
|
|
@@ -38,7 +38,7 @@ export class DependencyRegistryAdapter implements RegistryAdapter<InjectableConf
|
|
|
38
38
|
return combineClasses(this.#config, ...data);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
registerFactory(method: string
|
|
41
|
+
registerFactory(method: string, ...data: Partial<InjectableCandidate<unknown>>[]): InjectableCandidate {
|
|
42
42
|
const { candidates } = this.register();
|
|
43
43
|
candidates[method] ??= {
|
|
44
44
|
class: this.#cls,
|
|
@@ -62,17 +62,16 @@ export class DependencyRegistryAdapter implements RegistryAdapter<InjectableConf
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
finalize(): void {
|
|
65
|
-
for (const
|
|
66
|
-
const
|
|
67
|
-
const candidateType = SchemaRegistryIndex.get(
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
for (const method of Object.keys(this.#config.candidates)) {
|
|
66
|
+
const candidate = this.#config.candidates[method];
|
|
67
|
+
const candidateType = SchemaRegistryIndex.get(candidate.class).getMethodReturnType(method);
|
|
68
|
+
candidate.candidateType = candidateType;
|
|
69
|
+
candidate.qualifier ??= getDefaultQualifier(candidateType);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
getCandidateConfigs(): InjectableCandidate[] {
|
|
74
|
-
|
|
75
|
-
return entries
|
|
74
|
+
return Object.values(this.#config.candidates)
|
|
76
75
|
.filter(item => (item.enabled ?? true) === true || (typeof item.enabled === 'function' && item.enabled()))
|
|
77
76
|
.filter(item => item.method !== CONSTRUCTOR_PROPERTY || !describeFunction(item.candidateType)?.abstract);
|
|
78
77
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AppError, castKey, castTo, Class, describeFunction, getParentClass, hasFunction,
|
|
1
|
+
import { RegistryIndex, RegistryIndexStore, Registry } from '@travetto/registry';
|
|
2
|
+
import { AppError, castKey, castTo, Class, describeFunction, getParentClass, hasFunction, TypedObject } from '@travetto/runtime';
|
|
3
3
|
import { SchemaFieldConfig, SchemaParameterConfig, SchemaRegistryIndex } from '@travetto/schema';
|
|
4
4
|
|
|
5
5
|
import { Dependency, InjectableCandidate, InjectableClassMetadata, InjectableConfig, ResolutionType } from '../types';
|
|
@@ -32,63 +32,55 @@ export class DependencyRegistryIndex implements RegistryIndex {
|
|
|
32
32
|
return this.#instance.getCandidates<T>(candidateType);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
static
|
|
36
|
-
return this.#instance.getCandidates(candidateType).map(c => c.candidateType);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
static getInstances<T>(candidateType: Class<T>, predicate?: (cfg: InjectableCandidate<T>) => boolean): Promise<T[]> {
|
|
35
|
+
static getInstances<T>(candidateType: Class<T>, predicate?: (config: InjectableCandidate<T>) => boolean): Promise<T[]> {
|
|
40
36
|
return this.#instance.getInstances<T>(candidateType, predicate);
|
|
41
37
|
}
|
|
42
38
|
|
|
43
|
-
static injectFields<T extends { constructor: Class<T> }>(
|
|
44
|
-
return this.#instance.injectFields(cls,
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
static getOptional(cls: Class): InjectableConfig | undefined {
|
|
48
|
-
return this.#instance.store.getOptional(cls)?.get();
|
|
39
|
+
static injectFields<T extends { constructor: Class<T> }>(item: T, cls = item.constructor): Promise<T> {
|
|
40
|
+
return this.#instance.injectFields(cls, item, cls);
|
|
49
41
|
}
|
|
50
42
|
|
|
51
43
|
static registerClassMetadata(cls: Class, metadata: InjectableClassMetadata): void {
|
|
52
44
|
SchemaRegistryIndex.getForRegister(cls).registerMetadata<InjectableClassMetadata>(MetadataSymbol, metadata);
|
|
53
45
|
}
|
|
54
46
|
|
|
55
|
-
static registerParameterMetadata(cls: Class, method: string
|
|
47
|
+
static registerParameterMetadata(cls: Class, method: string, index: number, metadata: Dependency): void {
|
|
56
48
|
SchemaRegistryIndex.getForRegister(cls).registerParameterMetadata(method, index, MetadataSymbol, metadata);
|
|
57
49
|
}
|
|
58
50
|
|
|
59
|
-
static registerFieldMetadata(cls: Class, field: string
|
|
51
|
+
static registerFieldMetadata(cls: Class, field: string, metadata: Dependency): void {
|
|
60
52
|
SchemaRegistryIndex.getForRegister(cls).registerFieldMetadata(field, MetadataSymbol, metadata);
|
|
61
53
|
}
|
|
62
54
|
|
|
63
|
-
#proxies = new Map<string, Map<symbol | undefined, RetargettingProxy<unknown>>>();
|
|
64
55
|
#instances = new Map<Class, Map<symbol, unknown>>();
|
|
65
56
|
#instancePromises = new Map<Class, Map<symbol, Promise<unknown>>>();
|
|
66
57
|
#resolver = new DependencyRegistryResolver();
|
|
67
58
|
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
59
|
+
async #resolveDependencyValue(dependency: Dependency, input: SchemaFieldConfig | SchemaParameterConfig, cls: Class): Promise<unknown> {
|
|
60
|
+
try {
|
|
61
|
+
const target = dependency.target ?? input.type;
|
|
62
|
+
return await this.getInstance(target, dependency.qualifier, dependency.resolution);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
if (input.required?.active === false && error instanceof InjectionError && error.category === 'notfound') {
|
|
65
|
+
return undefined;
|
|
66
|
+
} else {
|
|
67
|
+
if (error && error instanceof Error) {
|
|
68
|
+
error.message = `${error.message} via=${cls.Ⲑid}[${input.name?.toString() ?? 'constructor'}]`;
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
74
72
|
}
|
|
73
|
+
}
|
|
75
74
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
console.debug('Registering proxy', { id: target.Ⲑid, qualifier: qualifier.toString() });
|
|
80
|
-
} else {
|
|
81
|
-
proxy = this.#proxies.get(targetId)!.get(qualifier)!;
|
|
82
|
-
proxy.setTarget(instance);
|
|
83
|
-
console.debug('Updating target', {
|
|
84
|
-
id: target.Ⲑid, qualifier: qualifier.toString(), instanceType: target.name
|
|
85
|
-
});
|
|
86
|
-
}
|
|
75
|
+
store = new RegistryIndexStore(DependencyRegistryAdapter);
|
|
76
|
+
|
|
77
|
+
/** @private */ constructor(source: unknown) { Registry.validateConstructor(source); }
|
|
87
78
|
|
|
88
|
-
|
|
79
|
+
getConfig(cls: Class): InjectableConfig {
|
|
80
|
+
return this.store.get(cls).get();
|
|
89
81
|
}
|
|
90
82
|
|
|
91
|
-
|
|
83
|
+
onCreate(cls: Class): void {
|
|
92
84
|
const adapter = this.store.get(cls);
|
|
93
85
|
|
|
94
86
|
for (const config of adapter.getCandidateConfigs()) {
|
|
@@ -97,55 +89,17 @@ export class DependencyRegistryIndex implements RegistryIndex {
|
|
|
97
89
|
const hasParentBase = (parentConfig || (parentClass && !!describeFunction(parentClass)?.abstract));
|
|
98
90
|
const baseParent = hasParentBase ? parentClass : undefined;
|
|
99
91
|
this.#resolver.registerClass(config, baseParent);
|
|
100
|
-
if (config.autoInject || forceCreate) {
|
|
101
|
-
// Don't wait
|
|
102
|
-
Util.queueMacroTask().then(() => {
|
|
103
|
-
this.getInstance(config.candidateType, config.qualifier);
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
#removeClass(cls: Class): void {
|
|
110
|
-
if (this.#instances.has(cls)) {
|
|
111
|
-
for (const [qualifier, config] of this.#resolver.getContainerEntries(cls)) {
|
|
112
|
-
try {
|
|
113
|
-
this.destroyInstance(config.candidateType, qualifier);
|
|
114
|
-
} catch { }
|
|
115
|
-
}
|
|
116
92
|
}
|
|
117
93
|
}
|
|
118
94
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
return undefined;
|
|
127
|
-
} else {
|
|
128
|
-
if (err && err instanceof Error) {
|
|
129
|
-
err.message = `${err.message} via=${src.Ⲑid}[${input.name?.toString() ?? 'constructor'}]`;
|
|
95
|
+
// Setup instances after change set complete
|
|
96
|
+
onChangeSetComplete(classes: Class[]): void {
|
|
97
|
+
for (const cls of classes) {
|
|
98
|
+
const adapter = this.store.get(cls);
|
|
99
|
+
for (const config of adapter.getCandidateConfigs()) {
|
|
100
|
+
if (config.autoInject) {
|
|
101
|
+
this.getInstance(config.candidateType, config.qualifier);
|
|
130
102
|
}
|
|
131
|
-
throw err;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
store = new RegistryIndexStore(DependencyRegistryAdapter);
|
|
137
|
-
|
|
138
|
-
getConfig(cls: Class): InjectableConfig {
|
|
139
|
-
return this.store.get(cls).get();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
process(events: ChangeEvent<Class>[]): void {
|
|
143
|
-
for (const ev of events) {
|
|
144
|
-
if ('prev' in ev) {
|
|
145
|
-
this.#removeClass(ev.prev);
|
|
146
|
-
}
|
|
147
|
-
if ('curr' in ev) {
|
|
148
|
-
this.#addClass(ev.curr, 'prev' in ev);
|
|
149
103
|
}
|
|
150
104
|
}
|
|
151
105
|
}
|
|
@@ -154,15 +108,15 @@ export class DependencyRegistryIndex implements RegistryIndex {
|
|
|
154
108
|
* Get all available candidates for a given type
|
|
155
109
|
*/
|
|
156
110
|
getCandidates<T>(candidateType: Class<T>): InjectableCandidate<T>[] {
|
|
157
|
-
return this.#resolver.getCandidateEntries(candidateType).map(([_,
|
|
111
|
+
return this.#resolver.getCandidateEntries(candidateType).map(([_, candidate]) => castTo<InjectableCandidate<T>>(candidate));
|
|
158
112
|
}
|
|
159
113
|
|
|
160
114
|
/**
|
|
161
115
|
* Get candidate instances by target type, with an optional filter
|
|
162
116
|
*/
|
|
163
|
-
getInstances<T>(candidateType: Class<T>, predicate?: (
|
|
164
|
-
const inputs = this.getCandidates<T>(candidateType).filter(
|
|
165
|
-
return Promise.all(inputs.map(
|
|
117
|
+
getInstances<T>(candidateType: Class<T>, predicate?: (config: InjectableCandidate<T>) => boolean): Promise<T[]> {
|
|
118
|
+
const inputs = this.getCandidates<T>(candidateType).filter(candidate => !predicate || predicate(candidate));
|
|
119
|
+
return Promise.all(inputs.map(candidate => this.getInstance<T>(candidate.class, candidate.qualifier)));
|
|
166
120
|
}
|
|
167
121
|
|
|
168
122
|
/**
|
|
@@ -185,13 +139,13 @@ export class DependencyRegistryIndex implements RegistryIndex {
|
|
|
185
139
|
const inputs = SchemaRegistryIndex.getOptional(candidateType)?.getFields() ?? {};
|
|
186
140
|
|
|
187
141
|
const promises = TypedObject.entries(inputs)
|
|
188
|
-
.filter(([
|
|
189
|
-
.map(async ([
|
|
142
|
+
.filter(([key, input]) => readMetadata(input) !== undefined && (input.access !== 'readonly' && instance[castKey(key)] === undefined))
|
|
143
|
+
.map(async ([key, input]) => [key, await this.#resolveDependencyValue(readMetadata(input) ?? {}, input, srcClass)] as const);
|
|
190
144
|
|
|
191
145
|
const pairs = await Promise.all(promises);
|
|
192
146
|
|
|
193
|
-
for (const [
|
|
194
|
-
instance[castKey(
|
|
147
|
+
for (const [key, value] of pairs) {
|
|
148
|
+
instance[castKey(key)] = castTo(value);
|
|
195
149
|
}
|
|
196
150
|
return instance;
|
|
197
151
|
}
|
|
@@ -217,12 +171,12 @@ export class DependencyRegistryIndex implements RegistryIndex {
|
|
|
217
171
|
SchemaRegistryIndex.get(targetType).getMetadata<InjectableClassMetadata>(MetadataSymbol) : undefined;
|
|
218
172
|
|
|
219
173
|
// Run post constructors
|
|
220
|
-
for (const
|
|
221
|
-
await
|
|
174
|
+
for (const operation of Object.values(metadata?.postConstruct ?? {})) {
|
|
175
|
+
await operation(inst);
|
|
222
176
|
}
|
|
223
177
|
|
|
224
178
|
// Proxy if necessary
|
|
225
|
-
return
|
|
179
|
+
return inst;
|
|
226
180
|
}
|
|
227
181
|
|
|
228
182
|
/**
|
|
@@ -250,10 +204,10 @@ export class DependencyRegistryIndex implements RegistryIndex {
|
|
|
250
204
|
const instance = await instancePromise;
|
|
251
205
|
this.#instances.get(target)!.set(qualifier, instance);
|
|
252
206
|
return instance;
|
|
253
|
-
} catch (
|
|
207
|
+
} catch (error) {
|
|
254
208
|
// Clear it out, don't save failed constructions
|
|
255
209
|
this.#instancePromises.get(target)!.delete(qualifier);
|
|
256
|
-
throw
|
|
210
|
+
throw error;
|
|
257
211
|
}
|
|
258
212
|
}
|
|
259
213
|
|
|
@@ -273,7 +227,6 @@ export class DependencyRegistryIndex implements RegistryIndex {
|
|
|
273
227
|
this.#instancePromises.get(target)?.delete(qualifier);
|
|
274
228
|
|
|
275
229
|
// May not exist
|
|
276
|
-
this.#proxies.get(target.Ⲑid)?.get(qualifier)?.setTarget(null);
|
|
277
230
|
console.debug('On uninstall', { id: target, qualifier: qualifier.toString(), classId: target });
|
|
278
231
|
}
|
|
279
232
|
}
|
|
@@ -6,11 +6,11 @@ import { InjectionError } from '../error';
|
|
|
6
6
|
|
|
7
7
|
type Resolved<T> = { candidate: InjectableCandidate<T>, qualifier: symbol, target: Class };
|
|
8
8
|
|
|
9
|
-
function setInMap<T>(map: Map<Class, Map<typeof key, T>>,
|
|
10
|
-
if (!map.has(
|
|
11
|
-
map.set(
|
|
9
|
+
function setInMap<T>(map: Map<Class, Map<typeof key, T>>, cls: Class, key: symbol | string, dest: T): void {
|
|
10
|
+
if (!map.has(cls)) {
|
|
11
|
+
map.set(cls, new Map());
|
|
12
12
|
}
|
|
13
|
-
map.get(
|
|
13
|
+
map.get(cls)!.set(key, dest);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export class DependencyRegistryResolver {
|
|
@@ -38,15 +38,17 @@ export class DependencyRegistryResolver {
|
|
|
38
38
|
if (qualifiers.has(PrimaryCandidateSymbol)) {
|
|
39
39
|
return PrimaryCandidateSymbol;
|
|
40
40
|
} else {
|
|
41
|
-
const filtered = resolved
|
|
41
|
+
const filtered = resolved
|
|
42
|
+
.filter(qualifier => !!qualifier)
|
|
43
|
+
.filter(qualifier => this.#defaultSymbols.has(qualifier));
|
|
42
44
|
// If there is only one default symbol
|
|
43
45
|
if (filtered.length === 1) {
|
|
44
46
|
return filtered[0];
|
|
45
47
|
} else if (filtered.length > 1) {
|
|
46
48
|
// If dealing with sub types, prioritize exact matches
|
|
47
49
|
const exact = this.getCandidateEntries(type)
|
|
48
|
-
.map(([_,
|
|
49
|
-
.filter(
|
|
50
|
+
.map(([_, candidate]) => candidate)
|
|
51
|
+
.filter(candidate => candidate.candidateType === type);
|
|
50
52
|
|
|
51
53
|
if (exact.length === 1) {
|
|
52
54
|
return exact[0].qualifier;
|
package/src/types.ts
CHANGED
|
@@ -32,7 +32,7 @@ export interface InjectableCandidate<T = unknown> {
|
|
|
32
32
|
/**
|
|
33
33
|
* Method that is injectable on class
|
|
34
34
|
*/
|
|
35
|
-
method: string
|
|
35
|
+
method: string;
|
|
36
36
|
/**
|
|
37
37
|
* Method handle
|
|
38
38
|
*/
|
|
@@ -74,7 +74,7 @@ export interface InjectableConfig<T = unknown> {
|
|
|
74
74
|
/**
|
|
75
75
|
* Candidates that are injectable
|
|
76
76
|
*/
|
|
77
|
-
candidates: Record<string
|
|
77
|
+
candidates: Record<string, InjectableCandidate>;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
export function getDefaultQualifier(cls: Class): symbol {
|
|
@@ -85,5 +85,5 @@ export function getDefaultQualifier(cls: Class): symbol {
|
|
|
85
85
|
export const PrimaryCandidateSymbol = Symbol();
|
|
86
86
|
|
|
87
87
|
export type InjectableClassMetadata = {
|
|
88
|
-
postConstruct: Record<string
|
|
88
|
+
postConstruct: Record<string, (<T>(inst: T) => Promise<void>)>;
|
|
89
89
|
};
|