@composed-di/core 0.5.2-alpha → 0.6.0-alpha

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.
Files changed (46) hide show
  1. package/dist/errors.d.ts +0 -2
  2. package/dist/errors.d.ts.map +1 -1
  3. package/dist/errors.js +4 -4
  4. package/dist/errors.js.map +1 -1
  5. package/dist/index.d.ts +0 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +0 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/serviceFactory.d.ts.map +1 -1
  10. package/dist/serviceFactory.js.map +1 -1
  11. package/dist/serviceKey.d.ts +6 -0
  12. package/dist/serviceKey.d.ts.map +1 -1
  13. package/dist/serviceKey.js.map +1 -1
  14. package/dist/serviceModule.d.ts +1 -11
  15. package/dist/serviceModule.d.ts.map +1 -1
  16. package/dist/serviceModule.js +3 -146
  17. package/dist/serviceModule.js.map +1 -1
  18. package/dist/serviceScope.d.ts.map +1 -1
  19. package/dist/serviceScope.js.map +1 -1
  20. package/dist/serviceSelector.d.ts.map +1 -1
  21. package/dist/serviceSelector.js.map +1 -1
  22. package/dist/utils.d.ts.map +1 -1
  23. package/dist/utils.js.map +1 -1
  24. package/package.json +17 -17
  25. package/src/errors.ts +2 -10
  26. package/src/index.ts +7 -9
  27. package/src/serviceFactory.ts +33 -33
  28. package/src/serviceKey.ts +11 -4
  29. package/src/serviceModule.ts +53 -217
  30. package/src/serviceScope.ts +2 -2
  31. package/src/serviceSelector.ts +4 -4
  32. package/src/utils.ts +103 -103
  33. package/dist/redactingEventListener.d.ts +0 -57
  34. package/dist/redactingEventListener.d.ts.map +0 -1
  35. package/dist/redactingEventListener.js +0 -89
  36. package/dist/redactingEventListener.js.map +0 -1
  37. package/dist/serviceEventListener.d.ts +0 -133
  38. package/dist/serviceEventListener.d.ts.map +0 -1
  39. package/dist/serviceEventListener.js +0 -3
  40. package/dist/serviceEventListener.js.map +0 -1
  41. package/dist/serviceModuleListener.d.ts +0 -133
  42. package/dist/serviceModuleListener.d.ts.map +0 -1
  43. package/dist/serviceModuleListener.js +0 -3
  44. package/dist/serviceModuleListener.js.map +0 -1
  45. package/src/redactingEventListener.ts +0 -132
  46. package/src/serviceModuleListener.ts +0 -139
@@ -1,6 +1,6 @@
1
- import { ServiceKey, ServiceSelectorKey } from './serviceKey';
2
- import { ServiceScope } from './serviceScope';
3
- import { ServiceSelector } from './serviceSelector';
1
+ import { ServiceKey, ServiceSelectorKey } from './serviceKey'
2
+ import { ServiceScope } from './serviceScope'
3
+ import { ServiceSelector } from './serviceSelector'
4
4
 
5
5
  // Helper types to extract the type from ServiceKey or ServiceSelectorKey
6
6
  type ServiceType<T> =
@@ -8,22 +8,22 @@ type ServiceType<T> =
8
8
  ? ServiceSelector<U>
9
9
  : T extends ServiceKey<infer U>
10
10
  ? U
11
- : never;
11
+ : never
12
12
 
13
13
  // Helper types to convert an array/tuple of ServiceKey to tuple of their types
14
14
  type DependencyTypes<T extends readonly ServiceKey<unknown>[]> = {
15
- [K in keyof T]: ServiceType<T[K]>;
16
- };
15
+ [K in keyof T]: ServiceType<T[K]>
16
+ }
17
17
 
18
18
  export abstract class ServiceFactory<
19
19
  const T,
20
20
  const D extends readonly ServiceKey<unknown>[] = [],
