mani-game-engine 1.0.0-pre.7 → 1.0.0-pre.70
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/LICENSE +1 -1
- package/lib/clock.d.ts +57 -0
- package/lib/clock.js +121 -0
- package/lib/clock.js.map +1 -0
- package/lib/ecsInjector.d.ts +45 -0
- package/lib/ecsInjector.js +220 -0
- package/lib/ecsInjector.js.map +1 -0
- package/lib/entity.d.ts +37 -0
- package/lib/entity.js +176 -0
- package/lib/entity.js.map +1 -0
- package/lib/gameEngine.d.ts +96 -0
- package/lib/gameEngine.js +423 -0
- package/lib/gameEngine.js.map +1 -0
- package/lib/index.d.ts +12 -0
- package/lib/index.js +37 -0
- package/lib/index.js.map +1 -0
- package/lib/injector.d.ts +130 -0
- package/lib/injector.js +324 -0
- package/lib/injector.js.map +1 -0
- package/lib/scope/scopeContext.d.ts +76 -0
- package/lib/scope/scopeContext.js +306 -0
- package/lib/scope/scopeContext.js.map +1 -0
- package/lib/systemContext.d.ts +15 -0
- package/lib/systemContext.js +39 -0
- package/lib/systemContext.js.map +1 -0
- package/lib/types.d.ts +83 -0
- package/lib/types.js +20 -0
- package/lib/types.js.map +1 -0
- package/lib/utils/map2k.d.ts +6 -0
- package/lib/utils/map2k.js +44 -0
- package/lib/utils/map2k.js.map +1 -0
- package/package.json +12 -15
- package/src/clock.ts +133 -81
- package/src/ecsInjector.ts +131 -36
- package/src/entity.ts +105 -5
- package/src/gameEngine.ts +459 -353
- package/src/index.ts +25 -9
- package/src/injector.ts +410 -0
- package/src/scope/scopeContext.ts +118 -32
- package/src/systemContext.ts +20 -2
- package/src/types.ts +24 -10
package/src/index.ts
CHANGED
|
@@ -1,17 +1,33 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
export {GameEngine, GameEngineOptions} from './gameEngine';
|
|
2
|
+
export {Entity} from './entity';
|
|
3
|
+
export {
|
|
4
|
+
Action,
|
|
5
|
+
AsyncAction,
|
|
6
|
+
Class,
|
|
7
|
+
CommandClass,
|
|
8
|
+
EngineSignals,
|
|
9
|
+
GameEnginePlugin,
|
|
10
|
+
System,
|
|
11
|
+
OnFixedUpdateParams,
|
|
12
|
+
OnUpdateParams,
|
|
13
|
+
OnEarlyUpdateParams,
|
|
14
|
+
Service,
|
|
15
|
+
Disposable,
|
|
16
|
+
} from './types';
|
|
17
|
+
export {
|
|
18
|
+
Scope, SCOPE_CONTEXT, ScopeContext, OnScopeSignal, scopeSignalHandlers, ScopeSignalOptions, ScopeMapping,
|
|
19
|
+
} from './scope/scopeContext';
|
|
20
|
+
export {SystemContext, OnEntitySignal} from './systemContext';
|
|
21
|
+
export {EcsInjector, EntityComponent, GetComponent,GetDynamicComponent, GetEntity, GetContext, GetSignal, OnSignal, GetEntitySignal, } from './ecsInjector';
|
|
7
22
|
|
|
8
23
|
// intellij doesnt auto resolve imports if we just export * from an external dependency
|
|
9
|
-
|
|
10
|
-
import {
|
|
24
|
+
|
|
25
|
+
import {ID, Inject, InjectId, Injector, InjectType, putIfAbsent} from './injector';
|
|
26
|
+
import {Signal, SignalBinding, SignalCallback, signalGroup} from 'mani-signal';
|
|
11
27
|
import {Clock} from './clock';
|
|
12
28
|
|
|
13
29
|
export {Injector, InjectType, InjectId, Inject, putIfAbsent, ID};
|
|
14
30
|
|
|
15
31
|
export {Clock};
|
|
16
32
|
|
|
17
|
-
export {Signal, SignalBinding, SignalCallback};
|
|
33
|
+
export {Signal, SignalBinding, SignalCallback, signalGroup};
|
package/src/injector.ts
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import {Disposable} from './types';
|
|
3
|
+
|
|
4
|
+
export type Class<T = any> = { name: string, new(...args: any[]): T; }
|
|
5
|
+
|
|
6
|
+
type ProviderFunction = () => unknown;
|
|
7
|
+
export type ResolverFunction = (context?: any) => unknown;
|
|
8
|
+
|
|
9
|
+
export type ID = string | symbol;
|
|
10
|
+
|
|
11
|
+
export type Dependency = { kind: string; index: number };
|
|
12
|
+
type TypeDependency = Dependency & { kind: 'type'; index: number; id: ID; };
|
|
13
|
+
type InjectDependency = Dependency & { kind: 'inject'; index: number; id: ID; type: Class; };
|
|
14
|
+
|
|
15
|
+
const enum TypeMappingKind { CLASS, SINGLETON, VALUE, PROVIDER}
|
|
16
|
+
|
|
17
|
+
type ClassTypeMapping = { kind: TypeMappingKind.CLASS; type: Class };
|
|
18
|
+
type SingletonTypeMapping = { kind: TypeMappingKind.SINGLETON; type: Class; injector: Injector };
|
|
19
|
+
type ValueTypeMapping = { kind: TypeMappingKind.VALUE; value: unknown; };
|
|
20
|
+
type ProviderTypeMapping = { kind: TypeMappingKind.PROVIDER; provider: ProviderFunction; };
|
|
21
|
+
// undefined kind is needed because there is no default mapping for types
|
|
22
|
+
type TypeMapping = ClassTypeMapping | SingletonTypeMapping | ValueTypeMapping | ProviderTypeMapping | { kind: undefined };
|
|
23
|
+
|
|
24
|
+
const enum ClassMappingKind { INSTANCE, VALUE, SINGLETON, PROVIDER}
|
|
25
|
+
|
|
26
|
+
type InstanceClassMapping = { kind: ClassMappingKind.INSTANCE; };
|
|
27
|
+
type ValueClassMapping = { kind: ClassMappingKind.VALUE; value: unknown; };
|
|
28
|
+
type SingletonClassMapping = { kind: ClassMappingKind.SINGLETON; injector: Injector };
|
|
29
|
+
type ProviderClassMapping = { kind: ClassMappingKind.PROVIDER; provider: ProviderFunction; };
|
|
30
|
+
type ClassMapping = InstanceClassMapping | ValueClassMapping | SingletonClassMapping | ProviderClassMapping;
|
|
31
|
+
|
|
32
|
+
// most of the class mappings are done with the default id, store them in the def field so we eliminate a second map lookup
|
|
33
|
+
type MapContainer = { map: Map<ID, ClassMapping>; def?: ClassMapping; };
|
|
34
|
+
type SingletonContainer = { map: Map<ID, Object>; def?: Object; };
|
|
35
|
+
type ClassResolverContainer = { map: Map<ID, ResolverFunction>; def?: ResolverFunction; };
|
|
36
|
+
|
|
37
|
+
export type ResolverContext = {
|
|
38
|
+
[propName: string]: any;
|
|
39
|
+
type: Class
|
|
40
|
+
kind: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const isInjectDependency = (dep: Dependency): dep is InjectDependency => dep.kind === 'inject';
|
|
44
|
+
const isTypeDependency = (dep: Dependency): dep is TypeDependency => dep.kind === 'type';
|
|
45
|
+
|
|
46
|
+
interface ClassMapper<T extends Class> {
|
|
47
|
+
get: () => InstanceType<T>;
|
|
48
|
+
toValue(value: InstanceType<T>): InstanceType<T>;
|
|
49
|
+
toSingleton(): GetCall<InstanceType<T>>;
|
|
50
|
+
toProvider(provider: () => InstanceType<T>): GetCall<InstanceType<T>>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
type GetCall<T > = { get: () => T };
|
|
54
|
+
|
|
55
|
+
interface TypeMapper<T> {
|
|
56
|
+
toClass<C extends Class<T>>(classValue: C): GetCall<T>;
|
|
57
|
+
toSingleton<C extends Class<T>>(classValue: C): GetCall<T>;
|
|
58
|
+
toValue(value: T): T;
|
|
59
|
+
toProvider(provider: () => T): GetCall<T>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// why is this not in javascript?! ...
|
|
63
|
+
export const putIfAbsent = <T extends Map<K, V>, K, V>(map: T, key: K, value: () => V) => {
|
|
64
|
+
let v = map.get(key);
|
|
65
|
+
if (!v) {
|
|
66
|
+
v = value();
|
|
67
|
+
map.set(key, v);
|
|
68
|
+
}
|
|
69
|
+
return v;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// helper method to create annotation functions
|
|
73
|
+
export const createDependencyAnnotation = (cb: (type: any, index: number, dependantType: Class) => Dependency) => (dependantType: Class, _propertyKey: any, index: number): any => {
|
|
74
|
+
const metadata = Reflect.getMetadata('design:paramtypes', dependantType);
|
|
75
|
+
const type = metadata[index];
|
|
76
|
+
if (type === dependantType) {
|
|
77
|
+
throw new Error('Could not inject class in itself.');
|
|
78
|
+
}
|
|
79
|
+
const depList = putIfAbsent(Injector.dependencyMap, dependantType, (): Dependency[] => []);
|
|
80
|
+
|
|
81
|
+
depList.push(cb(type, index, dependantType));
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Default DependencyAnnotations
|
|
85
|
+
export const Inject = createDependencyAnnotation((type, index) => ({kind: 'inject', index, type, id: ''}));
|
|
86
|
+
export const InjectId = (id: ID) => createDependencyAnnotation((type, index) => ({kind: 'inject', index, type, id}));
|
|
87
|
+
export const InjectType = (id: ID) => createDependencyAnnotation((_type, index) => ({kind: 'type', index, id}));
|
|
88
|
+
|
|
89
|
+
type DependencyExtensionResolver = (context: ResolverContext, dependency: Dependency) => ResolverFunction;
|
|
90
|
+
|
|
91
|
+
export class Injector {
|
|
92
|
+
static readonly dependencyMap = new Map<Class, Dependency[]>();
|
|
93
|
+
|
|
94
|
+
protected readonly typeMappings = new Map<ID, TypeMapping>();
|
|
95
|
+
protected readonly classMappings = new Map<Class, MapContainer>();
|
|
96
|
+
protected readonly parameterResolverArrays = new Map<Class, ResolverFunction[]>();
|
|
97
|
+
|
|
98
|
+
protected readonly classResolvers = new Map<Class, ClassResolverContainer>();
|
|
99
|
+
protected readonly typeResolvers = new Map<ID, ResolverFunction>();
|
|
100
|
+
|
|
101
|
+
protected readonly singletons = new Map<Class, SingletonContainer>();
|
|
102
|
+
protected readonly typeSingletons = new Map<ID, Object>();
|
|
103
|
+
|
|
104
|
+
protected readonly dependencyResolverExtensions: Map<string, DependencyExtensionResolver>;
|
|
105
|
+
private readonly disposables = new Set<Disposable>();
|
|
106
|
+
private disposed = false;
|
|
107
|
+
|
|
108
|
+
constructor(readonly parent?: Injector) {
|
|
109
|
+
this.dependencyResolverExtensions = parent ? parent.dependencyResolverExtensions : new Map<string, DependencyExtensionResolver>();
|
|
110
|
+
this.map(Injector).toValue(this);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
createChild(): this {
|
|
114
|
+
return new (<typeof Injector>this.constructor)(this) as this;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
addExtensionResolver(kind: string, resolver: DependencyExtensionResolver) {
|
|
118
|
+
this.dependencyResolverExtensions.set(kind, resolver);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
map<T extends Class>(type: T, id: ID = ''): ClassMapper<T> {
|
|
122
|
+
const mapper = new InternalClassMapper<T>(this, type, id);
|
|
123
|
+
const idMappings = putIfAbsent(this.classMappings, type as Class, (): MapContainer => ({map: new Map<ID, ClassMapping>()}));
|
|
124
|
+
if (id === '') {
|
|
125
|
+
idMappings.def = mapper.mapping;
|
|
126
|
+
} else {
|
|
127
|
+
idMappings.map.set(id, mapper.mapping);
|
|
128
|
+
}
|
|
129
|
+
return mapper;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
mapType<T>(id: ID): TypeMapper<T> {
|
|
133
|
+
const typeMapper = new InternalTypeMapper<T>(this, id);
|
|
134
|
+
this.typeMappings.set(id, typeMapper.mapping);
|
|
135
|
+
return typeMapper;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
getType<T>(id: ID): T {
|
|
139
|
+
const typeResolver = this.getTypeResolver(id);
|
|
140
|
+
if (!typeResolver) {
|
|
141
|
+
throw new Error(`No Mapping for Type with id: '${String(id)}'`);
|
|
142
|
+
}
|
|
143
|
+
return typeResolver() as T;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
get<T extends Class>(type: T, id: ID = ''): InstanceType<T> {
|
|
147
|
+
const resolver = this.getClassIdResolver(type, id);
|
|
148
|
+
if (!resolver) {
|
|
149
|
+
throw new Error(`No Mapping for Type ${type.name}` + String(id === '' ? '' : ` with id: '${String(id)}'`));
|
|
150
|
+
}
|
|
151
|
+
return resolver() as InstanceType<T>;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
createInstance<T extends Class>(type: T) {
|
|
155
|
+
return this.getCreateInstanceResolver(type)();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
protected createResolverArray(resolverContext: ResolverContext) {
|
|
159
|
+
const {type} = resolverContext;
|
|
160
|
+
const result: ResolverFunction[] = [];
|
|
161
|
+
const dependencies = Injector.dependencyMap.get(resolverContext.type);
|
|
162
|
+
if (!dependencies) {
|
|
163
|
+
return [];
|
|
164
|
+
}
|
|
165
|
+
for (const dependency of dependencies) {
|
|
166
|
+
let resolver: ResolverFunction;
|
|
167
|
+
if (isInjectDependency(dependency)) {
|
|
168
|
+
if (!dependency.type) throw new Error(`Undefined dependency type for ${type.name}. Check for circular dependency.`);
|
|
169
|
+
const classIdResolver = this.getClassIdResolver(dependency.type, dependency.id);
|
|
170
|
+
if (!classIdResolver) {
|
|
171
|
+
throw new Error(`Could not inject ${dependency.type.name} into ${resolverContext.type.name}`);
|
|
172
|
+
}
|
|
173
|
+
resolver = classIdResolver;
|
|
174
|
+
} else if (isTypeDependency(dependency)) {
|
|
175
|
+
const typeResolver = this.getTypeResolver(dependency.id);
|
|
176
|
+
if (!typeResolver) {
|
|
177
|
+
throw new Error(`Could not inject type with id '${String(dependency.id)}' into ${resolverContext.type.name}`);
|
|
178
|
+
}
|
|
179
|
+
resolver = typeResolver;
|
|
180
|
+
} else {
|
|
181
|
+
const extensionResolver = this.dependencyResolverExtensions.get(dependency.kind);
|
|
182
|
+
if (!extensionResolver) {
|
|
183
|
+
throw new Error(`no dependency resolver for '${dependency.kind}'`);
|
|
184
|
+
}
|
|
185
|
+
resolver = extensionResolver(resolverContext, dependency);
|
|
186
|
+
}
|
|
187
|
+
result[dependency.index] = resolver;
|
|
188
|
+
}
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
protected getClassMapping(type: Class, id: ID): ClassMapping | undefined {
|
|
193
|
+
const idMapping = this.classMappings.get(type);
|
|
194
|
+
if (!idMapping) {
|
|
195
|
+
if (!this.parent) return undefined;
|
|
196
|
+
return this.parent.getClassMapping(type, id);
|
|
197
|
+
}
|
|
198
|
+
const mapping = id === '' ? idMapping.def : idMapping.map.get(id);
|
|
199
|
+
if (!mapping) {
|
|
200
|
+
if (!this.parent) return undefined;
|
|
201
|
+
return this.parent.getClassMapping(type, id);
|
|
202
|
+
}
|
|
203
|
+
return mapping;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
protected getClassIdResolver(dependencyType: Class, id: ID) {
|
|
207
|
+
const getResolver = (): ResolverFunction | undefined => {
|
|
208
|
+
const mapping = this.getClassMapping(dependencyType, id);
|
|
209
|
+
if (!mapping) return undefined;
|
|
210
|
+
switch (mapping.kind) {
|
|
211
|
+
case ClassMappingKind.INSTANCE:
|
|
212
|
+
return this.getCreateInstanceResolver(dependencyType);
|
|
213
|
+
case ClassMappingKind.VALUE:
|
|
214
|
+
// we can cache the value for values
|
|
215
|
+
const instance = mapping.value;
|
|
216
|
+
return () => instance;
|
|
217
|
+
case ClassMappingKind.SINGLETON:
|
|
218
|
+
let singleton: unknown;
|
|
219
|
+
// use the injector defined in the mapping to get the right injector
|
|
220
|
+
const singletonContainer = putIfAbsent(mapping.injector.singletons, dependencyType, (): SingletonContainer => ({map: new Map<ID, Object>()}));
|
|
221
|
+
if (id === '') {
|
|
222
|
+
if (singletonContainer.def) {
|
|
223
|
+
singleton = singletonContainer.def;
|
|
224
|
+
} else {
|
|
225
|
+
singletonContainer.def = mapping.injector.createInstance(dependencyType);
|
|
226
|
+
singleton = singletonContainer.def;
|
|
227
|
+
}
|
|
228
|
+
} else {
|
|
229
|
+
singleton = putIfAbsent(singletonContainer.map, id, () => mapping.injector.createInstance(dependencyType));
|
|
230
|
+
}
|
|
231
|
+
return () => singleton;
|
|
232
|
+
case ClassMappingKind.PROVIDER:
|
|
233
|
+
// we can directly set the provider function as resolver
|
|
234
|
+
const providerInstance = mapping.provider();
|
|
235
|
+
this._registerDisposer(providerInstance as any);
|
|
236
|
+
return () => providerInstance;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const container = putIfAbsent(this.classResolvers, dependencyType, (): ClassResolverContainer => ({
|
|
241
|
+
def: undefined,
|
|
242
|
+
map: new Map<ID, ResolverFunction>(),
|
|
243
|
+
}));
|
|
244
|
+
|
|
245
|
+
if (id === '') {
|
|
246
|
+
if (container.def) {
|
|
247
|
+
return container.def;
|
|
248
|
+
}
|
|
249
|
+
const resolver = getResolver();
|
|
250
|
+
container.def = resolver;
|
|
251
|
+
return resolver;
|
|
252
|
+
} else {
|
|
253
|
+
return putIfAbsent(container.map, id, () => getResolver());
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
protected getTypeResolver(id: ID): ResolverFunction | undefined {
|
|
258
|
+
return putIfAbsent(this.typeResolvers, id, () => {
|
|
259
|
+
const mapping = this.getTypeMapping(id);
|
|
260
|
+
if (!mapping) return undefined;
|
|
261
|
+
if (mapping.kind === undefined) {
|
|
262
|
+
// mapping.kind is undefined if there is a type mapping without a target (toClass, toSingleton, toValue)
|
|
263
|
+
throw new Error(`No TypeMapping for id ${String(id)}.`);
|
|
264
|
+
}
|
|
265
|
+
if (mapping.kind === TypeMappingKind.VALUE) {
|
|
266
|
+
const instance = mapping.value;
|
|
267
|
+
return () => instance;
|
|
268
|
+
} else if (mapping.kind === TypeMappingKind.CLASS) {
|
|
269
|
+
return this.getCreateInstanceResolver(mapping.type);
|
|
270
|
+
} else if (mapping.kind === TypeMappingKind.SINGLETON) {
|
|
271
|
+
// use the injector defined in the mapping to get the right injector
|
|
272
|
+
const instance = putIfAbsent(mapping.injector.typeSingletons, id, () => mapping.injector.createInstance(mapping.type));
|
|
273
|
+
return () => instance;
|
|
274
|
+
} else {
|
|
275
|
+
// mapping kind has to be provider
|
|
276
|
+
const providerInstance = mapping.provider();
|
|
277
|
+
this._registerDisposer(providerInstance as any);
|
|
278
|
+
return () => providerInstance;
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
protected getCreateInstanceResolver(type: Class) {
|
|
284
|
+
const resolvers = putIfAbsent(this.parameterResolverArrays, type as Class, () => this.createResolverArray({
|
|
285
|
+
kind: 'class',
|
|
286
|
+
type: type,
|
|
287
|
+
}));
|
|
288
|
+
if (resolvers.length === 0) {
|
|
289
|
+
return () => {
|
|
290
|
+
const instance = new type();
|
|
291
|
+
this._registerDisposer(instance);
|
|
292
|
+
return instance;
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
const args = new Array(resolvers.length);
|
|
296
|
+
return () => {
|
|
297
|
+
for (let i = 0; i < args.length; i++) {
|
|
298
|
+
args[i] = resolvers[i]();
|
|
299
|
+
}
|
|
300
|
+
const instance = new type(...args);
|
|
301
|
+
this._registerDisposer(instance);
|
|
302
|
+
return instance;
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
protected getTypeMapping(id: ID): TypeMapping | undefined {
|
|
307
|
+
const mapping = this.typeMappings.get(id);
|
|
308
|
+
if (!mapping) {
|
|
309
|
+
if (!this.parent) return undefined;
|
|
310
|
+
return this.parent.getTypeMapping(id);
|
|
311
|
+
}
|
|
312
|
+
return mapping;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
public _registerDisposer(instance: Partial<Disposable>) {
|
|
316
|
+
instance.onDispose && this.disposables.add(instance as Disposable);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
public _dispose() {
|
|
320
|
+
if (this.disposed) throw new Error('Injector already disposed');
|
|
321
|
+
for (const disposable of this.disposables) {
|
|
322
|
+
disposable.onDispose();
|
|
323
|
+
}
|
|
324
|
+
this.disposed = true;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
class InternalTypeMapper<T> implements TypeMapper<T> {
|
|
329
|
+
mapping: TypeMapping = {kind: undefined};
|
|
330
|
+
|
|
331
|
+
private readonly getCall: GetCall<T>;
|
|
332
|
+
|
|
333
|
+
constructor(private readonly injector: Injector, id: ID) {
|
|
334
|
+
this.getCall = {get: () => this.injector.getType(id)};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
toClass<C extends Class<T>>(classValue: C):GetCall<T> {
|
|
338
|
+
Object.assign<TypeMapping, ClassTypeMapping>(this.mapping, {
|
|
339
|
+
kind: TypeMappingKind.CLASS,
|
|
340
|
+
type: classValue,
|
|
341
|
+
});
|
|
342
|
+
return this.getCall;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
toSingleton<C extends Class<T>>(classValue: C):GetCall<T> {
|
|
346
|
+
Object.assign<TypeMapping, SingletonTypeMapping>(this.mapping, {
|
|
347
|
+
kind: TypeMappingKind.SINGLETON,
|
|
348
|
+
type: classValue,
|
|
349
|
+
injector: this.injector,
|
|
350
|
+
});
|
|
351
|
+
return this.getCall;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
toValue(value: T):T {
|
|
355
|
+
Object.assign<TypeMapping, ValueTypeMapping>(this.mapping, {
|
|
356
|
+
kind: TypeMappingKind.VALUE,
|
|
357
|
+
value: value,
|
|
358
|
+
});
|
|
359
|
+
this.injector._registerDisposer(value as any);
|
|
360
|
+
return value;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
toProvider(provider: () => T):GetCall<T> {
|
|
364
|
+
Object.assign<TypeMapping, ProviderTypeMapping>(this.mapping, {
|
|
365
|
+
kind: TypeMappingKind.PROVIDER,
|
|
366
|
+
provider: provider,
|
|
367
|
+
});
|
|
368
|
+
return this.getCall;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
class InternalClassMapper<T extends Class> implements ClassMapper<T> {
|
|
373
|
+
// instance is the default class mapping
|
|
374
|
+
mapping: ClassMapping = {kind: ClassMappingKind.INSTANCE};
|
|
375
|
+
private readonly getCall: GetCall<InstanceType<T>>;
|
|
376
|
+
readonly get: () => InstanceType<T>;
|
|
377
|
+
|
|
378
|
+
constructor(private readonly injector: Injector, type: T, id: ID) {
|
|
379
|
+
this.getCall = {get: () => this.injector.get(type, id)};
|
|
380
|
+
this.get = ()=>this.injector.get(type, id);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
toValue(value: InstanceType<T>) {
|
|
384
|
+
Object.assign<ClassMapping, ValueClassMapping>(this.mapping, {
|
|
385
|
+
kind: ClassMappingKind.VALUE,
|
|
386
|
+
value: value,
|
|
387
|
+
});
|
|
388
|
+
this.injector._registerDisposer(value);
|
|
389
|
+
return value;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
toSingleton(): GetCall<InstanceType<T>> {
|
|
395
|
+
Object.assign<ClassMapping, SingletonClassMapping>(this.mapping, {
|
|
396
|
+
kind: ClassMappingKind.SINGLETON,
|
|
397
|
+
injector: this.injector,
|
|
398
|
+
});
|
|
399
|
+
this.mapping.kind = ClassMappingKind.SINGLETON;
|
|
400
|
+
return this.getCall;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
toProvider(provider: () => InstanceType<T>):GetCall<InstanceType<T>> {
|
|
404
|
+
Object.assign<ClassMapping, ProviderClassMapping>(this.mapping, {
|
|
405
|
+
kind: ClassMappingKind.PROVIDER,
|
|
406
|
+
provider: provider,
|
|
407
|
+
});
|
|
408
|
+
return this.getCall
|
|
409
|
+
}
|
|
410
|
+
}
|