• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2014 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * @constructor
33 * @param {!Array.<!WebInspector.ModuleManager.ModuleDescriptor>} descriptors
34 */
35WebInspector.ModuleManager = function(descriptors)
36{
37    /**
38     * @type {!Array.<!WebInspector.ModuleManager.Module>}
39     */
40    this._modules = [];
41    /**
42     * @type {!Object.<string, !WebInspector.ModuleManager.Module>}
43     */
44    this._modulesMap = {};
45    /**
46     * @type {!Array.<!WebInspector.ModuleManager.Extension>}
47     */
48    this._extensions = [];
49
50    /**
51     * @type {!Object.<string, !function(new:Object)>}
52     */
53    this._cachedTypeClasses = {};
54
55    /**
56     * @type {!Object.<string, !WebInspector.ModuleManager.ModuleDescriptor>}
57     */
58    this._descriptorsMap = {};
59    for (var i = 0; i < descriptors.length; ++i)
60        this._descriptorsMap[descriptors[i]["name"]] = descriptors[i];
61}
62
63WebInspector.ModuleManager.prototype = {
64    /**
65     * @param {!Array.<string>} configuration
66     */
67    registerModules: function(configuration)
68    {
69        for (var i = 0; i < configuration.length; ++i)
70            this.registerModule(configuration[i]);
71    },
72
73    /**
74     * @param {string} moduleName
75     */
76    registerModule: function(moduleName)
77    {
78        if (!this._descriptorsMap[moduleName]) {
79            var content = loadResource(moduleName + "/module.json");
80            if (!content)
81                throw new Error("Module is not defined: " + moduleName + " " + new Error().stack);
82            var module = /** @type {!WebInspector.ModuleManager.ModuleDescriptor} */ (self.eval("(" + content + ")"));
83            module["name"] = moduleName;
84            this._descriptorsMap[moduleName] = module;
85        }
86        var module = new WebInspector.ModuleManager.Module(this, this._descriptorsMap[moduleName]);
87        this._modules.push(module);
88        this._modulesMap[moduleName] = module;
89    },
90
91    /**
92     * @param {string} moduleName
93     */
94    loadModule: function(moduleName)
95    {
96        this._modulesMap[moduleName]._load();
97    },
98
99    /**
100     * @param {!WebInspector.ModuleManager.Extension} extension
101     * @param {?function(function(new:Object)):boolean} predicate
102     * @return {boolean}
103     */
104    _checkExtensionApplicability: function(extension, predicate)
105    {
106        if (!predicate)
107            return false;
108        var contextTypes = /** @type {!Array.<string>|undefined} */ (extension.descriptor().contextTypes);
109        if (!contextTypes)
110            return true;
111        for (var i = 0; i < contextTypes.length; ++i) {
112            var contextType = this._resolve(contextTypes[i]);
113            var isMatching = !!contextType && predicate(contextType);
114            if (isMatching)
115                return true;
116        }
117        return false;
118    },
119
120    /**
121     * @param {!WebInspector.ModuleManager.Extension} extension
122     * @param {?Object} context
123     * @return {boolean}
124     */
125    isExtensionApplicableToContext: function(extension, context)
126    {
127        if (!context)
128            return true;
129        return this._checkExtensionApplicability(extension, isInstanceOf);
130
131        /**
132         * @param {!Function} targetType
133         * @return {boolean}
134         */
135        function isInstanceOf(targetType)
136        {
137            return context instanceof targetType;
138        }
139    },
140
141    /**
142     * @param {!WebInspector.ModuleManager.Extension} extension
143     * @param {!Set.<!Function>=} currentContextTypes
144     * @return {boolean}
145     */
146    isExtensionApplicableToContextTypes: function(extension, currentContextTypes)
147    {
148        if (!extension.descriptor().contextTypes)
149            return true;
150
151        return this._checkExtensionApplicability(extension, currentContextTypes ? isContextTypeKnown : null);
152
153        /**
154         * @param {!Function} targetType
155         * @return {boolean}
156         */
157        function isContextTypeKnown(targetType)
158        {
159            return currentContextTypes.contains(targetType);
160        }
161    },
162
163    /**
164     * @param {string|!Function} type
165     * @param {?Object=} context
166     * @return {!Array.<!WebInspector.ModuleManager.Extension>}
167     */
168    extensions: function(type, context)
169    {
170        /**
171         * @param {!WebInspector.ModuleManager.Extension} extension
172         * @return {boolean}
173         */
174        function filter(extension)
175        {
176            if (extension._type !== type && extension._typeClass() !== type)
177                return false;
178            return !context || extension.isApplicable(context);
179        }
180        return this._extensions.filter(filter);
181    },
182
183    /**
184     * @param {string|!Function} type
185     * @param {?Object=} context
186     * @return {?WebInspector.ModuleManager.Extension}
187     */
188    extension: function(type, context)
189    {
190        return this.extensions(type, context)[0] || null;
191    },
192
193    /**
194     * @param {string|!Function} type
195     * @param {?Object=} context
196     * @return {!Array.<!Object>}
197     */
198    instances: function(type, context)
199    {
200        /**
201         * @param {!WebInspector.ModuleManager.Extension} extension
202         * @return {?Object}
203         */
204        function instantiate(extension)
205        {
206            return extension.instance();
207        }
208        return this.extensions(type, context).filter(instantiate).map(instantiate);
209    },
210
211    /**
212     * @param {string|!Function} type
213     * @param {?Object=} context
214     * @return {?Object}
215     */
216    instance: function(type, context)
217    {
218        var extension = this.extension(type, context);
219        return extension ? extension.instance() : null;
220    },
221
222    /**
223     * @param {string|!Function} type
224     * @param {string} nameProperty
225     * @param {string} orderProperty
226     * @return {function(string, string):number}
227     */
228    orderComparator: function(type, nameProperty, orderProperty)
229    {
230        var extensions = this.extensions(type);
231        var orderForName = {};
232        for (var i = 0; i < extensions.length; ++i) {
233            var descriptor = extensions[i].descriptor();
234            orderForName[descriptor[nameProperty]] = descriptor[orderProperty];
235        }
236
237        /**
238         * @param {string} name1
239         * @param {string} name2
240         * @return {number}
241         */
242        function result(name1, name2)
243        {
244            if (name1 in orderForName && name2 in orderForName)
245                return orderForName[name1] - orderForName[name2];
246            if (name1 in orderForName)
247                return -1;
248            if (name2 in orderForName)
249                return 1;
250            return name1.compareTo(name2);
251        }
252        return result;
253    },
254
255    /**
256     * @return {?function(new:Object)}
257     */
258    _resolve: function(typeName)
259    {
260        if (!this._cachedTypeClasses[typeName]) {
261            var path = typeName.split(".");
262            var object = window;
263            for (var i = 0; object && (i < path.length); ++i)
264                object = object[path[i]];
265            if (object)
266                this._cachedTypeClasses[typeName] = /** @type function(new:Object) */(object);
267        }
268        return this._cachedTypeClasses[typeName];
269    }
270}
271
272/**
273 * @constructor
274 */
275WebInspector.ModuleManager.ModuleDescriptor = function()
276{
277    /**
278     * @type {string}
279     */
280    this.name;
281
282    /**
283     * @type {!Array.<!WebInspector.ModuleManager.ExtensionDescriptor>}
284     */
285    this.extensions;
286
287    /**
288     * @type {!Array.<string>|undefined}
289     */
290    this.dependencies;
291
292    /**
293     * @type {!Array.<string>}
294     */
295    this.scripts;
296}
297
298/**
299 * @constructor
300 */
301WebInspector.ModuleManager.ExtensionDescriptor = function()
302{
303    /**
304     * @type {string}
305     */
306    this.type;
307
308    /**
309     * @type {string|undefined}
310     */
311    this.className;
312
313    /**
314     * @type {!Array.<string>|undefined}
315     */
316    this.contextTypes;
317}
318
319/**
320 * @constructor
321 * @param {!WebInspector.ModuleManager} manager
322 * @param {!WebInspector.ModuleManager.ModuleDescriptor} descriptor
323 */
324WebInspector.ModuleManager.Module = function(manager, descriptor)
325{
326    this._manager = manager;
327    this._descriptor = descriptor;
328    this._name = descriptor.name;
329    var extensions = /** @type {?Array.<!WebInspector.ModuleManager.ExtensionDescriptor>}*/ (descriptor.extensions);
330    for (var i = 0; extensions && i < extensions.length; ++i)
331        this._manager._extensions.push(new WebInspector.ModuleManager.Extension(this, extensions[i]));
332    this._loaded = false;
333}
334
335WebInspector.ModuleManager.Module.prototype = {
336    /**
337     * @return {string}
338     */
339    name: function()
340    {
341        return this._name;
342    },
343
344    _load: function()
345    {
346        if (this._loaded)
347            return;
348
349        if (this._isLoading) {
350            var oldStackTraceLimit = Error.stackTraceLimit;
351            Error.stackTraceLimit = 50;
352            console.assert(false, "Module " + this._name + " is loaded from itself: " + new Error().stack);
353            Error.stackTraceLimit = oldStackTraceLimit;
354            return;
355        }
356
357        this._isLoading = true;
358        var dependencies = this._descriptor.dependencies;
359        for (var i = 0; dependencies && i < dependencies.length; ++i)
360            this._manager.loadModule(dependencies[i]);
361        var scripts = this._descriptor.scripts;
362        for (var i = 0; scripts && i < scripts.length; ++i)
363            loadScript(this._name + "/" + scripts[i]);
364        this._isLoading = false;
365        this._loaded = true;
366    }
367}
368
369/**
370 * @constructor
371 * @param {!WebInspector.ModuleManager.Module} module
372 * @param {!WebInspector.ModuleManager.ExtensionDescriptor} descriptor
373 */
374WebInspector.ModuleManager.Extension = function(module, descriptor)
375{
376    this._module = module;
377    this._descriptor = descriptor;
378
379    this._type = descriptor.type;
380    this._hasTypeClass = !!this._type.startsWith("@");
381
382    /**
383     * @type {?string}
384     */
385    this._className = descriptor.className || null;
386}
387
388WebInspector.ModuleManager.Extension.prototype = {
389    /**
390     * @return {!Object}
391     */
392    descriptor: function()
393    {
394        return this._descriptor;
395    },
396
397    /**
398     * @return {!WebInspector.ModuleManager.Module}
399     */
400    module: function()
401    {
402        return this._module;
403    },
404
405    /**
406     * @return {?function(new:Object)}
407     */
408    _typeClass: function()
409    {
410        if (!this._hasTypeClass)
411            return null;
412        return this._module._manager._resolve(this._type.substring(1));
413    },
414
415    /**
416     * @param {?Object} context
417     * @return {boolean}
418     */
419    isApplicable: function(context)
420    {
421        return this._module._manager.isExtensionApplicableToContext(this, context);
422    },
423
424    /**
425     * @return {?Object}
426     */
427    instance: function()
428    {
429        if (!this._className)
430            return null;
431
432        if (!this._instance) {
433            this._module._load();
434
435            var constructorFunction = window.eval(this._className);
436            if (!(constructorFunction instanceof Function))
437                return null;
438
439            this._instance = new constructorFunction();
440        }
441        return this._instance;
442    }
443}
444
445/**
446 * @interface
447 */
448WebInspector.Renderer = function()
449{
450}
451
452WebInspector.Renderer.prototype = {
453    /**
454     * @param {!Object} object
455     * @return {?Element}
456     */
457    render: function(object) {}
458}
459
460/**
461 * @interface
462 */
463WebInspector.Revealer = function()
464{
465}
466
467/**
468 * @param {?Object} revealable
469 * @param {number=} lineNumber
470 */
471WebInspector.Revealer.reveal = function(revealable, lineNumber)
472{
473    if (!revealable)
474        return;
475    var revealer = WebInspector.moduleManager.instance(WebInspector.Revealer, revealable);
476    if (revealer)
477        revealer.reveal(revealable, lineNumber);
478}
479
480WebInspector.Revealer.prototype = {
481    /**
482     * @param {!Object} object
483     */
484    reveal: function(object) {}
485}
486
487WebInspector.moduleManager = new WebInspector.ModuleManager(allDescriptors);
488