21
21
  > {
22
- abstract provides: ServiceKey<T>;
23
- abstract dependsOn: D;
24
- abstract scope?: ServiceScope;
25
- abstract initialize: (...dependencies: DependencyTypes<D>) => T | Promise<T>;
26
- abstract dispose?: () => void;
22
+ abstract provides: ServiceKey<T>
23
+ abstract dependsOn: D
24
+ abstract scope?: ServiceScope
25
+ abstract initialize: (...dependencies: DependencyTypes<D>) => T | Promise<T>
26
+ abstract dispose?: () => void
27
27
 
28
28
  /**
29
29
  * Creates a singleton service factory that ensures a single instance of the provided service is initialized
@@ -39,14 +39,14 @@ export abstract class ServiceFactory<
39
39
  initialize,
40
40
  dispose = () => {},
41
41
  }: {
42
- scope?: ServiceScope;
43
- provides: ServiceKey<T>;
44
- dependsOn?: D;
45
- initialize: (...dependencies: DependencyTypes<D>) => T | Promise<T>;
46
- dispose?: (instance: T) => void;
42
+ scope?: ServiceScope
43
+ provides: ServiceKey<T>
44
+ dependsOn?: D
45
+ initialize: (...dependencies: DependencyTypes<D>) => T | Promise<T>
46
+ dispose?: (instance: T) => void
47
47
  }): ServiceFactory<T, D> {
48
- let promisedInstance: Promise<T> | undefined;
49
- let resolvedInstance: T | undefined;
48
+ let promisedInstance: Promise<T> | undefined
49
+ let resolvedInstance: T | undefined
50
50
 
51
51
  return {
52
52
  scope,
@@ -54,32 +54,32 @@ export abstract class ServiceFactory<
54
54
  dependsOn,
55
55
  async initialize(...dependencies: DependencyTypes<D>): Promise<T> {
56
56
  if (resolvedInstance !== undefined) {
57
- return resolvedInstance;
57
+ return resolvedInstance
58
58
  }
59
59
 
60
60
  if (promisedInstance !== undefined) {
61
- return promisedInstance;
61
+ return promisedInstance
62
62
  }
63
63
 
64
64
  // Store the reference to the promise so that concurrent requests can wait for it
65
65
  promisedInstance = (async () => {
66
66
  try {
67
- resolvedInstance = await initialize(...dependencies);
68
- return resolvedInstance;
67
+ resolvedInstance = await initialize(...dependencies)
68
+ return resolvedInstance
69
69
  } finally {
70
- promisedInstance = undefined;
70
+ promisedInstance = undefined
71
71
  }
72
- })();
73
- return promisedInstance;
72
+ })()
73
+ return promisedInstance
74
74
  },
75
75
  dispose(): void {
76
76
  if (resolvedInstance !== undefined) {
77
- dispose(resolvedInstance);
78
- resolvedInstance = undefined;
77
+ dispose(resolvedInstance)
78
+ resolvedInstance = undefined
79
79
  }
80
- promisedInstance = undefined;
80
+ promisedInstance = undefined
81
81
  },
82
- };
82
+ }
83
83
  }
84
84
 
85
85
  /**
@@ -91,14 +91,14 @@ export abstract class ServiceFactory<
91
91
  dependsOn,
92
92
  initialize,
93
93
  }: {
94
- provides: ServiceKey<T>;
95
- dependsOn: D;
96
- initialize: (...dependencies: DependencyTypes<D>) => T | Promise<T>;
94
+ provides: ServiceKey<T>
95
+ dependsOn: D
96
+ initialize: (...dependencies: DependencyTypes<D>) => T | Promise<T>
97
97
  }): ServiceFactory<T, D> {
98
98
  return {
99
99
  provides,
100
100
  dependsOn,
101
101
  initialize,
102
- };
102
+ }
103
103
  }
104
104
  }
package/src/serviceKey.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  // @ts-ignore
2
- import { ServiceSelector } from './serviceSelector';
2
+ import { ServiceSelector } from './serviceSelector'
3
3
 
4
4
  /**
5
5
  * A typed token used to identify and retrieve a service from a ServiceModule.
@@ -30,11 +30,18 @@ import { ServiceSelector } from './serviceSelector';
30
30
  * ```
31
31
  */
32
32
  export class ServiceKey<T> {
33
+ /**
34
+ * Phantom field that brands this key with the service type `T`.
35
+ * Exists only at the type level (`declare` emits no runtime code) and
36
+ * prevents keys of different service types from being interchangeable.
37
+ */
38
+ declare private readonly _type: T
39
+
33
40
  /**
34
41
  * A unique symbol that identifies this service key.
35
42
  * Used internally for identity comparison between keys.
36
43
  */
37
- public readonly symbol: symbol;
44
+ public readonly symbol: symbol
38
45
 
39
46
  /**
40
47
  * Creates a new ServiceKey with the given name.
@@ -42,7 +49,7 @@ export class ServiceKey<T> {
42
49
  * @param name A human-readable name for the service, used in error messages and debugging.
43
50
  */
44
51
  constructor(public readonly name: string) {
45
- this.symbol = Symbol(name);
52
+ this.symbol = Symbol(name)
46
53
  }
47
54
  }
48
55
 
@@ -90,6 +97,6 @@ export class ServiceSelectorKey<T> extends ServiceKey<ServiceSelector<T>> {
90
97
  * All keys must be registered in the ServiceModule for dependency validation to pass.
91
98
  */
92
99
  constructor(readonly values: ServiceKey<T>[]) {
93
- super(`ServiceSelector[${values}]`);
100
+ super(`ServiceSelector[${values}]`)
94
101
  }
95
102
  }
@@ -1,15 +1,11 @@
1
- import { ServiceKey, ServiceSelectorKey } from './serviceKey';
2
- import { ServiceFactory } from './serviceFactory';
3
- import { ServiceScope } from './serviceScope';
4
- import { ServiceSelector } from './serviceSelector';
5
- import { ServiceFactoryNotFoundError, ServiceModuleInitError } from './errors';
6
- import type {
7
- EventSpan,
8
- ServiceModuleListener,
9
- } from './serviceModuleListener';
1
+ import { ServiceKey, ServiceSelectorKey } from './serviceKey'
2
+ import { ServiceFactory } from './serviceFactory'
3
+ import { ServiceScope } from './serviceScope'
4
+ import { ServiceSelector } from './serviceSelector'
5
+ import { ServiceFactoryNotFoundError, ServiceModuleInitError } from './errors'
10
6
 
11
- type GenericFactory = ServiceFactory<unknown, readonly ServiceKey<any>[]>;
12
- type GenericKey = ServiceKey<any>;
7
+ type GenericFactory = ServiceFactory<unknown, readonly ServiceKey<any>[]>
8
+ type GenericKey = ServiceKey<any>
13
9
 
14
10
  /**
15
11
  * ServiceModule is a container for service factories and manages dependency resolution.
@@ -26,10 +22,10 @@ export class ServiceModule {
26
22
  * @param factories An array of service factories that this module will manage.
27
23
  */
28
24
  private constructor(readonly factories: GenericFactory[]) {
29
- checkCircularDependencies(this.factories);
25
+ checkCircularDependencies(this.factories)
30
26
  factories.forEach((factory) => {
31
- checkMissingDependencies(factory, this.factories);
32
- });
27
+ checkMissingDependencies(factory, this.factories)
28
+ })
33
29
  }
