UNPKG

monaco-editor

Version:
276 lines (275 loc) • 12.5 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); } return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); import { illegalState } from '../../../base/common/errors.js'; import { create } from '../../../base/common/types.js'; import { Graph } from './graph.js'; import { SyncDescriptor } from './descriptors.js'; import { IInstantiationService, _util, optional } from './instantiation.js'; import { ServiceCollection } from './serviceCollection.js'; // TRACING var _enableTracing = false; var InstantiationService = /** @class */ (function () { function InstantiationService(services, strict, parent) { if (services === void 0) { services = new ServiceCollection(); } if (strict === void 0) { strict = false; } this._services = services; this._strict = strict; this._parent = parent; this._services.set(IInstantiationService, this); } InstantiationService.prototype.createChild = function (services) { return new InstantiationService(services, this._strict, this); }; InstantiationService.prototype.invokeFunction = function (fn) { var _this = this; var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } var _trace = Trace.traceInvocation(fn); var _done = false; try { var accessor = { get: function (id, isOptional) { if (_done) { throw illegalState('service accessor is only valid during the invocation of its target method'); } var result = _this._getOrCreateServiceInstance(id, _trace); if (!result && isOptional !== optional) { throw new Error("[invokeFunction] unknown service '" + id + "'"); } return result; } }; return fn.apply(undefined, [accessor].concat(args)); } finally { _done = true; _trace.stop(); } }; InstantiationService.prototype.createInstance = function (ctorOrDescriptor) { var rest = []; for (var _i = 1; _i < arguments.length; _i++) { rest[_i - 1] = arguments[_i]; } var _trace; var result; if (ctorOrDescriptor instanceof SyncDescriptor) { _trace = Trace.traceCreation(ctorOrDescriptor.ctor); result = this._createInstance(ctorOrDescriptor.ctor, ctorOrDescriptor.staticArguments.concat(rest), _trace); } else { _trace = Trace.traceCreation(ctorOrDescriptor); result = this._createInstance(ctorOrDescriptor, rest, _trace); } _trace.stop(); return result; }; InstantiationService.prototype._createInstance = function (ctor, args, _trace) { if (args === void 0) { args = []; } // arguments defined by service decorators var serviceDependencies = _util.getServiceDependencies(ctor).sort(function (a, b) { return a.index - b.index; }); var serviceArgs = []; for (var _i = 0, serviceDependencies_1 = serviceDependencies; _i < serviceDependencies_1.length; _i++) { var dependency = serviceDependencies_1[_i]; var service = this._getOrCreateServiceInstance(dependency.id, _trace); if (!service && this._strict && !dependency.optional) { throw new Error("[createInstance] " + ctor.name + " depends on UNKNOWN service " + dependency.id + "."); } serviceArgs.push(service); } var firstServiceArgPos = serviceDependencies.length > 0 ? serviceDependencies[0].index : args.length; // check for argument mismatches, adjust static args if needed if (args.length !== firstServiceArgPos) { console.warn("[createInstance] First service dependency of " + ctor.name + " at position " + (firstServiceArgPos + 1) + " conflicts with " + args.length + " static arguments"); var delta = firstServiceArgPos - args.length; if (delta > 0) { args = args.concat(new Array(delta)); } else { args = args.slice(0, firstServiceArgPos); } } // now create the instance return create.apply(null, [ctor].concat(args, serviceArgs)); }; InstantiationService.prototype._setServiceInstance = function (id, instance) { 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'); } }; InstantiationService.prototype._getServiceInstanceOrDescriptor = function (id) { var instanceOrDesc = this._services.get(id); if (!instanceOrDesc && this._parent) { return this._parent._getServiceInstanceOrDescriptor(id); } else { return instanceOrDesc; } }; InstantiationService.prototype._getOrCreateServiceInstance = function (id, _trace) { var thing = this._getServiceInstanceOrDescriptor(id); if (thing instanceof SyncDescriptor) { return this._createAndCacheServiceInstance(id, thing, _trace.branch(id, true)); } else { _trace.branch(id, false); return thing; } }; InstantiationService.prototype._createAndCacheServiceInstance = function (id, desc, _trace) { var graph = new Graph(function (data) { return data.id.toString(); }); function throwCycleError() { var err = new Error('[createInstance] cyclic dependency between services'); err.message = graph.toString(); throw err; } var count = 0; var stack = [{ id: id, desc: desc, _trace: _trace }]; while (stack.length) { var item = stack.pop(); graph.lookupOrInsertNode(item); // TODO@joh use the graph to find a cycle // a weak heuristic for cycle checks if (count++ > 100) { throwCycleError(); } // check all dependencies for existence and if they need to be created first var dependencies = _util.getServiceDependencies(item.desc.ctor); for (var _i = 0, dependencies_1 = dependencies; _i < dependencies_1.length; _i++) { var dependency = dependencies_1[_i]; var 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) { var d = { id: dependency.id, desc: instanceOrDesc, _trace: item._trace.branch(dependency.id, true) }; graph.insertEdge(item, d); stack.push(d); } } } while (true) { var roots = graph.roots(); // if there is no more roots but still // nodes in the graph we have a cycle if (roots.length === 0) { if (!graph.isEmpty()) { throwCycleError(); } break; } for (var _a = 0, roots_1 = roots; _a < roots_1.length; _a++) { var data = roots_1[_a].data; // create instance and overwrite the service collections var instance = this._createServiceInstanceWithOwner(data.id, data.desc.ctor, data.desc.staticArguments, false, data._trace); this._setServiceInstance(data.id, instance); graph.removeNode(data); } } return this._getServiceInstanceOrDescriptor(id); }; InstantiationService.prototype._createServiceInstanceWithOwner = function (id, ctor, args, supportsDelayedInstantiation, _trace) { if (args === void 0) { args = []; } 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'); } }; InstantiationService.prototype._createServiceInstance = function (ctor, args, supportsDelayedInstantiation, _trace) { if (args === void 0) { args = []; } return this._createInstance(ctor, args, _trace); }; return InstantiationService; }()); export { InstantiationService }; var Trace = /** @class */ (function () { function Trace(type, name) { this.type = type; this.name = name; this._start = Date.now(); this._dep = []; } Trace.traceInvocation = function (ctor) { return !_enableTracing ? Trace._None : new Trace(1 /* Invocation */, ctor.name || ctor.toString().substring(0, 42).replace(/\n/g, '')); }; Trace.traceCreation = function (ctor) { return !_enableTracing ? Trace._None : new Trace(0 /* Creation */, ctor.name); }; Trace.prototype.branch = function (id, first) { var child = new Trace(2 /* Branch */, id.toString()); this._dep.push([id, first, child]); return child; }; Trace.prototype.stop = function () { var dur = Date.now() - this._start; Trace._totals += dur; var causedCreation = false; function printChild(n, trace) { var res = []; var prefix = new Array(n + 1).join('\t'); for (var _i = 0, _a = trace._dep; _i < _a.length; _i++) { var _b = _a[_i], id = _b[0], first = _b[1], child = _b[2]; if (first && child) { causedCreation = true; res.push(prefix + "CREATES -> " + id); var nested = printChild(n + 1, child); if (nested) { res.push(nested); } } else { res.push(prefix + "uses -> " + id); } } return res.join('\n'); } var lines = [ (this.type === 0 /* 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')); } }; Trace._None = new /** @class */ (function (_super) { __extends(class_1, _super); function class_1() { return _super.call(this, -1, null) || this; } class_1.prototype.stop = function () { }; class_1.prototype.branch = function () { return this; }; return class_1; }(Trace)); Trace._totals = 0; return Trace; }()); //#endregion