mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-28 07:40:30 -04:00
Merge from master
This commit is contained in:
@@ -2,19 +2,19 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as instantiation from './instantiation';
|
||||
|
||||
|
||||
export class SyncDescriptor<T> {
|
||||
|
||||
readonly ctor: any;
|
||||
readonly staticArguments: any[];
|
||||
readonly supportsDelayedInstantiation: boolean;
|
||||
|
||||
constructor(ctor: new (...args: any[]) => T, ..._staticArguments: any[]) {
|
||||
constructor(ctor: new (...args: any[]) => T, staticArguments: any[] = [], supportsDelayedInstantiation: boolean = false) {
|
||||
this.ctor = ctor;
|
||||
this.staticArguments = _staticArguments;
|
||||
this.staticArguments = staticArguments;
|
||||
this.supportsDelayedInstantiation = supportsDelayedInstantiation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ export interface CreateSyncFunc {
|
||||
<A1, A2, A3, A4, A5, A6, A7, A8, T>(ctor: instantiation.IConstructorSignature8<A1, A2, A3, A4, A5, A6, A7, A8, T>, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8): SyncDescriptor0<T>;
|
||||
}
|
||||
export const createSyncDescriptor: CreateSyncFunc = <T>(ctor: any, ...staticArguments: any[]): any => {
|
||||
return new SyncDescriptor<T>(ctor, ...staticArguments);
|
||||
return new SyncDescriptor<T>(ctor, staticArguments);
|
||||
};
|
||||
|
||||
export interface SyncDescriptor0<T> {
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { SyncDescriptor } from './descriptors';
|
||||
import { ServiceIdentifier, IConstructorSignature0 } from './instantiation';
|
||||
|
||||
export const Services = 'di.services';
|
||||
|
||||
export interface IServiceContribution<T> {
|
||||
id: ServiceIdentifier<T>;
|
||||
@@ -16,10 +14,10 @@ export interface IServiceContribution<T> {
|
||||
|
||||
const _registry: IServiceContribution<any>[] = [];
|
||||
|
||||
export function registerSingleton<T>(id: ServiceIdentifier<T>, ctor: IConstructorSignature0<T>): void {
|
||||
_registry.push({ id, descriptor: new SyncDescriptor<T>(ctor) });
|
||||
export function registerSingleton<T>(id: ServiceIdentifier<T>, ctor: IConstructorSignature0<T>, supportsDelayedInstantiation?: boolean): void {
|
||||
_registry.push({ id, descriptor: new SyncDescriptor<T>(ctor, [], supportsDelayedInstantiation) });
|
||||
}
|
||||
|
||||
export function getServices(): IServiceContribution<any>[] {
|
||||
return _registry;
|
||||
}
|
||||
}
|
||||
|
||||
88
src/vs/platform/instantiation/common/graph.ts
Normal file
88
src/vs/platform/instantiation/common/graph.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { isEmptyObject } from 'vs/base/common/types';
|
||||
import { forEach } from 'vs/base/common/collections';
|
||||
|
||||
export interface Node<T> {
|
||||
data: T;
|
||||
incoming: { [key: string]: Node<T> };
|
||||
outgoing: { [key: string]: Node<T> };
|
||||
}
|
||||
|
||||
function newNode<T>(data: T): Node<T> {
|
||||
return {
|
||||
data: data,
|
||||
incoming: Object.create(null),
|
||||
outgoing: Object.create(null)
|
||||
};
|
||||
}
|
||||
|
||||
export class Graph<T> {
|
||||
|
||||
private _nodes: { [key: string]: Node<T> } = Object.create(null);
|
||||
|
||||
constructor(private _hashFn: (element: T) => string) {
|
||||
// empty
|
||||
}
|
||||
|
||||
roots(): Node<T>[] {
|
||||
const ret: Node<T>[] = [];
|
||||
forEach(this._nodes, entry => {
|
||||
if (isEmptyObject(entry.value.outgoing)) {
|
||||
ret.push(entry.value);
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
insertEdge(from: T, to: T): void {
|
||||
const fromNode = this.lookupOrInsertNode(from),
|
||||
toNode = this.lookupOrInsertNode(to);
|
||||
|
||||
fromNode.outgoing[this._hashFn(to)] = toNode;
|
||||
toNode.incoming[this._hashFn(from)] = fromNode;
|
||||
}
|
||||
|
||||
removeNode(data: T): void {
|
||||
const key = this._hashFn(data);
|
||||
delete this._nodes[key];
|
||||
forEach(this._nodes, (entry) => {
|
||||
delete entry.value.outgoing[key];
|
||||
delete entry.value.incoming[key];
|
||||
});
|
||||
}
|
||||
|
||||
lookupOrInsertNode(data: T): Node<T> {
|
||||
const key = this._hashFn(data);
|
||||
let node = this._nodes[key];
|
||||
|
||||
if (!node) {
|
||||
node = newNode(data);
|
||||
this._nodes[key] = node;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
lookup(data: T): Node<T> {
|
||||
return this._nodes[this._hashFn(data)];
|
||||
}
|
||||
|
||||
isEmpty(): boolean {
|
||||
for (const _key in this._nodes) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
let data: string[] = [];
|
||||
forEach(this._nodes, entry => {
|
||||
data.push(`${entry.key}, (incoming)[${Object.keys(entry.value.incoming).join(', ')}], (outgoing)[${Object.keys(entry.value.outgoing).join(',')}]`);
|
||||
});
|
||||
return data.join('\n');
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { ServiceCollection } from './serviceCollection';
|
||||
import * as descriptors from './descriptors';
|
||||
@@ -63,42 +62,6 @@ export interface ServicesAccessor {
|
||||
get<T>(id: ServiceIdentifier<T>, isOptional?: typeof optional): T;
|
||||
}
|
||||
|
||||
export interface IFunctionSignature0<R> {
|
||||
(accessor: ServicesAccessor): R;
|
||||
}
|
||||
|
||||
export interface IFunctionSignature1<A1, R> {
|
||||
(accessor: ServicesAccessor, first: A1): R;
|
||||
}
|
||||
|
||||
export interface IFunctionSignature2<A1, A2, R> {
|
||||
(accessor: ServicesAccessor, first: A1, second: A2): R;
|
||||
}
|
||||
|
||||
export interface IFunctionSignature3<A1, A2, A3, R> {
|
||||
(accessor: ServicesAccessor, first: A1, second: A2, third: A3): R;
|
||||
}
|
||||
|
||||
export interface IFunctionSignature4<A1, A2, A3, A4, R> {
|
||||
(accessor: ServicesAccessor, first: A1, second: A2, third: A3, fourth: A4): R;
|
||||
}
|
||||
|
||||
export interface IFunctionSignature5<A1, A2, A3, A4, A5, R> {
|
||||
(accessor: ServicesAccessor, first: A1, second: A2, third: A3, fourth: A4, fifth: A5): R;
|
||||
}
|
||||
|
||||
export interface IFunctionSignature6<A1, A2, A3, A4, A5, A6, R> {
|
||||
(accessor: ServicesAccessor, first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6): R;
|
||||
}
|
||||
|
||||
export interface IFunctionSignature7<A1, A2, A3, A4, A5, A6, A7, R> {
|
||||
(accessor: ServicesAccessor, first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7): R;
|
||||
}
|
||||
|
||||
export interface IFunctionSignature8<A1, A2, A3, A4, A5, A6, A7, A8, R> {
|
||||
(accessor: ServicesAccessor, first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, eigth: A8): R;
|
||||
}
|
||||
|
||||
export const IInstantiationService = createDecorator<IInstantiationService>('instantiationService');
|
||||
|
||||
export interface IInstantiationService {
|
||||
@@ -132,15 +95,7 @@ export interface IInstantiationService {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
invokeFunction<R>(ctor: IFunctionSignature0<R>): R;
|
||||
invokeFunction<A1, R>(ctor: IFunctionSignature1<A1, R>, first: A1): R;
|
||||
invokeFunction<A1, A2, R>(ctor: IFunctionSignature2<A1, A2, R>, first: A1, second: A2): R;
|
||||
invokeFunction<A1, A2, A3, R>(ctor: IFunctionSignature3<A1, A2, A3, R>, first: A1, second: A2, third: A3): R;
|
||||
invokeFunction<A1, A2, A3, A4, R>(ctor: IFunctionSignature4<A1, A2, A3, A4, R>, first: A1, second: A2, third: A3, fourth: A4): R;
|
||||
invokeFunction<A1, A2, A3, A4, A5, R>(ctor: IFunctionSignature5<A1, A2, A3, A4, A5, R>, first: A1, second: A2, third: A3, fourth: A4, fifth: A5): R;
|
||||
invokeFunction<A1, A2, A3, A4, A5, A6, R>(ctor: IFunctionSignature6<A1, A2, A3, A4, A5, A6, R>, first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6): R;
|
||||
invokeFunction<A1, A2, A3, A4, A5, A6, A7, R>(ctor: IFunctionSignature7<A1, A2, A3, A4, A5, A6, A7, R>, first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7): R;
|
||||
invokeFunction<A1, A2, A3, A4, A5, A6, A7, A8, R>(ctor: IFunctionSignature8<A1, A2, A3, A4, A5, A6, A7, A8, R>, first: A1, second: A2, third: A3, fourth: A4, fifth: A5, sixth: A6, seventh: A7, eigth: A8): R;
|
||||
invokeFunction<R, TS extends any[]=[]>(fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS): R;
|
||||
|
||||
/**
|
||||
* Creates a child of this service which inherts all current services
|
||||
|
||||
@@ -2,137 +2,140 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { illegalState } from 'vs/base/common/errors';
|
||||
import { create } from 'vs/base/common/types';
|
||||
import * as assert from 'vs/base/common/assert';
|
||||
import { Graph } from 'vs/base/common/graph';
|
||||
import { Graph } from 'vs/platform/instantiation/common/graph';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { ServiceIdentifier, IInstantiationService, ServicesAccessor, _util, optional } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
|
||||
// TRACING
|
||||
const _enableTracing = false;
|
||||
|
||||
export class InstantiationService implements IInstantiationService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
private _services: ServiceCollection;
|
||||
private _strict: boolean;
|
||||
protected readonly _services: ServiceCollection;
|
||||
protected readonly _strict: boolean;
|
||||
protected readonly _parent?: InstantiationService;
|
||||
|
||||
constructor(services: ServiceCollection = new ServiceCollection(), strict: boolean = false) {
|
||||
constructor(services: ServiceCollection = new ServiceCollection(), strict: boolean = false, parent?: InstantiationService) {
|
||||
this._services = services;
|
||||
this._strict = strict;
|
||||
this._parent = parent;
|
||||
|
||||
this._services.set(IInstantiationService, this);
|
||||
}
|
||||
|
||||
createChild(services: ServiceCollection): IInstantiationService {
|
||||
this._services.forEach((id, thing) => {
|
||||
if (services.has(id)) {
|
||||
return;
|
||||
}
|
||||
// If we copy descriptors we might end up with
|
||||
// multiple instances of the same service
|
||||
if (thing instanceof SyncDescriptor) {
|
||||
thing = this._createAndCacheServiceInstance(id, thing);
|
||||
}
|
||||
services.set(id, thing);
|
||||
});
|
||||
return new InstantiationService(services, this._strict);
|
||||
return new InstantiationService(services, this._strict, this);
|
||||
}
|
||||
|
||||
invokeFunction<R>(signature: (accessor: ServicesAccessor, ...more: any[]) => R, ...args: any[]): R {
|
||||
let accessor: ServicesAccessor;
|
||||
invokeFunction<R, TS extends any[]=[]>(fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS): R {
|
||||
let _trace = Trace.traceInvocation(fn);
|
||||
let _done = false;
|
||||
try {
|
||||
accessor = {
|
||||
let accessor = {
|
||||
get: <T>(id: ServiceIdentifier<T>, isOptional?: typeof optional) => {
|
||||
const result = this._getOrCreateServiceInstance(id);
|
||||
|
||||
if (_done) {
|
||||
throw illegalState('service accessor is only valid during the invocation of its target method');
|
||||
}
|
||||
|
||||
const result = this._getOrCreateServiceInstance(id, _trace);
|
||||
if (!result && isOptional !== optional) {
|
||||
throw new Error(`[invokeFunction] unknown service '${id}'`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
return signature.apply(undefined, [accessor].concat(args));
|
||||
return fn.apply(undefined, [accessor].concat(args));
|
||||
} finally {
|
||||
accessor.get = function () {
|
||||
throw illegalState('service accessor is only valid during the invocation of its target method');
|
||||
};
|
||||
_done = true;
|
||||
_trace.stop();
|
||||
}
|
||||
}
|
||||
|
||||
createInstance(param: any, ...rest: any[]): any {
|
||||
|
||||
if (param instanceof SyncDescriptor) {
|
||||
// sync
|
||||
return this._createInstance(param, rest);
|
||||
|
||||
createInstance(ctorOrDescriptor: any | SyncDescriptor<any>, ...rest: any[]): any {
|
||||
let _trace: Trace;
|
||||
let result: any;
|
||||
if (ctorOrDescriptor instanceof SyncDescriptor) {
|
||||
_trace = Trace.traceCreation(ctorOrDescriptor.ctor);
|
||||
result = this._createInstance(ctorOrDescriptor.ctor, ctorOrDescriptor.staticArguments.concat(rest), _trace);
|
||||
} else {
|
||||
// sync, just ctor
|
||||
return this._createInstance(new SyncDescriptor(param), rest);
|
||||
_trace = Trace.traceCreation(ctorOrDescriptor);
|
||||
result = this._createInstance(ctorOrDescriptor, rest, _trace);
|
||||
}
|
||||
_trace.stop();
|
||||
return result;
|
||||
}
|
||||
|
||||
private _createInstance<T>(desc: SyncDescriptor<T>, args: any[]): T {
|
||||
|
||||
// arguments given by createInstance-call and/or the descriptor
|
||||
let staticArgs = desc.staticArguments.concat(args);
|
||||
private _createInstance<T>(ctor: any, args: any[] = [], _trace: Trace): T {
|
||||
|
||||
// arguments defined by service decorators
|
||||
let serviceDependencies = _util.getServiceDependencies(desc.ctor).sort((a, b) => a.index - b.index);
|
||||
let serviceDependencies = _util.getServiceDependencies(ctor).sort((a, b) => a.index - b.index);
|
||||
let serviceArgs: any[] = [];
|
||||
for (const dependency of serviceDependencies) {
|
||||
let service = this._getOrCreateServiceInstance(dependency.id);
|
||||
let service = this._getOrCreateServiceInstance(dependency.id, _trace);
|
||||
if (!service && this._strict && !dependency.optional) {
|
||||
throw new Error(`[createInstance] ${desc.ctor.name} depends on UNKNOWN service ${dependency.id}.`);
|
||||
throw new Error(`[createInstance] ${ctor.name} depends on UNKNOWN service ${dependency.id}.`);
|
||||
}
|
||||
serviceArgs.push(service);
|
||||
}
|
||||
|
||||
let firstServiceArgPos = serviceDependencies.length > 0 ? serviceDependencies[0].index : staticArgs.length;
|
||||
let firstServiceArgPos = serviceDependencies.length > 0 ? serviceDependencies[0].index : args.length;
|
||||
|
||||
// check for argument mismatches, adjust static args if needed
|
||||
if (staticArgs.length !== firstServiceArgPos) {
|
||||
console.warn(`[createInstance] First service dependency of ${desc.ctor.name} at position ${
|
||||
firstServiceArgPos + 1} conflicts with ${staticArgs.length} static arguments`);
|
||||
if (args.length !== firstServiceArgPos) {
|
||||
console.warn(`[createInstance] First service dependency of ${ctor.name} at position ${
|
||||
firstServiceArgPos + 1} conflicts with ${args.length} static arguments`);
|
||||
|
||||
let delta = firstServiceArgPos - staticArgs.length;
|
||||
let delta = firstServiceArgPos - args.length;
|
||||
if (delta > 0) {
|
||||
staticArgs = staticArgs.concat(new Array(delta));
|
||||
args = args.concat(new Array(delta));
|
||||
} else {
|
||||
staticArgs = staticArgs.slice(0, firstServiceArgPos);
|
||||
args = args.slice(0, firstServiceArgPos);
|
||||
}
|
||||
}
|
||||
|
||||
// // check for missing args
|
||||
// for (let i = 0; i < serviceArgs.length; i++) {
|
||||
// if (!serviceArgs[i]) {
|
||||
// console.warn(`${desc.ctor.name} MISSES service dependency ${serviceDependencies[i].id}`, new Error().stack);
|
||||
// }
|
||||
// }
|
||||
|
||||
// now create the instance
|
||||
const argArray = [desc.ctor];
|
||||
argArray.push(...staticArgs);
|
||||
argArray.push(...serviceArgs);
|
||||
|
||||
return <T>create.apply(null, argArray);
|
||||
return <T>create.apply(null, [ctor].concat(args, serviceArgs));
|
||||
}
|
||||
|
||||
private _getOrCreateServiceInstance<T>(id: ServiceIdentifier<T>): T {
|
||||
let thing = this._services.get(id);
|
||||
if (thing instanceof SyncDescriptor) {
|
||||
return this._createAndCacheServiceInstance(id, thing);
|
||||
private _setServiceInstance<T>(id: ServiceIdentifier<T>, instance: T): void {
|
||||
if (this._services.get(id) instanceof SyncDescriptor) {
|
||||
this._services.set(id, instance);
|
||||
} else if (this._parent) {
|
||||
this._parent._setServiceInstance(id, instance);
|
||||
} else {
|
||||
throw new Error('illegalState - setting UNKNOWN service instance');
|
||||
}
|
||||
}
|
||||
|
||||
private _getServiceInstanceOrDescriptor<T>(id: ServiceIdentifier<T>): T | SyncDescriptor<T> {
|
||||
let instanceOrDesc = this._services.get(id);
|
||||
if (!instanceOrDesc && this._parent) {
|
||||
return this._parent._getServiceInstanceOrDescriptor(id);
|
||||
} else {
|
||||
return instanceOrDesc;
|
||||
}
|
||||
}
|
||||
|
||||
private _getOrCreateServiceInstance<T>(id: ServiceIdentifier<T>, _trace: Trace): T {
|
||||
let thing = this._getServiceInstanceOrDescriptor(id);
|
||||
if (thing instanceof SyncDescriptor) {
|
||||
return this._createAndCacheServiceInstance(id, thing, _trace.branch(id, true));
|
||||
} else {
|
||||
_trace.branch(id, false);
|
||||
return thing;
|
||||
}
|
||||
}
|
||||
|
||||
private _createAndCacheServiceInstance<T>(id: ServiceIdentifier<T>, desc: SyncDescriptor<T>): T {
|
||||
assert.ok(this._services.get(id) instanceof SyncDescriptor);
|
||||
|
||||
const graph = new Graph<{ id: ServiceIdentifier<any>, desc: SyncDescriptor<any> }>(data => data.id.toString());
|
||||
private _createAndCacheServiceInstance<T>(id: ServiceIdentifier<T>, desc: SyncDescriptor<T>, _trace: Trace): T {
|
||||
type Triple = { id: ServiceIdentifier<any>, desc: SyncDescriptor<any>, _trace: Trace };
|
||||
const graph = new Graph<Triple>(data => data.id.toString());
|
||||
|
||||
function throwCycleError() {
|
||||
const err = new Error('[createInstance] cyclic dependency between services');
|
||||
@@ -141,9 +144,9 @@ export class InstantiationService implements IInstantiationService {
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
const stack = [{ id, desc }];
|
||||
const stack = [{ id, desc, _trace }];
|
||||
while (stack.length) {
|
||||
const item = stack.pop();
|
||||
const item = stack.pop()!;
|
||||
graph.lookupOrInsertNode(item);
|
||||
|
||||
// TODO@joh use the graph to find a cycle
|
||||
@@ -152,17 +155,17 @@ export class InstantiationService implements IInstantiationService {
|
||||
throwCycleError();
|
||||
}
|
||||
|
||||
// check all dependencies for existence and if the need to be created first
|
||||
// check all dependencies for existence and if they need to be created first
|
||||
let dependencies = _util.getServiceDependencies(item.desc.ctor);
|
||||
for (let dependency of dependencies) {
|
||||
|
||||
let instanceOrDesc = this._services.get(dependency.id);
|
||||
if (!instanceOrDesc) {
|
||||
let instanceOrDesc = this._getServiceInstanceOrDescriptor(dependency.id);
|
||||
if (!instanceOrDesc && !dependency.optional) {
|
||||
console.warn(`[createInstance] ${id} depends on ${dependency.id} which is NOT registered.`);
|
||||
}
|
||||
|
||||
if (instanceOrDesc instanceof SyncDescriptor) {
|
||||
const d = { id: dependency.id, desc: instanceOrDesc };
|
||||
const d = { id: dependency.id, desc: instanceOrDesc, _trace: item._trace.branch(dependency.id, true) };
|
||||
graph.insertEdge(item, d);
|
||||
stack.push(d);
|
||||
}
|
||||
@@ -175,20 +178,110 @@ export class InstantiationService implements IInstantiationService {
|
||||
// if there is no more roots but still
|
||||
// nodes in the graph we have a cycle
|
||||
if (roots.length === 0) {
|
||||
if (graph.length !== 0) {
|
||||
if (!graph.isEmpty()) {
|
||||
throwCycleError();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (let root of roots) {
|
||||
for (let { data } of roots) {
|
||||
// create instance and overwrite the service collections
|
||||
const instance = this._createInstance(root.data.desc, []);
|
||||
this._services.set(root.data.id, instance);
|
||||
graph.removeNode(root.data);
|
||||
const instance = this._createServiceInstanceWithOwner(data.id, data.desc.ctor, data.desc.staticArguments, false, data._trace);
|
||||
this._setServiceInstance(data.id, instance);
|
||||
graph.removeNode(data);
|
||||
}
|
||||
}
|
||||
|
||||
return <T>this._services.get(id);
|
||||
return <T>this._getServiceInstanceOrDescriptor(id);
|
||||
}
|
||||
|
||||
private _createServiceInstanceWithOwner<T>(id: ServiceIdentifier<T>, ctor: any, args: any[] = [], supportsDelayedInstantiation: boolean, _trace: Trace): T {
|
||||
if (this._services.get(id) instanceof SyncDescriptor) {
|
||||
return this._createServiceInstance(ctor, args, supportsDelayedInstantiation, _trace);
|
||||
} else if (this._parent) {
|
||||
return this._parent._createServiceInstanceWithOwner(id, ctor, args, supportsDelayedInstantiation, _trace);
|
||||
} else {
|
||||
throw new Error('illegalState - creating UNKNOWN service instance');
|
||||
}
|
||||
}
|
||||
|
||||
protected _createServiceInstance<T>(ctor: any, args: any[] = [], supportsDelayedInstantiation: boolean, _trace: Trace): T {
|
||||
return this._createInstance(ctor, args, _trace);
|
||||
}
|
||||
}
|
||||
|
||||
//#region -- tracing ---
|
||||
|
||||
const enum TraceType {
|
||||
Creation, Invocation, Branch
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}} - Export trace
|
||||
export class Trace {
|
||||
|
||||
private static _None = new class extends Trace {
|
||||
constructor() { super(-1, null); }
|
||||
stop() { }
|
||||
branch() { return this; }
|
||||
};
|
||||
|
||||
static traceInvocation(ctor: any): Trace {
|
||||
return !_enableTracing ? Trace._None : new Trace(TraceType.Invocation, ctor.name || (ctor.toString() as string).substring(0, 42).replace(/\n/g, ''));
|
||||
}
|
||||
|
||||
static traceCreation(ctor: any): Trace {
|
||||
return !_enableTracing ? Trace._None : new Trace(TraceType.Creation, ctor.name);
|
||||
}
|
||||
|
||||
private static _totals: number = 0;
|
||||
private readonly _start: number = Date.now();
|
||||
private readonly _dep: [ServiceIdentifier<any>, boolean, Trace?][] = [];
|
||||
|
||||
private constructor(
|
||||
readonly type: TraceType,
|
||||
readonly name: string | null
|
||||
) { }
|
||||
|
||||
branch(id: ServiceIdentifier<any>, first: boolean): Trace {
|
||||
let child = new Trace(TraceType.Branch, id.toString());
|
||||
this._dep.push([id, first, child]);
|
||||
return child;
|
||||
}
|
||||
|
||||
stop() {
|
||||
let dur = Date.now() - this._start;
|
||||
Trace._totals += dur;
|
||||
|
||||
let causedCreation = false;
|
||||
|
||||
function printChild(n: number, trace: Trace) {
|
||||
let res: string[] = [];
|
||||
let prefix = new Array(n + 1).join('\t');
|
||||
for (const [id, first, child] of trace._dep) {
|
||||
if (first && child) {
|
||||
causedCreation = true;
|
||||
res.push(`${prefix}CREATES -> ${id}`);
|
||||
let nested = printChild(n + 1, child);
|
||||
if (nested) {
|
||||
res.push(nested);
|
||||
}
|
||||
} else {
|
||||
res.push(`${prefix}uses -> ${id}`);
|
||||
}
|
||||
}
|
||||
return res.join('\n');
|
||||
}
|
||||
|
||||
let lines = [
|
||||
`${this.type === TraceType.Creation ? 'CREATE' : 'CALL'} ${this.name}`,
|
||||
`${printChild(1, this)}`,
|
||||
`DONE, took ${dur.toFixed(2)}ms (grand total ${Trace._totals.toFixed(2)}ms)`
|
||||
];
|
||||
|
||||
if (dur > 2 || causedCreation) {
|
||||
console.log(lines.join('\n'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { SyncDescriptor } from './descriptors';
|
||||
|
||||
39
src/vs/platform/instantiation/node/instantiationService.ts
Normal file
39
src/vs/platform/instantiation/node/instantiationService.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { IdleValue } from 'vs/base/common/async';
|
||||
import { InstantiationService as BaseInstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
// this is in the /node/-layer because it depends on Proxy which isn't available
|
||||
// in IE11 and therefore not in the /common/-layer
|
||||
|
||||
export class InstantiationService extends BaseInstantiationService {
|
||||
|
||||
createChild(services: ServiceCollection): IInstantiationService {
|
||||
return new InstantiationService(services, this._strict, this);
|
||||
}
|
||||
|
||||
protected _createServiceInstance<T>(ctor: any, args: any[] = [], supportsDelayedInstantiation: boolean, _trace): T {
|
||||
if (supportsDelayedInstantiation) {
|
||||
return InstantiationService._newIdleProxyService(() => super._createServiceInstance(ctor, args, supportsDelayedInstantiation, _trace));
|
||||
} else {
|
||||
return super._createServiceInstance(ctor, args, supportsDelayedInstantiation, _trace);
|
||||
}
|
||||
}
|
||||
|
||||
private static _newIdleProxyService<T>(executor: () => T): T {
|
||||
const idle = new IdleValue(executor);
|
||||
return <T>new Proxy(Object.create(null), {
|
||||
get(_target: T, prop: PropertyKey): any {
|
||||
return idle.getValue()[prop];
|
||||
},
|
||||
set(_target: T, p: PropertyKey, value: any): boolean {
|
||||
idle.getValue()[p] = value;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
55
src/vs/platform/instantiation/test/common/graph.test.ts
Normal file
55
src/vs/platform/instantiation/test/common/graph.test.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { Graph } from 'vs/platform/instantiation/common/graph';
|
||||
|
||||
suite('Graph', () => {
|
||||
var graph: Graph<string>;
|
||||
|
||||
setup(() => {
|
||||
graph = new Graph<string>(s => s);
|
||||
});
|
||||
|
||||
test('is possible to lookup nodes that don\'t exist', function () {
|
||||
assert.deepEqual(graph.lookup('ddd'), null);
|
||||
});
|
||||
|
||||
test('inserts nodes when not there yet', function () {
|
||||
assert.deepEqual(graph.lookup('ddd'), null);
|
||||
assert.deepEqual(graph.lookupOrInsertNode('ddd').data, 'ddd');
|
||||
assert.deepEqual(graph.lookup('ddd').data, 'ddd');
|
||||
});
|
||||
|
||||
test('can remove nodes and get length', function () {
|
||||
assert.ok(graph.isEmpty());
|
||||
assert.deepEqual(graph.lookup('ddd'), null);
|
||||
assert.deepEqual(graph.lookupOrInsertNode('ddd').data, 'ddd');
|
||||
assert.ok(!graph.isEmpty());
|
||||
graph.removeNode('ddd');
|
||||
assert.deepEqual(graph.lookup('ddd'), null);
|
||||
assert.ok(graph.isEmpty());
|
||||
});
|
||||
|
||||
test('root', () => {
|
||||
graph.insertEdge('1', '2');
|
||||
var roots = graph.roots();
|
||||
assert.equal(roots.length, 1);
|
||||
assert.equal(roots[0].data, '2');
|
||||
|
||||
graph.insertEdge('2', '1');
|
||||
roots = graph.roots();
|
||||
assert.equal(roots.length, 0);
|
||||
});
|
||||
|
||||
test('root complex', function () {
|
||||
graph.insertEdge('1', '2');
|
||||
graph.insertEdge('1', '3');
|
||||
graph.insertEdge('3', '4');
|
||||
|
||||
var roots = graph.roots();
|
||||
assert.equal(roots.length, 2);
|
||||
assert(['2', '4'].every(n => roots.some(node => node.data === n)));
|
||||
});
|
||||
});
|
||||
@@ -2,8 +2,6 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { createDecorator, optional, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
@@ -3,14 +3,12 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as sinon from 'sinon';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
|
||||
interface IServiceMock<T> {
|
||||
id: ServiceIdentifier<T>;
|
||||
|
||||
Reference in New Issue
Block a user