34
30
 
35
31
  /**
@@ -40,15 +36,15 @@ export class ServiceModule {
40
36
  * @throws {ServiceFactoryNotFoundError} If no suitable factory is found for the given key.
41
37
  */
42
38
  public async get<T>(key: ServiceKey<T>): Promise<T> {
43
- const factory = this.factories.find((factory: GenericFactory) => {
44
- return isSuitable(key, factory);
45
- });
39
+ const factory = this.factories.find((candidate: GenericFactory) => {
40
+ return isSuitable(key, candidate)
41
+ })
46
42
 
47
43
  // Check if a factory to supply the requested key was not found
48
44
  if (!factory) {
49
45
  throw new ServiceFactoryNotFoundError(
50
46
  `Could not find a suitable factory for ${key.name}`,
51
- );
47
+ )
52
48
  }
53
49
 
54
50
  // Resolve all dependencies first
@@ -56,14 +52,14 @@ export class ServiceModule {
56
52
  factory.dependsOn.map((dependencyKey: ServiceKey<unknown>) => {
57
53
  // If the dependency is a ServiceSelectorKey, create a ServiceSelector instance
58
54
  if (dependencyKey instanceof ServiceSelectorKey) {
59
- return new ServiceSelector(this, dependencyKey);
55
+ return new ServiceSelector(this, dependencyKey)
60
56
  }
61
- return this.get(dependencyKey);
57
+ return this.get(dependencyKey)
62
58
  }),
63
- );
59
+ )
64
60
 
