├── README.md ├── analyze.js ├── analyze.py ├── jspanda.py ├── panda.gif ├── payload.js ├── pollute.png ├── testfiles ├── protopollution_closure.js ├── protopollution_freeze_test.html ├── protopollution_test.html └── testfile └── url.txt /README.md: -------------------------------------------------------------------------------- 1 | # JSPanda 2 | 3 | [![Panda](panda.gif)](https://www.youtube.com/watch?v=6At3qjurhOs) 4 | 5 | JSpanda is client-side prototype pollution vulnerability scanner. It has two key features, scanning vulnerability the supplied URLs and analyzing the JavaScript libraries' source code. 6 | 7 | However, JSpanda cannot detect advanced prototype pollution vulnerabilities. 8 | 9 | ## **How JSPanda works?** 10 | 11 | - Uses multiple payloads for prototype pollution vulnerability. 12 | - Gathers all the links in the targets for scanning and add payloads to JSpanda-obtained URLs, navigates to each URL with headless Chromedriver. 13 | - Scans all words in the source code of potentially vulnerable JavaScript library and it creates a simple JS PoC by finding the script gadget, helping you analyze the code manually. 14 | 15 | ## **Requirements** 16 | 17 | - Download latest version of Google Chrome and Chromedriver 18 | - Selenium 19 | 20 | ## **Usage** 21 | 22 | Scan: python3.7 jspanda.py 23 | 24 | - Add URLs to url.txt file, *for instance : example.com* 25 | 26 | Basic Source Code Analysis : python3.7 analyze.py 27 | 28 | - Add a JavaScript library's source code to analyze.js 29 | - Generate PoC code using analyze.py 30 | - Execute PoC code on Chrome's console. It pollutes all the words collected from the source code and show it on the screen. So it may generate false positive results. These outputs provide additional information to researchers, do not automate everything. 31 | 32 | ### Demonstration 33 | 34 | [![asciicast](https://asciinema.org/a/BOazgAVyW6yHqhUE3fEYcCiML.svg)](https://asciinema.org/a/BOazgAVyW6yHqhUE3fEYcCiML) 35 | 36 | ### Source code analysis - Screenshot 37 | 38 | ![Untitled](https://github.com/RedSection/jspanda/blob/main/pollute.png?raw=true) 39 | 40 | **Supporting Materials :** 41 | 42 | [https://twitter.com/har1sec/status/1314469278322655233](https://twitter.com/har1sec/status/1314469278322655233) 43 | 44 | 45 | [https://github.com/BlackFan/client-side-prototype-pollution](https://github.com/BlackFan/client-side-prototype-pollution) 46 | 47 | 48 | [https://github.com/ThePacketBender/notes/blob/01c0b834f6e3ee4d934b087b2d92c9e484dc2a50/web/prototype_pollution.txt](https://github.com/ThePacketBender/notes/blob/01c0b834f6e3ee4d934b087b2d92c9e484dc2a50/web/prototype_pollution.txt) 49 | 50 | [https://habr.com/ru/company/huawei/blog/547178/](https://habr.com/ru/company/huawei/blog/547178/) 51 | 52 | [https://infosecwriteups.com/javascript-prototype-pollution-practice-of-finding-and-exploitation-f97284333b2](https://infosecwriteups.com/javascript-prototype-pollution-practice-of-finding-and-exploitation-f97284333b2) 53 | 54 | [https://github.com/securitum/research/tree/master/r2020_prototype-pollution](https://github.com/securitum/research/tree/master/r2020_prototype-pollution) 55 | 56 | 57 | [Learn Prototype Pollution in Series - Part 2](https://attacker-codeninja.github.io/2021-07-05-Learn-Prototype-Pollution-Part-2/) 58 | 59 | [dwisiswant0/ppfuzz](https://github.com/dwisiswant0/ppfuzz) 60 | 61 | [GitHub - raverrr/plution: Prototype pollution scanner using headless chrome](https://github.com/raverrr/plution) 62 | 63 | [JavaScript Prototype Poisoning Vulnerabilities in the Wild](https://medium.com/intrinsic-blog/javascript-prototype-poisoning-vulnerabilities-in-the-wild-7bc15347c96) 64 | 65 | [The Complete Guide to Prototype Pollution Vulnerabilities](https://www.whitesourcesoftware.com/resources/blog/prototype-pollution-vulnerabilities/) 66 | -------------------------------------------------------------------------------- /analyze.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright The Closure Library Authors. 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Bootstrap for the Google JS Library (Closure). 9 | * 10 | * In uncompiled mode base.js will attempt to load Closure's deps file, unless 11 | * the global CLOSURE_NO_DEPS is set to true. This allows projects 12 | * to include their own deps file(s) from different locations. 13 | * 14 | * Avoid including base.js more than once. This is strictly discouraged and not 15 | * supported. goog.require(...) won't work properly in that case. 16 | * 17 | * @provideGoog 18 | */ 19 | 20 | 21 | /** 22 | * @define {boolean} Overridden to true by the compiler. 23 | */ 24 | var COMPILED = false; 25 | 26 | 27 | /** 28 | * Base namespace for the Closure library. Checks to see goog is already 29 | * defined in the current scope before assigning to prevent clobbering if 30 | * base.js is loaded more than once. 31 | * 32 | * @const 33 | */ 34 | var goog = goog || {}; 35 | 36 | /** 37 | * Reference to the global object. 38 | * https://www.ecma-international.org/ecma-262/9.0/index.html#sec-global-object 39 | * 40 | * More info on this implementation here: 41 | * https://docs.google.com/document/d/1NAeW4Wk7I7FV0Y2tcUFvQdGMc89k2vdgSXInw8_nvCI/edit 42 | * 43 | * @const 44 | * @suppress {undefinedVars} self won't be referenced unless `this` is falsy. 45 | * @type {!Global} 46 | */ 47 | goog.global = 48 | // Check `this` first for backwards compatibility. 49 | // Valid unless running as an ES module or in a function wrapper called 50 | // without setting `this` properly. 51 | // Note that base.js can't usefully be imported as an ES module, but it may 52 | // be compiled into bundles that are loadable as ES modules. 53 | this || 54 | // https://developer.mozilla.org/en-US/docs/Web/API/Window/self 55 | // For in-page browser environments and workers. 56 | self; 57 | 58 | 59 | /** 60 | * A hook for overriding the define values in uncompiled mode. 61 | * 62 | * In uncompiled mode, `CLOSURE_UNCOMPILED_DEFINES` may be defined before 63 | * loading base.js. If a key is defined in `CLOSURE_UNCOMPILED_DEFINES`, 64 | * `goog.define` will use the value instead of the default value. This 65 | * allows flags to be overwritten without compilation (this is normally 66 | * accomplished with the compiler's "define" flag). 67 | * 68 | * Example: 69 | *
  70 |  *   var CLOSURE_UNCOMPILED_DEFINES = {'goog.DEBUG': false};
  71 |  * 
