1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*
* This was heavily inspired from microsoft/vscode's dependency injection system (MIT).
*/
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IInstantiationService, IServiceIdentifier } from 'common/services/Services';
import { getServiceDependencies } from 'common/services/ServiceRegistry';
export class ServiceCollection {
private _entries = new Map<IServiceIdentifier<any>, any>();
constructor(...entries: [IServiceIdentifier<any>, any][]) {
for (const [id, service] of entries) {
this.set(id, service);
}
}
public set<T>(id: IServiceIdentifier<T>, instance: T): T {
const result = this._entries.get(id);
this._entries.set(id, instance);
return result;
}
public forEach(callback: (id: IServiceIdentifier<any>, instance: any) => any): void {
this._entries.forEach((value, key) => callback(key, value));
}
public has(id: IServiceIdentifier<any>): boolean {
return this._entries.has(id);
}
public get<T>(id: IServiceIdentifier<T>): T | undefined {
return this._entries.get(id);
}
}
export class InstantiationService implements IInstantiationService {
public serviceBrand: undefined;
private readonly _services: ServiceCollection = new ServiceCollection();
constructor() {
this._services.set(IInstantiationService, this);
}
public setService<T>(id: IServiceIdentifier<T>, instance: T): void {
this._services.set(id, instance);
}
public getService<T>(id: IServiceIdentifier<T>): T | undefined {
return this._services.get(id);
}
public createInstance<T>(ctor: any, ...args: any[]): T {
const serviceDependencies = getServiceDependencies(ctor).sort((a, b) => a.index - b.index);
const serviceArgs: any[] = [];
for (const dependency of serviceDependencies) {
const service = this._services.get(dependency.id);
if (!service) {
throw new Error(`[createInstance] ${ctor.name} depends on UNKNOWN service ${dependency.id}.`);
}
serviceArgs.push(service);
}
const firstServiceArgPos = serviceDependencies.length > 0 ? serviceDependencies[0].index : args.length;
// check for argument mismatches, adjust static args if needed
if (args.length !== firstServiceArgPos) {
throw new Error(`[createInstance] First service dependency of ${ctor.name} at position ${firstServiceArgPos + 1} conflicts with ${args.length} static arguments`);
}
// now create the instance
return new ctor(...[...args, ...serviceArgs]);
}
}
|