/** * 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, any>(); constructor(...entries: [IServiceIdentifier, any][]) { for (const [id, service] of entries) { this.set(id, service); } } public set(id: IServiceIdentifier, instance: T): T { const result = this._entries.get(id); this._entries.set(id, instance); return result; } public forEach(callback: (id: IServiceIdentifier, instance: any) => any): void { this._entries.forEach((value, key) => callback(key, value)); } public has(id: IServiceIdentifier): boolean { return this._entries.has(id); } public get(id: IServiceIdentifier): 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(id: IServiceIdentifier, instance: T): void { this._services.set(id, instance); } public getService(id: IServiceIdentifier): T | undefined { return this._services.get(id); } public createInstance(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]); } }