65
61
  // Call the factory to retrieve the dependency
66
- return factory.initialize(...dependencies);
62
+ return factory.initialize(...dependencies)
67
63
  }
68
64
 
69
65
  /**
@@ -74,12 +70,12 @@ export class ServiceModule {
74
70
  */
75
71
  public async getOrNull<T>(key: ServiceKey<T>): Promise<T | null> {
76
72
  try {
77
- return await this.get(key);
73
+ return await this.get(key)
78
74
  } catch (error) {
79
75
  if (error instanceof ServiceFactoryNotFoundError) {
80
- return null;
76
+ return null
81
77
  }
82
- throw error;
78
+ throw error
83
79
  }
84
80
  }
85
81
 
@@ -96,9 +92,9 @@ export class ServiceModule {
96
92
  public dispose(scope?: ServiceScope) {
97
93
  const factories = scope
98
94
  ? this.factories.filter((f) => f.scope === scope)
99
- : this.factories;
95
+ : this.factories
100
96
 
101
- factories.forEach((factory) => factory.dispose?.());
97
+ factories.forEach((factory) => factory.dispose?.())
102
98
  }
103
99
 
104
100
  /**
@@ -107,44 +103,24 @@ export class ServiceModule {
107
103
  * If multiple factories provide the same
108
104
  * ServiceKey, the last one in the list takes precedence.
109
105
  *
110
- * When a listener is provided, every factory is wrapped with instrumentation:
111
- * the listener is notified when a service is initialized or disposed and when
112
- * a method is called on a service instance, and may return an EventSpan per
113
- * operation to observe its completion. Service instances are wrapped in a
114
- * Proxy to observe method calls, and errors are rethrown after being
115
- * reported, so behavior is otherwise unchanged.
116
- *
117
106
  * @param entries - An array of ServiceModule or GenericFactory
118
107
  * instances to be processed into a single ServiceModule.
119
- * @param listener - An optional ServiceEventListener notified of service
120
- * lifecycle events and method calls in the resulting module.
121
108
  * @return A new ServiceModule containing the deduplicated factories.
122
109
  * @throws {ServiceModuleInitError} If circular or missing dependencies are detected during module creation.
123
110
  */
124
- static from(
125
- entries: (ServiceModule | GenericFactory)[],
126
- listener?: ServiceModuleListener,
127
- ): ServiceModule {
111
+ static from(entries: (ServiceModule | GenericFactory)[]): ServiceModule {
128
112
  // Flatten entries and keep only the last factory for each ServiceKey
129
113
  const flattened = entries.flatMap((e) =>
130
114
  e instanceof ServiceModule ? e.factories : [e],
131
- );
115
+ )
132
116
 
133
- const byKey = new Map<symbol, GenericFactory>();
117
+ const byKey = new Map<symbol, GenericFactory>()
134
118
  // Later factories overwrite earlier ones (last-wins)
135
119
  for (const f of flattened) {
136
- byKey.set(f.provides.symbol, f);
137
- }
138
-
139
- if (listener) {
140
- return new ServiceModule(
141
- Array.from(byKey.values()).map((factory) => {
142
- return makeObservable(listener, factory);
143
- }),
144
- );
120
+ byKey.set(f.provides.symbol, f)
145
121
  }
146
122
 
147
- return new ServiceModule(Array.from(byKey.values()));
123
+ return new ServiceModule(Array.from(byKey.values()))
148
124
  }
149
125
  }
