Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / common / ModuleManager.js
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  */
35 WebInspector.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
63 WebInspector.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      * @return {?Object}
214      */
215     instance: function(type, context)
216     {
217         var extension = this.extension(type, context);
218         return extension ? extension.instance() : null;
219     },
220
221     /**
222      * @param {string|!Function} type
223      * @param {string} nameProperty
224      * @param {string} orderProperty
225      * @return {function(string, string):number}
226      */
227     orderComparator: function(type, nameProperty, orderProperty)
228     {
229         var extensions = this.extensions(type);
230         var orderForName = {};
231         for (var i = 0; i < extensions.length; ++i) {
232             var descriptor = extensions[i].descriptor();
233             orderForName[descriptor[nameProperty]] = descriptor[orderProperty];
234         }
235
236         /**
237          * @param {string} name1
238          * @param {string} name2
239          * @return {number}
240          */
241         function result(name1, name2)
242         {
243             if (name1 in orderForName && name2 in orderForName)
244                 return orderForName[name1] - orderForName[name2];
245             if (name1 in orderForName)
246                 return -1;
247             if (name2 in orderForName)
248                 return 1;
249             return name1.compareTo(name2);
250         }
251         return result;
252     },
253
254     /**
255      * @return {?function(new:Object)}
256      */
257     _resolve: function(typeName)
258     {
259         if (!this._cachedTypeClasses[typeName]) {
260             var path = typeName.split(".");
261             var object = window;
262             for (var i = 0; object && (i < path.length); ++i)
263                 object = object[path[i]];
264             if (object)
265                 this._cachedTypeClasses[typeName] = /** @type function(new:Object) */(object);
266         }
267         return this._cachedTypeClasses[typeName];
268     }
269 }
270
271 /**
272  * @constructor
273  */
274 WebInspector.ModuleManager.ModuleDescriptor = function()
275 {
276     /**
277      * @type {string}
278      */
279     this.name;
280
281     /**
282      * @type {!Array.<!WebInspector.ModuleManager.ExtensionDescriptor>}
283      */
284     this.extensions;
285
286     /**
287      * @type {!Array.<!string>|undefined}
288      */
289     this.dependencies;
290
291     /**
292      * @type {!Array.<string>}
293      */
294     this.scripts;
295 }
296
297 /**
298  * @constructor
299  */
300 WebInspector.ModuleManager.ExtensionDescriptor = function()
301 {
302     /**
303      * @type {string}
304      */
305     this.type;
306
307     /**
308      * @type {string|undefined}
309      */
310     this.className;
311
312     /**
313      * @type {!Array.<string>|undefined}
314      */
315     this.contextTypes;
316 }
317
318 /**
319  * @constructor
320  * @param {!WebInspector.ModuleManager} manager
321  * @param {!WebInspector.ModuleManager.ModuleDescriptor} descriptor
322  */
323 WebInspector.ModuleManager.Module = function(manager, descriptor)
324 {
325     this._manager = manager;
326     this._descriptor = descriptor;
327     this._name = descriptor.name;
328     var extensions = /** @type {?Array.<!WebInspector.ModuleManager.ExtensionDescriptor>}*/ (descriptor.extensions);
329     for (var i = 0; extensions && i < extensions.length; ++i)
330         this._manager._extensions.push(new WebInspector.ModuleManager.Extension(this, extensions[i]));
331     this._loaded = false;
332 }
333
334 WebInspector.ModuleManager.Module.prototype = {
335     /**
336      * @return {string}
337      */
338     name: function()
339     {
340         return this._name;
341     },
342
343     _load: function()
344     {
345         if (this._loaded)
346             return;
347
348         if (this._isLoading) {
349             var oldStackTraceLimit = Error.stackTraceLimit;
350             Error.stackTraceLimit = 50;
351             console.assert(false, "Module " + this._name + " is loaded from itself: " + new Error().stack);
352             Error.stackTraceLimit = oldStackTraceLimit;
353             return;
354         }
355
356         this._isLoading = true;
357         var dependencies = this._descriptor.dependencies;
358         for (var i = 0; dependencies && i < dependencies.length; ++i)
359             this._manager.loadModule(dependencies[i]);
360         var scripts = this._descriptor.scripts;
361         for (var i = 0; scripts && i < scripts.length; ++i)
362             loadScript(this._name + "/" + scripts[i]);
363         this._isLoading = false;
364         this._loaded = true;
365     }
366 }
367
368 /**
369  * @constructor
370  * @param {!WebInspector.ModuleManager.Module} module
371  * @param {!WebInspector.ModuleManager.ExtensionDescriptor} descriptor
372  */
373 WebInspector.ModuleManager.Extension = function(module, descriptor)
374 {
375     this._module = module;
376     this._descriptor = descriptor;
377
378     this._type = descriptor.type;
379     this._hasTypeClass = !!this._type.startsWith("@");
380
381     /**
382      * @type {?string}
383      */
384     this._className = descriptor.className || null;
385 }
386
387 WebInspector.ModuleManager.Extension.prototype = {
388     /**
389      * @return {!Object}
390      */
391     descriptor: function()
392     {
393         return this._descriptor;
394     },
395
396     /**
397      * @return {!WebInspector.ModuleManager.Module}
398      */
399     module: function()
400     {
401         return this._module;
402     },
403
404     /**
405      * @return {?function(new:Object)}
406      */
407     _typeClass: function()
408     {
409         if (!this._hasTypeClass)
410             return null;
411         return this._module._manager._resolve(this._type.substring(1));
412     },
413
414     /**
415      * @param {?Object} context
416      * @return {boolean}
417      */
418     isApplicable: function(context)
419     {
420         return this._module._manager.isExtensionApplicableToContext(this, context);
421     },
422
423     /**
424      * @return {?Object}
425      */
426     instance: function()
427     {
428         if (!this._className)
429             return null;
430
431         if (!this._instance) {
432             this._module._load();
433
434             var constructorFunction = window.eval(this._className);
435             if (!(constructorFunction instanceof Function))
436                 return null;
437
438             this._instance = new constructorFunction();
439         }
440         return this._instance;
441     }
442 }
443
444 /**
445  * @interface
446  */
447 WebInspector.Renderer = function()
448 {
449 }
450
451 WebInspector.Renderer.prototype = {
452     /**
453      * @param {!Object} object
454      * @return {?Element}
455      */
456     render: function(object) {}
457 }
458
459 /**
460  * @interface
461  */
462 WebInspector.Revealer = function()
463 {
464 }
465
466 /**
467  * @param {?Object} revealable
468  * @param {number=} lineNumber
469  */
470 WebInspector.Revealer.reveal = function(revealable, lineNumber)
471 {
472     if (!revealable)
473         return;
474     var revealer = WebInspector.moduleManager.instance(WebInspector.Revealer, revealable);
475     if (revealer)
476         revealer.reveal(revealable, lineNumber);
477 }
478
479 WebInspector.Revealer.prototype = {
480     /**
481      * @param {!Object} object
482      */
483     reveal: function(object) {}
484 }
485
486 WebInspector.moduleManager = new WebInspector.ModuleManager(allDescriptors);