/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { ServiceCollection } from './serviceCollection'; import * as descriptors from './descriptors'; // ------ internal util export namespace _util { export const serviceIds = new Map>(); export const DI_TARGET = '$di$target'; export const DI_DEPENDENCIES = '$di$dependencies'; export function getServiceDependencies( ctor: any ): { id: ServiceIdentifier; index: number; optional: boolean }[] { return ctor[DI_DEPENDENCIES] || []; } } // --- interfaces ------ export type BrandedService = { _serviceBrand: undefined }; export interface IConstructorSignature0 { new (...services: BrandedService[]): T; } export interface IConstructorSignature1 { new (first: A1, ...services: Services): T; } export interface IConstructorSignature2 { new (first: A1, second: A2, ...services: BrandedService[]): T; } export interface IConstructorSignature3 { new (first: A1, second: A2, third: A3, ...services: BrandedService[]): T; } export interface IConstructorSignature4 { new ( first: A1, second: A2, third: A3, fourth: A4, ...services: BrandedService[] ): T; } export interface IConstructorSignature5 { new ( first: A1, second: A2, third: A3, fourth: A4, fifth: A5, ...services: BrandedService[] ): T; } export interface IConstructorSignature6 { new ( first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, ...services: BrandedService[] ): T; } export interface IConstructorSignature7 { new ( first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, ...services: BrandedService[] ): T; } export interface IConstructorSignature8 { new ( first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, eigth: A8, ...services: BrandedService[] ): T; } export interface ServicesAccessor { get(id: ServiceIdentifier): T; get(id: ServiceIdentifier, isOptional: typeof optional): T | undefined; } export const IInstantiationService = createDecorator( 'instantiationService' ); /** * Given a list of arguments as a tuple, attempt to extract the leading, non-service arguments * to their own tuple. */ type GetLeadingNonServiceArgs = Args extends [...BrandedService[]] ? [] : Args extends [infer A1, ...BrandedService[]] ? [A1] : Args extends [infer A1, infer A2, ...BrandedService[]] ? [A1, A2] : Args extends [infer A1, infer A2, infer A3, ...BrandedService[]] ? [A1, A2, A3] : Args extends [infer A1, infer A2, infer A3, infer A4, ...BrandedService[]] ? [A1, A2, A3, A4] : Args extends [ infer A1, infer A2, infer A3, infer A4, infer A5, ...BrandedService[] ] ? [A1, A2, A3, A4, A5] : Args extends [ infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, ...BrandedService[] ] ? [A1, A2, A3, A4, A5, A6] : Args extends [ infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7, ...BrandedService[] ] ? [A1, A2, A3, A4, A5, A6, A7] : Args extends [ infer A1, infer A2, infer A3, infer A4, infer A5, infer A6, infer A7, infer A8, ...BrandedService[] ] ? [A1, A2, A3, A4, A5, A6, A7, A8] : never; export interface IInstantiationService { readonly _serviceBrand: undefined; /** * Synchronously creates an instance that is denoted by * the descriptor */ createInstance(descriptor: descriptors.SyncDescriptor0): T; createInstance( descriptor: descriptors.SyncDescriptor1, a1: A1 ): T; createInstance( descriptor: descriptors.SyncDescriptor2, a1: A1, a2: A2 ): T; createInstance( descriptor: descriptors.SyncDescriptor3, a1: A1, a2: A2, a3: A3 ): T; createInstance( descriptor: descriptors.SyncDescriptor4, a1: A1, a2: A2, a3: A3, a4: A4 ): T; createInstance( descriptor: descriptors.SyncDescriptor5, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5 ): T; createInstance( descriptor: descriptors.SyncDescriptor6, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6 ): T; createInstance( descriptor: descriptors.SyncDescriptor7, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7 ): T; createInstance( descriptor: descriptors.SyncDescriptor8, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8 ): T; createInstance< Ctor extends new (...args: any[]) => any, R extends InstanceType >( t: Ctor, ...args: GetLeadingNonServiceArgs> ): R; /** * */ invokeFunction( fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS ): R; /** * Creates a child of this service which inherts all current services * and adds/overwrites the given services */ createChild(services: ServiceCollection): IInstantiationService; } /** * Identifies a service of type T */ export interface ServiceIdentifier { (...args: any[]): void; type: T; } function storeServiceDependency( id: Function, target: Function, index: number, optional: boolean ): void { if ((target as any)[_util.DI_TARGET] === target) { (target as any)[_util.DI_DEPENDENCIES].push({ id, index, optional }); } else { (target as any)[_util.DI_DEPENDENCIES] = [{ id, index, optional }]; (target as any)[_util.DI_TARGET] = target; } } /** * The *only* valid way to create a {{ServiceIdentifier}}. */ export function createDecorator(serviceId: string): ServiceIdentifier { if (_util.serviceIds.has(serviceId)) { return _util.serviceIds.get(serviceId)!; } const id = function (target: Function, key: string, index: number): any { if (arguments.length !== 3) { throw new Error( '@IServiceName-decorator can only be used to decorate a parameter' ); } storeServiceDependency(id, target, index, false); }; id.toString = () => serviceId; _util.serviceIds.set(serviceId, id); return id; } export function refineServiceDecorator( serviceIdentifier: ServiceIdentifier ): ServiceIdentifier { return >serviceIdentifier; } /** * Mark a service dependency as optional. */ export function optional(serviceIdentifier: ServiceIdentifier) { return function (target: Function, key: string, index: number) { if (arguments.length !== 3) { throw new Error( '@optional-decorator can only be used to decorate a parameter' ); } storeServiceDependency(serviceIdentifier, target, index, true); }; }