150
126
 
@@ -155,48 +131,48 @@ export class ServiceModule {
155
131
  * @throws {ServiceModuleInitError} If a circular dependency is detected.
156
132
  */
157
133
  function checkCircularDependencies(factories: GenericFactory[]) {
158
- const factoryMap = new Map<symbol, GenericFactory>();
134
+ const factoryMap = new Map<symbol, GenericFactory>()
159
135
  for (const f of factories) {
160
- factoryMap.set(f.provides.symbol, f);
136
+ factoryMap.set(f.provides.symbol, f)
161
137
  }
162
138
 
163
- const visited = new Set<symbol>();
164
- const stack = new Set<symbol>();
139
+ const visited = new Set<symbol>()
140
+ const stack = new Set<symbol>()
165
141
 
166
142
  function walk(factory: GenericFactory, path: string[]) {
167
- const symbol = factory.provides.symbol;
143
+ const symbol = factory.provides.symbol
168
144
 
169
145
  if (stack.has(symbol)) {
170
- const cyclePath = [...path, factory.provides.name].join(' -> ');
146
+ const cyclePath = [...path, factory.provides.name].join(' -> ')
171
147
  throw new ServiceModuleInitError(
172
148
  `Circular dependency detected: ${cyclePath}`,
173
- );
149
+ )
174
150
  }
175
151
 
176
152
  if (visited.has(symbol)) {
177
- return;
153
+ return
178
154
  }
179
155
 
180
- visited.add(symbol);
181
- stack.add(symbol);
156
+ visited.add(symbol)
157
+ stack.add(symbol)
182
158
 
183
159
  for (const depKey of factory.dependsOn) {
184
160
  const keysToCheck =
185
- depKey instanceof ServiceSelectorKey ? depKey.values : [depKey];
161
+ depKey instanceof ServiceSelectorKey ? depKey.values : [depKey]
186
162
 
187
163
  for (const key of keysToCheck) {
188
- const depFactory = factoryMap.get(key.symbol);
164
+ const depFactory = factoryMap.get(key.symbol)
189
165
  if (depFactory) {
190
- walk(depFactory, [...path, factory.provides.name]);
166
+ walk(depFactory, [...path, factory.provides.name])
191
167
  }
192
168
  }
193
169
  }
194
170
 
195
- stack.delete(symbol);
171
+ stack.delete(symbol)
196
172
  }
197
173
 
198
174
  for (const factory of factories) {
199
- walk(factory, []);
175
+ walk(factory, [])
200
176
  }
201
177
  }
202
178
 
