Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/Runtime.js

Issue 2466123002: DevTools: reformat front-end code to match chromium style. (Closed)
Patch Set: all done Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2014 Google Inc. All rights reserved. 2 * Copyright (C) 2014 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer 11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the 12 * in the documentation and/or other materials provided with the
13 * distribution. 13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its 14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from 15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission. 16 * this software without specific prior written permission.
17 * 17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30
31 // This gets all concatenated module descriptors in the release mode. 30 // This gets all concatenated module descriptors in the release mode.
32 var allDescriptors = []; 31 var allDescriptors = [];
33 var applicationDescriptor; 32 var applicationDescriptor;
34 var _loadedScripts = {}; 33 var _loadedScripts = {};
35 34
36 // FIXME: This is a workaround to force Closure compiler provide 35 // FIXME: This is a workaround to force Closure compiler provide
37 // the standard ES6 runtime for all modules. This should be removed 36 // the standard ES6 runtime for all modules. This should be removed
38 // once Closure provides standard externs for Map et al. 37 // once Closure provides standard externs for Map et al.
39 for (var k of []) {} 38 for (var k of []) {
39 }
40 40
41 (function() { 41 (function() {
42 var baseUrl = self.location ? self.location.origin + self.location.pathname : ""; 42 var baseUrl = self.location ? self.location.origin + self.location.pathname : '';
43 self._importScriptPathPrefix = baseUrl.substring(0, baseUrl.lastIndexOf("/") + 1); 43 self._importScriptPathPrefix = baseUrl.substring(0, baseUrl.lastIndexOf('/') + 1);
44 })(); 44 })();
45 45
46 /** 46 /**
47 * @constructor 47 * @unrestricted
48 * @param {!Array.<!Runtime.ModuleDescriptor>} descriptors
49 */ 48 */
50 function Runtime(descriptors) 49 var Runtime = class {
51 { 50 /**
51 * @param {!Array.<!Runtime.ModuleDescriptor>} descriptors
52 */
53 constructor(descriptors) {
52 /** @type {!Array<!Runtime.Module>} */ 54 /** @type {!Array<!Runtime.Module>} */
53 this._modules = []; 55 this._modules = [];
54 /** @type {!Object<string, !Runtime.Module>} */ 56 /** @type {!Object<string, !Runtime.Module>} */
55 this._modulesMap = {}; 57 this._modulesMap = {};
56 /** @type {!Array<!Runtime.Extension>} */ 58 /** @type {!Array<!Runtime.Extension>} */
57 this._extensions = []; 59 this._extensions = [];
58 /** @type {!Object<string, !function(new:Object)>} */ 60 /** @type {!Object<string, !function(new:Object)>} */
59 this._cachedTypeClasses = {}; 61 this._cachedTypeClasses = {};
60 /** @type {!Object<string, !Runtime.ModuleDescriptor>} */ 62 /** @type {!Object<string, !Runtime.ModuleDescriptor>} */
61 this._descriptorsMap = {}; 63 this._descriptorsMap = {};
62 64
63 for (var i = 0; i < descriptors.length; ++i) 65 for (var i = 0; i < descriptors.length; ++i)
64 this._registerModule(descriptors[i]); 66 this._registerModule(descriptors[i]);
65 } 67 }
66 68
67 /** 69 /**
68 * @param {string} url 70 * @param {string} url
69 * @return {!Promise.<string>} 71 * @return {!Promise.<string>}
70 */ 72 */
71 Runtime.loadResourcePromise = function(url) 73 static loadResourcePromise(url) {
72 {
73 return new Promise(load); 74 return new Promise(load);
74 75
75 /** 76 /**
76 * @param {function(?)} fulfill 77 * @param {function(?)} fulfill
77 * @param {function(*)} reject 78 * @param {function(*)} reject
78 */ 79 */
79 function load(fulfill, reject) 80 function load(fulfill, reject) {
80 { 81 var xhr = new XMLHttpRequest();
81 var xhr = new XMLHttpRequest(); 82 xhr.open('GET', url, true);
82 xhr.open("GET", url, true); 83 xhr.onreadystatechange = onreadystatechange;
83 xhr.onreadystatechange = onreadystatechange;
84 84
85 /** 85 /**
86 * @param {Event} e 86 * @param {Event} e
87 */ 87 */
88 function onreadystatechange(e) 88 function onreadystatechange(e) {
89 { 89 if (xhr.readyState !== XMLHttpRequest.DONE)
90 if (xhr.readyState !== XMLHttpRequest.DONE) 90 return;
91 return;
92 91
93 if ([0, 200, 304].indexOf(xhr.status) === -1) // Testing harness fi le:/// results in 0. 92 if ([0, 200, 304].indexOf(xhr.status) === -1) // Testing harness file:/ // results in 0.
94 reject(new Error("While loading from url " + url + " server resp onded with a status of " + xhr.status)); 93 reject(new Error('While loading from url ' + url + ' server responded with a status of ' + xhr.status));
95 else 94 else
96 fulfill(e.target.response); 95 fulfill(e.target.response);
97 } 96 }
98 xhr.send(null); 97 xhr.send(null);
99 } 98 }
100 }; 99 }
101 100
102 /** 101 /**
103 * http://tools.ietf.org/html/rfc3986#section-5.2.4 102 * http://tools.ietf.org/html/rfc3986#section-5.2.4
104 * @param {string} path 103 * @param {string} path
105 * @return {string} 104 * @return {string}
106 */ 105 */
107 Runtime.normalizePath = function(path) 106 static normalizePath(path) {
108 { 107 if (path.indexOf('..') === -1 && path.indexOf('.') === -1)
109 if (path.indexOf("..") === -1 && path.indexOf(".") === -1) 108 return path;
110 return path;
111 109
112 var normalizedSegments = []; 110 var normalizedSegments = [];
113 var segments = path.split("/"); 111 var segments = path.split('/');
114 for (var i = 0; i < segments.length; i++) { 112 for (var i = 0; i < segments.length; i++) {
115 var segment = segments[i]; 113 var segment = segments[i];
116 if (segment === ".") 114 if (segment === '.')
117 continue; 115 continue;
118 else if (segment === "..") 116 else if (segment === '..')
119 normalizedSegments.pop(); 117 normalizedSegments.pop();
120 else if (segment) 118 else if (segment)
121 normalizedSegments.push(segment); 119 normalizedSegments.push(segment);
122 } 120 }
123 var normalizedPath = normalizedSegments.join("/"); 121 var normalizedPath = normalizedSegments.join('/');
124 if (normalizedPath[normalizedPath.length - 1] === "/") 122 if (normalizedPath[normalizedPath.length - 1] === '/')
125 return normalizedPath; 123 return normalizedPath;
126 if (path[0] === "/" && normalizedPath) 124 if (path[0] === '/' && normalizedPath)
127 normalizedPath = "/" + normalizedPath; 125 normalizedPath = '/' + normalizedPath;
128 if ((path[path.length - 1] === "/") || (segments[segments.length - 1] === ". ") || (segments[segments.length - 1] === "..")) 126 if ((path[path.length - 1] === '/') || (segments[segments.length - 1] === '. ') ||
129 normalizedPath = normalizedPath + "/"; 127 (segments[segments.length - 1] === '..'))
128 normalizedPath = normalizedPath + '/';
130 129
131 return normalizedPath; 130 return normalizedPath;
132 }; 131 }
133 132
134 /** 133 /**
135 * @param {!Array.<string>} scriptNames 134 * @param {!Array.<string>} scriptNames
136 * @param {string=} base 135 * @param {string=} base
137 * @return {!Promise.<undefined>} 136 * @return {!Promise.<undefined>}
138 */ 137 */
139 Runtime._loadScriptsPromise = function(scriptNames, base) 138 static _loadScriptsPromise(scriptNames, base) {
140 {
141 /** @type {!Array<!Promise<undefined>>} */ 139 /** @type {!Array<!Promise<undefined>>} */
142 var promises = []; 140 var promises = [];
143 /** @type {!Array<string>} */ 141 /** @type {!Array<string>} */
144 var urls = []; 142 var urls = [];
145 var sources = new Array(scriptNames.length); 143 var sources = new Array(scriptNames.length);
146 var scriptToEval = 0; 144 var scriptToEval = 0;
147 for (var i = 0; i < scriptNames.length; ++i) { 145 for (var i = 0; i < scriptNames.length; ++i) {
148 var scriptName = scriptNames[i]; 146 var scriptName = scriptNames[i];
149 var sourceURL = (base || self._importScriptPathPrefix) + scriptName; 147 var sourceURL = (base || self._importScriptPathPrefix) + scriptName;
150 148
151 var schemaIndex = sourceURL.indexOf("://") + 3; 149 var schemaIndex = sourceURL.indexOf('://') + 3;
152 var pathIndex = sourceURL.indexOf("/", schemaIndex); 150 var pathIndex = sourceURL.indexOf('/', schemaIndex);
153 if (pathIndex === -1) 151 if (pathIndex === -1)
154 pathIndex = sourceURL.length; 152 pathIndex = sourceURL.length;
155 sourceURL = sourceURL.substring(0, pathIndex) + Runtime.normalizePath(so urceURL.substring(pathIndex)); 153 sourceURL = sourceURL.substring(0, pathIndex) + Runtime.normalizePath(sour ceURL.substring(pathIndex));
156 154
157 if (_loadedScripts[sourceURL]) 155 if (_loadedScripts[sourceURL])
158 continue; 156 continue;
159 urls.push(sourceURL); 157 urls.push(sourceURL);
160 promises.push(Runtime.loadResourcePromise(sourceURL).then(scriptSourceLo aded.bind(null, i), scriptSourceLoaded.bind(null, i, undefined))); 158 promises.push(Runtime.loadResourcePromise(sourceURL).then(
159 scriptSourceLoaded.bind(null, i), scriptSourceLoaded.bind(null, i, und efined)));
161 } 160 }
162 return Promise.all(promises).then(undefined); 161 return Promise.all(promises).then(undefined);
163 162
164 /** 163 /**
165 * @param {number} scriptNumber 164 * @param {number} scriptNumber
166 * @param {string=} scriptSource 165 * @param {string=} scriptSource
167 */ 166 */
168 function scriptSourceLoaded(scriptNumber, scriptSource) 167 function scriptSourceLoaded(scriptNumber, scriptSource) {
169 { 168 sources[scriptNumber] = scriptSource || '';
170 sources[scriptNumber] = scriptSource || ""; 169 // Eval scripts as fast as possible.
171 // Eval scripts as fast as possible. 170 while (typeof sources[scriptToEval] !== 'undefined') {
172 while (typeof sources[scriptToEval] !== "undefined") { 171 evaluateScript(urls[scriptToEval], sources[scriptToEval]);
173 evaluateScript(urls[scriptToEval], sources[scriptToEval]); 172 ++scriptToEval;
174 ++scriptToEval; 173 }
175 }
176 } 174 }
177 175
178 /** 176 /**
179 * @param {string} sourceURL 177 * @param {string} sourceURL
180 * @param {string=} scriptSource 178 * @param {string=} scriptSource
181 */ 179 */
182 function evaluateScript(sourceURL, scriptSource) 180 function evaluateScript(sourceURL, scriptSource) {
183 { 181 _loadedScripts[sourceURL] = true;
184 _loadedScripts[sourceURL] = true; 182 if (!scriptSource) {
185 if (!scriptSource) { 183 // Do not reject, as this is normal in the hosted mode.
186 // Do not reject, as this is normal in the hosted mode. 184 console.error('Empty response arrived for script \'' + sourceURL + '\'') ;
187 console.error("Empty response arrived for script '" + sourceURL + "' "); 185 return;
188 return; 186 }
189 } 187 self.eval(scriptSource + '\n//# sourceURL=' + sourceURL);
190 self.eval(scriptSource + "\n//# sourceURL=" + sourceURL);
191 } 188 }
192 }; 189 }
193 190
194 /** 191 /**
195 * @type {!Object.<string, string>} 192 * @param {string} url
196 */ 193 * @param {boolean} appendSourceURL
197 Runtime._queryParamsObject = { __proto__: null }; 194 * @return {!Promise<undefined>}
198 195 */
199 Runtime._instanceSymbol = Symbol("instance"); 196 static loadResourceIntoCache(url, appendSourceURL) {
200 Runtime._extensionSymbol = Symbol("extension"); 197 return Runtime.loadResourcePromise(url).then(
201 198 cacheResource.bind(this, url), cacheResource.bind(this, url, undefined)) ;
202 /**
203 * @type {!Object.<string, string>}
204 */
205 Runtime.cachedResources = { __proto__: null };
206
207 /**
208 * @param {string} url
209 * @param {boolean} appendSourceURL
210 * @return {!Promise<undefined>}
211 */
212 Runtime.loadResourceIntoCache = function(url, appendSourceURL)
213 {
214 return Runtime.loadResourcePromise(url).then(cacheResource.bind(this, url), cacheResource.bind(this, url, undefined));
215 199
216 /** 200 /**
217 * @param {string} path 201 * @param {string} path
218 * @param {string=} content 202 * @param {string=} content
219 */ 203 */
220 function cacheResource(path, content) 204 function cacheResource(path, content) {
221 { 205 if (!content) {
222 if (!content) { 206 console.error('Failed to load resource: ' + path);
223 console.error("Failed to load resource: " + path); 207 return;
224 return; 208 }
225 } 209 var sourceURL = appendSourceURL ? Runtime.resolveSourceURL(path) : '';
226 var sourceURL = appendSourceURL ? Runtime.resolveSourceURL(path) : ""; 210 Runtime.cachedResources[path] = content + sourceURL;
227 Runtime.cachedResources[path] = content + sourceURL;
228 } 211 }
229 }; 212 }
230 213
231 /** 214 /**
232 * @param {string} appName 215 * @param {string} appName
233 * @return {!Promise.<undefined>} 216 * @return {!Promise.<undefined>}
234 */ 217 */
235 Runtime.startApplication = function(appName) 218 static startApplication(appName) {
236 { 219 console.timeStamp('Runtime.startApplication');
237 console.timeStamp("Runtime.startApplication");
238 220
239 var allDescriptorsByName = {}; 221 var allDescriptorsByName = {};
240 for (var i = 0; i < allDescriptors.length; ++i) { 222 for (var i = 0; i < allDescriptors.length; ++i) {
241 var d = allDescriptors[i]; 223 var d = allDescriptors[i];
242 allDescriptorsByName[d["name"]] = d; 224 allDescriptorsByName[d['name']] = d;
243 } 225 }
244 226
245 var applicationPromise; 227 var applicationPromise;
246 if (applicationDescriptor) 228 if (applicationDescriptor)
247 applicationPromise = Promise.resolve(applicationDescriptor); 229 applicationPromise = Promise.resolve(applicationDescriptor);
248 else 230 else
249 applicationPromise = Runtime.loadResourcePromise(appName + ".json").then (JSON.parse.bind(JSON)); 231 applicationPromise = Runtime.loadResourcePromise(appName + '.json').then(J SON.parse.bind(JSON));
250 232
251 return applicationPromise.then(parseModuleDescriptors); 233 return applicationPromise.then(parseModuleDescriptors);
252 234
253 /** 235 /**
254 * @param {!{modules: !Array.<!Object>, has_html: boolean}} appDescriptor 236 * @param {!{modules: !Array.<!Object>, has_html: boolean}} appDescriptor
255 * @return {!Promise.<undefined>} 237 * @return {!Promise.<undefined>}
256 */ 238 */
257 function parseModuleDescriptors(appDescriptor) 239 function parseModuleDescriptors(appDescriptor) {
258 { 240 var configuration = appDescriptor.modules;
259 var configuration = appDescriptor.modules; 241 var moduleJSONPromises = [];
260 var moduleJSONPromises = []; 242 var coreModuleNames = [];
261 var coreModuleNames = []; 243 for (var i = 0; i < configuration.length; ++i) {
262 for (var i = 0; i < configuration.length; ++i) { 244 var descriptor = configuration[i];
263 var descriptor = configuration[i]; 245 var name = descriptor['name'];
264 var name = descriptor["name"]; 246 var moduleJSON = allDescriptorsByName[name];
265 var moduleJSON = allDescriptorsByName[name]; 247 if (moduleJSON)
266 if (moduleJSON) 248 moduleJSONPromises.push(Promise.resolve(moduleJSON));
267 moduleJSONPromises.push(Promise.resolve(moduleJSON)); 249 else
268 else 250 moduleJSONPromises.push(Runtime.loadResourcePromise(name + '/module.js on').then(JSON.parse.bind(JSON)));
269 moduleJSONPromises.push(Runtime.loadResourcePromise(name + "/mod ule.json").then(JSON.parse.bind(JSON))); 251 if (descriptor['type'] === 'autostart')
270 if (descriptor["type"] === "autostart") 252 coreModuleNames.push(name);
271 coreModuleNames.push(name); 253 }
254
255 return Promise.all(moduleJSONPromises).then(instantiateRuntime);
256
257 /**
258 * @param {!Array.<!Object>} moduleDescriptors
259 * @return {!Promise.<undefined>}
260 */
261 function instantiateRuntime(moduleDescriptors) {
262 for (var i = 0; i < moduleDescriptors.length; ++i) {
263 moduleDescriptors[i].name = configuration[i]['name'];
264 moduleDescriptors[i].condition = configuration[i]['condition'];
265 moduleDescriptors[i].remote = configuration[i]['type'] === 'remote';
272 } 266 }
273 267 self.runtime = new Runtime(moduleDescriptors);
274 return Promise.all(moduleJSONPromises).then(instantiateRuntime); 268 if (coreModuleNames)
275 269 return /** @type {!Promise<undefined>} */ (self.runtime._loadAutoStart Modules(coreModuleNames));
276 /** 270 return Promise.resolve();
277 * @param {!Array.<!Object>} moduleDescriptors 271 }
278 * @return {!Promise.<undefined>} 272 }
279 */ 273 }
280 function instantiateRuntime(moduleDescriptors) 274
281 { 275 /**
282 for (var i = 0; i < moduleDescriptors.length; ++i) { 276 * @param {string} appName
283 moduleDescriptors[i].name = configuration[i]["name"]; 277 * @return {!Promise.<undefined>}
284 moduleDescriptors[i].condition = configuration[i]["condition"]; 278 */
285 moduleDescriptors[i].remote = configuration[i]["type"] === "remo te"; 279 static startWorker(appName) {
286 } 280 return Runtime.startApplication(appName).then(sendWorkerReady);
287 self.runtime = new Runtime(moduleDescriptors); 281
288 if (coreModuleNames) 282 function sendWorkerReady() {
289 return /** @type {!Promise<undefined>} */ (self.runtime._loadAut oStartModules(coreModuleNames)); 283 self.postMessage('workerReady');
290 return Promise.resolve(); 284 }
291 } 285 }
292 } 286
287 /**
288 * @param {string} appName
289 */
290 static startSharedWorker(appName) {
291 var startPromise = Runtime.startApplication(appName);
292
293 /**
294 * @param {!MessageEvent} event
295 */
296 self.onconnect = function(event) {
297 var newPort = /** @type {!MessagePort} */ (event.ports[0]);
298 startPromise.then(sendWorkerReadyAndContinue);
299
300 function sendWorkerReadyAndContinue() {
301 newPort.postMessage('workerReady');
302 if (Runtime._sharedWorkerNewPortCallback)
303 Runtime._sharedWorkerNewPortCallback.call(null, newPort);
304 else
305 Runtime._sharedWorkerConnectedPorts.push(newPort);
306 }
307 };
308 }
309
310 /**
311 * @param {function(!MessagePort)} callback
312 */
313 static setSharedWorkerNewPortCallback(callback) {
314 Runtime._sharedWorkerNewPortCallback = callback;
315 while (Runtime._sharedWorkerConnectedPorts.length) {
316 var port = Runtime._sharedWorkerConnectedPorts.shift();
317 callback.call(null, port);
318 }
319 }
320
321 /**
322 * @param {string} name
323 * @return {?string}
324 */
325 static queryParam(name) {
326 return Runtime._queryParamsObject[name] || null;
327 }
328
329 /**
330 * @return {!Object}
331 */
332 static _experimentsSetting() {
333 try {
334 return /** @type {!Object} */ (
335 JSON.parse(self.localStorage && self.localStorage['experiments'] ? sel f.localStorage['experiments'] : '{}'));
336 } catch (e) {
337 console.error('Failed to parse localStorage[\'experiments\']');
338 return {};
339 }
340 }
341
342 static _assert(value, message) {
343 if (value)
344 return;
345 Runtime._originalAssert.call(Runtime._console, value, message + ' ' + new Er ror().stack);
346 }
347
348 /**
349 * @param {string} platform
350 */
351 static setPlatform(platform) {
352 Runtime._platform = platform;
353 }
354
355 /**
356 * @param {!Object} descriptor
357 * @return {boolean}
358 */
359 static _isDescriptorEnabled(descriptor) {
360 var activatorExperiment = descriptor['experiment'];
361 if (activatorExperiment === '*')
362 return Runtime.experiments.supportEnabled();
363 if (activatorExperiment && activatorExperiment.startsWith('!') &&
364 Runtime.experiments.isEnabled(activatorExperiment.substring(1)))
365 return false;
366 if (activatorExperiment && !activatorExperiment.startsWith('!') &&
367 !Runtime.experiments.isEnabled(activatorExperiment))
368 return false;
369 var condition = descriptor['condition'];
370 if (condition && !condition.startsWith('!') && !Runtime.queryParam(condition ))
371 return false;
372 if (condition && condition.startsWith('!') && Runtime.queryParam(condition.s ubstring(1)))
373 return false;
374 return true;
375 }
376
377 /**
378 * @param {string} path
379 * @return {string}
380 */
381 static resolveSourceURL(path) {
382 var sourceURL = self.location.href;
383 if (self.location.search)
384 sourceURL = sourceURL.replace(self.location.search, '');
385 sourceURL = sourceURL.substring(0, sourceURL.lastIndexOf('/') + 1) + path;
386 return '\n/*# sourceURL=' + sourceURL + ' */';
387 }
388
389 useTestBase() {
390 Runtime._remoteBase = 'http://localhost:8000/inspector-sources/';
391 if (Runtime.queryParam('debugFrontend'))
392 Runtime._remoteBase += 'debug/';
393 }
394
395 /**
396 * @param {!Runtime.ModuleDescriptor} descriptor
397 */
398 _registerModule(descriptor) {
399 var module = new Runtime.Module(this, descriptor);
400 this._modules.push(module);
401 this._modulesMap[descriptor['name']] = module;
402 }
403
404 /**
405 * @param {string} moduleName
406 * @return {!Promise.<undefined>}
407 */
408 loadModulePromise(moduleName) {
409 return this._modulesMap[moduleName]._loadPromise();
410 }
411
412 /**
413 * @param {!Array.<string>} moduleNames
414 * @return {!Promise.<!Array.<*>>}
415 */
416 _loadAutoStartModules(moduleNames) {
417 var promises = [];
418 for (var i = 0; i < moduleNames.length; ++i)
419 promises.push(this.loadModulePromise(moduleNames[i]));
420 return Promise.all(promises);
421 }
422
423 /**
424 * @param {!Runtime.Extension} extension
425 * @param {?function(function(new:Object)):boolean} predicate
426 * @return {boolean}
427 */
428 _checkExtensionApplicability(extension, predicate) {
429 if (!predicate)
430 return false;
431 var contextTypes = extension.descriptor().contextTypes;
432 if (!contextTypes)
433 return true;
434 for (var i = 0; i < contextTypes.length; ++i) {
435 var contextType = this._resolve(contextTypes[i]);
436 var isMatching = !!contextType && predicate(contextType);
437 if (isMatching)
438 return true;
439 }
440 return false;
441 }
442
443 /**
444 * @param {!Runtime.Extension} extension
445 * @param {?Object} context
446 * @return {boolean}
447 */
448 isExtensionApplicableToContext(extension, context) {
449 if (!context)
450 return true;
451 return this._checkExtensionApplicability(extension, isInstanceOf);
452
453 /**
454 * @param {!Function} targetType
455 * @return {boolean}
456 */
457 function isInstanceOf(targetType) {
458 return context instanceof targetType;
459 }
460 }
461
462 /**
463 * @param {!Runtime.Extension} extension
464 * @param {!Set.<!Function>=} currentContextTypes
465 * @return {boolean}
466 */
467 isExtensionApplicableToContextTypes(extension, currentContextTypes) {
468 if (!extension.descriptor().contextTypes)
469 return true;
470
471 return this._checkExtensionApplicability(extension, currentContextTypes ? is ContextTypeKnown : null);
472
473 /**
474 * @param {!Function} targetType
475 * @return {boolean}
476 */
477 function isContextTypeKnown(targetType) {
478 return currentContextTypes.has(targetType);
479 }
480 }
481
482 /**
483 * @param {*} type
484 * @param {?Object=} context
485 * @param {boolean=} sortByTitle
486 * @return {!Array.<!Runtime.Extension>}
487 */
488 extensions(type, context, sortByTitle) {
489 return this._extensions.filter(filter).sort(sortByTitle ? titleComparator : orderComparator);
490
491 /**
492 * @param {!Runtime.Extension} extension
493 * @return {boolean}
494 */
495 function filter(extension) {
496 if (extension._type !== type && extension._typeClass() !== type)
497 return false;
498 if (!extension.enabled())
499 return false;
500 return !context || extension.isApplicable(context);
501 }
502
503 /**
504 * @param {!Runtime.Extension} extension1
505 * @param {!Runtime.Extension} extension2
506 * @return {number}
507 */
508 function orderComparator(extension1, extension2) {
509 var order1 = extension1.descriptor()['order'] || 0;
510 var order2 = extension2.descriptor()['order'] || 0;
511 return order1 - order2;
512 }
513
514 /**
515 * @param {!Runtime.Extension} extension1
516 * @param {!Runtime.Extension} extension2
517 * @return {number}
518 */
519 function titleComparator(extension1, extension2) {
520 var title1 = extension1.title() || '';
521 var title2 = extension2.title() || '';
522 return title1.localeCompare(title2);
523 }
524 }
525
526 /**
527 * @param {*} type
528 * @param {?Object=} context
529 * @return {?Runtime.Extension}
530 */
531 extension(type, context) {
532 return this.extensions(type, context)[0] || null;
533 }
534
535 /**
536 * @param {*} type
537 * @param {?Object=} context
538 * @return {!Promise.<!Array.<!Object>>}
539 */
540 allInstances(type, context) {
541 return Promise.all(this.extensions(type, context).map(extension => extension .instance()));
542 }
543
544 /**
545 * @return {?function(new:Object)}
546 */
547 _resolve(typeName) {
548 if (!this._cachedTypeClasses[typeName]) {
549 var path = typeName.split('.');
550 var object = self;
551 for (var i = 0; object && (i < path.length); ++i)
552 object = object[path[i]];
553 if (object)
554 this._cachedTypeClasses[typeName] = /** @type function(new:Object) */ (o bject);
555 }
556 return this._cachedTypeClasses[typeName] || null;
557 }
558
559 /**
560 * @param {!Function} constructorFunction
561 * @return {!Object}
562 */
563 sharedInstance(constructorFunction) {
564 if (Runtime._instanceSymbol in constructorFunction)
565 return constructorFunction[Runtime._instanceSymbol];
566 var instance = new constructorFunction();
567 constructorFunction[Runtime._instanceSymbol] = instance;
568 return instance;
569 }
570 }
571
572 ;
573
574
575 /**
576 * @type {!Object.<string, string>}
577 */
578 Runtime._queryParamsObject = {
579 __proto__: null
293 }; 580 };
294 581
582 Runtime._instanceSymbol = Symbol('instance');
583 Runtime._extensionSymbol = Symbol('extension');
584
295 /** 585 /**
296 * @param {string} appName 586 * @type {!Object.<string, string>}
297 * @return {!Promise.<undefined>}
298 */ 587 */
299 Runtime.startWorker = function(appName) 588 Runtime.cachedResources = {
300 { 589 __proto__: null
301 return Runtime.startApplication(appName).then(sendWorkerReady);
302
303 function sendWorkerReady()
304 {
305 self.postMessage("workerReady");
306 }
307 }; 590 };
308 591
592
309 /** @type {?function(!MessagePort)} */ 593 /** @type {?function(!MessagePort)} */
310 Runtime._sharedWorkerNewPortCallback = null; 594 Runtime._sharedWorkerNewPortCallback = null;
311 /** @type {!Array<!MessagePort>} */ 595 /** @type {!Array<!MessagePort>} */
312 Runtime._sharedWorkerConnectedPorts = []; 596 Runtime._sharedWorkerConnectedPorts = [];
313 597
314 /**
315 * @param {string} appName
316 */
317 Runtime.startSharedWorker = function(appName)
318 {
319 var startPromise = Runtime.startApplication(appName);
320
321 /**
322 * @param {!MessageEvent} event
323 */
324 self.onconnect = function(event)
325 {
326 var newPort = /** @type {!MessagePort} */ (event.ports[0]);
327 startPromise.then(sendWorkerReadyAndContinue);
328
329 function sendWorkerReadyAndContinue()
330 {
331 newPort.postMessage("workerReady");
332 if (Runtime._sharedWorkerNewPortCallback)
333 Runtime._sharedWorkerNewPortCallback.call(null, newPort);
334 else
335 Runtime._sharedWorkerConnectedPorts.push(newPort);
336 }
337 };
338 };
339
340 /**
341 * @param {function(!MessagePort)} callback
342 */
343 Runtime.setSharedWorkerNewPortCallback = function(callback)
344 {
345 Runtime._sharedWorkerNewPortCallback = callback;
346 while (Runtime._sharedWorkerConnectedPorts.length) {
347 var port = Runtime._sharedWorkerConnectedPorts.shift();
348 callback.call(null, port);
349 }
350 };
351
352 /**
353 * @param {string} name
354 * @return {?string}
355 */
356 Runtime.queryParam = function(name)
357 {
358 return Runtime._queryParamsObject[name] || null;
359 };
360
361 /**
362 * @return {!Object}
363 */
364 Runtime._experimentsSetting = function()
365 {
366 try {
367 return /** @type {!Object} */ (JSON.parse(self.localStorage && self.loca lStorage["experiments"] ? self.localStorage["experiments"] : "{}"));
368 } catch (e) {
369 console.error("Failed to parse localStorage['experiments']");
370 return {};
371 }
372 };
373 598
374 Runtime._console = console; 599 Runtime._console = console;
375 Runtime._originalAssert = console.assert; 600 Runtime._originalAssert = console.assert;
376 Runtime._assert = function(value, message) 601
377 { 602
378 if (value) 603 Runtime._platform = '';
379 return; 604
380 Runtime._originalAssert.call(Runtime._console, value, message + " " + new Er ror().stack);
381 };
382
383 Runtime._platform = "";
384 605
385 /** 606 /**
386 * @param {string} platform 607 * @unrestricted
387 */ 608 */
388 Runtime.setPlatform = function(platform) 609 Runtime.ModuleDescriptor = class {
389 { 610 constructor() {
390 Runtime._platform = platform;
391 };
392
393 Runtime.prototype = {
394 useTestBase: function()
395 {
396 Runtime._remoteBase = "http://localhost:8000/inspector-sources/";
397 if (Runtime.queryParam("debugFrontend"))
398 Runtime._remoteBase += "debug/";
399 },
400
401 /**
402 * @param {!Runtime.ModuleDescriptor} descriptor
403 */
404 _registerModule: function(descriptor)
405 {
406 var module = new Runtime.Module(this, descriptor);
407 this._modules.push(module);
408 this._modulesMap[descriptor["name"]] = module;
409 },
410
411 /**
412 * @param {string} moduleName
413 * @return {!Promise.<undefined>}
414 */
415 loadModulePromise: function(moduleName)
416 {
417 return this._modulesMap[moduleName]._loadPromise();
418 },
419
420 /**
421 * @param {!Array.<string>} moduleNames
422 * @return {!Promise.<!Array.<*>>}
423 */
424 _loadAutoStartModules: function(moduleNames)
425 {
426 var promises = [];
427 for (var i = 0; i < moduleNames.length; ++i)
428 promises.push(this.loadModulePromise(moduleNames[i]));
429 return Promise.all(promises);
430 },
431
432 /**
433 * @param {!Runtime.Extension} extension
434 * @param {?function(function(new:Object)):boolean} predicate
435 * @return {boolean}
436 */
437 _checkExtensionApplicability: function(extension, predicate)
438 {
439 if (!predicate)
440 return false;
441 var contextTypes = extension.descriptor().contextTypes;
442 if (!contextTypes)
443 return true;
444 for (var i = 0; i < contextTypes.length; ++i) {
445 var contextType = this._resolve(contextTypes[i]);
446 var isMatching = !!contextType && predicate(contextType);
447 if (isMatching)
448 return true;
449 }
450 return false;
451 },
452
453 /**
454 * @param {!Runtime.Extension} extension
455 * @param {?Object} context
456 * @return {boolean}
457 */
458 isExtensionApplicableToContext: function(extension, context)
459 {
460 if (!context)
461 return true;
462 return this._checkExtensionApplicability(extension, isInstanceOf);
463
464 /**
465 * @param {!Function} targetType
466 * @return {boolean}
467 */
468 function isInstanceOf(targetType)
469 {
470 return context instanceof targetType;
471 }
472 },
473
474 /**
475 * @param {!Runtime.Extension} extension
476 * @param {!Set.<!Function>=} currentContextTypes
477 * @return {boolean}
478 */
479 isExtensionApplicableToContextTypes: function(extension, currentContextTypes )
480 {
481 if (!extension.descriptor().contextTypes)
482 return true;
483
484 return this._checkExtensionApplicability(extension, currentContextTypes ? isContextTypeKnown : null);
485
486 /**
487 * @param {!Function} targetType
488 * @return {boolean}
489 */
490 function isContextTypeKnown(targetType)
491 {
492 return currentContextTypes.has(targetType);
493 }
494 },
495
496 /**
497 * @param {*} type
498 * @param {?Object=} context
499 * @param {boolean=} sortByTitle
500 * @return {!Array.<!Runtime.Extension>}
501 */
502 extensions: function(type, context, sortByTitle)
503 {
504 return this._extensions.filter(filter).sort(sortByTitle ? titleComparato r : orderComparator);
505
506 /**
507 * @param {!Runtime.Extension} extension
508 * @return {boolean}
509 */
510 function filter(extension)
511 {
512 if (extension._type !== type && extension._typeClass() !== type)
513 return false;
514 if (!extension.enabled())
515 return false;
516 return !context || extension.isApplicable(context);
517 }
518
519 /**
520 * @param {!Runtime.Extension} extension1
521 * @param {!Runtime.Extension} extension2
522 * @return {number}
523 */
524 function orderComparator(extension1, extension2)
525 {
526 var order1 = extension1.descriptor()["order"] || 0;
527 var order2 = extension2.descriptor()["order"] || 0;
528 return order1 - order2;
529 }
530
531 /**
532 * @param {!Runtime.Extension} extension1
533 * @param {!Runtime.Extension} extension2
534 * @return {number}
535 */
536 function titleComparator(extension1, extension2)
537 {
538 var title1 = extension1.title() || "";
539 var title2 = extension2.title() || "";
540 return title1.localeCompare(title2);
541 }
542 },
543
544 /**
545 * @param {*} type
546 * @param {?Object=} context
547 * @return {?Runtime.Extension}
548 */
549 extension: function(type, context)
550 {
551 return this.extensions(type, context)[0] || null;
552 },
553
554 /**
555 * @param {*} type
556 * @param {?Object=} context
557 * @return {!Promise.<!Array.<!Object>>}
558 */
559 allInstances: function(type, context)
560 {
561 return Promise.all(this.extensions(type, context).map(extension => exten sion.instance()));
562 },
563
564 /**
565 * @return {?function(new:Object)}
566 */
567 _resolve: function(typeName)
568 {
569 if (!this._cachedTypeClasses[typeName]) {
570 var path = typeName.split(".");
571 var object = self;
572 for (var i = 0; object && (i < path.length); ++i)
573 object = object[path[i]];
574 if (object)
575 this._cachedTypeClasses[typeName] = /** @type function(new:Objec t) */(object);
576 }
577 return this._cachedTypeClasses[typeName] || null;
578 },
579
580 /**
581 * @param {!Function} constructorFunction
582 * @return {!Object}
583 */
584 sharedInstance: function(constructorFunction)
585 {
586 if (Runtime._instanceSymbol in constructorFunction)
587 return constructorFunction[Runtime._instanceSymbol];
588 var instance = new constructorFunction();
589 constructorFunction[Runtime._instanceSymbol] = instance;
590 return instance;
591 }
592 };
593
594 /**
595 * @constructor
596 */
597 Runtime.ModuleDescriptor = function()
598 {
599 /** 611 /**
600 * @type {string} 612 * @type {string}
601 */ 613 */
602 this.name; 614 this.name;
603 615
604 /** 616 /**
605 * @type {!Array.<!Runtime.ExtensionDescriptor>} 617 * @type {!Array.<!Runtime.ExtensionDescriptor>}
606 */ 618 */
607 this.extensions; 619 this.extensions;
608 620
609 /** 621 /**
610 * @type {!Array.<string>|undefined} 622 * @type {!Array.<string>|undefined}
611 */ 623 */
612 this.dependencies; 624 this.dependencies;
613 625
614 /** 626 /**
615 * @type {!Array.<string>} 627 * @type {!Array.<string>}
616 */ 628 */
617 this.scripts; 629 this.scripts;
618 630
619 /** 631 /**
620 * @type {string|undefined} 632 * @type {string|undefined}
621 */ 633 */
622 this.condition; 634 this.condition;
623 635
624 /** 636 /**
625 * @type {boolean|undefined} 637 * @type {boolean|undefined}
626 */ 638 */
627 this.remote; 639 this.remote;
640 }
628 }; 641 };
629 642
630 /** 643 /**
631 * @constructor 644 * @unrestricted
632 */ 645 */
633 Runtime.ExtensionDescriptor = function() 646 Runtime.ExtensionDescriptor = class {
634 { 647 constructor() {
635 /** 648 /**
636 * @type {string} 649 * @type {string}
637 */ 650 */
638 this.type; 651 this.type;
639 652
640 /** 653 /**
641 * @type {string|undefined} 654 * @type {string|undefined}
642 */ 655 */
643 this.className; 656 this.className;
644 657
645 /** 658 /**
646 * @type {string|undefined} 659 * @type {string|undefined}
647 */ 660 */
648 this.factoryName; 661 this.factoryName;
649 662
650 /** 663 /**
651 * @type {!Array.<string>|undefined} 664 * @type {!Array.<string>|undefined}
652 */ 665 */
653 this.contextTypes; 666 this.contextTypes;
667 }
654 }; 668 };
655 669
656 /** 670 /**
657 * @constructor 671 * @unrestricted
658 * @param {!Runtime} manager
659 * @param {!Runtime.ModuleDescriptor} descriptor
660 */ 672 */
661 Runtime.Module = function(manager, descriptor) 673 Runtime.Module = class {
662 { 674 /**
675 * @param {!Runtime} manager
676 * @param {!Runtime.ModuleDescriptor} descriptor
677 */
678 constructor(manager, descriptor) {
663 this._manager = manager; 679 this._manager = manager;
664 this._descriptor = descriptor; 680 this._descriptor = descriptor;
665 this._name = descriptor.name; 681 this._name = descriptor.name;
666 /** @type {!Array<!Runtime.Extension>} */ 682 /** @type {!Array<!Runtime.Extension>} */
667 this._extensions = []; 683 this._extensions = [];
668 684
669 /** @type {!Map<string, !Array<!Runtime.Extension>>} */ 685 /** @type {!Map<string, !Array<!Runtime.Extension>>} */
670 this._extensionsByClassName = new Map(); 686 this._extensionsByClassName = new Map();
671 var extensions = /** @type {?Array.<!Runtime.ExtensionDescriptor>} */ (descr iptor.extensions); 687 var extensions = /** @type {?Array.<!Runtime.ExtensionDescriptor>} */ (descr iptor.extensions);
672 for (var i = 0; extensions && i < extensions.length; ++i) { 688 for (var i = 0; extensions && i < extensions.length; ++i) {
673 var extension = new Runtime.Extension(this, extensions[i]); 689 var extension = new Runtime.Extension(this, extensions[i]);
674 this._manager._extensions.push(extension); 690 this._manager._extensions.push(extension);
675 this._extensions.push(extension); 691 this._extensions.push(extension);
676 } 692 }
677 this._loadedForTest = false; 693 this._loadedForTest = false;
694 }
695
696 /**
697 * @return {string}
698 */
699 name() {
700 return this._name;
701 }
702
703 /**
704 * @return {boolean}
705 */
706 enabled() {
707 return Runtime._isDescriptorEnabled(this._descriptor);
708 }
709
710 /**
711 * @param {string} name
712 * @return {string}
713 */
714 resource(name) {
715 var fullName = this._name + '/' + name;
716 var content = Runtime.cachedResources[fullName];
717 if (!content)
718 throw new Error(fullName + ' not preloaded. Check module.json');
719 return content;
720 }
721
722 /**
723 * @return {!Promise.<undefined>}
724 */
725 _loadPromise() {
726 if (!this.enabled())
727 return Promise.reject(new Error('Module ' + this._name + ' is not enabled' ));
728
729 if (this._pendingLoadPromise)
730 return this._pendingLoadPromise;
731
732 var dependencies = this._descriptor.dependencies;
733 var dependencyPromises = [];
734 for (var i = 0; dependencies && i < dependencies.length; ++i)
735 dependencyPromises.push(this._manager._modulesMap[dependencies[i]]._loadPr omise());
736
737 this._pendingLoadPromise = Promise.all(dependencyPromises)
738 .then(this._loadResources.bind(this))
739 .then(this._loadScripts.bind(this))
740 .then(() => this._loadedForTest = true);
741
742 return this._pendingLoadPromise;
743 }
744
745 /**
746 * @return {!Promise.<undefined>}
747 * @this {Runtime.Module}
748 */
749 _loadResources() {
750 var resources = this._descriptor['resources'];
751 if (!resources || !resources.length)
752 return Promise.resolve();
753 var promises = [];
754 for (var i = 0; i < resources.length; ++i) {
755 var url = this._modularizeURL(resources[i]);
756 promises.push(Runtime.loadResourceIntoCache(url, true));
757 }
758 return Promise.all(promises).then(undefined);
759 }
760
761 /**
762 * @return {!Promise.<undefined>}
763 */
764 _loadScripts() {
765 if (!this._descriptor.scripts || !this._descriptor.scripts.length)
766 return Promise.resolve();
767 return Runtime._loadScriptsPromise(this._descriptor.scripts.map(this._modula rizeURL, this), this._remoteBase());
768 }
769
770 /**
771 * @param {string} resourceName
772 */
773 _modularizeURL(resourceName) {
774 return Runtime.normalizePath(this._name + '/' + resourceName);
775 }
776
777 /**
778 * @return {string|undefined}
779 */
780 _remoteBase() {
781 return !Runtime.queryParam('debugFrontend') && this._descriptor.remote && Ru ntime._remoteBase || undefined;
782 }
783
784 /**
785 * @param {string} value
786 * @return {string}
787 */
788 substituteURL(value) {
789 var base = this._remoteBase() || '';
790 return value.replace(/@url\(([^\)]*?)\)/g, convertURL.bind(this));
791
792 function convertURL(match, url) {
793 return base + this._modularizeURL(url);
794 }
795 }
678 }; 796 };
679 797
680 Runtime.Module.prototype = {
681 /**
682 * @return {string}
683 */
684 name: function()
685 {
686 return this._name;
687 },
688
689 /**
690 * @return {boolean}
691 */
692 enabled: function()
693 {
694 return Runtime._isDescriptorEnabled(this._descriptor);
695 },
696
697 /**
698 * @param {string} name
699 * @return {string}
700 */
701 resource: function(name)
702 {
703 var fullName = this._name + "/" + name;
704 var content = Runtime.cachedResources[fullName];
705 if (!content)
706 throw new Error(fullName + " not preloaded. Check module.json");
707 return content;
708 },
709
710 /**
711 * @return {!Promise.<undefined>}
712 */
713 _loadPromise: function()
714 {
715 if (!this.enabled())
716 return Promise.reject(new Error("Module " + this._name + " is not en abled"));
717
718 if (this._pendingLoadPromise)
719 return this._pendingLoadPromise;
720
721 var dependencies = this._descriptor.dependencies;
722 var dependencyPromises = [];
723 for (var i = 0; dependencies && i < dependencies.length; ++i)
724 dependencyPromises.push(this._manager._modulesMap[dependencies[i]]._ loadPromise());
725
726 this._pendingLoadPromise = Promise.all(dependencyPromises)
727 .then(this._loadResources.bind(this))
728 .then(this._loadScripts.bind(this))
729 .then(() => this._loadedForTest = true);
730
731 return this._pendingLoadPromise;
732 },
733
734 /**
735 * @return {!Promise.<undefined>}
736 * @this {Runtime.Module}
737 */
738 _loadResources: function()
739 {
740 var resources = this._descriptor["resources"];
741 if (!resources || !resources.length)
742 return Promise.resolve();
743 var promises = [];
744 for (var i = 0; i < resources.length; ++i) {
745 var url = this._modularizeURL(resources[i]);
746 promises.push(Runtime.loadResourceIntoCache(url, true));
747 }
748 return Promise.all(promises).then(undefined);
749 },
750
751 /**
752 * @return {!Promise.<undefined>}
753 */
754 _loadScripts: function()
755 {
756 if (!this._descriptor.scripts || !this._descriptor.scripts.length)
757 return Promise.resolve();
758 return Runtime._loadScriptsPromise(this._descriptor.scripts.map(this._mo dularizeURL, this), this._remoteBase());
759 },
760
761 /**
762 * @param {string} resourceName
763 */
764 _modularizeURL: function(resourceName)
765 {
766 return Runtime.normalizePath(this._name + "/" + resourceName);
767 },
768
769 /**
770 * @return {string|undefined}
771 */
772 _remoteBase: function()
773 {
774 return !Runtime.queryParam("debugFrontend") && this._descriptor.remote & & Runtime._remoteBase || undefined;
775 },
776
777 /**
778 * @param {string} value
779 * @return {string}
780 */
781 substituteURL: function(value)
782 {
783 var base = this._remoteBase() || "";
784 return value.replace(/@url\(([^\)]*?)\)/g, convertURL.bind(this));
785
786 function convertURL(match, url)
787 {
788 return base + this._modularizeURL(url);
789 }
790 }
791 };
792 798
793 /** 799 /**
794 * @param {!Object} descriptor 800 * @unrestricted
795 * @return {boolean}
796 */ 801 */
797 Runtime._isDescriptorEnabled = function(descriptor) 802 Runtime.Extension = class {
798 { 803 /**
799 var activatorExperiment = descriptor["experiment"]; 804 * @param {!Runtime.Module} module
800 if (activatorExperiment === "*") 805 * @param {!Runtime.ExtensionDescriptor} descriptor
801 return Runtime.experiments.supportEnabled(); 806 */
802 if (activatorExperiment && activatorExperiment.startsWith("!") && Runtime.ex periments.isEnabled(activatorExperiment.substring(1))) 807 constructor(module, descriptor) {
803 return false;
804 if (activatorExperiment && !activatorExperiment.startsWith("!") && !Runtime. experiments.isEnabled(activatorExperiment))
805 return false;
806 var condition = descriptor["condition"];
807 if (condition && !condition.startsWith("!") && !Runtime.queryParam(condition ))
808 return false;
809 if (condition && condition.startsWith("!") && Runtime.queryParam(condition.s ubstring(1)))
810 return false;
811 return true;
812 };
813
814 /**
815 * @constructor
816 * @param {!Runtime.Module} module
817 * @param {!Runtime.ExtensionDescriptor} descriptor
818 */
819 Runtime.Extension = function(module, descriptor)
820 {
821 this._module = module; 808 this._module = module;
822 this._descriptor = descriptor; 809 this._descriptor = descriptor;
823 810
824 this._type = descriptor.type; 811 this._type = descriptor.type;
825 this._hasTypeClass = this._type.charAt(0) === "@"; 812 this._hasTypeClass = this._type.charAt(0) === '@';
826 813
827 /** 814 /**
828 * @type {?string} 815 * @type {?string}
829 */ 816 */
830 this._className = descriptor.className || null; 817 this._className = descriptor.className || null;
831 this._factoryName = descriptor.factoryName || null; 818 this._factoryName = descriptor.factoryName || null;
819 }
820
821 /**
822 * @return {!Object}
823 */
824 descriptor() {
825 return this._descriptor;
826 }
827
828 /**
829 * @return {!Runtime.Module}
830 */
831 module() {
832 return this._module;
833 }
834
835 /**
836 * @return {boolean}
837 */
838 enabled() {
839 return this._module.enabled() && Runtime._isDescriptorEnabled(this.descripto r());
840 }
841
842 /**
843 * @return {?function(new:Object)}
844 */
845 _typeClass() {
846 if (!this._hasTypeClass)
847 return null;
848 return this._module._manager._resolve(this._type.substring(1));
849 }
850
851 /**
852 * @param {?Object} context
853 * @return {boolean}
854 */
855 isApplicable(context) {
856 return this._module._manager.isExtensionApplicableToContext(this, context);
857 }
858
859 /**
860 * @return {!Promise.<!Object>}
861 */
862 instance() {
863 return this._module._loadPromise().then(this._createInstance.bind(this));
864 }
865
866 /**
867 * @return {!Object}
868 */
869 _createInstance() {
870 var className = this._className || this._factoryName;
871 if (!className)
872 throw new Error('Could not instantiate extension with no class');
873 var constructorFunction = self.eval(/** @type {string} */ (className));
874 if (!(constructorFunction instanceof Function))
875 throw new Error('Could not instantiate: ' + className);
876 if (this._className)
877 return this._module._manager.sharedInstance(constructorFunction);
878 return new constructorFunction(this);
879 }
880
881 /**
882 * @return {string}
883 */
884 title() {
885 // FIXME: should be WebInspector.UIString() but runtime is not l10n aware ye t.
886 return this._descriptor['title-' + Runtime._platform] || this._descriptor['t itle'];
887 }
888
889 /**
890 * @param {function(new:Object)} contextType
891 * @return {boolean}
892 */
893 hasContextType(contextType) {
894 var contextTypes = this.descriptor().contextTypes;
895 if (!contextTypes)
896 return false;
897 for (var i = 0; i < contextTypes.length; ++i) {
898 if (contextType === this._module._manager._resolve(contextTypes[i]))
899 return true;
900 }
901 return false;
902 }
832 }; 903 };
833 904
834 Runtime.Extension.prototype = {
835 /**
836 * @return {!Object}
837 */
838 descriptor: function()
839 {
840 return this._descriptor;
841 },
842
843 /**
844 * @return {!Runtime.Module}
845 */
846 module: function()
847 {
848 return this._module;
849 },
850
851 /**
852 * @return {boolean}
853 */
854 enabled: function()
855 {
856 return this._module.enabled() && Runtime._isDescriptorEnabled(this.descr iptor());
857 },
858
859 /**
860 * @return {?function(new:Object)}
861 */
862 _typeClass: function()
863 {
864 if (!this._hasTypeClass)
865 return null;
866 return this._module._manager._resolve(this._type.substring(1));
867 },
868
869 /**
870 * @param {?Object} context
871 * @return {boolean}
872 */
873 isApplicable: function(context)
874 {
875 return this._module._manager.isExtensionApplicableToContext(this, contex t);
876 },
877
878 /**
879 * @return {!Promise.<!Object>}
880 */
881 instance: function()
882 {
883 return this._module._loadPromise().then(this._createInstance.bind(this)) ;
884 },
885
886 /**
887 * @return {!Object}
888 */
889 _createInstance: function()
890 {
891 var className = this._className || this._factoryName;
892 if (!className)
893 throw new Error("Could not instantiate extension with no class");
894 var constructorFunction = self.eval(/** @type {string} */(className));
895 if (!(constructorFunction instanceof Function))
896 throw new Error("Could not instantiate: " + className);
897 if (this._className)
898 return this._module._manager.sharedInstance(constructorFunction);
899 return new constructorFunction(this);
900 },
901
902 /**
903 * @return {string}
904 */
905 title: function()
906 {
907 // FIXME: should be WebInspector.UIString() but runtime is not l10n awar e yet.
908 return this._descriptor["title-" + Runtime._platform] || this._descripto r["title"];
909 },
910
911 /**
912 * @param {function(new:Object)} contextType
913 * @return {boolean}
914 */
915 hasContextType: function(contextType)
916 {
917 var contextTypes = this.descriptor().contextTypes;
918 if (!contextTypes)
919 return false;
920 for (var i = 0; i < contextTypes.length; ++i) {
921 if (contextType === this._module._manager._resolve(contextTypes[i]))
922 return true;
923 }
924 return false;
925 }
926 };
927
928 /** 905 /**
929 * @constructor 906 * @unrestricted
930 */ 907 */
931 Runtime.ExperimentsSupport = function() 908 Runtime.ExperimentsSupport = class {
932 { 909 constructor() {
933 this._supportEnabled = Runtime.queryParam("experiments") !== null; 910 this._supportEnabled = Runtime.queryParam('experiments') !== null;
934 this._experiments = []; 911 this._experiments = [];
935 this._experimentNames = {}; 912 this._experimentNames = {};
936 this._enabledTransiently = {}; 913 this._enabledTransiently = {};
914 }
915
916 /**
917 * @return {!Array.<!Runtime.Experiment>}
918 */
919 allConfigurableExperiments() {
920 var result = [];
921 for (var i = 0; i < this._experiments.length; i++) {
922 var experiment = this._experiments[i];
923 if (!this._enabledTransiently[experiment.name])
924 result.push(experiment);
925 }
926 return result;
927 }
928
929 /**
930 * @return {boolean}
931 */
932 supportEnabled() {
933 return this._supportEnabled;
934 }
935
936 /**
937 * @param {!Object} value
938 */
939 _setExperimentsSetting(value) {
940 if (!self.localStorage)
941 return;
942 self.localStorage['experiments'] = JSON.stringify(value);
943 }
944
945 /**
946 * @param {string} experimentName
947 * @param {string} experimentTitle
948 * @param {boolean=} hidden
949 */
950 register(experimentName, experimentTitle, hidden) {
951 Runtime._assert(!this._experimentNames[experimentName], 'Duplicate registrat ion of experiment ' + experimentName);
952 this._experimentNames[experimentName] = true;
953 this._experiments.push(new Runtime.Experiment(this, experimentName, experime ntTitle, !!hidden));
954 }
955
956 /**
957 * @param {string} experimentName
958 * @return {boolean}
959 */
960 isEnabled(experimentName) {
961 this._checkExperiment(experimentName);
962
963 if (this._enabledTransiently[experimentName])
964 return true;
965 if (!this.supportEnabled())
966 return false;
967
968 return !!Runtime._experimentsSetting()[experimentName];
969 }
970
971 /**
972 * @param {string} experimentName
973 * @param {boolean} enabled
974 */
975 setEnabled(experimentName, enabled) {
976 this._checkExperiment(experimentName);
977 var experimentsSetting = Runtime._experimentsSetting();
978 experimentsSetting[experimentName] = enabled;
979 this._setExperimentsSetting(experimentsSetting);
980 }
981
982 /**
983 * @param {!Array.<string>} experimentNames
984 */
985 setDefaultExperiments(experimentNames) {
986 for (var i = 0; i < experimentNames.length; ++i) {
987 this._checkExperiment(experimentNames[i]);
988 this._enabledTransiently[experimentNames[i]] = true;
989 }
990 }
991
992 /**
993 * @param {string} experimentName
994 */
995 enableForTest(experimentName) {
996 this._checkExperiment(experimentName);
997 this._enabledTransiently[experimentName] = true;
998 }
999
1000 clearForTest() {
1001 this._experiments = [];
1002 this._experimentNames = {};
1003 this._enabledTransiently = {};
1004 }
1005
1006 cleanUpStaleExperiments() {
1007 var experimentsSetting = Runtime._experimentsSetting();
1008 var cleanedUpExperimentSetting = {};
1009 for (var i = 0; i < this._experiments.length; ++i) {
1010 var experimentName = this._experiments[i].name;
1011 if (experimentsSetting[experimentName])
1012 cleanedUpExperimentSetting[experimentName] = true;
1013 }
1014 this._setExperimentsSetting(cleanedUpExperimentSetting);
1015 }
1016
1017 /**
1018 * @param {string} experimentName
1019 */
1020 _checkExperiment(experimentName) {
1021 Runtime._assert(this._experimentNames[experimentName], 'Unknown experiment ' + experimentName);
1022 }
937 }; 1023 };
938 1024
939 Runtime.ExperimentsSupport.prototype = {
940 /**
941 * @return {!Array.<!Runtime.Experiment>}
942 */
943 allConfigurableExperiments: function()
944 {
945 var result = [];
946 for (var i = 0; i < this._experiments.length; i++) {
947 var experiment = this._experiments[i];
948 if (!this._enabledTransiently[experiment.name])
949 result.push(experiment);
950 }
951 return result;
952 },
953
954 /**
955 * @return {boolean}
956 */
957 supportEnabled: function()
958 {
959 return this._supportEnabled;
960 },
961
962 /**
963 * @param {!Object} value
964 */
965 _setExperimentsSetting: function(value)
966 {
967 if (!self.localStorage)
968 return;
969 self.localStorage["experiments"] = JSON.stringify(value);
970 },
971
972 /**
973 * @param {string} experimentName
974 * @param {string} experimentTitle
975 * @param {boolean=} hidden
976 */
977 register: function(experimentName, experimentTitle, hidden)
978 {
979 Runtime._assert(!this._experimentNames[experimentName], "Duplicate regis tration of experiment " + experimentName);
980 this._experimentNames[experimentName] = true;
981 this._experiments.push(new Runtime.Experiment(this, experimentName, expe rimentTitle, !!hidden));
982 },
983
984 /**
985 * @param {string} experimentName
986 * @return {boolean}
987 */
988 isEnabled: function(experimentName)
989 {
990 this._checkExperiment(experimentName);
991
992 if (this._enabledTransiently[experimentName])
993 return true;
994 if (!this.supportEnabled())
995 return false;
996
997 return !!Runtime._experimentsSetting()[experimentName];
998 },
999
1000 /**
1001 * @param {string} experimentName
1002 * @param {boolean} enabled
1003 */
1004 setEnabled: function(experimentName, enabled)
1005 {
1006 this._checkExperiment(experimentName);
1007 var experimentsSetting = Runtime._experimentsSetting();
1008 experimentsSetting[experimentName] = enabled;
1009 this._setExperimentsSetting(experimentsSetting);
1010 },
1011
1012 /**
1013 * @param {!Array.<string>} experimentNames
1014 */
1015 setDefaultExperiments: function(experimentNames)
1016 {
1017 for (var i = 0; i < experimentNames.length; ++i) {
1018 this._checkExperiment(experimentNames[i]);
1019 this._enabledTransiently[experimentNames[i]] = true;
1020 }
1021 },
1022
1023 /**
1024 * @param {string} experimentName
1025 */
1026 enableForTest: function(experimentName)
1027 {
1028 this._checkExperiment(experimentName);
1029 this._enabledTransiently[experimentName] = true;
1030 },
1031
1032 clearForTest: function()
1033 {
1034 this._experiments = [];
1035 this._experimentNames = {};
1036 this._enabledTransiently = {};
1037 },
1038
1039 cleanUpStaleExperiments: function()
1040 {
1041 var experimentsSetting = Runtime._experimentsSetting();
1042 var cleanedUpExperimentSetting = {};
1043 for (var i = 0; i < this._experiments.length; ++i) {
1044 var experimentName = this._experiments[i].name;
1045 if (experimentsSetting[experimentName])
1046 cleanedUpExperimentSetting[experimentName] = true;
1047 }
1048 this._setExperimentsSetting(cleanedUpExperimentSetting);
1049 },
1050
1051 /**
1052 * @param {string} experimentName
1053 */
1054 _checkExperiment: function(experimentName)
1055 {
1056 Runtime._assert(this._experimentNames[experimentName], "Unknown experime nt " + experimentName);
1057 }
1058 };
1059
1060 /** 1025 /**
1061 * @constructor 1026 * @unrestricted
1062 * @param {!Runtime.ExperimentsSupport} experiments
1063 * @param {string} name
1064 * @param {string} title
1065 * @param {boolean} hidden
1066 */ 1027 */
1067 Runtime.Experiment = function(experiments, name, title, hidden) 1028 Runtime.Experiment = class {
1068 { 1029 /**
1030 * @param {!Runtime.ExperimentsSupport} experiments
1031 * @param {string} name
1032 * @param {string} title
1033 * @param {boolean} hidden
1034 */
1035 constructor(experiments, name, title, hidden) {
1069 this.name = name; 1036 this.name = name;
1070 this.title = title; 1037 this.title = title;
1071 this.hidden = hidden; 1038 this.hidden = hidden;
1072 this._experiments = experiments; 1039 this._experiments = experiments;
1040 }
1041
1042 /**
1043 * @return {boolean}
1044 */
1045 isEnabled() {
1046 return this._experiments.isEnabled(this.name);
1047 }
1048
1049 /**
1050 * @param {boolean} enabled
1051 */
1052 setEnabled(enabled) {
1053 this._experiments.setEnabled(this.name, enabled);
1054 }
1073 }; 1055 };
1074 1056
1075 Runtime.Experiment.prototype = {
1076 /**
1077 * @return {boolean}
1078 */
1079 isEnabled: function()
1080 {
1081 return this._experiments.isEnabled(this.name);
1082 },
1083
1084 /**
1085 * @param {boolean} enabled
1086 */
1087 setEnabled: function(enabled)
1088 {
1089 this._experiments.setEnabled(this.name, enabled);
1090 }
1091 };
1092
1093 {(function parseQueryParameters()
1094 { 1057 {
1058 (function parseQueryParameters() {
1095 var queryParams = location.search; 1059 var queryParams = location.search;
1096 if (!queryParams) 1060 if (!queryParams)
1097 return; 1061 return;
1098 var params = queryParams.substring(1).split("&"); 1062 var params = queryParams.substring(1).split('&');
1099 for (var i = 0; i < params.length; ++i) { 1063 for (var i = 0; i < params.length; ++i) {
1100 var pair = params[i].split("="); 1064 var pair = params[i].split('=');
1101 var name = pair.shift(); 1065 var name = pair.shift();
1102 Runtime._queryParamsObject[name] = pair.join("="); 1066 Runtime._queryParamsObject[name] = pair.join('=');
1103 } 1067 }
1104 })();} 1068 })();
1105 1069 }
1106 1070
1107 // This must be constructed after the query parameters have been parsed. 1071 // This must be constructed after the query parameters have been parsed.
1108 Runtime.experiments = new Runtime.ExperimentsSupport(); 1072 Runtime.experiments = new Runtime.ExperimentsSupport();
1109 1073
1110 /** 1074 /**
1111 * @type {?string} 1075 * @type {?string}
1112 */ 1076 */
1113 Runtime._remoteBase = Runtime.queryParam("remoteBase"); 1077 Runtime._remoteBase = Runtime.queryParam('remoteBase');
1114 {(function validateRemoteBase()
1115 { 1078 {
1079 (function validateRemoteBase() {
1116 var remoteBaseRegexp = /^https:\/\/chrome-devtools-frontend\.appspot\.com\/s erve_file\/@[0-9a-zA-Z]+\/?$/; 1080 var remoteBaseRegexp = /^https:\/\/chrome-devtools-frontend\.appspot\.com\/s erve_file\/@[0-9a-zA-Z]+\/?$/;
1117 if (Runtime._remoteBase && !remoteBaseRegexp.test(Runtime._remoteBase)) 1081 if (Runtime._remoteBase && !remoteBaseRegexp.test(Runtime._remoteBase))
1118 Runtime._remoteBase = null; 1082 Runtime._remoteBase = null;
1119 })();} 1083 })();
1084 }
1120 1085
1121 /**
1122 * @param {string} path
1123 * @return {string}
1124 */
1125 Runtime.resolveSourceURL = function(path)
1126 {
1127 var sourceURL = self.location.href;
1128 if (self.location.search)
1129 sourceURL = sourceURL.replace(self.location.search, "");
1130 sourceURL = sourceURL.substring(0, sourceURL.lastIndexOf("/") + 1) + path;
1131 return "\n/*# sourceURL=" + sourceURL + " */";
1132 };
1133 1086
1134 /** 1087 /**
1135 * @interface 1088 * @interface
1136 */ 1089 */
1137 function ServicePort() { } 1090 function ServicePort() {
1091 }
1138 1092
1139 ServicePort.prototype = { 1093 ServicePort.prototype = {
1140 /** 1094 /**
1141 * @param {function(string)} messageHandler 1095 * @param {function(string)} messageHandler
1142 * @param {function(string)} closeHandler 1096 * @param {function(string)} closeHandler
1143 */ 1097 */
1144 setHandlers: function(messageHandler, closeHandler) { }, 1098 setHandlers: function(messageHandler, closeHandler) {},
1145 1099
1146 /** 1100 /**
1147 * @param {string} message 1101 * @param {string} message
1148 * @return {!Promise<boolean>} 1102 * @return {!Promise<boolean>}
1149 */ 1103 */
1150 send: function(message) { }, 1104 send: function(message) {},
1151 1105
1152 /** 1106 /**
1153 * @return {!Promise<boolean>} 1107 * @return {!Promise<boolean>}
1154 */ 1108 */
1155 close: function() { } 1109 close: function() {}
1156 }; 1110 };
1157 1111
1158 /** @type {!Runtime} */ 1112 /** @type {!Runtime} */
1159 var runtime; 1113 var runtime;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698