72 | * 73 | * @type {Object|undefined} 74 | */ 75 | goog.global.CLOSURE_UNCOMPILED_DEFINES; 76 | 77 | 78 | /** 79 | * A hook for overriding the define values in uncompiled or compiled mode, 80 | * like CLOSURE_UNCOMPILED_DEFINES but effective in compiled code. In 81 | * uncompiled code CLOSURE_UNCOMPILED_DEFINES takes precedence. 82 | * 83 | * Also unlike CLOSURE_UNCOMPILED_DEFINES the values must be number, boolean or 84 | * string literals or the compiler will emit an error. 85 | * 86 | * While any @define value may be set, only those set with goog.define will be 87 | * effective for uncompiled code. 88 | * 89 | * Example: 90 | *
  91 |  *   var CLOSURE_DEFINES = {'goog.DEBUG': false} ;
  92 |  * 
93 | * 94 | * @type {Object|undefined} 95 | */ 96 | goog.global.CLOSURE_DEFINES; 97 | 98 | 99 | /** 100 | * Builds an object structure for the provided namespace path, ensuring that 101 | * names that already exist are not overwritten. For example: 102 | * "a.b.c" -> a = {};a.b={};a.b.c={}; 103 | * Used by goog.provide and goog.exportSymbol. 104 | * @param {string} name The name of the object that this file defines. 105 | * @param {*=} object The object to expose at the end of the path. 106 | * @param {boolean=} overwriteImplicit If object is set and a previous call 107 | * implicitly constructed the namespace given by name, this parameter 108 | * controls whether object should overwrite the implicitly constructed 109 | * namespace or be merged into it. Defaults to false. 110 | * @param {?Object=} objectToExportTo The object to add the path to; if this 111 | * field is not specified, its value defaults to `goog.global`. 112 | * @private 113 | */ 114 | goog.exportPath_ = function(name, object, overwriteImplicit, objectToExportTo) { 115 | var parts = name.split('.'); 116 | var cur = objectToExportTo || goog.global; 117 | 118 | // Internet Explorer exhibits strange behavior when throwing errors from 119 | // methods externed in this manner. See the testExportSymbolExceptions in 120 | // base_test.html for an example. 121 | if (!(parts[0] in cur) && typeof cur.execScript != 'undefined') { 122 | cur.execScript('var ' + parts[0]); 123 | } 124 | 125 | for (var part; parts.length && (part = parts.shift());) { 126 | if (!parts.length && object !== undefined) { 127 | if (!overwriteImplicit && goog.isObject(object) && 128 | goog.isObject(cur[part])) { 129 | // Merge properties on object (the input parameter) with the existing 130 | // implicitly defined namespace, so as to not clobber previously 131 | // defined child namespaces. 132 | for (var prop in object) { 133 | if (object.hasOwnProperty(prop)) { 134 | cur[part][prop] = object[prop]; 135 | } 136 | } 137 | } else { 138 | // Either there is no existing implicit namespace, or overwriteImplicit 139 | // is set to true, so directly assign object (the input parameter) to 140 | // the namespace. 141 | cur[part] = object; 142 | } 143 | } else if (cur[part] && cur[part] !== Object.prototype[part]) { 144 | cur = cur[part]; 145 | } else { 146 | cur = cur[part] = {}; 147 | } 148 | } 149 | }; 150 | 151 | 152 | /** 153 | * Defines a named value. In uncompiled mode, the value is retrieved from 154 | * CLOSURE_DEFINES or CLOSURE_UNCOMPILED_DEFINES if the object is defined and 155 | * has the property specified, and otherwise used the defined defaultValue. 156 | * When compiled the default can be overridden using the compiler options or the 157 | * value set in the CLOSURE_DEFINES object. Returns the defined value so that it 158 | * can be used safely in modules. Note that the value type MUST be either 159 | * boolean, number, or string. 160 | * 161 | * @param {string} name The distinguished name to provide. 162 | * @param {T} defaultValue 163 | * @return {T} The defined value. 164 | * @template T 165 | */ 166 | goog.define = function(name, defaultValue) { 167 | var value = defaultValue; 168 | if (!COMPILED) { 169 | var uncompiledDefines = goog.global.CLOSURE_UNCOMPILED_DEFINES; 170 | var defines = goog.global.CLOSURE_DEFINES; 171 | if (uncompiledDefines && 172 | // Anti DOM-clobbering runtime check (b/37736576). 173 | /** @type {?} */ (uncompiledDefines).nodeType === undefined && 174 | Object.prototype.hasOwnProperty.call(uncompiledDefines, name)) { 175 | value = uncompiledDefines[name]; 176 | } else if ( 177 | defines && 178 | // Anti DOM-clobbering runtime check (b/37736576). 179 | /** @type {?} */ (defines).nodeType === undefined && 180 | Object.prototype.hasOwnProperty.call(defines, name)) { 181 | value = defines[name]; 182 | } 183 | } 184 | return value; 185 | }; 186 | 187 | 188 | /** 189 | * @define {number} Integer year indicating the set of browser features that are 190 | * guaranteed to be present. This is defined to include exactly features that 191 | * work correctly on all "modern" browsers that are stable on January 1 of the 192 | * specified year. For example, 193 | * ```js 194 | * if (goog.FEATURESET_YEAR >= 2019) { 195 | * // use APIs known to be available on all major stable browsers Jan 1, 2019 196 | * } else { 197 | * // polyfill for older browsers 198 | * } 199 | * ``` 200 | * This is intended to be the primary define for removing 201 | * unnecessary browser compatibility code (such as ponyfills and workarounds), 202 | * and should inform the default value for most other defines: 203 | * ```js 204 | * const ASSUME_NATIVE_PROMISE = 205 | * goog.define('ASSUME_NATIVE_PROMISE', goog.FEATURESET_YEAR >= 2016); 206 | * ``` 207 | * 208 | * The default assumption is that IE9 is the lowest supported browser, which was 209 | * first available Jan 1, 2012. 210 | * 211 | * TODO(user): Reference more thorough documentation when it's available. 212 | */ 213 | goog.FEATURESET_YEAR = goog.define('goog.FEATURESET_YEAR', 2012); 214 | 215 | 216 | /** 217 | * @define {boolean} DEBUG is provided as a convenience so that debugging code 218 | * that should not be included in a production. It can be easily stripped 219 | * by specifying --define goog.DEBUG=false to the Closure Compiler aka 220 | * JSCompiler. For example, most toString() methods should be declared inside an 221 | * "if (goog.DEBUG)" conditional because they are generally used for debugging 222 | * purposes and it is difficult for the JSCompiler to statically determine 223 | * whether they are used. 224 | */ 225 | goog.DEBUG = goog.define('goog.DEBUG', true); 226 | 227 | 228 | /** 229 | * @define {string} LOCALE defines the locale being used for compilation. It is 230 | * used to select locale specific data to be compiled in js binary. BUILD rule 231 | * can specify this value by "--define goog.LOCALE=" as a compiler 232 | * option. 233 | * 234 | * Take into account that the locale code format is important. You should use 235 | * the canonical Unicode format with hyphen as a delimiter. Language must be 236 | * lowercase, Language Script - Capitalized, Region - UPPERCASE. 237 | * There are few examples: pt-BR, en, en-US, sr-Latin-BO, zh-Hans-CN. 238 | * 239 | * See more info about locale codes here: 240 | * http://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers 241 | * 242 | * For language codes you should use values defined by ISO 693-1. See it here 243 | * http://www.w3.org/WAI/ER/IG/ert/iso639.htm. There is only one exception from 244 | * this rule: the Hebrew language. For legacy reasons the old code (iw) should 245 | * be used instead of the new code (he). 246 | * 247 | */ 248 | goog.LOCALE = goog.define('goog.LOCALE', 'en'); // default to en 249 | 250 | 251 | /** 252 | * This method is intended to be used for bookkeeping purposes. We would 253 | * like to distinguish uses of goog.LOCALE used for code stripping purposes 254 | * and uses of goog.LOCALE for other uses (such as URL parameters). 255 | * 256 | * This allows us to ban direct uses of goog.LOCALE and to ensure that all 257 | * code has been transformed to our new localization build scheme. 258 | * 259 | * @return {string} 260 | * 261 | */ 262 | goog.getLocale = function() { 263 | return goog.LOCALE; 264 | }; 265 | 266 | 267 | /** 268 | * @define {boolean} Whether this code is running on trusted sites. 269 | * 270 | * On untrusted sites, several native functions can be defined or overridden by 271 | * external libraries like Prototype, Datejs, and JQuery and setting this flag 272 | * to false forces closure to use its own implementations when possible. 273 | * 274 | * If your JavaScript can be loaded by a third party site and you are wary about 275 | * relying on non-standard implementations, specify 276 | * "--define goog.TRUSTED_SITE=false" to the compiler. 277 | */ 278 | goog.TRUSTED_SITE = goog.define('goog.TRUSTED_SITE', true); 279 | 280 | 281 | /** 282 | * @define {boolean} Whether code that calls {@link goog.setTestOnly} should 283 | * be disallowed in the compilation unit. 284 | */ 285 | goog.DISALLOW_TEST_ONLY_CODE = 286 | goog.define('goog.DISALLOW_TEST_ONLY_CODE', COMPILED && !goog.DEBUG); 287 | 288 | 289 | /** 290 | * @define {boolean} Whether to use a Chrome app CSP-compliant method for 291 | * loading scripts via goog.require. @see appendScriptSrcNode_. 292 | */ 293 | goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING = 294 | goog.define('goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING', false); 295 | 296 | 297 | /** 298 | * Defines a namespace in Closure. 299 | * 300 | * A namespace may only be defined once in a codebase. It may be defined using 301 | * goog.provide() or goog.module(). 302 | * 303 | * The presence of one or more goog.provide() calls in a file indicates 304 | * that the file defines the given objects/namespaces. 305 | * Provided symbols must not be null or undefined. 306 | * 307 | * In addition, goog.provide() creates the object stubs for a namespace 308 | * (for example, goog.provide("goog.foo.bar") will create the object 309 | * goog.foo.bar if it does not already exist). 310 | * 311 | * Build tools also scan for provide/require/module statements 312 | * to discern dependencies, build dependency files (see deps.js), etc. 313 | * 314 | * @see goog.require 315 | * @see goog.module 316 | * @param {string} name Namespace provided by this file in the form 317 | * "goog.package.part". 318 | * deprecated Use goog.module (see b/159289405) 319 | */ 320 | goog.provide = function(name) { 321 | if (goog.isInModuleLoader_()) { 322 | throw new Error('goog.provide cannot be used within a module.'); 323 | } 324 | if (!COMPILED) { 325 | // Ensure that the same namespace isn't provided twice. 326 | // A goog.module/goog.provide maps a goog.require to a specific file 327 | if (goog.isProvided_(name)) { 328 | throw new Error('Namespace "' + name + '" already declared.'); 329 | } 330 | } 331 | 332 | goog.constructNamespace_(name); 333 | }; 334 | 335 | 336 | /** 337 | * @param {string} name Namespace provided by this file in the form 338 | * "goog.package.part". 339 | * @param {?Object=} object The object to embed in the namespace. 340 | * @param {boolean=} overwriteImplicit If object is set and a previous call 341 | * implicitly constructed the namespace given by name, this parameter 342 | * controls whether opt_obj should overwrite the implicitly constructed 343 | * namespace or be merged into it. Defaults to false. 344 | * @private 345 | */ 346 | goog.constructNamespace_ = function(name, object, overwriteImplicit) { 347 | if (!COMPILED) { 348 | delete goog.implicitNamespaces_[name]; 349 | 350 | var namespace = name; 351 | while ((namespace = namespace.substring(0, namespace.lastIndexOf('.')))) { 352 | if (goog.getObjectByName(namespace)) { 353 | break; 354 | } 355 | goog.implicitNamespaces_[namespace] = true; 356 | } 357 | } 358 | 359 | goog.exportPath_(name, object, overwriteImplicit); 360 | }; 361 | 362 | 363 | /** 364 | * According to the CSP3 spec a nonce must be a valid base64 string. 365 | * @see https://www.w3.org/TR/CSP3/#grammardef-base64-value 366 | * @private @const 367 | */ 368 | goog.NONCE_PATTERN_ = /^[\w+/_-]+[=]{0,2}$/; 369 | 370 | 371 | /** 372 | * Returns CSP nonce, if set for any script tag. 373 | * @param {?Window=} opt_window The window context used to retrieve the nonce. 374 | * Defaults to global context. 375 | * @return {string} CSP nonce or empty string if no nonce is present. 376 | * @private 377 | */ 378 | goog.getScriptNonce_ = function(opt_window) { 379 | var doc = (opt_window || goog.global).document; 380 | var script = doc.querySelector && doc.querySelector('script[nonce]'); 381 | if (script) { 382 | // Try to get the nonce from the IDL property first, because browsers that 383 | // implement additional nonce protection features (currently only Chrome) to 384 | // prevent nonce stealing via CSS do not expose the nonce via attributes. 385 | // See https://github.com/whatwg/html/issues/2369 386 | var nonce = script['nonce'] || script.getAttribute('nonce'); 387 | if (nonce && goog.NONCE_PATTERN_.test(nonce)) { 388 | return nonce; 389 | } 390 | } 391 | return ''; 392 | }; 393 | 394 | 395 | /** 396 | * Module identifier validation regexp. 397 | * Note: This is a conservative check, it is very possible to be more lenient, 398 | * the primary exclusion here is "/" and "\" and a leading ".", these 399 | * restrictions are intended to leave the door open for using goog.require 400 | * with relative file paths rather than module identifiers. 401 | * @private 402 | */ 403 | goog.VALID_MODULE_RE_ = /^[a-zA-Z_$][a-zA-Z0-9._$]*$/; 404 | 405 | 406 | /** 407 | * Defines a module in Closure. 408 | * 409 | * Marks that this file must be loaded as a module and claims the namespace. 410 | * 411 | * A namespace may only be defined once in a codebase. It may be defined using 412 | * goog.provide() or goog.module(). 413 | * 414 | * goog.module() has three requirements: 415 | * - goog.module may not be used in the same file as goog.provide. 416 | * - goog.module must be the first statement in the file. 417 | * - only one goog.module is allowed per file. 418 | * 419 | * When a goog.module annotated file is loaded, it is enclosed in 420 | * a strict function closure. This means that: 421 | * - any variables declared in a goog.module file are private to the file 422 | * (not global), though the compiler is expected to inline the module. 423 | * - The code must obey all the rules of "strict" JavaScript. 424 | * - the file will be marked as "use strict" 425 | * 426 | * NOTE: unlike goog.provide, goog.module does not declare any symbols by 427 | * itself. If declared symbols are desired, use 428 | * goog.module.declareLegacyNamespace(). 429 | * 430 | * 431 | * See the public goog.module proposal: http://goo.gl/Va1hin 432 | * 433 | * @param {string} name Namespace provided by this file in the form 434 | * "goog.package.part", is expected but not required. 435 | * @return {void} 436 | */ 437 | goog.module = function(name) { 438 | if (typeof name !== 'string' || !name || 439 | name.search(goog.VALID_MODULE_RE_) == -1) { 440 | throw new Error('Invalid module identifier'); 441 | } 442 | if (!goog.isInGoogModuleLoader_()) { 443 | throw new Error( 444 | 'Module ' + name + ' has been loaded incorrectly. Note, ' + 445 | 'modules cannot be loaded as normal scripts. They require some kind of ' + 446 | 'pre-processing step. You\'re likely trying to load a module via a ' + 447 | 'script tag or as a part of a concatenated bundle without rewriting the ' + 448 | 'module. For more info see: ' + 449 | 'https://github.com/google/closure-library/wiki/goog.module:-an-ES6-module-like-alternative-to-goog.provide.'); 450 | } 451 | if (goog.moduleLoaderState_.moduleName) { 452 | throw new Error('goog.module may only be called once per module.'); 453 | } 454 | 455 | // Store the module name for the loader. 456 | goog.moduleLoaderState_.moduleName = name; 457 | if (!COMPILED) { 458 | // Ensure that the same namespace isn't provided twice. 459 | // A goog.module/goog.provide maps a goog.require to a specific file 460 | if (goog.isProvided_(name)) { 461 | throw new Error('Namespace "' + name + '" already declared.'); 462 | } 463 | delete goog.implicitNamespaces_[name]; 464 | } 465 | }; 466 | 467 | 468 | /** 469 | * @param {string} name The module identifier. 470 | * @return {?} The module exports for an already loaded module or null. 471 | * 472 | * Note: This is not an alternative to goog.require, it does not 473 | * indicate a hard dependency, instead it is used to indicate 474 | * an optional dependency or to access the exports of a module 475 | * that has already been loaded. 476 | * @suppress {missingProvide} 477 | */ 478 | goog.module.get = function(name) { 479 | return goog.module.getInternal_(name); 480 | }; 481 | 482 | 483 | /** 484 | * @param {string} name The module identifier. 485 | * @return {?} The module exports for an already loaded module or null. 486 | * @private 487 | */ 488 | goog.module.getInternal_ = function(name) { 489 | if (!COMPILED) { 490 | if (name in goog.loadedModules_) { 491 | return goog.loadedModules_[name].exports; 492 | } else if (!goog.implicitNamespaces_[name]) { 493 | var ns = goog.getObjectByName(name); 494 | return ns != null ? ns : null; 495 | } 496 | } 497 | return null; 498 | }; 499 | 500 | 501 | /** 502 | * Types of modules the debug loader can load. 503 | * @enum {string} 504 | */ 505 | goog.ModuleType = { 506 | ES6: 'es6', 507 | GOOG: 'goog' 508 | }; 509 | 510 | 511 | /** 512 | * @private {?{ 513 | * moduleName: (string|undefined), 514 | * declareLegacyNamespace:boolean, 515 | * type: ?goog.ModuleType 516 | * }} 517 | */ 518 | goog.moduleLoaderState_ = null; 519 | 520 | 521 | /** 522 | * @private 523 | * @return {boolean} Whether a goog.module or an es6 module is currently being 524 | * initialized. 525 | */ 526 | goog.isInModuleLoader_ = function() { 527 | return goog.isInGoogModuleLoader_() || goog.isInEs6ModuleLoader_(); 528 | }; 529 | 530 | 531 | /** 532 | * @private 533 | * @return {boolean} Whether a goog.module is currently being initialized. 534 | */ 535 | goog.isInGoogModuleLoader_ = function() { 536 | return !!goog.moduleLoaderState_ && 537 | goog.moduleLoaderState_.type == goog.ModuleType.GOOG; 538 | }; 539 | 540 | 541 | /** 542 | * @private 543 | * @return {boolean} Whether an es6 module is currently being initialized. 544 | */ 545 | goog.isInEs6ModuleLoader_ = function() { 546 | var inLoader = !!goog.moduleLoaderState_ && 547 | goog.moduleLoaderState_.type == goog.ModuleType.ES6; 548 | 549 | if (inLoader) { 550 | return true; 551 | } 552 | 553 | var jscomp = goog.global['$jscomp']; 554 | 555 | if (jscomp) { 556 | // jscomp may not have getCurrentModulePath if this is a compiled bundle 557 | // that has some of the runtime, but not all of it. This can happen if 558 | // optimizations are turned on so the unused runtime is removed but renaming 559 | // and Closure pass are off (so $jscomp is still named $jscomp and the 560 | // goog.provide/require calls still exist). 561 | if (typeof jscomp.getCurrentModulePath != 'function') { 562 | return false; 563 | } 564 | 565 | // Bundled ES6 module. 566 | return !!jscomp.getCurrentModulePath(); 567 | } 568 | 569 | return false; 570 | }; 571 | 572 | 573 | /** 574 | * Provide the module's exports as a globally accessible object under the 575 | * module's declared name. This is intended to ease migration to goog.module 576 | * for files that have existing usages. 577 | * @suppress {missingProvide} 578 | */ 579 | goog.module.declareLegacyNamespace = function() { 580 | if (!COMPILED && !goog.isInGoogModuleLoader_()) { 581 | throw new Error( 582 | 'goog.module.declareLegacyNamespace must be called from ' + 583 | 'within a goog.module'); 584 | } 585 | if (!COMPILED && !goog.moduleLoaderState_.moduleName) { 586 | throw new Error( 587 | 'goog.module must be called prior to ' + 588 | 'goog.module.declareLegacyNamespace.'); 589 | } 590 | goog.moduleLoaderState_.declareLegacyNamespace = true; 591 | }; 592 | 593 | 594 | /** 595 | * Associates an ES6 module with a Closure module ID so that is available via 596 | * goog.require. The associated ID acts like a goog.module ID - it does not 597 | * create any global names, it is merely available via goog.require / 598 | * goog.module.get / goog.forwardDeclare / goog.requireType. goog.require and 599 | * goog.module.get will return the entire module as if it was import *'d. This 600 | * allows Closure files to reference ES6 modules for the sake of migration. 601 | * 602 | * @param {string} namespace 603 | * @suppress {missingProvide} 604 | */ 605 | goog.declareModuleId = function(namespace) { 606 | if (!COMPILED) { 607 | if (!goog.isInEs6ModuleLoader_()) { 608 | throw new Error( 609 | 'goog.declareModuleId may only be called from ' + 610 | 'within an ES6 module'); 611 | } 612 | if (goog.moduleLoaderState_ && goog.moduleLoaderState_.moduleName) { 613 | throw new Error( 614 | 'goog.declareModuleId may only be called once per module.'); 615 | } 616 | if (namespace in goog.loadedModules_) { 617 | throw new Error( 618 | 'Module with namespace "' + namespace + '" already exists.'); 619 | } 620 | } 621 | if (goog.moduleLoaderState_) { 622 | // Not bundled - debug loading. 623 | goog.moduleLoaderState_.moduleName = namespace; 624 | } else { 625 | // Bundled - not debug loading, no module loader state. 626 | var jscomp = goog.global['$jscomp']; 627 | if (!jscomp || typeof jscomp.getCurrentModulePath != 'function') { 628 | throw new Error( 629 | 'Module with namespace "' + namespace + 630 | '" has been loaded incorrectly.'); 631 | } 632 | var exports = jscomp.require(jscomp.getCurrentModulePath()); 633 | goog.loadedModules_[namespace] = { 634 | exports: exports, 635 | type: goog.ModuleType.ES6, 636 | moduleId: namespace 637 | }; 638 | } 639 | }; 640 | 641 | 642 | /** 643 | * Marks that the current file should only be used for testing, and never for 644 | * live code in production. 645 | * 646 | * In the case of unit tests, the message may optionally be an exact namespace 647 | * for the test (e.g. 'goog.stringTest'). The linter will then ignore the extra 648 | * provide (if not explicitly defined in the code). 649 | * 650 | * @param {string=} opt_message Optional message to add to the error that's 651 | * raised when used in production code. 652 | */ 653 | goog.setTestOnly = function(opt_message) { 654 | if (goog.DISALLOW_TEST_ONLY_CODE) { 655 | opt_message = opt_message || ''; 656 | throw new Error( 657 | 'Importing test-only code into non-debug environment' + 658 | (opt_message ? ': ' + opt_message : '.')); 659 | } 660 | }; 661 | 662 | 663 | /** 664 | * Forward declares a symbol. This is an indication to the compiler that the 665 | * symbol may be used in the source yet is not required and may not be provided 666 | * in compilation. 667 | * 668 | * The most common usage of forward declaration is code that takes a type as a 669 | * function parameter but does not need to require it. By forward declaring 670 | * instead of requiring, no hard dependency is made, and (if not required 671 | * elsewhere) the namespace may never be required and thus, not be pulled 672 | * into the JavaScript binary. If it is required elsewhere, it will be type 673 | * checked as normal. 674 | * 675 | * Before using goog.forwardDeclare, please read the documentation at 676 | * https://github.com/google/closure-compiler/wiki/Bad-Type-Annotation to 677 | * understand the options and tradeoffs when working with forward declarations. 678 | * 679 | * @param {string} name The namespace to forward declare in the form of 680 | * "goog.package.part". 681 | * @deprecated See go/noforwarddeclaration, Use `goog.requireType` instead. 682 | */ 683 | goog.forwardDeclare = function(name) {}; 684 | 685 | 686 | /** 687 | * Forward declare type information. Used to assign types to goog.global 688 | * referenced object that would otherwise result in unknown type references 689 | * and thus block property disambiguation. 690 | */ 691 | goog.forwardDeclare('Document'); 692 | goog.forwardDeclare('HTMLScriptElement'); 693 | goog.forwardDeclare('XMLHttpRequest'); 694 | 695 | 696 | if (!COMPILED) { 697 | /** 698 | * Check if the given name has been goog.provided. This will return false for 699 | * names that are available only as implicit namespaces. 700 | * @param {string} name name of the object to look for. 701 | * @return {boolean} Whether the name has been provided. 702 | * @private 703 | */ 704 | goog.isProvided_ = function(name) { 705 | return (name in goog.loadedModules_) || 706 | (!goog.implicitNamespaces_[name] && goog.getObjectByName(name) != null); 707 | }; 708 | 709 | /** 710 | * Namespaces implicitly defined by goog.provide. For example, 711 | * goog.provide('goog.events.Event') implicitly declares that 'goog' and 712 | * 'goog.events' must be namespaces. 713 | * 714 | * @type {!Object} 715 | * @private 716 | */ 717 | goog.implicitNamespaces_ = {'goog.module': true}; 718 | 719 | // NOTE: We add goog.module as an implicit namespace as goog.module is defined 720 | // here and because the existing module package has not been moved yet out of 721 | // the goog.module namespace. This satisifies both the debug loader and 722 | // ahead-of-time dependency management. 723 | } 724 | 725 | 726 | /** 727 | * Returns an object based on its fully qualified external name. The object 728 | * is not found if null or undefined. If you are using a compilation pass that 729 | * renames property names beware that using this function will not find renamed 730 | * properties. 731 | * 732 | * @param {string} name The fully qualified name. 733 | * @param {Object=} opt_obj The object within which to look; default is 734 | * |goog.global|. 735 | * @return {?} The value (object or primitive) or, if not found, null. 736 | */ 737 | goog.getObjectByName = function(name, opt_obj) { 738 | var parts = name.split('.'); 739 | var cur = opt_obj || goog.global; 740 | for (var i = 0; i < parts.length; i++) { 741 | cur = cur[parts[i]]; 742 | if (cur == null) { 743 | return null; 744 | } 745 | } 746 | return cur; 747 | }; 748 | 749 | 750 | /** 751 | * Adds a dependency from a file to the files it requires. 752 | * @param {string} relPath The path to the js file. 753 | * @param {!Array} provides An array of strings with 754 | * the names of the objects this file provides. 755 | * @param {!Array} requires An array of strings with 756 | * the names of the objects this file requires. 757 | * @param {boolean|!Object=} opt_loadFlags Parameters indicating 758 | * how the file must be loaded. The boolean 'true' is equivalent 759 | * to {'module': 'goog'} for backwards-compatibility. Valid properties 760 | * and values include {'module': 'goog'} and {'lang': 'es6'}. 761 | */ 762 | goog.addDependency = function(relPath, provides, requires, opt_loadFlags) { 763 | if (!COMPILED && goog.DEPENDENCIES_ENABLED) { 764 | goog.debugLoader_.addDependency(relPath, provides, requires, opt_loadFlags); 765 | } 766 | }; 767 | 768 | 769 | // NOTE(nnaze): The debug DOM loader was included in base.js as an original way 770 | // to do "debug-mode" development. The dependency system can sometimes be 771 | // confusing, as can the debug DOM loader's asynchronous nature. 772 | // 773 | // With the DOM loader, a call to goog.require() is not blocking -- the script 774 | // will not load until some point after the current script. If a namespace is 775 | // needed at runtime, it needs to be defined in a previous script, or loaded via 776 | // require() with its registered dependencies. 777 | // 778 | // User-defined namespaces may need their own deps file. For a reference on 779 | // creating a deps file, see: 780 | // Externally: https://developers.google.com/closure/library/docs/depswriter 781 | // 782 | // Because of legacy clients, the DOM loader can't be easily removed from 783 | // base.js. Work was done to make it disableable or replaceable for 784 | // different environments (DOM-less JavaScript interpreters like Rhino or V8, 785 | // for example). See bootstrap/ for more information. 786 | 787 | 788 | /** 789 | * @define {boolean} Whether to enable the debug loader. 790 | * 791 | * If enabled, a call to goog.require() will attempt to load the namespace by 792 | * appending a script tag to the DOM (if the namespace has been registered). 793 | * 794 | * If disabled, goog.require() will simply assert that the namespace has been 795 | * provided (and depend on the fact that some outside tool correctly ordered 796 | * the script). 797 | */ 798 | goog.ENABLE_DEBUG_LOADER = goog.define('goog.ENABLE_DEBUG_LOADER', true); 799 | 800 | 801 | /** 802 | * @param {string} msg 803 | * @private 804 | */ 805 | goog.logToConsole_ = function(msg) { 806 | if (goog.global.console) { 807 | goog.global.console['error'](msg); 808 | } 809 | }; 810 | 811 | 812 | /** 813 | * Implements a system for the dynamic resolution of dependencies that works in 814 | * parallel with the BUILD system. 815 | * 816 | * Note that all calls to goog.require will be stripped by the compiler. 817 | * 818 | * @see goog.provide 819 | * @param {string} namespace Namespace (as was given in goog.provide, 820 | * goog.module, or goog.declareModuleId) in the form 821 | * "goog.package.part". 822 | * @return {?} If called within a goog.module or ES6 module file, the associated 823 | * namespace or module otherwise null. 824 | */ 825 | goog.require = function(namespace) { 826 | if (!COMPILED) { 827 | // Might need to lazy load on old IE. 828 | if (goog.ENABLE_DEBUG_LOADER) { 829 | goog.debugLoader_.requested(namespace); 830 | } 831 | 832 | // If the object already exists we do not need to do anything. 833 | if (goog.isProvided_(namespace)) { 834 | if (goog.isInModuleLoader_()) { 835 | return goog.module.getInternal_(namespace); 836 | } 837 | } else if (goog.ENABLE_DEBUG_LOADER) { 838 | var moduleLoaderState = goog.moduleLoaderState_; 839 | goog.moduleLoaderState_ = null; 840 | try { 841 | goog.debugLoader_.load_(namespace); 842 | } finally { 843 | goog.moduleLoaderState_ = moduleLoaderState; 844 | } 845 | } 846 | 847 | return null; 848 | } 849 | }; 850 | 851 | 852 | /** 853 | * Requires a symbol for its type information. This is an indication to the 854 | * compiler that the symbol may appear in type annotations, yet it is not 855 | * referenced at runtime. 856 | * 857 | * When called within a goog.module or ES6 module file, the return value may be 858 | * assigned to or destructured into a variable, but it may not be otherwise used 859 | * in code outside of a type annotation. 860 | * 861 | * Note that all calls to goog.requireType will be stripped by the compiler. 862 | * 863 | * @param {string} namespace Namespace (as was given in goog.provide, 864 | * goog.module, or goog.declareModuleId) in the form 865 | * "goog.package.part". 866 | * @return {?} 867 | */ 868 | goog.requireType = function(namespace) { 869 | // Return an empty object so that single-level destructuring of the return 870 | // value doesn't crash at runtime when using the debug loader. Multi-level 871 | // destructuring isn't supported. 872 | return {}; 873 | }; 874 | 875 | 876 | /** 877 | * Path for included scripts. 878 | * @type {string} 879 | */ 880 | goog.basePath = ''; 881 | 882 | 883 | /** 884 | * A hook for overriding the base path. 885 | * @type {string|undefined} 886 | */ 887 | goog.global.CLOSURE_BASE_PATH; 888 | 889 | 890 | /** 891 | * Whether to attempt to load Closure's deps file. By default, when uncompiled, 892 | * deps files will attempt to be loaded. 893 | * @type {boolean|undefined} 894 | */ 895 | goog.global.CLOSURE_NO_DEPS; 896 | 897 | 898 | /** 899 | * A function to import a single script. This is meant to be overridden when 900 | * Closure is being run in non-HTML contexts, such as web workers. It's defined 901 | * in the global scope so that it can be set before base.js is loaded, which 902 | * allows deps.js to be imported properly. 903 | * 904 | * The first parameter the script source, which is a relative URI. The second, 905 | * optional parameter is the script contents, in the event the script needed 906 | * transformation. It should return true if the script was imported, false 907 | * otherwise. 908 | * @type {(function(string, string=): boolean)|undefined} 909 | */ 910 | goog.global.CLOSURE_IMPORT_SCRIPT; 911 | 912 | 913 | /** 914 | * Null function used for default values of callbacks, etc. 915 | * @return {void} Nothing. 916 | * @deprecated use '()=>{}' or 'function(){}' instead. 917 | */ 918 | goog.nullFunction = function() {}; 919 | 920 | 921 | /** 922 | * When defining a class Foo with an abstract method bar(), you can do: 923 | * Foo.prototype.bar = goog.abstractMethod 924 | * 925 | * Now if a subclass of Foo fails to override bar(), an error will be thrown 926 | * when bar() is invoked. 927 | * 928 | * @type {!Function} 929 | * @throws {Error} when invoked to indicate the method should be overridden. 930 | * @deprecated Use "@abstract" annotation instead of goog.abstractMethod in new 931 | * code. See 932 | * https://github.com/google/closure-compiler/wiki/@abstract-classes-and-methods 933 | */ 934 | goog.abstractMethod = function() { 935 | throw new Error('unimplemented abstract method'); 936 | }; 937 | 938 | 939 | /** 940 | * Adds a `getInstance` static method that always returns the same 941 | * instance object. 942 | * @param {!Function} ctor The constructor for the class to add the static 943 | * method to. 944 | * @suppress {missingProperties} 'instance_' isn't a property on 'Function' 945 | * but we don't have a better type to use here. 946 | */ 947 | goog.addSingletonGetter = function(ctor) { 948 | // instance_ is immediately set to prevent issues with sealed constructors 949 | // such as are encountered when a constructor is returned as the export object 950 | // of a goog.module in unoptimized code. 951 | // Delcare type to avoid conformance violations that ctor.instance_ is unknown 952 | /** @type {undefined|!Object} @suppress {underscore} */ 953 | ctor.instance_ = undefined; 954 | ctor.getInstance = function() { 955 | if (ctor.instance_) { 956 | return ctor.instance_; 957 | } 958 | if (goog.DEBUG) { 959 | // NOTE: JSCompiler can't optimize away Array#push. 960 | goog.instantiatedSingletons_[goog.instantiatedSingletons_.length] = ctor; 961 | } 962 | // Cast to avoid conformance violations that ctor.instance_ is unknown 963 | return /** @type {!Object|undefined} */ (ctor.instance_) = new ctor; 964 | }; 965 | }; 966 | 967 | 968 | /** 969 | * All singleton classes that have been instantiated, for testing. Don't read 970 | * it directly, use the `goog.testing.singleton` module. The compiler 971 | * removes this variable if unused. 972 | * @type {!Array} 973 | * @private 974 | */ 975 | goog.instantiatedSingletons_ = []; 976 | 977 | 978 | /** 979 | * @define {boolean} Whether to load goog.modules using `eval` when using 980 | * the debug loader. This provides a better debugging experience as the 981 | * source is unmodified and can be edited using Chrome Workspaces or similar. 982 | * However in some environments the use of `eval` is banned 983 | * so we provide an alternative. 984 | */ 985 | goog.LOAD_MODULE_USING_EVAL = goog.define('goog.LOAD_MODULE_USING_EVAL', true); 986 | 987 | 988 | /** 989 | * @define {boolean} Whether the exports of goog.modules should be sealed when 990 | * possible. 991 | */ 992 | goog.SEAL_MODULE_EXPORTS = goog.define('goog.SEAL_MODULE_EXPORTS', goog.DEBUG); 993 | 994 | 995 | /** 996 | * The registry of initialized modules: 997 | * The module identifier or path to module exports map. 998 | * @private @const {!Object} 999 | */ 1000 | goog.loadedModules_ = {}; 1001 | 1002 | 1003 | /** 1004 | * True if the debug loader enabled and used. 1005 | * @const {boolean} 1006 | */ 1007 | goog.DEPENDENCIES_ENABLED = !COMPILED && goog.ENABLE_DEBUG_LOADER; 1008 | 1009 | 1010 | /** 1011 | * @define {string} How to decide whether to transpile. Valid values 1012 | * are 'always', 'never', and 'detect'. The default ('detect') is to 1013 | * use feature detection to determine which language levels need 1014 | * transpilation. 1015 | */ 1016 | // NOTE(sdh): we could expand this to accept a language level to bypass 1017 | // detection: e.g. goog.TRANSPILE == 'es5' would transpile ES6 files but 1018 | // would leave ES3 and ES5 files alone. 1019 | goog.TRANSPILE = goog.define('goog.TRANSPILE', 'detect'); 1020 | 1021 | /** 1022 | * @define {boolean} If true assume that ES modules have already been 1023 | * transpiled by the jscompiler (in the same way that transpile.js would 1024 | * transpile them - to jscomp modules). Useful only for servers that wish to use 1025 | * the debug loader and transpile server side. Thus this is only respected if 1026 | * goog.TRANSPILE is "never". 1027 | */ 1028 | goog.ASSUME_ES_MODULES_TRANSPILED = 1029 | goog.define('goog.ASSUME_ES_MODULES_TRANSPILED', false); 1030 | 1031 | 1032 | /** 1033 | * @define {string} If a file needs to be transpiled what the output language 1034 | * should be. By default this is the highest language level this file detects 1035 | * the current environment supports. Generally this flag should not be set, but 1036 | * it could be useful to override. Example: If the current environment supports 1037 | * ES6 then by default ES7+ files will be transpiled to ES6, unless this is 1038 | * overridden. 1039 | * 1040 | * Valid values include: es3, es5, es6, es7, and es8. Anything not recognized 1041 | * is treated as es3. 1042 | * 1043 | * Note that setting this value does not force transpilation. Just if 1044 | * transpilation occurs this will be the output. So this is most useful when 1045 | * goog.TRANSPILE is set to 'always' and then forcing the language level to be 1046 | * something lower than what the environment detects. 1047 | */ 1048 | goog.TRANSPILE_TO_LANGUAGE = goog.define('goog.TRANSPILE_TO_LANGUAGE', ''); 1049 | 1050 | 1051 | /** 1052 | * @define {string} Path to the transpiler. Executing the script at this 1053 | * path (relative to base.js) should define a function $jscomp.transpile. 1054 | */ 1055 | goog.TRANSPILER = goog.define('goog.TRANSPILER', 'transpile.js'); 1056 | 1057 | 1058 | /** 1059 | * @define {string} Trusted Types policy name. If non-empty then Closure will 1060 | * use Trusted Types. 1061 | */ 1062 | goog.TRUSTED_TYPES_POLICY_NAME = 1063 | goog.define('goog.TRUSTED_TYPES_POLICY_NAME', 'goog'); 1064 | 1065 | 1066 | /** 1067 | * @package {?boolean} 1068 | * Visible for testing. 1069 | */ 1070 | goog.hasBadLetScoping = null; 1071 | 1072 | 1073 | /** 1074 | * @param {function(?):?|string} moduleDef The module definition. 1075 | */ 1076 | goog.loadModule = function(moduleDef) { 1077 | // NOTE: we allow function definitions to be either in the from 1078 | // of a string to eval (which keeps the original source intact) or 1079 | // in a eval forbidden environment (CSP) we allow a function definition 1080 | // which in its body must call `goog.module`, and return the exports 1081 | // of the module. 1082 | var previousState = goog.moduleLoaderState_; 1083 | try { 1084 | goog.moduleLoaderState_ = { 1085 | moduleName: '', 1086 | declareLegacyNamespace: false, 1087 | type: goog.ModuleType.GOOG 1088 | }; 1089 | var origExports = {}; 1090 | var exports = origExports; 1091 | if (typeof moduleDef === 'function') { 1092 | exports = moduleDef.call(undefined, exports); 1093 | } else if (typeof moduleDef === 'string') { 1094 | exports = goog.loadModuleFromSource_.call(undefined, exports, moduleDef); 1095 | } else { 1096 | throw new Error('Invalid module definition'); 1097 | } 1098 | 1099 | var moduleName = goog.moduleLoaderState_.moduleName; 1100 | if (typeof moduleName === 'string' && moduleName) { 1101 | // Don't seal legacy namespaces as they may be used as a parent of 1102 | // another namespace 1103 | if (goog.moduleLoaderState_.declareLegacyNamespace) { 1104 | // Whether exports was overwritten via default export assignment. 1105 | // This is important for legacy namespaces as it dictates whether 1106 | // previously a previously loaded implicit namespace should be clobbered 1107 | // or not. 1108 | var isDefaultExport = origExports !== exports; 1109 | goog.constructNamespace_(moduleName, exports, isDefaultExport); 1110 | } else if ( 1111 | goog.SEAL_MODULE_EXPORTS && Object.seal && 1112 | typeof exports == 'object' && exports != null) { 1113 | Object.seal(exports); 1114 | } 1115 | 1116 | var data = { 1117 | exports: exports, 1118 | type: goog.ModuleType.GOOG, 1119 | moduleId: goog.moduleLoaderState_.moduleName 1120 | }; 1121 | goog.loadedModules_[moduleName] = data; 1122 | } else { 1123 | throw new Error('Invalid module name \"' + moduleName + '\"'); 1124 | } 1125 | } finally { 1126 | goog.moduleLoaderState_ = previousState; 1127 | } 1128 | }; 1129 | 1130 | 1131 | /** 1132 | * @private @const 1133 | */ 1134 | goog.loadModuleFromSource_ = 1135 | /** @type {function(!Object, string):?} */ (function(exports) { 1136 | // NOTE: we avoid declaring parameters or local variables here to avoid 1137 | // masking globals or leaking values into the module definition. 1138 | 'use strict'; 1139 | eval(goog.CLOSURE_EVAL_PREFILTER_.createScript(arguments[1])); 1140 | return exports; 1141 | }); 1142 | 1143 | 1144 | /** 1145 | * Normalize a file path by removing redundant ".." and extraneous "." file 1146 | * path components. 1147 | * @param {string} path 1148 | * @return {string} 1149 | * @private 1150 | */ 1151 | goog.normalizePath_ = function(path) { 1152 | var components = path.split('/'); 1153 | var i = 0; 1154 | while (i < components.length) { 1155 | if (components[i] == '.') { 1156 | components.splice(i, 1); 1157 | } else if ( 1158 | i && components[i] == '..' && components[i - 1] && 1159 | components[i - 1] != '..') { 1160 | components.splice(--i, 2); 1161 | } else { 1162 | i++; 1163 | } 1164 | } 1165 | return components.join('/'); 1166 | }; 1167 | 1168 | 1169 | /** 1170 | * Provides a hook for loading a file when using Closure's goog.require() API 1171 | * with goog.modules. In particular this hook is provided to support Node.js. 1172 | * 1173 | * @type {(function(string):string)|undefined} 1174 | */ 1175 | goog.global.CLOSURE_LOAD_FILE_SYNC; 1176 | 1177 | 1178 | /** 1179 | * Loads file by synchronous XHR. Should not be used in production environments. 1180 | * @param {string} src Source URL. 1181 | * @return {?string} File contents, or null if load failed. 1182 | * @private 1183 | */ 1184 | goog.loadFileSync_ = function(src) { 1185 | if (goog.global.CLOSURE_LOAD_FILE_SYNC) { 1186 | return goog.global.CLOSURE_LOAD_FILE_SYNC(src); 1187 | } else { 1188 | try { 1189 | /** @type {XMLHttpRequest} */ 1190 | var xhr = new goog.global['XMLHttpRequest'](); 1191 | xhr.open('get', src, false); 1192 | xhr.send(); 1193 | // NOTE: Successful http: requests have a status of 200, but successful 1194 | // file: requests may have a status of zero. Any other status, or a 1195 | // thrown exception (particularly in case of file: requests) indicates 1196 | // some sort of error, which we treat as a missing or unavailable file. 1197 | return xhr.status == 0 || xhr.status == 200 ? xhr.responseText : null; 1198 | } catch (err) { 1199 | // No need to rethrow or log, since errors should show up on their own. 1200 | return null; 1201 | } 1202 | } 1203 | }; 1204 | 1205 | 1206 | /** 1207 | * Lazily retrieves the transpiler and applies it to the source. 1208 | * @param {string} code JS code. 1209 | * @param {string} path Path to the code. 1210 | * @param {string} target Language level output. 1211 | * @return {string} The transpiled code. 1212 | * @private 1213 | */ 1214 | goog.transpile_ = function(code, path, target) { 1215 | var jscomp = goog.global['$jscomp']; 1216 | if (!jscomp) { 1217 | goog.global['$jscomp'] = jscomp = {}; 1218 | } 1219 | var transpile = jscomp.transpile; 1220 | if (!transpile) { 1221 | var transpilerPath = goog.basePath + goog.TRANSPILER; 1222 | var transpilerCode = goog.loadFileSync_(transpilerPath); 1223 | if (transpilerCode) { 1224 | // This must be executed synchronously, since by the time we know we 1225 | // need it, we're about to load and write the ES6 code synchronously, 1226 | // so a normal script-tag load will be too slow. Wrapped in a function 1227 | // so that code is eval'd in the global scope. 1228 | (function() { 1229 | (0, eval)(transpilerCode + '\n//# sourceURL=' + transpilerPath); 1230 | }).call(goog.global); 1231 | // Even though the transpiler is optional, if $gwtExport is found, it's 1232 | // a sign the transpiler was loaded and the $jscomp.transpile *should* 1233 | // be there. 1234 | if (goog.global['$gwtExport'] && goog.global['$gwtExport']['$jscomp'] && 1235 | !goog.global['$gwtExport']['$jscomp']['transpile']) { 1236 | throw new Error( 1237 | 'The transpiler did not properly export the "transpile" ' + 1238 | 'method. $gwtExport: ' + JSON.stringify(goog.global['$gwtExport'])); 1239 | } 1240 | // transpile.js only exports a single $jscomp function, transpile. We 1241 | // grab just that and add it to the existing definition of $jscomp which 1242 | // contains the polyfills. 1243 | goog.global['$jscomp'].transpile = 1244 | goog.global['$gwtExport']['$jscomp']['transpile']; 1245 | jscomp = goog.global['$jscomp']; 1246 | transpile = jscomp.transpile; 1247 | } 1248 | } 1249 | if (!transpile) { 1250 | // The transpiler is an optional component. If it's not available then 1251 | // replace it with a pass-through function that simply logs. 1252 | var suffix = ' requires transpilation but no transpiler was found.'; 1253 | transpile = jscomp.transpile = function(code, path) { 1254 | // TODO(sdh): figure out some way to get this error to show up 1255 | // in test results, noting that the failure may occur in many 1256 | // different ways, including in loadModule() before the test 1257 | // runner even comes up. 1258 | goog.logToConsole_(path + suffix); 1259 | return code; 1260 | }; 1261 | } 1262 | // Note: any transpilation errors/warnings will be logged to the console. 1263 | return transpile(code, path, target); 1264 | }; 1265 | 1266 | //============================================================================== 1267 | // Language Enhancements 1268 | //============================================================================== 1269 | 1270 | 1271 | /** 1272 | * This is a "fixed" version of the typeof operator. It differs from the typeof 1273 | * operator in such a way that null returns 'null' and arrays return 'array'. 1274 | * @param {?} value The value to get the type of. 1275 | * @return {string} The name of the type. 1276 | */ 1277 | goog.typeOf = function(value) { 1278 | var s = typeof value; 1279 | 1280 | if (s != 'object') { 1281 | return s; 1282 | } 1283 | 1284 | if (!value) { 1285 | return 'null'; 1286 | } 1287 | 1288 | if (Array.isArray(value)) { 1289 | return 'array'; 1290 | } 1291 | return s; 1292 | }; 1293 | 1294 | 1295 | /** 1296 | * Returns true if the object looks like an array. To qualify as array like 1297 | * the value needs to be either a NodeList or an object with a Number length 1298 | * property. Note that for this function neither strings nor functions are 1299 | * considered "array-like". 1300 | * 1301 | * @param {?} val Variable to test. 1302 | * @return {boolean} Whether variable is an array. 1303 | */ 1304 | goog.isArrayLike = function(val) { 1305 | var type = goog.typeOf(val); 1306 | // We do not use goog.isObject here in order to exclude function values. 1307 | return type == 'array' || type == 'object' && typeof val.length == 'number'; 1308 | }; 1309 | 1310 | 1311 | /** 1312 | * Returns true if the object looks like a Date. To qualify as Date-like the 1313 | * value needs to be an object and have a getFullYear() function. 1314 | * @param {?} val Variable to test. 1315 | * @return {boolean} Whether variable is a like a Date. 1316 | */ 1317 | goog.isDateLike = function(val) { 1318 | return goog.isObject(val) && typeof val.getFullYear == 'function'; 1319 | }; 1320 | 1321 | 1322 | /** 1323 | * Returns true if the specified value is an object. This includes arrays and 1324 | * functions. 1325 | * @param {?} val Variable to test. 1326 | * @return {boolean} Whether variable is an object. 1327 | */ 1328 | goog.isObject = function(val) { 1329 | var type = typeof val; 1330 | return type == 'object' && val != null || type == 'function'; 1331 | // return Object(val) === val also works, but is slower, especially if val is 1332 | // not an object. 1333 | }; 1334 | 1335 | 1336 | /** 1337 | * Gets a unique ID for an object. This mutates the object so that further calls 1338 | * with the same object as a parameter returns the same value. The unique ID is 1339 | * guaranteed to be unique across the current session amongst objects that are 1340 | * passed into `getUid`. There is no guarantee that the ID is unique or 1341 | * consistent across sessions. It is unsafe to generate unique ID for function 1342 | * prototypes. 1343 | * 1344 | * @param {Object} obj The object to get the unique ID for. 1345 | * @return {number} The unique ID for the object. 1346 | */ 1347 | goog.getUid = function(obj) { 1348 | // TODO(arv): Make the type stricter, do not accept null. 1349 | return Object.prototype.hasOwnProperty.call(obj, goog.UID_PROPERTY_) && 1350 | obj[goog.UID_PROPERTY_] || 1351 | (obj[goog.UID_PROPERTY_] = ++goog.uidCounter_); 1352 | }; 1353 | 1354 | 1355 | /** 1356 | * Whether the given object is already assigned a unique ID. 1357 | * 1358 | * This does not modify the object. 1359 | * 1360 | * @param {!Object} obj The object to check. 1361 | * @return {boolean} Whether there is an assigned unique id for the object. 1362 | */ 1363 | goog.hasUid = function(obj) { 1364 | return !!obj[goog.UID_PROPERTY_]; 1365 | }; 1366 | 1367 | 1368 | /** 1369 | * Removes the unique ID from an object. This is useful if the object was 1370 | * previously mutated using `goog.getUid` in which case the mutation is 1371 | * undone. 1372 | * @param {Object} obj The object to remove the unique ID field from. 1373 | */ 1374 | goog.removeUid = function(obj) { 1375 | // TODO(arv): Make the type stricter, do not accept null. 1376 | 1377 | // In IE, DOM nodes are not instances of Object and throw an exception if we 1378 | // try to delete. Instead we try to use removeAttribute. 1379 | if (obj !== null && 'removeAttribute' in obj) { 1380 | obj.removeAttribute(goog.UID_PROPERTY_); 1381 | } 1382 | 1383 | try { 1384 | delete obj[goog.UID_PROPERTY_]; 1385 | } catch (ex) { 1386 | } 1387 | }; 1388 | 1389 | 1390 | /** 1391 | * Name for unique ID property. Initialized in a way to help avoid collisions 1392 | * with other closure JavaScript on the same page. 1393 | * @type {string} 1394 | * @private 1395 | */ 1396 | goog.UID_PROPERTY_ = 'closure_uid_' + ((Math.random() * 1e9) >>> 0); 1397 | 1398 | 1399 | /** 1400 | * Counter for UID. 1401 | * @type {number} 1402 | * @private 1403 | */ 1404 | goog.uidCounter_ = 0; 1405 | 1406 | 1407 | /** 1408 | * Clones a value. The input may be an Object, Array, or basic type. Objects and 1409 | * arrays will be cloned recursively. 1410 | * 1411 | * WARNINGS: 1412 | * goog.cloneObject does not detect reference loops. Objects that 1413 | * refer to themselves will cause infinite recursion. 1414 | * 1415 | * goog.cloneObject is unaware of unique identifiers, and copies 1416 | * UIDs created by getUid into cloned results. 1417 | * 1418 | * @param {*} obj The value to clone. 1419 | * @return {*} A clone of the input value. 1420 | * @deprecated goog.cloneObject is unsafe. Prefer the goog.object methods. 1421 | */ 1422 | goog.cloneObject = function(obj) { 1423 | var type = goog.typeOf(obj); 1424 | if (type == 'object' || type == 'array') { 1425 | if (typeof obj.clone === 'function') { 1426 | return obj.clone(); 1427 | } 1428 | if (typeof Map !== 'undefined' && obj instanceof Map) { 1429 | return new Map(obj); 1430 | } else if (typeof Set !== 'undefined' && obj instanceof Set) { 1431 | return new Set(obj); 1432 | } 1433 | var clone = type == 'array' ? [] : {}; 1434 | for (var key in obj) { 1435 | clone[key] = goog.cloneObject(obj[key]); 1436 | } 1437 | return clone; 1438 | } 1439 | 1440 | return obj; 1441 | }; 1442 | 1443 | 1444 | /** 1445 | * A native implementation of goog.bind. 1446 | * @param {?function(this:T, ...)} fn A function to partially apply. 1447 | * @param {T} selfObj Specifies the object which this should point to when the 1448 | * function is run. 1449 | * @param {...*} var_args Additional arguments that are partially applied to the 1450 | * function. 1451 | * @return {!Function} A partially-applied form of the function goog.bind() was 1452 | * invoked as a method of. 1453 | * @template T 1454 | * @private 1455 | */ 1456 | goog.bindNative_ = function(fn, selfObj, var_args) { 1457 | return /** @type {!Function} */ (fn.call.apply(fn.bind, arguments)); 1458 | }; 1459 | 1460 | 1461 | /** 1462 | * A pure-JS implementation of goog.bind. 1463 | * @param {?function(this:T, ...)} fn A function to partially apply. 1464 | * @param {T} selfObj Specifies the object which this should point to when the 1465 | * function is run. 1466 | * @param {...*} var_args Additional arguments that are partially applied to the 1467 | * function. 1468 | * @return {!Function} A partially-applied form of the function goog.bind() was 1469 | * invoked as a method of. 1470 | * @template T 1471 | * @private 1472 | */ 1473 | goog.bindJs_ = function(fn, selfObj, var_args) { 1474 | if (!fn) { 1475 | throw new Error(); 1476 | } 1477 | 1478 | if (arguments.length > 2) { 1479 | var boundArgs = Array.prototype.slice.call(arguments, 2); 1480 | return function() { 1481 | // Prepend the bound arguments to the current arguments. 1482 | var newArgs = Array.prototype.slice.call(arguments); 1483 | Array.prototype.unshift.apply(newArgs, boundArgs); 1484 | return fn.apply(selfObj, newArgs); 1485 | }; 1486 | 1487 | } else { 1488 | return function() { 1489 | return fn.apply(selfObj, arguments); 1490 | }; 1491 | } 1492 | }; 1493 | 1494 | 1495 | /** 1496 | * Partially applies this function to a particular 'this object' and zero or 1497 | * more arguments. The result is a new function with some arguments of the first 1498 | * function pre-filled and the value of this 'pre-specified'. 1499 | * 1500 | * Remaining arguments specified at call-time are appended to the pre-specified 1501 | * ones. 1502 | * 1503 | * Also see: {@link #partial}. 1504 | * 1505 | * Usage: 1506 | *
var barMethBound = goog.bind(myFunction, myObj, 'arg1', 'arg2');
1507 |  * barMethBound('arg3', 'arg4');
1508 | * 1509 | * @param {?function(this:T, ...)} fn A function to partially apply. 1510 | * @param {T} selfObj Specifies the object which this should point to when the 1511 | * function is run. 1512 | * @param {...*} var_args Additional arguments that are partially applied to the 1513 | * function. 1514 | * @return {!Function} A partially-applied form of the function goog.bind() was 1515 | * invoked as a method of. 1516 | * @template T 1517 | * @suppress {deprecated} See above. 1518 | * @deprecated use `=> {}` or Function.prototype.bind instead. 1519 | */ 1520 | goog.bind = function(fn, selfObj, var_args) { 1521 | // TODO(nicksantos): narrow the type signature. 1522 | if (Function.prototype.bind && 1523 | // NOTE(nicksantos): Somebody pulled base.js into the default Chrome 1524 | // extension environment. This means that for Chrome extensions, they get 1525 | // the implementation of Function.prototype.bind that calls goog.bind 1526 | // instead of the native one. Even worse, we don't want to introduce a 1527 | // circular dependency between goog.bind and Function.prototype.bind, so 1528 | // we have to hack this to make sure it works correctly. 1529 | Function.prototype.bind.toString().indexOf('native code') != -1) { 1530 | goog.bind = goog.bindNative_; 1531 | } else { 1532 | goog.bind = goog.bindJs_; 1533 | } 1534 | return goog.bind.apply(null, arguments); 1535 | }; 1536 | 1537 | 1538 | /** 1539 | * Like goog.bind(), except that a 'this object' is not required. Useful when 1540 | * the target function is already bound. 1541 | * 1542 | * Usage: 1543 | * var g = goog.partial(f, arg1, arg2); 1544 | * g(arg3, arg4); 1545 | * 1546 | * @param {Function} fn A function to partially apply. 1547 | * @param {...*} var_args Additional arguments that are partially applied to fn. 1548 | * @return {!Function} A partially-applied form of the function goog.partial() 1549 | * was invoked as a method of. 1550 | */ 1551 | goog.partial = function(fn, var_args) { 1552 | var args = Array.prototype.slice.call(arguments, 1); 1553 | return function() { 1554 | // Clone the array (with slice()) and append additional arguments 1555 | // to the existing arguments. 1556 | var newArgs = args.slice(); 1557 | newArgs.push.apply(newArgs, arguments); 1558 | return fn.apply(/** @type {?} */ (this), newArgs); 1559 | }; 1560 | }; 1561 | 1562 | 1563 | /** 1564 | * Copies all the members of a source object to a target object. This method 1565 | * does not work on all browsers for all objects that contain keys such as 1566 | * toString or hasOwnProperty. Use goog.object.extend for this purpose. 1567 | * 1568 | * NOTE: Some have advocated for the use of goog.mixin to setup classes 1569 | * with multiple inheritence (traits, mixins, etc). However, as it simply 1570 | * uses "for in", this is not compatible with ES6 classes whose methods are 1571 | * non-enumerable. Changing this, would break cases where non-enumerable 1572 | * properties are not expected. 1573 | * 1574 | * @param {Object} target Target. 1575 | * @param {Object} source Source. 1576 | * @deprecated Prefer Object.assign 1577 | */ 1578 | goog.mixin = function(target, source) { 1579 | for (var x in source) { 1580 | target[x] = source[x]; 1581 | } 1582 | 1583 | // For IE7 or lower, the for-in-loop does not contain any properties that are 1584 | // not enumerable on the prototype object (for example, isPrototypeOf from 1585 | // Object.prototype) but also it will not include 'replace' on objects that 1586 | // extend String and change 'replace' (not that it is common for anyone to 1587 | // extend anything except Object). 1588 | }; 1589 | 1590 | 1591 | /** 1592 | * @return {number} An integer value representing the number of milliseconds 1593 | * between midnight, January 1, 1970 and the current time. 1594 | * @deprecated Use Date.now 1595 | */ 1596 | goog.now = function() { 1597 | return Date.now(); 1598 | }; 1599 | 1600 | 1601 | /** 1602 | * Evals JavaScript in the global scope. 1603 | * 1604 | * Throws an exception if neither execScript or eval is defined. 1605 | * @param {string|!TrustedScript} script JavaScript string. 1606 | */ 1607 | goog.globalEval = function(script) { 1608 | (0, eval)(script); 1609 | }; 1610 | 1611 | 1612 | /** 1613 | * Optional map of CSS class names to obfuscated names used with 1614 | * goog.getCssName(). 1615 | * @private {!Object|undefined} 1616 | * @see goog.setCssNameMapping 1617 | */ 1618 | goog.cssNameMapping_; 1619 | 1620 | 1621 | /** 1622 | * Optional obfuscation style for CSS class names. Should be set to either 1623 | * 'BY_WHOLE' or 'BY_PART' if defined. 1624 | * @type {string|undefined} 1625 | * @private 1626 | * @see goog.setCssNameMapping 1627 | */ 1628 | goog.cssNameMappingStyle_; 1629 | 1630 | 1631 | 1632 | /** 1633 | * A hook for modifying the default behavior goog.getCssName. The function 1634 | * if present, will receive the standard output of the goog.getCssName as 1635 | * its input. 1636 | * 1637 | * @type {(function(string):string)|undefined} 1638 | */ 1639 | goog.global.CLOSURE_CSS_NAME_MAP_FN; 1640 | 1641 | 1642 | /** 1643 | * Handles strings that are intended to be used as CSS class names. 1644 | * 1645 | * This function works in tandem with @see goog.setCssNameMapping. 1646 | * 1647 | * Without any mapping set, the arguments are simple joined with a hyphen and 1648 | * passed through unaltered. 1649 | * 1650 | * When there is a mapping, there are two possible styles in which these 1651 | * mappings are used. In the BY_PART style, each part (i.e. in between hyphens) 1652 | * of the passed in css name is rewritten according to the map. In the BY_WHOLE 1653 | * style, the full css name is looked up in the map directly. If a rewrite is 1654 | * not specified by the map, the compiler will output a warning. 1655 | * 1656 | * When the mapping is passed to the compiler, it will replace calls to 1657 | * goog.getCssName with the strings from the mapping, e.g. 1658 | * var x = goog.getCssName('foo'); 1659 | * var y = goog.getCssName(this.baseClass, 'active'); 1660 | * becomes: 1661 | * var x = 'foo'; 1662 | * var y = this.baseClass + '-active'; 1663 | * 1664 | * If one argument is passed it will be processed, if two are passed only the 1665 | * modifier will be processed, as it is assumed the first argument was generated 1666 | * as a result of calling goog.getCssName. 1667 | * 1668 | * @param {string} className The class name. 1669 | * @param {string=} opt_modifier A modifier to be appended to the class name. 1670 | * @return {string} The class name or the concatenation of the class name and 1671 | * the modifier. 1672 | */ 1673 | goog.getCssName = function(className, opt_modifier) { 1674 | // String() is used for compatibility with compiled soy where the passed 1675 | // className can be non-string objects. 1676 | if (String(className).charAt(0) == '.') { 1677 | throw new Error( 1678 | 'className passed in goog.getCssName must not start with ".".' + 1679 | ' You passed: ' + className); 1680 | } 1681 | 1682 | var getMapping = function(cssName) { 1683 | return goog.cssNameMapping_[cssName] || cssName; 1684 | }; 1685 | 1686 | var renameByParts = function(cssName) { 1687 | // Remap all the parts individually. 1688 | var parts = cssName.split('-'); 1689 | var mapped = []; 1690 | for (var i = 0; i < parts.length; i++) { 1691 | mapped.push(getMapping(parts[i])); 1692 | } 1693 | return mapped.join('-'); 1694 | }; 1695 | 1696 | var rename; 1697 | if (goog.cssNameMapping_) { 1698 | rename = 1699 | goog.cssNameMappingStyle_ == 'BY_WHOLE' ? getMapping : renameByParts; 1700 | } else { 1701 | rename = function(a) { 1702 | return a; 1703 | }; 1704 | } 1705 | 1706 | var result = 1707 | opt_modifier ? className + '-' + rename(opt_modifier) : rename(className); 1708 | 1709 | // The special CLOSURE_CSS_NAME_MAP_FN allows users to specify further 1710 | // processing of the class name. 1711 | if (goog.global.CLOSURE_CSS_NAME_MAP_FN) { 1712 | return goog.global.CLOSURE_CSS_NAME_MAP_FN(result); 1713 | } 1714 | 1715 | return result; 1716 | }; 1717 | 1718 | 1719 | /** 1720 | * Sets the map to check when returning a value from goog.getCssName(). Example: 1721 | *
1722 |  * goog.setCssNameMapping({
1723 |  *   "goog": "a",
1724 |  *   "disabled": "b",
1725 |  * });
1726 |  *
1727 |  * var x = goog.getCssName('goog');
1728 |  * // The following evaluates to: "a a-b".
1729 |  * goog.getCssName('goog') + ' ' + goog.getCssName(x, 'disabled')
1730 |  * 
1731 | * When declared as a map of string literals to string literals, the JSCompiler 1732 | * will replace all calls to goog.getCssName() using the supplied map if the 1733 | * --process_closure_primitives flag is set. 1734 | * 1735 | * @param {!Object} mapping A map of strings to strings where keys are possible 1736 | * arguments to goog.getCssName() and values are the corresponding values 1737 | * that should be returned. 1738 | * @param {string=} opt_style The style of css name mapping. There are two valid 1739 | * options: 'BY_PART', and 'BY_WHOLE'. 1740 | * @see goog.getCssName for a description. 1741 | */ 1742 | goog.setCssNameMapping = function(mapping, opt_style) { 1743 | goog.cssNameMapping_ = mapping; 1744 | goog.cssNameMappingStyle_ = opt_style; 1745 | }; 1746 | 1747 | 1748 | /** 1749 | * To use CSS renaming in compiled mode, one of the input files should have a 1750 | * call to goog.setCssNameMapping() with an object literal that the JSCompiler 1751 | * can extract and use to replace all calls to goog.getCssName(). In uncompiled 1752 | * mode, JavaScript code should be loaded before this base.js file that declares 1753 | * a global variable, CLOSURE_CSS_NAME_MAPPING, which is used below. This is 1754 | * to ensure that the mapping is loaded before any calls to goog.getCssName() 1755 | * are made in uncompiled mode. 1756 | * 1757 | * A hook for overriding the CSS name mapping. 1758 | * @type {!Object|undefined} 1759 | */ 1760 | goog.global.CLOSURE_CSS_NAME_MAPPING; 1761 | 1762 | 1763 | if (!COMPILED && goog.global.CLOSURE_CSS_NAME_MAPPING) { 1764 | // This does not call goog.setCssNameMapping() because the JSCompiler 1765 | // requires that goog.setCssNameMapping() be called with an object literal. 1766 | goog.cssNameMapping_ = goog.global.CLOSURE_CSS_NAME_MAPPING; 1767 | } 1768 | 1769 | 1770 | /** 1771 | * Gets a localized message. 1772 | * 1773 | * This function is a compiler primitive. If you give the compiler a localized 1774 | * message bundle, it will replace the string at compile-time with a localized 1775 | * version, and expand goog.getMsg call to a concatenated string. 1776 | * 1777 | * Messages must be initialized in the form: 1778 | * 1779 | * var MSG_NAME = goog.getMsg('Hello {$placeholder}', {'placeholder': 'world'}); 1780 | * 1781 | * 1782 | * This function produces a string which should be treated as plain text. Use 1783 | * {@link goog.html.SafeHtmlFormatter} in conjunction with goog.getMsg to 1784 | * produce SafeHtml. 1785 | * 1786 | * @param {string} str Translatable string, places holders in the form {$foo}. 1787 | * @param {Object=} opt_values Maps place holder name to value. 1788 | * @param {{html: (boolean|undefined), 1789 | * unescapeHtmlEntities: (boolean|undefined)}=} opt_options Options: 1790 | * html: Escape '<' in str to '<'. Used by Closure Templates where the 1791 | * generated code size and performance is critical which is why {@link 1792 | * goog.html.SafeHtmlFormatter} is not used. The value must be literal true 1793 | * or false. 1794 | * unescapeHtmlEntities: Unescape common html entities: >, <, ', 1795 | * " and &. Used for messages not in HTML context, such as with 1796 | * `textContent` property. 1797 | * @return {string} message with placeholders filled. 1798 | */ 1799 | goog.getMsg = function(str, opt_values, opt_options) { 1800 | if (opt_options && opt_options.html) { 1801 | // Note that '&' is not replaced because the translation can contain HTML 1802 | // entities. 1803 | str = str.replace(/') 1809 | .replace(/'/g, '\'') 1810 | .replace(/"/g, '"') 1811 | .replace(/&/g, '&'); 1812 | } 1813 | if (opt_values) { 1814 | str = str.replace(/\{\$([^}]+)}/g, function(match, key) { 1815 | return (opt_values != null && key in opt_values) ? opt_values[key] : 1816 | match; 1817 | }); 1818 | } 1819 | return str; 1820 | }; 1821 | 1822 | 1823 | /** 1824 | * Gets a localized message. If the message does not have a translation, gives a 1825 | * fallback message. 1826 | * 1827 | * This is useful when introducing a new message that has not yet been 1828 | * translated into all languages. 1829 | * 1830 | * This function is a compiler primitive. Must be used in the form: 1831 | * var x = goog.getMsgWithFallback(MSG_A, MSG_B); 1832 | * where MSG_A and MSG_B were initialized with goog.getMsg. 1833 | * 1834 | * @param {string} a The preferred message. 1835 | * @param {string} b The fallback message. 1836 | * @return {string} The best translated message. 1837 | */ 1838 | goog.getMsgWithFallback = function(a, b) { 1839 | return a; 1840 | }; 1841 | 1842 | 1843 | /** 1844 | * Exposes an unobfuscated global namespace path for the given object. 1845 | * Note that fields of the exported object *will* be obfuscated, unless they are 1846 | * exported in turn via this function or goog.exportProperty. 1847 | * 1848 | * Also handy for making public items that are defined in anonymous closures. 1849 | * 1850 | * ex. goog.exportSymbol('public.path.Foo', Foo); 1851 | * 1852 | * ex. goog.exportSymbol('public.path.Foo.staticFunction', Foo.staticFunction); 1853 | * public.path.Foo.staticFunction(); 1854 | * 1855 | * ex. goog.exportSymbol('public.path.Foo.prototype.myMethod', 1856 | * Foo.prototype.myMethod); 1857 | * new public.path.Foo().myMethod(); 1858 | * 1859 | * @param {string} publicPath Unobfuscated name to export. 1860 | * @param {*} object Object the name should point to. 1861 | * @param {?Object=} objectToExportTo The object to add the path to; default 1862 | * is goog.global. 1863 | */ 1864 | goog.exportSymbol = function(publicPath, object, objectToExportTo) { 1865 | goog.exportPath_( 1866 | publicPath, object, /* overwriteImplicit= */ true, objectToExportTo); 1867 | }; 1868 | 1869 | 1870 | /** 1871 | * Exports a property unobfuscated into the object's namespace. 1872 | * ex. goog.exportProperty(Foo, 'staticFunction', Foo.staticFunction); 1873 | * ex. goog.exportProperty(Foo.prototype, 'myMethod', Foo.prototype.myMethod); 1874 | * @param {Object} object Object whose static property is being exported. 1875 | * @param {string} publicName Unobfuscated name to export. 1876 | * @param {*} symbol Object the name should point to. 1877 | */ 1878 | goog.exportProperty = function(object, publicName, symbol) { 1879 | object[publicName] = symbol; 1880 | }; 1881 | 1882 | 1883 | /** 1884 | * Inherit the prototype methods from one constructor into another. 1885 | * 1886 | * Usage: 1887 | *
1888 |  * function ParentClass(a, b) { }
1889 |  * ParentClass.prototype.foo = function(a) { };
1890 |  *
1891 |  * function ChildClass(a, b, c) {
1892 |  *   ChildClass.base(this, 'constructor', a, b);
1893 |  * }
1894 |  * goog.inherits(ChildClass, ParentClass);
1895 |  *
1896 |  * var child = new ChildClass('a', 'b', 'see');
1897 |  * child.foo(); // This works.
1898 |  * 
1899 | * 1900 | * @param {!Function} childCtor Child class. 1901 | * @param {!Function} parentCtor Parent class. 1902 | * @suppress {strictMissingProperties} superClass_ and base is not defined on 1903 | * Function. 1904 | * @deprecated Use ECMAScript class syntax instead. 1905 | */ 1906 | goog.inherits = function(childCtor, parentCtor) { 1907 | /** @constructor */ 1908 | function tempCtor() {} 1909 | tempCtor.prototype = parentCtor.prototype; 1910 | childCtor.superClass_ = parentCtor.prototype; 1911 | childCtor.prototype = new tempCtor(); 1912 | /** @override */ 1913 | childCtor.prototype.constructor = childCtor; 1914 | 1915 | /** 1916 | * Calls superclass constructor/method. 1917 | * 1918 | * This function is only available if you use goog.inherits to 1919 | * express inheritance relationships between classes. 1920 | * 1921 | * NOTE: This is a replacement for goog.base and for superClass_ 1922 | * property defined in childCtor. 1923 | * 1924 | * @param {!Object} me Should always be "this". 1925 | * @param {string} methodName The method name to call. Calling 1926 | * superclass constructor can be done with the special string 1927 | * 'constructor'. 1928 | * @param {...*} var_args The arguments to pass to superclass 1929 | * method/constructor. 1930 | * @return {*} The return value of the superclass method/constructor. 1931 | */ 1932 | childCtor.base = function(me, methodName, var_args) { 1933 | // Copying using loop to avoid deop due to passing arguments object to 1934 | // function. This is faster in many JS engines as of late 2014. 1935 | var args = new Array(arguments.length - 2); 1936 | for (var i = 2; i < arguments.length; i++) { 1937 | args[i - 2] = arguments[i]; 1938 | } 1939 | return parentCtor.prototype[methodName].apply(me, args); 1940 | }; 1941 | }; 1942 | 1943 | 1944 | /** 1945 | * Allow for aliasing within scope functions. This function exists for 1946 | * uncompiled code - in compiled code the calls will be inlined and the aliases 1947 | * applied. In uncompiled code the function is simply run since the aliases as 1948 | * written are valid JavaScript. 1949 | * 1950 | * 1951 | * @param {function()} fn Function to call. This function can contain aliases 1952 | * to namespaces (e.g. "var dom = goog.dom") or classes 1953 | * (e.g. "var Timer = goog.Timer"). 1954 | * @deprecated Use goog.module instead. 1955 | */ 1956 | goog.scope = function(fn) { 1957 | if (goog.isInModuleLoader_()) { 1958 | throw new Error('goog.scope is not supported within a module.'); 1959 | } 1960 | fn.call(goog.global); 1961 | }; 1962 | 1963 | 1964 | /* 1965 | * To support uncompiled, strict mode bundles that use eval to divide source 1966 | * like so: 1967 | * eval('someSource;//# sourceUrl sourcefile.js'); 1968 | * We need to export the globally defined symbols "goog" and "COMPILED". 1969 | * Exporting "goog" breaks the compiler optimizations, so we required that 1970 | * be defined externally. 1971 | * NOTE: We don't use goog.exportSymbol here because we don't want to trigger 1972 | * extern generation when that compiler option is enabled. 1973 | */ 1974 | if (!COMPILED) { 1975 | goog.global['COMPILED'] = COMPILED; 1976 | } 1977 | 1978 | 1979 | //============================================================================== 1980 | // goog.defineClass implementation 1981 | //============================================================================== 1982 | 1983 | 1984 | /** 1985 | * Creates a restricted form of a Closure "class": 1986 | * - from the compiler's perspective, the instance returned from the 1987 | * constructor is sealed (no new properties may be added). This enables 1988 | * better checks. 1989 | * - the compiler will rewrite this definition to a form that is optimal 1990 | * for type checking and optimization (initially this will be a more 1991 | * traditional form). 1992 | * 1993 | * @param {Function} superClass The superclass, Object or null. 1994 | * @param {goog.defineClass.ClassDescriptor} def 1995 | * An object literal describing 1996 | * the class. It may have the following properties: 1997 | * "constructor": the constructor function 1998 | * "statics": an object literal containing methods to add to the constructor 1999 | * as "static" methods or a function that will receive the constructor 2000 | * function as its only parameter to which static properties can 2001 | * be added. 2002 | * all other properties are added to the prototype. 2003 | * @return {!Function} The class constructor. 2004 | * @deprecated Use ECMAScript class syntax instead. 2005 | */ 2006 | goog.defineClass = function(superClass, def) { 2007 | // TODO(johnlenz): consider making the superClass an optional parameter. 2008 | var constructor = def.constructor; 2009 | var statics = def.statics; 2010 | // Wrap the constructor prior to setting up the prototype and static methods. 2011 | if (!constructor || constructor == Object.prototype.constructor) { 2012 | constructor = function() { 2013 | throw new Error( 2014 | 'cannot instantiate an interface (no constructor defined).'); 2015 | }; 2016 | } 2017 | 2018 | var cls = goog.defineClass.createSealingConstructor_(constructor, superClass); 2019 | if (superClass) { 2020 | goog.inherits(cls, superClass); 2021 | } 2022 | 2023 | // Remove all the properties that should not be copied to the prototype. 2024 | delete def.constructor; 2025 | delete def.statics; 2026 | 2027 | goog.defineClass.applyProperties_(cls.prototype, def); 2028 | if (statics != null) { 2029 | if (statics instanceof Function) { 2030 | statics(cls); 2031 | } else { 2032 | goog.defineClass.applyProperties_(cls, statics); 2033 | } 2034 | } 2035 | 2036 | return cls; 2037 | }; 2038 | 2039 | 2040 | /** 2041 | * @typedef {{ 2042 | * constructor: (!Function|undefined), 2043 | * statics: (Object|undefined|function(Function):void) 2044 | * }} 2045 | */ 2046 | goog.defineClass.ClassDescriptor; 2047 | 2048 | 2049 | /** 2050 | * @define {boolean} Whether the instances returned by goog.defineClass should 2051 | * be sealed when possible. 2052 | * 2053 | * When sealing is disabled the constructor function will not be wrapped by 2054 | * goog.defineClass, making it incompatible with ES6 class methods. 2055 | */ 2056 | goog.defineClass.SEAL_CLASS_INSTANCES = 2057 | goog.define('goog.defineClass.SEAL_CLASS_INSTANCES', goog.DEBUG); 2058 | 2059 | 2060 | /** 2061 | * If goog.defineClass.SEAL_CLASS_INSTANCES is enabled and Object.seal is 2062 | * defined, this function will wrap the constructor in a function that seals the 2063 | * results of the provided constructor function. 2064 | * 2065 | * @param {!Function} ctr The constructor whose results maybe be sealed. 2066 | * @param {Function} superClass The superclass constructor. 2067 | * @return {!Function} The replacement constructor. 2068 | * @private 2069 | */ 2070 | goog.defineClass.createSealingConstructor_ = function(ctr, superClass) { 2071 | if (!goog.defineClass.SEAL_CLASS_INSTANCES) { 2072 | // Do now wrap the constructor when sealing is disabled. Angular code 2073 | // depends on this for injection to work properly. 2074 | return ctr; 2075 | } 2076 | 2077 | // NOTE: The sealing behavior has been removed 2078 | 2079 | /** 2080 | * @this {Object} 2081 | * @return {?} 2082 | */ 2083 | var wrappedCtr = function() { 2084 | // Don't seal an instance of a subclass when it calls the constructor of 2085 | // its super class as there is most likely still setup to do. 2086 | var instance = ctr.apply(this, arguments) || this; 2087 | instance[goog.UID_PROPERTY_] = instance[goog.UID_PROPERTY_]; 2088 | 2089 | return instance; 2090 | }; 2091 | 2092 | return wrappedCtr; 2093 | }; 2094 | 2095 | 2096 | 2097 | // TODO(johnlenz): share these values with the goog.object 2098 | /** 2099 | * The names of the fields that are defined on Object.prototype. 2100 | * @type {!Array} 2101 | * @private 2102 | * @const 2103 | */ 2104 | goog.defineClass.OBJECT_PROTOTYPE_FIELDS_ = [ 2105 | 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 2106 | 'toLocaleString', 'toString', 'valueOf' 2107 | ]; 2108 | 2109 | 2110 | // TODO(johnlenz): share this function with the goog.object 2111 | /** 2112 | * @param {!Object} target The object to add properties to. 2113 | * @param {!Object} source The object to copy properties from. 2114 | * @private 2115 | */ 2116 | goog.defineClass.applyProperties_ = function(target, source) { 2117 | // TODO(johnlenz): update this to support ES5 getters/setters 2118 | 2119 | var key; 2120 | for (key in source) { 2121 | if (Object.prototype.hasOwnProperty.call(source, key)) { 2122 | target[key] = source[key]; 2123 | } 2124 | } 2125 | 2126 | // For IE the for-in-loop does not contain any properties that are not 2127 | // enumerable on the prototype object (for example isPrototypeOf from 2128 | // Object.prototype) and it will also not include 'replace' on objects that 2129 | // extend String and change 'replace' (not that it is common for anyone to 2130 | // extend anything except Object). 2131 | for (var i = 0; i < goog.defineClass.OBJECT_PROTOTYPE_FIELDS_.length; i++) { 2132 | key = goog.defineClass.OBJECT_PROTOTYPE_FIELDS_[i]; 2133 | if (Object.prototype.hasOwnProperty.call(source, key)) { 2134 | target[key] = source[key]; 2135 | } 2136 | } 2137 | }; 2138 | 2139 | /** 2140 | * Returns the parameter. 2141 | * @param {string} s 2142 | * @return {string} 2143 | * @private 2144 | */ 2145 | goog.identity_ = function(s) { 2146 | return s; 2147 | }; 2148 | 2149 | 2150 | /** 2151 | * Creates Trusted Types policy if Trusted Types are supported by the browser. 2152 | * The policy just blesses any string as a Trusted Type. It is not visibility 2153 | * restricted because anyone can also call trustedTypes.createPolicy directly. 2154 | * However, the allowed names should be restricted by a HTTP header and the 2155 | * reference to the created policy should be visibility restricted. 2156 | * @param {string} name 2157 | * @return {?TrustedTypePolicy} 2158 | */ 2159 | goog.createTrustedTypesPolicy = function(name) { 2160 | var policy = null; 2161 | var policyFactory = goog.global.trustedTypes; 2162 | if (!policyFactory || !policyFactory.createPolicy) { 2163 | return policy; 2164 | } 2165 | // trustedTypes.createPolicy throws if called with a name that is already 2166 | // registered, even in report-only mode. Until the API changes, catch the 2167 | // error not to break the applications functionally. In such case, the code 2168 | // will fall back to using regular Safe Types. 2169 | // TODO(koto): Remove catching once createPolicy API stops throwing. 2170 | try { 2171 | policy = policyFactory.createPolicy(name, { 2172 | createHTML: goog.identity_, 2173 | createScript: goog.identity_, 2174 | createScriptURL: goog.identity_ 2175 | }); 2176 | } catch (e) { 2177 | goog.logToConsole_(e.message); 2178 | } 2179 | return policy; 2180 | }; 2181 | 2182 | // There's a bug in the compiler where without collapse properties the 2183 | // Closure namespace defines do not guard code correctly. To help reduce code 2184 | // size also check for !COMPILED even though it redundant until this is fixed. 2185 | if (!COMPILED && goog.DEPENDENCIES_ENABLED) { 2186 | 2187 | 2188 | /** 2189 | * Tries to detect whether the current browser is Edge, based on the user 2190 | * agent. This matches only pre-Chromium Edge. 2191 | * @see https://docs.microsoft.com/en-us/microsoft-edge/web-platform/user-agent-string 2192 | * @return {boolean} True if the current browser is Edge. 2193 | * @private 2194 | */ 2195 | goog.isEdge_ = function() { 2196 | var userAgent = goog.global.navigator && goog.global.navigator.userAgent ? 2197 | goog.global.navigator.userAgent : 2198 | ''; 2199 | var edgeRe = /Edge\/(\d+)(\.\d)*/i; 2200 | return !!userAgent.match(edgeRe); 2201 | }; 2202 | 2203 | 2204 | /** 2205 | * Tries to detect whether is in the context of an HTML document. 2206 | * @return {boolean} True if it looks like HTML document. 2207 | * @private 2208 | */ 2209 | goog.inHtmlDocument_ = function() { 2210 | /** @type {!Document} */ 2211 | var doc = goog.global.document; 2212 | return doc != null && 'write' in doc; // XULDocument misses write. 2213 | }; 2214 | 2215 | 2216 | /** 2217 | * We'd like to check for if the document readyState is 'loading'; however 2218 | * there are bugs on IE 10 and below where the readyState being anything other 2219 | * than 'complete' is not reliable. 2220 | * @return {boolean} 2221 | * @private 2222 | */ 2223 | goog.isDocumentLoading_ = function() { 2224 | // attachEvent is available on IE 6 thru 10 only, and thus can be used to 2225 | // detect those browsers. 2226 | /** @type {!HTMLDocument} */ 2227 | var doc = goog.global.document; 2228 | return doc.attachEvent ? doc.readyState != 'complete' : 2229 | doc.readyState == 'loading'; 2230 | }; 2231 | 2232 | 2233 | /** 2234 | * Tries to detect the base path of base.js script that bootstraps Closure. 2235 | * @private 2236 | */ 2237 | goog.findBasePath_ = function() { 2238 | if (goog.global.CLOSURE_BASE_PATH != undefined && 2239 | // Anti DOM-clobbering runtime check (b/37736576). 2240 | typeof goog.global.CLOSURE_BASE_PATH === 'string') { 2241 | goog.basePath = goog.global.CLOSURE_BASE_PATH; 2242 | return; 2243 | } else if (!goog.inHtmlDocument_()) { 2244 | return; 2245 | } 2246 | /** @type {!Document} */ 2247 | var doc = goog.global.document; 2248 | // If we have a currentScript available, use it exclusively. 2249 | var currentScript = doc.currentScript; 2250 | if (currentScript) { 2251 | var scripts = [currentScript]; 2252 | } else { 2253 | var scripts = doc.getElementsByTagName('SCRIPT'); 2254 | } 2255 | // Search backwards since the current script is in almost all cases the one 2256 | // that has base.js. 2257 | for (var i = scripts.length - 1; i >= 0; --i) { 2258 | var script = /** @type {!HTMLScriptElement} */ (scripts[i]); 2259 | var src = script.src; 2260 | var qmark = src.lastIndexOf('?'); 2261 | var l = qmark == -1 ? src.length : qmark; 2262 | if (src.substr(l - 7, 7) == 'base.js') { 2263 | goog.basePath = src.substr(0, l - 7); 2264 | return; 2265 | } 2266 | } 2267 | }; 2268 | 2269 | goog.findBasePath_(); 2270 | 2271 | /** @struct @constructor @final */ 2272 | goog.Transpiler = function() { 2273 | /** @private {?Object} */ 2274 | this.requiresTranspilation_ = null; 2275 | /** @private {string} */ 2276 | this.transpilationTarget_ = goog.TRANSPILE_TO_LANGUAGE; 2277 | }; 2278 | /** 2279 | * Returns a newly created map from language mode string to a boolean 2280 | * indicating whether transpilation should be done for that mode as well as 2281 | * the highest level language that this environment supports. 2282 | * 2283 | * Guaranteed invariant: 2284 | * For any two modes, l1 and l2 where l2 is a newer mode than l1, 2285 | * `map[l1] == true` implies that `map[l2] == true`. 2286 | * 2287 | * Note this method is extracted and used elsewhere, so it cannot rely on 2288 | * anything external (it should easily be able to be transformed into a 2289 | * standalone, top level function). 2290 | * 2291 | * @private 2292 | * @return {{ 2293 | * target: string, 2294 | * map: !Object 2295 | * }} 2296 | */ 2297 | goog.Transpiler.prototype.createRequiresTranspilation_ = function() { 2298 | var transpilationTarget = 'es3'; 2299 | var /** !Object */ requiresTranspilation = {'es3': false}; 2300 | var transpilationRequiredForAllLaterModes = false; 2301 | 2302 | /** 2303 | * Adds an entry to requiresTranspliation for the given language mode. 2304 | * 2305 | * IMPORTANT: Calls must be made in order from oldest to newest language 2306 | * mode. 2307 | * @param {string} modeName 2308 | * @param {function(): boolean} isSupported Returns true if the JS engine 2309 | * supports the given mode. 2310 | */ 2311 | function addNewerLanguageTranspilationCheck(modeName, isSupported) { 2312 | if (transpilationRequiredForAllLaterModes) { 2313 | requiresTranspilation[modeName] = true; 2314 | } else if (isSupported()) { 2315 | transpilationTarget = modeName; 2316 | requiresTranspilation[modeName] = false; 2317 | } else { 2318 | requiresTranspilation[modeName] = true; 2319 | transpilationRequiredForAllLaterModes = true; 2320 | } 2321 | } 2322 | 2323 | /** 2324 | * Does the given code evaluate without syntax errors and return a truthy 2325 | * result? 2326 | */ 2327 | function /** boolean */ evalCheck(/** string */ code) { 2328 | try { 2329 | return !!eval(goog.CLOSURE_EVAL_PREFILTER_.createScript(code)); 2330 | } catch (ignored) { 2331 | return false; 2332 | } 2333 | } 2334 | 2335 | // Identify ES3-only browsers by their incorrect treatment of commas. 2336 | addNewerLanguageTranspilationCheck('es5', function() { 2337 | return evalCheck('[1,].length==1'); 2338 | }); 2339 | addNewerLanguageTranspilationCheck('es6', function() { 2340 | // Edge has a non-deterministic (i.e., not reproducible) bug with ES6: 2341 | // https://github.com/Microsoft/ChakraCore/issues/1496. 2342 | if (goog.isEdge_()) { 2343 | // The Reflect.construct test below is flaky on Edge. It can sometimes 2344 | // pass or fail on 40 15.15063, so just exit early for Edge and treat 2345 | // it as ES5. Until we're on a more up to date version just always use 2346 | // ES5. See https://github.com/Microsoft/ChakraCore/issues/3217. 2347 | return false; 2348 | } 2349 | // Test es6: [FF50 (?), Edge 14 (?), Chrome 50] 2350 | // (a) default params (specifically shadowing locals), 2351 | // (b) destructuring, (c) block-scoped functions, 2352 | // (d) for-of (const), (e) new.target/Reflect.construct 2353 | var es6fullTest = 2354 | 'class X{constructor(){if(new.target!=String)throw 1;this.x=42}}' + 2355 | 'let q=Reflect.construct(X,[],String);if(q.x!=42||!(q instanceof ' + 2356 | 'String))throw 1;for(const a of[2,3]){if(a==2)continue;function ' + 2357 | 'f(z={a}){let a=0;return z.a}{function f(){return 0;}}return f()' + 2358 | '==3}'; 2359 | 2360 | return evalCheck('(()=>{"use strict";' + es6fullTest + '})()'); 2361 | }); 2362 | // ** and **= are the only new features in 'es7' 2363 | addNewerLanguageTranspilationCheck('es7', function() { 2364 | return evalCheck('2**3==8'); 2365 | }); 2366 | // async functions are the only new features in 'es8' 2367 | addNewerLanguageTranspilationCheck('es8', function() { 2368 | return evalCheck('async()=>1,1'); 2369 | }); 2370 | addNewerLanguageTranspilationCheck('es9', function() { 2371 | return evalCheck('({...rest}={}),1'); 2372 | }); 2373 | // optional catch binding, unescaped unicode paragraph separator in strings 2374 | addNewerLanguageTranspilationCheck('es_2019', function() { 2375 | return evalCheck('let r;try{r="\u2029"}catch{};r'); 2376 | }); 2377 | // optional chaining, nullish coalescing 2378 | // untested/unsupported: bigint, import meta 2379 | addNewerLanguageTranspilationCheck('es_2020', function() { 2380 | return evalCheck('null?.x??1'); 2381 | }); 2382 | addNewerLanguageTranspilationCheck('es_next', function() { 2383 | return false; // assume it always need to transpile 2384 | }); 2385 | return {target: transpilationTarget, map: requiresTranspilation}; 2386 | }; 2387 | 2388 | 2389 | /** 2390 | * Determines whether the given language needs to be transpiled. 2391 | * @param {string} lang 2392 | * @param {string|undefined} module 2393 | * @return {boolean} 2394 | */ 2395 | goog.Transpiler.prototype.needsTranspile = function(lang, module) { 2396 | if (goog.TRANSPILE == 'always') { 2397 | return true; 2398 | } else if (goog.TRANSPILE == 'never') { 2399 | return false; 2400 | } else if (!this.requiresTranspilation_) { 2401 | var obj = this.createRequiresTranspilation_(); 2402 | this.requiresTranspilation_ = obj.map; 2403 | this.transpilationTarget_ = this.transpilationTarget_ || obj.target; 2404 | } 2405 | if (lang in this.requiresTranspilation_) { 2406 | if (this.requiresTranspilation_[lang]) { 2407 | return true; 2408 | } else if ( 2409 | goog.inHtmlDocument_() && module == 'es6' && 2410 | !('noModule' in goog.global.document.createElement('script'))) { 2411 | return true; 2412 | } else { 2413 | return false; 2414 | } 2415 | } else { 2416 | throw new Error('Unknown language mode: ' + lang); 2417 | } 2418 | }; 2419 | 2420 | 2421 | /** 2422 | * Lazily retrieves the transpiler and applies it to the source. 2423 | * @param {string} code JS code. 2424 | * @param {string} path Path to the code. 2425 | * @return {string} The transpiled code. 2426 | */ 2427 | goog.Transpiler.prototype.transpile = function(code, path) { 2428 | // TODO(johnplaisted): We should delete goog.transpile_ and just have this 2429 | // function. But there's some compile error atm where goog.global is being 2430 | // stripped incorrectly without this. 2431 | return goog.transpile_(code, path, this.transpilationTarget_); 2432 | }; 2433 | 2434 | 2435 | /** @private @final {!goog.Transpiler} */ 2436 | goog.transpiler_ = new goog.Transpiler(); 2437 | 2438 | /** 2439 | * Rewrites closing script tags in input to avoid ending an enclosing script 2440 | * tag. 2441 | * 2442 | * @param {string} str 2443 | * @return {string} 2444 | * @private 2445 | */ 2446 | goog.protectScriptTag_ = function(str) { 2447 | return str.replace(/<\/(SCRIPT)/ig, '\\x3c/$1'); 2448 | }; 2449 | 2450 | 2451 | /** 2452 | * A debug loader is responsible for downloading and executing javascript 2453 | * files in an unbundled, uncompiled environment. 2454 | * 2455 | * This can be custimized via the setDependencyFactory method, or by 2456 | * CLOSURE_IMPORT_SCRIPT/CLOSURE_LOAD_FILE_SYNC. 2457 | * 2458 | * @struct @constructor @final @private 2459 | */ 2460 | goog.DebugLoader_ = function() { 2461 | /** @private @const {!Object} */ 2462 | this.dependencies_ = {}; 2463 | /** @private @const {!Object} */ 2464 | this.idToPath_ = {}; 2465 | /** @private @const {!Object} */ 2466 | this.written_ = {}; 2467 | /** @private @const {!Array} */ 2468 | this.loadingDeps_ = []; 2469 | /** @private {!Array} */ 2470 | this.depsToLoad_ = []; 2471 | /** @private {boolean} */ 2472 | this.paused_ = false; 2473 | /** @private {!goog.DependencyFactory} */ 2474 | this.factory_ = new goog.DependencyFactory(goog.transpiler_); 2475 | /** @private @const {!Object} */ 2476 | this.deferredCallbacks_ = {}; 2477 | /** @private @const {!Array} */ 2478 | this.deferredQueue_ = []; 2479 | }; 2480 | 2481 | /** 2482 | * @param {!Array} namespaces 2483 | * @param {function(): undefined} callback Function to call once all the 2484 | * namespaces have loaded. 2485 | */ 2486 | goog.DebugLoader_.prototype.bootstrap = function(namespaces, callback) { 2487 | var cb = callback; 2488 | function resolve() { 2489 | if (cb) { 2490 | goog.global.setTimeout(cb, 0); 2491 | cb = null; 2492 | } 2493 | } 2494 | 2495 | if (!namespaces.length) { 2496 | resolve(); 2497 | return; 2498 | } 2499 | 2500 | var deps = []; 2501 | for (var i = 0; i < namespaces.length; i++) { 2502 | var path = this.getPathFromDeps_(namespaces[i]); 2503 | if (!path) { 2504 | throw new Error('Unregonized namespace: ' + namespaces[i]); 2505 | } 2506 | deps.push(this.dependencies_[path]); 2507 | } 2508 | 2509 | var require = goog.require; 2510 | var loaded = 0; 2511 | for (var i = 0; i < namespaces.length; i++) { 2512 | require(namespaces[i]); 2513 | deps[i].onLoad(function() { 2514 | if (++loaded == namespaces.length) { 2515 | resolve(); 2516 | } 2517 | }); 2518 | } 2519 | }; 2520 | 2521 | 2522 | /** 2523 | * Loads the Closure Dependency file. 2524 | * 2525 | * Exposed a public function so CLOSURE_NO_DEPS can be set to false, base 2526 | * loaded, setDependencyFactory called, and then this called. i.e. allows 2527 | * custom loading of the deps file. 2528 | */ 2529 | goog.DebugLoader_.prototype.loadClosureDeps = function() { 2530 | // Circumvent addDependency, which would try to transpile deps.js if 2531 | // transpile is set to always. 2532 | var relPath = 'deps.js'; 2533 | this.depsToLoad_.push(this.factory_.createDependency( 2534 | goog.normalizePath_(goog.basePath + relPath), relPath, [], [], {}, 2535 | false)); 2536 | this.loadDeps_(); 2537 | }; 2538 | 2539 | 2540 | /** 2541 | * Notifies the debug loader when a dependency has been requested. 2542 | * 2543 | * @param {string} absPathOrId Path of the dependency or goog id. 2544 | * @param {boolean=} opt_force 2545 | */ 2546 | goog.DebugLoader_.prototype.requested = function(absPathOrId, opt_force) { 2547 | var path = this.getPathFromDeps_(absPathOrId); 2548 | if (path && 2549 | (opt_force || this.areDepsLoaded_(this.dependencies_[path].requires))) { 2550 | var callback = this.deferredCallbacks_[path]; 2551 | if (callback) { 2552 | delete this.deferredCallbacks_[path]; 2553 | callback(); 2554 | } 2555 | } 2556 | }; 2557 | 2558 | 2559 | /** 2560 | * Sets the dependency factory, which can be used to create custom 2561 | * goog.Dependency implementations to control how dependencies are loaded. 2562 | * 2563 | * @param {!goog.DependencyFactory} factory 2564 | */ 2565 | goog.DebugLoader_.prototype.setDependencyFactory = function(factory) { 2566 | this.factory_ = factory; 2567 | }; 2568 | 2569 | 2570 | /** 2571 | * Travserses the dependency graph and queues the given dependency, and all of 2572 | * its transitive dependencies, for loading and then starts loading if not 2573 | * paused. 2574 | * 2575 | * @param {string} namespace 2576 | * @private 2577 | */ 2578 | goog.DebugLoader_.prototype.load_ = function(namespace) { 2579 | if (!this.getPathFromDeps_(namespace)) { 2580 | var errorMessage = 'goog.require could not find: ' + namespace; 2581 | goog.logToConsole_(errorMessage); 2582 | } else { 2583 | var loader = this; 2584 | 2585 | var deps = []; 2586 | 2587 | /** @param {string} namespace */ 2588 | var visit = function(namespace) { 2589 | var path = loader.getPathFromDeps_(namespace); 2590 | 2591 | if (!path) { 2592 | throw new Error('Bad dependency path or symbol: ' + namespace); 2593 | } 2594 | 2595 | if (loader.written_[path]) { 2596 | return; 2597 | } 2598 | 2599 | loader.written_[path] = true; 2600 | 2601 | var dep = loader.dependencies_[path]; 2602 | for (var i = 0; i < dep.requires.length; i++) { 2603 | if (!goog.isProvided_(dep.requires[i])) { 2604 | visit(dep.requires[i]); 2605 | } 2606 | } 2607 | 2608 | deps.push(dep); 2609 | }; 2610 | 2611 | visit(namespace); 2612 | 2613 | var wasLoading = !!this.depsToLoad_.length; 2614 | this.depsToLoad_ = this.depsToLoad_.concat(deps); 2615 | 2616 | if (!this.paused_ && !wasLoading) { 2617 | this.loadDeps_(); 2618 | } 2619 | } 2620 | }; 2621 | 2622 | 2623 | /** 2624 | * Loads any queued dependencies until they are all loaded or paused. 2625 | * 2626 | * @private 2627 | */ 2628 | goog.DebugLoader_.prototype.loadDeps_ = function() { 2629 | var loader = this; 2630 | var paused = this.paused_; 2631 | 2632 | while (this.depsToLoad_.length && !paused) { 2633 | (function() { 2634 | var loadCallDone = false; 2635 | var dep = loader.depsToLoad_.shift(); 2636 | 2637 | var loaded = false; 2638 | loader.loading_(dep); 2639 | 2640 | var controller = { 2641 | pause: function() { 2642 | if (loadCallDone) { 2643 | throw new Error('Cannot call pause after the call to load.'); 2644 | } else { 2645 | paused = true; 2646 | } 2647 | }, 2648 | resume: function() { 2649 | if (loadCallDone) { 2650 | loader.resume_(); 2651 | } else { 2652 | // Some dep called pause and then resume in the same load call. 2653 | // Just keep running this same loop. 2654 | paused = false; 2655 | } 2656 | }, 2657 | loaded: function() { 2658 | if (loaded) { 2659 | throw new Error('Double call to loaded.'); 2660 | } 2661 | 2662 | loaded = true; 2663 | loader.loaded_(dep); 2664 | }, 2665 | pending: function() { 2666 | // Defensive copy. 2667 | var pending = []; 2668 | for (var i = 0; i < loader.loadingDeps_.length; i++) { 2669 | pending.push(loader.loadingDeps_[i]); 2670 | } 2671 | return pending; 2672 | }, 2673 | /** 2674 | * @param {goog.ModuleType} type 2675 | */ 2676 | setModuleState: function(type) { 2677 | goog.moduleLoaderState_ = { 2678 | type: type, 2679 | moduleName: '', 2680 | declareLegacyNamespace: false 2681 | }; 2682 | }, 2683 | /** @type {function(string, string, string=)} */ 2684 | registerEs6ModuleExports: function( 2685 | path, exports, opt_closureNamespace) { 2686 | if (opt_closureNamespace) { 2687 | goog.loadedModules_[opt_closureNamespace] = { 2688 | exports: exports, 2689 | type: goog.ModuleType.ES6, 2690 | moduleId: opt_closureNamespace || '' 2691 | }; 2692 | } 2693 | }, 2694 | /** @type {function(string, ?)} */ 2695 | registerGoogModuleExports: function(moduleId, exports) { 2696 | goog.loadedModules_[moduleId] = { 2697 | exports: exports, 2698 | type: goog.ModuleType.GOOG, 2699 | moduleId: moduleId 2700 | }; 2701 | }, 2702 | clearModuleState: function() { 2703 | goog.moduleLoaderState_ = null; 2704 | }, 2705 | defer: function(callback) { 2706 | if (loadCallDone) { 2707 | throw new Error( 2708 | 'Cannot register with defer after the call to load.'); 2709 | } 2710 | loader.defer_(dep, callback); 2711 | }, 2712 | areDepsLoaded: function() { 2713 | return loader.areDepsLoaded_(dep.requires); 2714 | } 2715 | }; 2716 | 2717 | try { 2718 | dep.load(controller); 2719 | } finally { 2720 | loadCallDone = true; 2721 | } 2722 | })(); 2723 | } 2724 | 2725 | if (paused) { 2726 | this.pause_(); 2727 | } 2728 | }; 2729 | 2730 | 2731 | /** @private */ 2732 | goog.DebugLoader_.prototype.pause_ = function() { 2733 | this.paused_ = true; 2734 | }; 2735 | 2736 | 2737 | /** @private */ 2738 | goog.DebugLoader_.prototype.resume_ = function() { 2739 | if (this.paused_) { 2740 | this.paused_ = false; 2741 | this.loadDeps_(); 2742 | } 2743 | }; 2744 | 2745 | 2746 | /** 2747 | * Marks the given dependency as loading (load has been called but it has not 2748 | * yet marked itself as finished). Useful for dependencies that want to know 2749 | * what else is loading. Example: goog.modules cannot eval if there are 2750 | * loading dependencies. 2751 | * 2752 | * @param {!goog.Dependency} dep 2753 | * @private 2754 | */ 2755 | goog.DebugLoader_.prototype.loading_ = function(dep) { 2756 | this.loadingDeps_.push(dep); 2757 | }; 2758 | 2759 | 2760 | /** 2761 | * Marks the given dependency as having finished loading and being available 2762 | * for require. 2763 | * 2764 | * @param {!goog.Dependency} dep 2765 | * @private 2766 | */ 2767 | goog.DebugLoader_.prototype.loaded_ = function(dep) { 2768 | for (var i = 0; i < this.loadingDeps_.length; i++) { 2769 | if (this.loadingDeps_[i] == dep) { 2770 | this.loadingDeps_.splice(i, 1); 2771 | break; 2772 | } 2773 | } 2774 | 2775 | for (var i = 0; i < this.deferredQueue_.length; i++) { 2776 | if (this.deferredQueue_[i] == dep.path) { 2777 | this.deferredQueue_.splice(i, 1); 2778 | break; 2779 | } 2780 | } 2781 | 2782 | if (this.loadingDeps_.length == this.deferredQueue_.length && 2783 | !this.depsToLoad_.length) { 2784 | // Something has asked to load these, but they may not be directly 2785 | // required again later, so load them now that we know we're done loading 2786 | // everything else. e.g. a goog module entry point. 2787 | while (this.deferredQueue_.length) { 2788 | this.requested(this.deferredQueue_.shift(), true); 2789 | } 2790 | } 2791 | 2792 | dep.loaded(); 2793 | }; 2794 | 2795 | 2796 | /** 2797 | * @param {!Array} pathsOrIds 2798 | * @return {boolean} 2799 | * @private 2800 | */ 2801 | goog.DebugLoader_.prototype.areDepsLoaded_ = function(pathsOrIds) { 2802 | for (var i = 0; i < pathsOrIds.length; i++) { 2803 | var path = this.getPathFromDeps_(pathsOrIds[i]); 2804 | if (!path || 2805 | (!(path in this.deferredCallbacks_) && 2806 | !goog.isProvided_(pathsOrIds[i]))) { 2807 | return false; 2808 | } 2809 | } 2810 | 2811 | return true; 2812 | }; 2813 | 2814 | 2815 | /** 2816 | * @param {string} absPathOrId 2817 | * @return {?string} 2818 | * @private 2819 | */ 2820 | goog.DebugLoader_.prototype.getPathFromDeps_ = function(absPathOrId) { 2821 | if (absPathOrId in this.idToPath_) { 2822 | return this.idToPath_[absPathOrId]; 2823 | } else if (absPathOrId in this.dependencies_) { 2824 | return absPathOrId; 2825 | } else { 2826 | return null; 2827 | } 2828 | }; 2829 | 2830 | 2831 | /** 2832 | * @param {!goog.Dependency} dependency 2833 | * @param {!Function} callback 2834 | * @private 2835 | */ 2836 | goog.DebugLoader_.prototype.defer_ = function(dependency, callback) { 2837 | this.deferredCallbacks_[dependency.path] = callback; 2838 | this.deferredQueue_.push(dependency.path); 2839 | }; 2840 | 2841 | 2842 | /** 2843 | * Interface for goog.Dependency implementations to have some control over 2844 | * loading of dependencies. 2845 | * 2846 | * @record 2847 | */ 2848 | goog.LoadController = function() {}; 2849 | 2850 | 2851 | /** 2852 | * Tells the controller to halt loading of more dependencies. 2853 | */ 2854 | goog.LoadController.prototype.pause = function() {}; 2855 | 2856 | 2857 | /** 2858 | * Tells the controller to resume loading of more dependencies if paused. 2859 | */ 2860 | goog.LoadController.prototype.resume = function() {}; 2861 | 2862 | 2863 | /** 2864 | * Tells the controller that this dependency has finished loading. 2865 | * 2866 | * This causes this to be removed from pending() and any load callbacks to 2867 | * fire. 2868 | */ 2869 | goog.LoadController.prototype.loaded = function() {}; 2870 | 2871 | 2872 | /** 2873 | * List of dependencies on which load has been called but which have not 2874 | * called loaded on their controller. This includes the current dependency. 2875 | * 2876 | * @return {!Array} 2877 | */ 2878 | goog.LoadController.prototype.pending = function() {}; 2879 | 2880 | 2881 | /** 2882 | * Registers an object as an ES6 module's exports so that goog.modules may 2883 | * require it by path. 2884 | * 2885 | * @param {string} path Full path of the module. 2886 | * @param {?} exports 2887 | * @param {string=} opt_closureNamespace Closure namespace to associate with 2888 | * this module. 2889 | */ 2890 | goog.LoadController.prototype.registerEs6ModuleExports = function( 2891 | path, exports, opt_closureNamespace) {}; 2892 | 2893 | 2894 | /** 2895 | * Sets the current module state. 2896 | * 2897 | * @param {goog.ModuleType} type Type of module. 2898 | */ 2899 | goog.LoadController.prototype.setModuleState = function(type) {}; 2900 | 2901 | 2902 | /** 2903 | * Clears the current module state. 2904 | */ 2905 | goog.LoadController.prototype.clearModuleState = function() {}; 2906 | 2907 | 2908 | /** 2909 | * Registers a callback to call once the dependency is actually requested 2910 | * via goog.require + all of the immediate dependencies have been loaded or 2911 | * all other files have been loaded. Allows for lazy loading until 2912 | * require'd without pausing dependency loading, which is needed on old IE. 2913 | * 2914 | * @param {!Function} callback 2915 | */ 2916 | goog.LoadController.prototype.defer = function(callback) {}; 2917 | 2918 | 2919 | /** 2920 | * @return {boolean} 2921 | */ 2922 | goog.LoadController.prototype.areDepsLoaded = function() {}; 2923 | 2924 | 2925 | /** 2926 | * Basic super class for all dependencies Closure Library can load. 2927 | * 2928 | * This default implementation is designed to load untranspiled, non-module 2929 | * scripts in a web broswer. 2930 | * 2931 | * For transpiled non-goog.module files {@see goog.TranspiledDependency}. 2932 | * For goog.modules see {@see goog.GoogModuleDependency}. 2933 | * For untranspiled ES6 modules {@see goog.Es6ModuleDependency}. 2934 | * 2935 | * @param {string} path Absolute path of this script. 2936 | * @param {string} relativePath Path of this script relative to goog.basePath. 2937 | * @param {!Array} provides goog.provided or goog.module symbols 2938 | * in this file. 2939 | * @param {!Array} requires goog symbols or relative paths to Closure 2940 | * this depends on. 2941 | * @param {!Object} loadFlags 2942 | * @struct @constructor 2943 | */ 2944 | goog.Dependency = function( 2945 | path, relativePath, provides, requires, loadFlags) { 2946 | /** @const */ 2947 | this.path = path; 2948 | /** @const */ 2949 | this.relativePath = relativePath; 2950 | /** @const */ 2951 | this.provides = provides; 2952 | /** @const */ 2953 | this.requires = requires; 2954 | /** @const */ 2955 | this.loadFlags = loadFlags; 2956 | /** @private {boolean} */ 2957 | this.loaded_ = false; 2958 | /** @private {!Array} */ 2959 | this.loadCallbacks_ = []; 2960 | }; 2961 | 2962 | 2963 | /** 2964 | * @return {string} The pathname part of this dependency's path if it is a 2965 | * URI. 2966 | */ 2967 | goog.Dependency.prototype.getPathName = function() { 2968 | var pathName = this.path; 2969 | var protocolIndex = pathName.indexOf('://'); 2970 | if (protocolIndex >= 0) { 2971 | pathName = pathName.substring(protocolIndex + 3); 2972 | var slashIndex = pathName.indexOf('/'); 2973 | if (slashIndex >= 0) { 2974 | pathName = pathName.substring(slashIndex + 1); 2975 | } 2976 | } 2977 | return pathName; 2978 | }; 2979 | 2980 | 2981 | /** 2982 | * @param {function()} callback Callback to fire as soon as this has loaded. 2983 | * @final 2984 | */ 2985 | goog.Dependency.prototype.onLoad = function(callback) { 2986 | if (this.loaded_) { 2987 | callback(); 2988 | } else { 2989 | this.loadCallbacks_.push(callback); 2990 | } 2991 | }; 2992 | 2993 | 2994 | /** 2995 | * Marks this dependency as loaded and fires any callbacks registered with 2996 | * onLoad. 2997 | * @final 2998 | */ 2999 | goog.Dependency.prototype.loaded = function() { 3000 | this.loaded_ = true; 3001 | var callbacks = this.loadCallbacks_; 3002 | this.loadCallbacks_ = []; 3003 | for (var i = 0; i < callbacks.length; i++) { 3004 | callbacks[i](); 3005 | } 3006 | }; 3007 | 3008 | 3009 | /** 3010 | * Whether or not document.written / appended script tags should be deferred. 3011 | * 3012 | * @private {boolean} 3013 | */ 3014 | goog.Dependency.defer_ = false; 3015 | 3016 | 3017 | /** 3018 | * Map of script ready / state change callbacks. Old IE cannot handle putting 3019 | * these properties on goog.global. 3020 | * 3021 | * @private @const {!Object} 3022 | */ 3023 | goog.Dependency.callbackMap_ = {}; 3024 | 3025 | 3026 | /** 3027 | * @param {function(...?):?} callback 3028 | * @return {string} 3029 | * @private 3030 | */ 3031 | goog.Dependency.registerCallback_ = function(callback) { 3032 | var key = Math.random().toString(32); 3033 | goog.Dependency.callbackMap_[key] = callback; 3034 | return key; 3035 | }; 3036 | 3037 | 3038 | /** 3039 | * @param {string} key 3040 | * @private 3041 | */ 3042 | goog.Dependency.unregisterCallback_ = function(key) { 3043 | delete goog.Dependency.callbackMap_[key]; 3044 | }; 3045 | 3046 | 3047 | /** 3048 | * @param {string} key 3049 | * @param {...?} var_args 3050 | * @private 3051 | * @suppress {unusedPrivateMembers} 3052 | */ 3053 | goog.Dependency.callback_ = function(key, var_args) { 3054 | if (key in goog.Dependency.callbackMap_) { 3055 | var callback = goog.Dependency.callbackMap_[key]; 3056 | var args = []; 3057 | for (var i = 1; i < arguments.length; i++) { 3058 | args.push(arguments[i]); 3059 | } 3060 | callback.apply(undefined, args); 3061 | } else { 3062 | var errorMessage = 'Callback key ' + key + 3063 | ' does not exist (was base.js loaded more than once?).'; 3064 | throw Error(errorMessage); 3065 | } 3066 | }; 3067 | 3068 | 3069 | /** 3070 | * Starts loading this dependency. This dependency can pause loading if it 3071 | * needs to and resume it later via the controller interface. 3072 | * 3073 | * When this is loaded it should call controller.loaded(). Note that this will 3074 | * end up calling the loaded method of this dependency; there is no need to 3075 | * call it explicitly. 3076 | * 3077 | * @param {!goog.LoadController} controller 3078 | */ 3079 | goog.Dependency.prototype.load = function(controller) { 3080 | if (goog.global.CLOSURE_IMPORT_SCRIPT) { 3081 | if (goog.global.CLOSURE_IMPORT_SCRIPT(this.path)) { 3082 | controller.loaded(); 3083 | } else { 3084 | controller.pause(); 3085 | } 3086 | return; 3087 | } 3088 | 3089 | if (!goog.inHtmlDocument_()) { 3090 | goog.logToConsole_( 3091 | 'Cannot use default debug loader outside of HTML documents.'); 3092 | if (this.relativePath == 'deps.js') { 3093 | // Some old code is relying on base.js auto loading deps.js failing with 3094 | // no error before later setting CLOSURE_IMPORT_SCRIPT. 3095 | // CLOSURE_IMPORT_SCRIPT should be set *before* base.js is loaded, or 3096 | // CLOSURE_NO_DEPS set to true. 3097 | goog.logToConsole_( 3098 | 'Consider setting CLOSURE_IMPORT_SCRIPT before loading base.js, ' + 3099 | 'or setting CLOSURE_NO_DEPS to true.'); 3100 | controller.loaded(); 3101 | } else { 3102 | controller.pause(); 3103 | } 3104 | return; 3105 | } 3106 | 3107 | /** @type {!HTMLDocument} */ 3108 | var doc = goog.global.document; 3109 | 3110 | // If the user tries to require a new symbol after document load, 3111 | // something has gone terribly wrong. Doing a document.write would 3112 | // wipe out the page. This does not apply to the CSP-compliant method 3113 | // of writing script tags. 3114 | if (doc.readyState == 'complete' && 3115 | !goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING) { 3116 | // Certain test frameworks load base.js multiple times, which tries 3117 | // to write deps.js each time. If that happens, just fail silently. 3118 | // These frameworks wipe the page between each load of base.js, so this 3119 | // is OK. 3120 | var isDeps = /\bdeps.js$/.test(this.path); 3121 | if (isDeps) { 3122 | controller.loaded(); 3123 | return; 3124 | } else { 3125 | throw Error('Cannot write "' + this.path + '" after document load'); 3126 | } 3127 | } 3128 | 3129 | var nonce = goog.getScriptNonce_(); 3130 | if (!goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING && 3131 | goog.isDocumentLoading_()) { 3132 | var key; 3133 | var callback = function(script) { 3134 | if (script.readyState && script.readyState != 'complete') { 3135 | script.onload = callback; 3136 | return; 3137 | } 3138 | goog.Dependency.unregisterCallback_(key); 3139 | controller.loaded(); 3140 | }; 3141 | key = goog.Dependency.registerCallback_(callback); 3142 | 3143 | var defer = goog.Dependency.defer_ ? ' defer' : ''; 3144 | var nonceAttr = nonce ? ' nonce="' + nonce + '"' : ''; 3145 | var script = ' 6 | 7 | 11 | -------------------------------------------------------------------------------- /testfiles/protopollution_test.html: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | -------------------------------------------------------------------------------- /testfiles/testfile: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /url.txt: -------------------------------------------------------------------------------- 1 | example.com --------------------------------------------------------------------------------