@@ -211,31 +187,31 @@ function checkMissingDependencies(
211
187
  factory: GenericFactory,
212
188
  factories: GenericFactory[],
213
189
  ) {
214
- const missingDependencies: GenericKey[] = [];
190
+ const missingDependencies: GenericKey[] = []
215
191
 
216
192
  factory.dependsOn.forEach((dependencyKey: GenericKey) => {
217
193
  // For ServiceSelectorKey, check all contained keys are registered
218
194
  if (dependencyKey instanceof ServiceSelectorKey) {
219
195
  dependencyKey.values.forEach((key) => {
220
196
  if (!isRegistered(key, factories)) {
221
- missingDependencies.push(key);
197
+ missingDependencies.push(key)
222
198
  }
223
- });
199
+ })
224
200
  } else if (!isRegistered(dependencyKey, factories)) {
225
- missingDependencies.push(dependencyKey);
201
+ missingDependencies.push(dependencyKey)
226
202
  }
227
- });
203
+ })
228
204
 
229
205
  if (missingDependencies.length === 0) {
230
- return;
206
+ return
231
207
  }
232
208
 
233
209
  const dependencyList = missingDependencies
234
210
  .map((dependencyKey) => ` -> ${dependencyKey.name}`)
235
- .join('\n');
211
+ .join('\n')
236
212
  throw new ServiceModuleInitError(
237
213
  `${factory.provides.name} will fail because it depends on:\n ${dependencyList}`,
238
- );
214
+ )
239
215
  }
240
216
 
241
217
  /**
@@ -246,7 +222,7 @@ function checkMissingDependencies(
246
222
  * @returns True if a factory provides the given key, false otherwise.
247
223
  */
248
224
  function isRegistered(key: GenericKey, factories: GenericFactory[]) {
249
- return factories.some((factory) => factory.provides?.symbol === key?.symbol);
225
+ return factories.some((factory) => factory.provides?.symbol === key?.symbol)
250
226
  }
251
227
 
252
228
  /**
@@ -260,145 +236,5 @@ function isSuitable<T, D extends readonly ServiceKey<any>[]>(
260
236
  key: ServiceKey<T>,
261
237
  factory: ServiceFactory<any, D>,
262
238
  ): factory is ServiceFactory<T, D> {
263
- return factory?.provides?.symbol === key?.symbol;
264
- }
265
-
266
- /**
267
- * Wraps a given service factory with instrumentation to notify a listener of
268
- * lifecycle events and method calls.
269
- *
270
- * For each of initialize, dispose, and method calls, the listener is invoked
271
- * at the start of the operation and may return an EventSpan whose `end` is
272
- * called with the outcome when the operation finishes. Errors are rethrown
273
- * after being reported.
274
- *
275
- * @param listener The listener notified of lifecycle and method call events.
276
- * @param delegate The original service factory to be instrumented.
277
- * @return A new service factory that provides the same dependencies but includes event notification logic.
278
- */
279
- function makeObservable<T, D extends readonly ServiceKey<any>[]>(
280
- listener: ServiceModuleListener,
281
- delegate: ServiceFactory<any, D>,
282
- ): ServiceFactory<T, D> {
283
- const key = delegate.provides;
284
-
285
- return ServiceFactory.singleton({
286
- scope: delegate.scope,
287
- provides: delegate.provides,
288
- dependsOn: delegate.dependsOn,
289
- dispose: () => {
290
- const dispose = delegate.dispose;
291
- if (dispose) {
292
- const span = listener.onDispose?.({ key });
293
- try {
294
- invokeWithin(span, dispose);
295
- } catch (error) {
296
- span?.end?.({ type: 'failure', error });
297
- throw error;
298
- }
299
- span?.end?.({ type: 'success', value: undefined });
300
- }
301
- },
302
- initialize: async (...args) => {
303
- const span = listener.onInitialize?.({ key });
304
- try {
305
- const instance = observeMethodCalls(
306
- await invokeWithin(span, () => delegate.initialize(...args)),
307
- listener,
308
- key,
309
- );
310
- span?.end?.({ type: 'success', value: instance });
311
- return instance;
312
- } catch (error) {
313
- span?.end?.({ type: 'failure', error });
314
- throw error;
315
- }
316
- },
317
- });
318
- }
319
-
320
- /**
321
- * Wraps an object with a Proxy to notify the listener of method calls.
322
- *
323
- * Methods returning a promise report their outcome when the promise
324
- * settles, not when the method returns.
325
- *
326
- * @param thing The object whose method calls need to be observed.
327
- * @param listener The listener notified of method call events.
328
- * @param key The service key used to identify the service in events.
329
- * @return A Proxy wrapping the input object, with all method calls being reported.
330
- */
331
- function observeMethodCalls(
332
- thing: any,
333
- listener: ServiceModuleListener,
334
- key: ServiceKey<unknown>,
335
- ): any {
336
- if (typeof thing !== 'object' || thing === null) {
337
- return thing;
338
- }
339
-
340
- const className = classNameOf(thing);
341
-
342
- return new Proxy(thing, {
343
- get(target, prop) {
344
- const value = Reflect.get(target, prop);
345
- if (typeof value === 'function' && typeof prop === 'string') {
346
- return (...args: unknown[]) => {
347
- const span = listener.onMethodCall?.({
348
- key,
349
- className,
350
- functionName: prop,
351
- args,
352
- });
353
- try {
354
- const result = invokeWithin(span, () => value.apply(target, args));
355
- if (result instanceof Promise) {
356
- return result.then(
357
- (resolved) => {
358
- span?.end?.({ type: 'success', value: resolved });
359
- return resolved;
360
- },
361
- (error) => {
362
- span?.end?.({ type: 'failure', error });
363
- throw error;
364
- },
365
- );
366
- }
367
- span?.end?.({ type: 'success', value: result });
368
- return result;
369
- } catch (error) {
370
- span?.end?.({ type: 'failure', error });
371
- throw error;
372
- }
373
- };
374
- }
375
- return value;
376
- },
377
- });
378
- }
379
-
380
- /**
381
- * Invokes an operation through the EventSpan's `run` wrapper when the
382
- * listener provided one, so it can establish ambient state (tracing
383
- * context) around the operation; invokes the operation directly otherwise.
384
- *
385
- * @param span The EventSpan returned by the listener, if any.
386
- * @param fn The thunk performing the operation.
387
- * @returns The value returned by `fn`.
388
- */
389
- function invokeWithin<T>(span: EventSpan | void, fn: () => T): T {
390
- return span?.run ? span.run(fn) : fn();
391
- }
392
-
393
- /**
394
- * Resolves the class name of a service instance, or undefined for values
395
- * that are not instances of a named class (plain object literals,
396
- * null-prototype objects).
397
- *
398
- * @param thing The service instance to inspect.
399
- * @returns The constructor name, or undefined when there is none to report.
400
- */
401
- function classNameOf(thing: object): string | undefined {
402
- const name = thing.constructor?.name;
403
- return name && name !== 'Object' ? name : undefined;
239
+ return factory?.provides?.symbol === key?.symbol
404
240
  }
@@ -1,7 +1,7 @@
1
1
  export class ServiceScope {
2
- readonly symbol: symbol;
2
+ readonly symbol: symbol
3
3
 
4
4
  constructor(readonly name: string) {
5
- this.symbol = Symbol(name);
5
+ this.symbol = Symbol(name)
6
6
  }
7
7
  }
@@ -1,5 +1,5 @@
1
- import { ServiceKey, ServiceSelectorKey } from './serviceKey';
2
- import { ServiceModule } from './serviceModule';
1
+ import { ServiceKey, ServiceSelectorKey } from './serviceKey'
2
+ import { ServiceModule } from './serviceModule'
3
3
 
4
4
  /**
5
5
  * A runtime selector that provides access to multiple service implementations of the same type.
@@ -63,6 +63,6 @@ export class ServiceSelector<T> {
63
63
  * ```
64
64
  */
65
65
  get(key: ServiceKey<T>): Promise<T> {
66
- return this.serviceModule.get(key);
66
+ return this.serviceModule.get(key)
67
67
  }
68
- }
68
+ }