diff options
author | Florian Dold <florian.dold@gmail.com> | 2016-09-26 18:00:21 +0200 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2016-09-26 18:00:26 +0200 |
commit | 211e8c25d52644552cb37531cdb637f4f12c8782 (patch) | |
tree | 1ba56cb19a88b5dc9cbc4950b4814d84128ab3db | |
parent | c89c90b7fa69b030c82f8cc73a29f89987016250 (diff) |
fix bug in retrying logic for reserve status
-rw-r--r-- | lib/vendor/system-csp-production.src.js | 1621 | ||||
-rw-r--r-- | lib/wallet/chromeBadge.ts | 5 | ||||
-rw-r--r-- | lib/wallet/wallet.ts | 12 |
3 files changed, 1010 insertions, 628 deletions
diff --git a/lib/vendor/system-csp-production.src.js b/lib/vendor/system-csp-production.src.js index 0887780ca..9c5e56532 100644 --- a/lib/vendor/system-csp-production.src.js +++ b/lib/vendor/system-csp-production.src.js @@ -1,8 +1,71 @@ /* - * SystemJS v0.19.17 + * SystemJS v0.19.39 */ (function() { -function bootstrap() {(function(__global) { +function bootstrap() {// from https://gist.github.com/Yaffle/1088850 +(function(global) { +function URLPolyfill(url, baseURL) { + if (typeof url != 'string') + throw new TypeError('URL must be a string'); + var m = String(url).replace(/^\s+|\s+$/g, "").match(/^([^:\/?#]+:)?(?:\/\/(?:([^:@\/?#]*)(?::([^:@\/?#]*))?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/); + if (!m) + throw new RangeError('Invalid URL format'); + var protocol = m[1] || ""; + var username = m[2] || ""; + var password = m[3] || ""; + var host = m[4] || ""; + var hostname = m[5] || ""; + var port = m[6] || ""; + var pathname = m[7] || ""; + var search = m[8] || ""; + var hash = m[9] || ""; + if (baseURL !== undefined) { + var base = baseURL instanceof URLPolyfill ? baseURL : new URLPolyfill(baseURL); + var flag = !protocol && !host && !username; + if (flag && !pathname && !search) + search = base.search; + if (flag && pathname[0] !== "/") + pathname = (pathname ? (((base.host || base.username) && !base.pathname ? "/" : "") + base.pathname.slice(0, base.pathname.lastIndexOf("/") + 1) + pathname) : base.pathname); + // dot segments removal + var output = []; + pathname.replace(/^(\.\.?(\/|$))+/, "") + .replace(/\/(\.(\/|$))+/g, "/") + .replace(/\/\.\.$/, "/../") + .replace(/\/?[^\/]*/g, function (p) { + if (p === "/..") + output.pop(); + else + output.push(p); + }); + pathname = output.join("").replace(/^\//, pathname[0] === "/" ? "/" : ""); + if (flag) { + port = base.port; + hostname = base.hostname; + host = base.host; + password = base.password; + username = base.username; + } + if (!protocol) + protocol = base.protocol; + } + + // convert URLs to use / always + pathname = pathname.replace(/\\/g, '/'); + + this.origin = host ? protocol + (protocol !== "" || host !== "" ? "//" : "") + host : ""; + this.href = protocol + (protocol && host || protocol == "file:" ? "//" : "") + (username !== "" ? username + (password !== "" ? ":" + password : "") + "@" : "") + host + pathname + search + hash; + this.protocol = protocol; + this.username = username; + this.password = password; + this.host = host; + this.hostname = hostname; + this.port = port; + this.pathname = pathname; + this.search = search; + this.hash = hash; +} +global.URLPolyfill = URLPolyfill; +})(typeof self != 'undefined' ? self : global);(function(__global) { var isWorker = typeof window == 'undefined' && typeof self != 'undefined' && typeof importScripts != 'undefined'; var isBrowser = typeof window != 'undefined' && typeof document != 'undefined'; @@ -37,24 +100,32 @@ function bootstrap() {(function(__global) { } })(); + var errArgs = new Error(0, '_').fileName == '_'; + function addToError(err, msg) { - var newErr; - if (err instanceof Error) { - newErr = new Error(err.message, err.fileName, err.lineNumber); - if (isBrowser) { - newErr.message = err.message + '\n\t' + msg; - newErr.stack = err.stack; + // parse the stack removing loader code lines for simplification + if (!err.originalErr) { + var stack = ((err.message || err) + (err.stack ? '\n' + err.stack : '')).toString().split('\n'); + var newStack = []; + for (var i = 0; i < stack.length; i++) { + if (typeof $__curScript == 'undefined' || stack[i].indexOf($__curScript.src) == -1) + newStack.push(stack[i]); } - else { - // node errors only look correct with the stack modified - newErr.message = err.message; - newErr.stack = err.stack + '\n\t' + msg; - } - } - else { - newErr = err + '\n\t' + msg; } - + + var newMsg = '(SystemJS) ' + (newStack ? newStack.join('\n\t') : err.message.substr(11)) + '\n\t' + msg; + + // Convert file:/// URLs to paths in Node + if (!isBrowser) + newMsg = newMsg.replace(isWindows ? /file:\/\/\//g : /file:\/\//g, ''); + + var newErr = errArgs ? new Error(newMsg, err.fileName, err.lineNumber) : new Error(newMsg); + + newErr.stack = newMsg; + + // track the original error + newErr.originalErr = err.originalErr || err; + return newErr; } @@ -68,6 +139,7 @@ function bootstrap() {(function(__global) { } var baseURI; + // environent baseURI detection if (typeof document != 'undefined' && document.getElementsByTagName) { baseURI = document.baseURI; @@ -76,8 +148,13 @@ function bootstrap() {(function(__global) { var bases = document.getElementsByTagName('base'); baseURI = bases[0] && bases[0].href || window.location.href; } + } + else if (typeof location != 'undefined') { + baseURI = __global.location.href; + } - // sanitize out the hash and querystring + // sanitize out the hash and querystring + if (baseURI) { baseURI = baseURI.split('#')[0].split('?')[0]; baseURI = baseURI.substr(0, baseURI.lastIndexOf('/') + 1); } @@ -86,14 +163,17 @@ function bootstrap() {(function(__global) { if (isWindows) baseURI = baseURI.replace(/\\/g, '/'); } - else if (typeof location != 'undefined') { - baseURI = __global.location.href; - } else { throw new TypeError('No environment baseURI'); } - var URL = __global.URLPolyfill || __global.URL; + try { + var nativeURL = new __global.URL('test:///').protocol == 'test:'; + } + catch(e) {} + + var URL = nativeURL ? __global.URL : __global.URLPolyfill; + /* ********************************************************************************************* @@ -239,11 +319,13 @@ function logloads(loads) { // 15.2.3.2 Load Records and LoadRequest Objects + var anonCnt = 0; + // 15.2.3.2.1 function createLoad(name) { return { status: 'loading', - name: name, + name: name || '<Anonymous' + ++anonCnt + '>', linkSets: [], dependencies: [], metadata: {} @@ -288,7 +370,6 @@ function logloads(loads) { load = loader.loads[i]; if (load.name != name) continue; - console.assert(load.status == 'loading' || load.status == 'loaded', 'loading or loaded'); return load; } @@ -328,8 +409,6 @@ function logloads(loads) { ); } - var anonCnt = 0; - // 15.2.4.5 function proceedToTranslate(loader, load, p) { p @@ -338,6 +417,8 @@ function logloads(loads) { if (load.status != 'loading') return; + load.address = load.address || load.name; + return Promise.resolve(loader.loaderObj.translate({ name: load.name, metadata: load.metadata, address: load.address, source: source })) // 15.2.4.5.2 CallInstantiate @@ -348,38 +429,14 @@ function logloads(loads) { // 15.2.4.5.3 InstantiateSucceeded .then(function(instantiateResult) { - if (instantiateResult === undefined) { - load.address = load.address || '<Anonymous Module ' + ++anonCnt + '>'; - - // instead of load.kind, use load.isDeclarative - load.isDeclarative = true; - return transpile.call(loader.loaderObj, load) - .then(function(transpiled) { - // Hijack System.register to set declare function - var curSystem = __global.System; - var curRegister = curSystem.register; - curSystem.register = function(name, deps, declare) { - if (typeof name != 'string') { - declare = deps; - deps = name; - } - // store the registered declaration as load.declare - // store the deps as load.deps - load.declare = declare; - load.depsList = deps; - } - // empty {} context is closest to undefined 'this' we can get - __eval(transpiled, load.address, {}); - curSystem.register = curRegister; - }); - } - else if (typeof instantiateResult == 'object') { - load.depsList = instantiateResult.deps || []; - load.execute = instantiateResult.execute; - load.isDeclarative = false; - } - else - throw TypeError('Invalid instantiate return value'); + if (instantiateResult === undefined) + throw new TypeError('Declarative modules unsupported in the polyfill.'); + + if (typeof instantiateResult != 'object') + throw new TypeError('Invalid instantiate return value'); + + load.depsList = instantiateResult.deps || []; + load.execute = instantiateResult.execute; }) // 15.2.4.6 ProcessLoadDependencies .then(function() { @@ -421,8 +478,6 @@ function logloads(loads) { // console.log('LoadSucceeded ' + load.name); // snapshot(loader); - console.assert(load.status == 'loading', 'is loading'); - load.status = 'loaded'; var linkSets = load.linkSets.concat([]); @@ -525,8 +580,6 @@ function logloads(loads) { if (load.status == 'failed') return; - console.assert(load.status == 'loading' || load.status == 'loaded', 'loading or loaded on link set'); - for (var i = 0, l = linkSet.loads.length; i < l; i++) if (linkSet.loads[i] == load) return; @@ -601,9 +654,7 @@ function logloads(loads) { var loads = [].concat(linkSet.loads); for (var i = 0, l = loads.length; i < l; i++) { var load = loads[i]; - load.module = !load.isDeclarative ? { - module: _newModule({}) - } : { + load.module = { name: load.name, module: _newModule({}), evaluated: true @@ -691,13 +742,12 @@ function logloads(loads) { depMap: depMap, address: load.address, metadata: load.metadata, - source: load.source, - kind: load.isDeclarative ? 'declarative' : 'dynamic' + source: load.source }; } // if not anonymous, add to the module table if (load.name) { - console.assert(!loader.modules[load.name], 'load not in module table'); + console.assert(!loader.modules[load.name] || loader.modules[load.name].module === load.module.module, 'load not in module table'); loader.modules[load.name] = load.module; } var loadIndex = indexOf.call(loader.loads, load); @@ -771,7 +821,6 @@ function logloads(loads) { get: function(key) { if (!this._loader.modules[key]) return; - doEnsureEvaluated(this._loader.modules[key], [], this); return this._loader.modules[key].module; }, // 26.3.3.7 @@ -791,16 +840,14 @@ function logloads(loads) { .then(function(name) { var loader = loaderObj._loader; - if (loader.modules[name]) { - doEnsureEvaluated(loader.modules[name], [], loader._loader); + if (loader.modules[name]) return loader.modules[name].module; - } return loader.importPromises[name] || createImportPromise(loaderObj, name, loadModule(loader, name, {}) .then(function(load) { delete loader.importPromises[name]; - return evaluateLoadedModule(loader, load); + return load.module.module; })); }); }, @@ -830,7 +877,7 @@ function logloads(loads) { var sourcePromise = Promise.resolve(source); var loader = this._loader; var p = linkSet.done.then(function() { - return evaluateLoadedModule(loader, load); + return load.module.module; }); proceedToTranslate(loader, load, sourcePromise); return p; @@ -855,10 +902,16 @@ function logloads(loads) { enumerable: true, get: function () { return obj[key]; + }, + set: function() { + throw new Error('Module exports cannot be changed externally.'); } }); })(pNames[i]); + if (Object.freeze) + Object.freeze(m); + return m; }, // 26.3.3.14 @@ -874,9 +927,7 @@ function logloads(loads) { // 26.3.3.17 @@toStringTag not implemented // 26.3.3.18.1 - normalize: function(name, referrerName, referrerAddress) { - return name; - }, + normalize: function(name, referrerName, referrerAddress) {}, // 26.3.3.18.2 locate: function(load) { return load.name; @@ -894,8 +945,9 @@ function logloads(loads) { }; var _newModule = Loader.prototype.newModule; + /* - * ES6 Module Declarative Linking Code - Dev Build Only + * ES6 Module Declarative Linking Code */ function link(linkSet, linkError) { @@ -922,57 +974,98 @@ function logloads(loads) { } } - function evaluateLoadedModule(loader, load) { - console.assert(load.status == 'linked', 'is linked ' + load.name); - return load.module.module; - } +})(); - function doEnsureEvaluated() {} +var System; - function transpile() { - throw new TypeError('ES6 transpilation is only provided in the dev module loader build.'); - } -})();/* -********************************************************************************************* +// SystemJS Loader Class and Extension helpers +function SystemJSLoader() { + Loader.call(this); - System Loader Implementation + this.paths = {}; + this._loader.paths = {}; - - Implemented to https://github.com/jorendorff/js-loaders/blob/master/browser-loader.js + systemJSConstructor.call(this); +} - - <script type="module"> supported +// inline Object.create-style class extension +function SystemProto() {}; +SystemProto.prototype = Loader.prototype; +SystemJSLoader.prototype = new SystemProto(); +SystemJSLoader.prototype.constructor = SystemJSLoader; -********************************************************************************************* -*/ +var systemJSConstructor; -var System; +function hook(name, hook) { + SystemJSLoader.prototype[name] = hook(SystemJSLoader.prototype[name] || function() {}); +} +function hookConstructor(hook) { + systemJSConstructor = hook(systemJSConstructor || function() {}); +} -function SystemLoader() { - Loader.call(this); - this.paths = {}; + +var absURLRegEx = /^[^\/]+:\/\//; +function isAbsolute(name) { + return name.match(absURLRegEx); +} +function isRel(name) { + return (name[0] == '.' && (!name[1] || name[1] == '/' || name[1] == '.')) || name[0] == '/'; +} +function isPlain(name) { + return !isRel(name) && !isAbsolute(name); +} + +var baseURIObj = new URL(baseURI); + +function urlResolve(name, parent) { + // url resolution shortpaths + if (name[0] == '.') { + // dot-relative url normalization + if (name[1] == '/' && name[2] != '.') + return (parent && parent.substr(0, parent.lastIndexOf('/') + 1) || baseURI) + name.substr(2); + } + else if (name[0] != '/' && name.indexOf(':') == -1) { + // plain parent normalization + return (parent && parent.substr(0, parent.lastIndexOf('/') + 1) || baseURI) + name; + } + + return new URL(name, parent && parent.replace(/#/g, '%05') || baseURIObj).href.replace(/%05/g, '#'); } // NB no specification provided for System.paths, used ideas discussed in https://github.com/jorendorff/js-loaders/issues/25 -function applyPaths(paths, name) { +function applyPaths(loader, name) { // most specific (most number of slashes in path) match wins var pathMatch = '', wildcard, maxWildcardPrefixLen = 0; + var paths = loader.paths; + var pathsCache = loader._loader.paths; + // check to see if we have a paths entry for (var p in paths) { - var pathParts = p.split('*'); - if (pathParts.length > 2) - throw new TypeError('Only one wildcard in a path is permitted'); + if (paths.hasOwnProperty && !paths.hasOwnProperty(p)) + continue; + + // paths sanitization + var path = paths[p]; + if (path !== pathsCache[p]) + path = paths[p] = pathsCache[p] = urlResolve(paths[p], isRel(paths[p]) ? baseURI : loader.baseURL); // exact path match - if (pathParts.length == 1) { + if (p.indexOf('*') === -1) { if (name == p) return paths[p]; // support trailing / in paths rules - else if (name.substr(0, p.length - 1) == p.substr(0, p.length - 1) && (name.length < p.length || name[p.length - 1] == p[p.length - 1]) && paths[p][paths[p].length - 1] == '/') - return paths[p].substr(0, paths[p].length - 1) + (name.length > p.length ? '/' + name.substr(p.length) : ''); + else if (name.substr(0, p.length - 1) == p.substr(0, p.length - 1) && (name.length < p.length || name[p.length - 1] == p[p.length - 1]) && (paths[p][paths[p].length - 1] == '/' || paths[p] == '')) { + return paths[p].substr(0, paths[p].length - 1) + (name.length > p.length ? (paths[p] && '/' || '') + name.substr(p.length) : ''); + } } // wildcard path match else { + var pathParts = p.split('*'); + if (pathParts.length > 2) + throw new TypeError('Only one wildcard in a path is permitted'); + var wildcardPrefixLen = pathParts[0].length; if (wildcardPrefixLen >= maxWildcardPrefixLen && name.substr(0, pathParts[0].length) == pathParts[0] && @@ -991,36 +1084,6 @@ function applyPaths(paths, name) { return outPath; } -// inline Object.create-style class extension -function LoaderProto() {} -LoaderProto.prototype = Loader.prototype; -SystemLoader.prototype = new LoaderProto(); -// SystemJS Loader Class and Extension helpers - -function SystemJSLoader() { - SystemLoader.call(this); - - systemJSConstructor.call(this); -} - -// inline Object.create-style class extension -function SystemProto() {}; -SystemProto.prototype = SystemLoader.prototype; -SystemJSLoader.prototype = new SystemProto(); -SystemJSLoader.prototype.constructor = SystemJSLoader; - -// remove ESML instantiate -SystemJSLoader.prototype.instantiate = function() {}; - -var systemJSConstructor; - -function hook(name, hook) { - SystemJSLoader.prototype[name] = hook(SystemJSLoader.prototype[name] || function() {}); -} -function hookConstructor(hook) { - systemJSConstructor = hook(systemJSConstructor || function() {}); -} - function dedupe(deps) { var newDeps = []; for (var i = 0, l = deps.length; i < l; i++) @@ -1057,20 +1120,18 @@ catch(e) { function getESModule(exports) { var esModule = {}; // don't trigger getters/setters in environments that support them - if (typeof exports == 'object' || typeof exports == 'function') { - if (getOwnPropertyDescriptor) { - var d; - for (var p in exports) - if (d = Object.getOwnPropertyDescriptor(exports, p)) - defineProperty(esModule, p, d); - } - else { - var hasOwnProperty = exports && exports.hasOwnProperty; - for (var p in exports) { - if (!hasOwnProperty || exports.hasOwnProperty(p)) - esModule[p] = exports[p]; + if ((typeof exports == 'object' || typeof exports == 'function') && exports !== __global) { + if (getOwnPropertyDescriptor) { + for (var p in exports) { + // The default property is copied to esModule later on + if (p === 'default') + continue; + defineOrCopyProperty(esModule, exports, p); + } + } + else { + extend(esModule, exports); } - } } esModule['default'] = exports; defineProperty(esModule, '__useDefault', { @@ -1079,23 +1140,40 @@ function getESModule(exports) { return esModule; } +function defineOrCopyProperty(targetObj, sourceObj, propName) { + try { + var d; + if (d = Object.getOwnPropertyDescriptor(sourceObj, propName)) + defineProperty(targetObj, propName, d); + } + catch (ex) { + // Object.getOwnPropertyDescriptor threw an exception, fall back to normal set property + // we dont need hasOwnProperty here because getOwnPropertyDescriptor would have returned undefined above + targetObj[propName] = sourceObj[propName]; + return false; + } +} + function extend(a, b, prepend) { + var hasOwnProperty = b && b.hasOwnProperty; for (var p in b) { + if (hasOwnProperty && !b.hasOwnProperty(p)) + continue; if (!prepend || !(p in a)) a[p] = b[p]; } return a; } -// package configuration options -var packageProperties = ['main', 'format', 'defaultExtension', 'meta', 'map', 'basePath', 'depCache']; - // meta first-level extends where: // array + array appends // object + object extends // other properties replace function extendMeta(a, b, prepend) { + var hasOwnProperty = b && b.hasOwnProperty; for (var p in b) { + if (hasOwnProperty && !b.hasOwnProperty(p)) + continue; var val = b[p]; if (!(p in a)) a[p] = val; @@ -1108,32 +1186,196 @@ function extendMeta(a, b, prepend) { } } +function extendPkgConfig(pkgCfgA, pkgCfgB, pkgName, loader, warnInvalidProperties) { + for (var prop in pkgCfgB) { + if (indexOf.call(['main', 'format', 'defaultExtension', 'basePath'], prop) != -1) { + pkgCfgA[prop] = pkgCfgB[prop]; + } + else if (prop == 'map') { + extend(pkgCfgA.map = pkgCfgA.map || {}, pkgCfgB.map); + } + else if (prop == 'meta') { + extend(pkgCfgA.meta = pkgCfgA.meta || {}, pkgCfgB.meta); + } + else if (prop == 'depCache') { + for (var d in pkgCfgB.depCache) { + var dNormalized; + + if (d.substr(0, 2) == './') + dNormalized = pkgName + '/' + d.substr(2); + else + dNormalized = coreResolve.call(loader, d); + loader.depCache[dNormalized] = (loader.depCache[dNormalized] || []).concat(pkgCfgB.depCache[d]); + } + } + else if (warnInvalidProperties && indexOf.call(['browserConfig', 'nodeConfig', 'devConfig', 'productionConfig'], prop) == -1 && + (!pkgCfgB.hasOwnProperty || pkgCfgB.hasOwnProperty(prop))) { + warn.call(loader, '"' + prop + '" is not a valid package configuration option in package ' + pkgName); + } + } +} + +// deeply-merge (to first level) config with any existing package config +function setPkgConfig(loader, pkgName, cfg, prependConfig) { + var pkg; + + // first package is config by reference for fast path, cloned after that + if (!loader.packages[pkgName]) { + pkg = loader.packages[pkgName] = cfg; + } + else { + var basePkg = loader.packages[pkgName]; + pkg = loader.packages[pkgName] = {}; + + extendPkgConfig(pkg, prependConfig ? cfg : basePkg, pkgName, loader, prependConfig); + extendPkgConfig(pkg, prependConfig ? basePkg : cfg, pkgName, loader, !prependConfig); + } + + // main object becomes main map + if (typeof pkg.main == 'object') { + pkg.map = pkg.map || {}; + pkg.map['./@main'] = pkg.main; + pkg.main['default'] = pkg.main['default'] || './'; + pkg.main = '@main'; + } + + return pkg; +} + function warn(msg) { if (this.warnings && typeof console != 'undefined' && console.warn) console.warn(msg); -}var absURLRegEx = /^[^\/]+:\/\//; - -function readMemberExpression(p, value) { - var pParts = p.split('.'); - while (pParts.length) - value = value[pParts.shift()]; - return value; } + var fetchTextFromURL; + if (typeof XMLHttpRequest != 'undefined') { + fetchTextFromURL = function(url, authorization, fulfill, reject) { + var xhr = new XMLHttpRequest(); + var sameDomain = true; + var doTimeout = false; + if (!('withCredentials' in xhr)) { + // check if same domain + var domainCheck = /^(\w+:)?\/\/([^\/]+)/.exec(url); + if (domainCheck) { + sameDomain = domainCheck[2] === window.location.host; + if (domainCheck[1]) + sameDomain &= domainCheck[1] === window.location.protocol; + } + } + if (!sameDomain && typeof XDomainRequest != 'undefined') { + xhr = new XDomainRequest(); + xhr.onload = load; + xhr.onerror = error; + xhr.ontimeout = error; + xhr.onprogress = function() {}; + xhr.timeout = 0; + doTimeout = true; + } + function load() { + fulfill(xhr.responseText); + } + function error() { + reject(new Error('XHR error' + (xhr.status ? ' (' + xhr.status + (xhr.statusText ? ' ' + xhr.statusText : '') + ')' : '') + ' loading ' + url)); + } -var baseURLCache = {}; -function getBaseURLObj() { - if (baseURLCache[this.baseURL]) - return baseURLCache[this.baseURL]; + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + // in Chrome on file:/// URLs, status is 0 + if (xhr.status == 0) { + if (xhr.responseText) { + load(); + } + else { + // when responseText is empty, wait for load or error event + // to inform if it is a 404 or empty file + xhr.addEventListener('error', error); + xhr.addEventListener('load', load); + } + } + else if (xhr.status === 200) { + load(); + } + else { + error(); + } + } + }; + xhr.open("GET", url, true); + + if (xhr.setRequestHeader) { + xhr.setRequestHeader('Accept', 'application/x-es-module, */*'); + // can set "authorization: true" to enable withCredentials only + if (authorization) { + if (typeof authorization == 'string') + xhr.setRequestHeader('Authorization', authorization); + xhr.withCredentials = true; + } + } - // normalize baseURL if not already - if (this.baseURL[this.baseURL.length - 1] != '/') - this.baseURL += '/'; + if (doTimeout) { + setTimeout(function() { + xhr.send(); + }, 0); + } else { + xhr.send(null); + } + }; + } + else if (typeof require != 'undefined' && typeof process != 'undefined') { + var fs; + fetchTextFromURL = function(url, authorization, fulfill, reject) { + if (url.substr(0, 8) != 'file:///') + throw new Error('Unable to fetch "' + url + '". Only file URLs of the form file:/// allowed running in Node.'); + fs = fs || require('fs'); + if (isWindows) + url = url.replace(/\//g, '\\').substr(8); + else + url = url.substr(7); + return fs.readFile(url, function(err, data) { + if (err) { + return reject(err); + } + else { + // Strip Byte Order Mark out if it's the leading char + var dataString = data + ''; + if (dataString[0] === '\ufeff') + dataString = dataString.substr(1); - var baseURL = new URL(this.baseURL, baseURI); + fulfill(dataString); + } + }); + }; + } + else if (typeof self != 'undefined' && typeof self.fetch != 'undefined') { + fetchTextFromURL = function(url, authorization, fulfill, reject) { + var opts = { + headers: {'Accept': 'application/x-es-module, */*'} + }; - this.baseURL = baseURL.href; + if (authorization) { + if (typeof authorization == 'string') + opts.headers['Authorization'] = authorization; + opts.credentials = 'include'; + } - return (baseURLCache[this.baseURL] = baseURL); + fetch(url, opts) + .then(function (r) { + if (r.ok) { + return r.text(); + } else { + throw new Error('Fetch error: ' + r.status + ' ' + r.statusText); + } + }) + .then(fulfill, reject); + } + } + else { + throw new TypeError('No environment fetch API available.'); + } +function readMemberExpression(p, value) { + var pParts = p.split('.'); + while (pParts.length) + value = value[pParts.shift()]; + return value; } function getMapMatch(map, name) { @@ -1152,48 +1394,57 @@ function getMapMatch(map, name) { return bestMatch; } -function setProduction(isProduction) { - this.set('@system-env', this.newModule({ +function prepareBaseURL(loader) { + // ensure baseURl is fully normalized + if (this._loader.baseURL !== this.baseURL) { + if (this.baseURL[this.baseURL.length - 1] != '/') + this.baseURL += '/'; + + this._loader.baseURL = this.baseURL = new URL(this.baseURL, baseURIObj).href; + } +} + +var envModule; +function setProduction(isProduction, isBuilder) { + this.set('@system-env', envModule = this.newModule({ browser: isBrowser, node: !!this._nodeRequire, - production: isProduction + production: !isBuilder && isProduction, + dev: isBuilder || !isProduction, + build: isBuilder, + 'default': true })); } -var baseURIObj = new URL(baseURI); - hookConstructor(function(constructor) { return function() { constructor.call(this); // support baseURL - this.baseURL = baseURI.substr(0, baseURI.lastIndexOf('/') + 1); + this.baseURL = baseURI; - // support map + // support map and paths this.map = {}; + // make the location of the system.js script accessible + if (typeof $__curScript != 'undefined') + this.scriptSrc = $__curScript.src; + // global behaviour flags this.warnings = false; this.defaultJSExtensions = false; - this.globalEvaluationScope = true; this.pluginFirst = false; + this.loaderErrorStack = false; // by default load ".json" files as json // leading * meta doesn't need normalization // NB add this in next breaking release // this.meta['*.json'] = { format: 'json' }; - // Default settings for globalEvaluationScope: - // Disabled for WebWorker, Chrome Extensions and jsdom - if (isWorker - || isBrowser && window.chrome && window.chrome.extension - || isBrowser && navigator.userAgent.match(/^Node\.js/)) - this.globalEvaluationScope = false; - // support the empty module, as a concept this.set('@empty', this.newModule({})); - setProduction.call(this, false); + setProduction.call(this, false, false); }; }); @@ -1201,11 +1452,6 @@ hookConstructor(function(constructor) { if (typeof require != 'undefined' && typeof process != 'undefined' && !process.browser) SystemJSLoader.prototype._nodeRequire = require; -var nodeCoreModules = ['assert', 'buffer', 'child_process', 'cluster', 'console', 'constants', - 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https', 'module', 'net', 'os', 'path', - 'process', 'punycode', 'querystring', 'readline', 'repl', 'stream', 'string_decoder', 'sys', 'timers', - 'tls', 'tty', 'url', 'util', 'vm', 'zlib']; - /* Core SystemJS Normalization @@ -1219,54 +1465,66 @@ var nodeCoreModules = ['assert', 'buffer', 'child_process', 'cluster', 'console' defines the `decanonicalize` function and normalizes everything into a URL. */ -hook('normalize', function(normalize) { - return function(name, parentName) { - // first run map config - if (name[0] != '.' && name[0] != '/' && !name.match(absURLRegEx)) { - var mapMatch = getMapMatch(this.map, name); - if (mapMatch) - name = this.map[mapMatch] + name.substr(mapMatch.length); - } - // dynamically load node-core modules when requiring `@node/fs` for example - if (name.substr(0, 6) == '@node/' && nodeCoreModules.indexOf(name.substr(6)) != -1) { - if (!this._nodeRequire) - throw new TypeError('Error loading ' + name + '. Can only load node core modules in Node.'); - this.set(name, this.newModule(getESModule(this._nodeRequire(name.substr(6))))); - } - - // relative URL-normalization - if (name[0] == '.' || name[0] == '/') { - if (parentName) - name = new URL(name, parentName.replace(/#/g, '%05')).href.replace(/%05/g, '#'); - else - name = new URL(name, baseURIObj).href; - } +var parentModuleContext; +function getNodeModule(name, baseURL) { + if (!isPlain(name)) + throw new Error('Node module ' + name + ' can\'t be loaded as it is not a package require.'); - // if the module is in the registry already, use that - if (this.has(name)) - return name; + if (!parentModuleContext) { + var Module = this._nodeRequire('module'); + var base = baseURL.substr(isWindows ? 8 : 7); + parentModuleContext = new Module(base); + parentModuleContext.paths = Module._nodeModulePaths(base); + } + return parentModuleContext.require(name); +} - if (name.match(absURLRegEx)) { - // defaultJSExtensions backwards compatibility - if (this.defaultJSExtensions && name.substr(name.length - 3, 3) != '.js') - name += '.js'; - return name; - } +function coreResolve(name, parentName) { + // standard URL resolution + if (isRel(name)) + return urlResolve(name, parentName); + else if (isAbsolute(name)) + return name; - // applyPaths implementation provided from ModuleLoader system.js source - name = applyPaths(this.paths, name) || name; + // plain names not starting with './', '://' and '/' go through custom resolution + var mapMatch = getMapMatch(this.map, name); - // defaultJSExtensions backwards compatibility - if (this.defaultJSExtensions && name.substr(name.length - 3, 3) != '.js') - name += '.js'; + if (mapMatch) { + name = this.map[mapMatch] + name.substr(mapMatch.length); - // ./x, /x -> page-relative - if (name[0] == '.' || name[0] == '/') - return new URL(name, baseURIObj).href; - // x -> baseURL-relative + if (isRel(name)) + return urlResolve(name); + else if (isAbsolute(name)) + return name; + } + + if (this.has(name)) + return name; + + // dynamically load node-core modules when requiring `@node/fs` for example + if (name.substr(0, 6) == '@node/') { + if (!this._nodeRequire) + throw new TypeError('Error loading ' + name + '. Can only load node core modules in Node.'); + if (this.builder) + this.set(name, this.newModule({})); else - return new URL(name, getBaseURLObj.call(this)).href; + this.set(name, this.newModule(getESModule(getNodeModule.call(this, name.substr(6), this.baseURL)))); + return name; + } + + // prepare the baseURL to ensure it is normalized + prepareBaseURL.call(this); + + return applyPaths(this, name) || this.baseURL + name; +} + +hook('normalize', function(normalize) { + return function(name, parentName, skipExt) { + var resolved = coreResolve.call(this, name, parentName); + if (this.defaultJSExtensions && !skipExt && resolved.substr(resolved.length - 3, 3) != '.js' && !isPlain(resolved)) + resolved += '.js'; + return resolved; }; }); @@ -1325,7 +1583,7 @@ hook('translate', function(systemTranslate) { return function(load) { if (load.metadata.format == 'detect') load.metadata.format = undefined; - return systemTranslate.call(this, load); + return systemTranslate.apply(this, arguments); }; }); @@ -1402,10 +1660,43 @@ hook('instantiate', function(instantiate) { For easy normalization canonicalization with latest URL support. */ -SystemJSLoader.prototype.env = 'development'; +function envSet(loader, cfg, envCallback) { + if (envModule.browser && cfg.browserConfig) + envCallback(cfg.browserConfig); + if (envModule.node && cfg.nodeConfig) + envCallback(cfg.nodeConfig); + if (envModule.dev && cfg.devConfig) + envCallback(cfg.devConfig); + if (envModule.build && cfg.buildConfig) + envCallback(cfg.buildConfig); + if (envModule.production && cfg.productionConfig) + envCallback(cfg.productionConfig); +} -SystemJSLoader.prototype.config = function(cfg) { +SystemJSLoader.prototype.getConfig = function(name) { + var cfg = {}; var loader = this; + for (var p in loader) { + if (loader.hasOwnProperty && !loader.hasOwnProperty(p) || p in SystemJSLoader.prototype && p != 'transpiler') + continue; + if (indexOf.call(['_loader', 'amdDefine', 'amdRequire', 'defined', 'failed', 'version', 'loads'], p) == -1) + cfg[p] = loader[p]; + } + cfg.production = envModule.production; + return cfg; +}; + +var curCurScript; +SystemJSLoader.prototype.config = function(cfg, isEnvConfig) { + var loader = this; + + if ('loaderErrorStack' in cfg) { + curCurScript = $__curScript; + if (cfg.loaderErrorStack) + $__curScript = undefined; + else + $__curScript = curCurScript; + } if ('warnings' in cfg) loader.warnings = cfg.warnings; @@ -1414,20 +1705,47 @@ SystemJSLoader.prototype.config = function(cfg) { if (cfg.transpilerRuntime === false) loader._loader.loadedTranspilerRuntime = true; - // always configure baseURL first - if (cfg.baseURL) { - var hasConfig = false; - function checkHasConfig(obj) { - for (var p in obj) - return true; + if ('production' in cfg || 'build' in cfg) + setProduction.call(loader, !!cfg.production, !!(cfg.build || envModule && envModule.build)); + + if (!isEnvConfig) { + // if using nodeConfig / browserConfig / productionConfig, take baseURL from there + // these exceptions will be unnecessary when we can properly implement config queuings + var baseURL; + envSet(loader, cfg, function(cfg) { + baseURL = baseURL || cfg.baseURL; + }); + baseURL = baseURL || cfg.baseURL; + + // always configure baseURL first + if (baseURL) { + var hasConfig = false; + function checkHasConfig(obj) { + for (var p in obj) + if (obj.hasOwnProperty(p)) + return true; + } + if (checkHasConfig(loader.packages) || checkHasConfig(loader.meta) || checkHasConfig(loader.depCache) || checkHasConfig(loader.bundles) || checkHasConfig(loader.packageConfigPaths)) + throw new TypeError('Incorrect configuration order. The baseURL must be configured with the first SystemJS.config call.'); + + this.baseURL = baseURL; + prepareBaseURL.call(this); } - if (checkHasConfig(loader.packages) || checkHasConfig(loader.meta) || checkHasConfig(loader.depCache) || checkHasConfig(loader.bundles) || checkHasConfig(loader.packageConfigPaths)) - throw new TypeError('Incorrect configuration order. The baseURL must be configured with the first SystemJS.config call.'); - loader.baseURL = cfg.baseURL; + if (cfg.paths) + extend(loader.paths, cfg.paths); + + envSet(loader, cfg, function(cfg) { + if (cfg.paths) + extend(loader.paths, cfg.paths); + }); - // sanitize baseURL - getBaseURLObj.call(loader); + // warn on wildcard path deprecations + if (this.warnings) { + for (var p in loader.paths) + if (p.indexOf('*') != -1) + warn.call(loader, 'Paths configuration "' + p + '" -> "' + loader.paths[p] + '" uses wildcards which are being deprecated for simpler trailing "/" folder paths.'); + } } if (cfg.defaultJSExtensions) { @@ -1438,14 +1756,6 @@ SystemJSLoader.prototype.config = function(cfg) { if (cfg.pluginFirst) loader.pluginFirst = cfg.pluginFirst; - if (cfg.production) - setProduction.call(loader, true); - - if (cfg.paths) { - for (var p in cfg.paths) - loader.paths[p] = cfg.paths[p]; - } - if (cfg.map) { var objMaps = ''; for (var p in cfg.map) { @@ -1455,11 +1765,10 @@ SystemJSLoader.prototype.config = function(cfg) { if (typeof v !== 'string') { objMaps += (objMaps.length ? ', ' : '') + '"' + p + '"'; - var prop = loader.decanonicalize(p + (p[p.length - 1] != '/' ? '/' : '')); - - // allow trailing '/' in package config - if (prop[prop.length - 1] == '/') - prop = prop.substr(0, prop.length - 1); + var defaultJSExtension = loader.defaultJSExtensions && p.substr(p.length - 3, 3) != '.js'; + var prop = loader.decanonicalize(p); + if (defaultJSExtension && prop.substr(prop.length - 3, 3) == '.js') + prop = prop.substr(0, prop.length - 3); // if a package main, revert it var pkgMatch = ''; @@ -1488,9 +1797,8 @@ SystemJSLoader.prototype.config = function(cfg) { for (var i = 0; i < cfg.packageConfigPaths.length; i++) { var path = cfg.packageConfigPaths[i]; var packageLength = Math.max(path.lastIndexOf('*') + 1, path.lastIndexOf('/')); - var normalized = loader.decanonicalize(path.substr(0, packageLength) + '/'); - normalized = normalized.substr(0, normalized.length - 1) + path.substr(packageLength); - packageConfigPaths[i] = normalized; + var normalized = coreResolve.call(loader, path.substr(0, packageLength)); + packageConfigPaths[i] = normalized + path.substr(packageLength); } loader.packageConfigPaths = packageConfigPaths; } @@ -1498,8 +1806,13 @@ SystemJSLoader.prototype.config = function(cfg) { if (cfg.bundles) { for (var p in cfg.bundles) { var bundle = []; - for (var i = 0; i < cfg.bundles[p].length; i++) - bundle.push(loader.decanonicalize(cfg.bundles[p][i])); + for (var i = 0; i < cfg.bundles[p].length; i++) { + var defaultJSExtension = loader.defaultJSExtensions && cfg.bundles[p][i].substr(cfg.bundles[p][i].length - 3, 3) != '.js'; + var normalizedBundleDep = loader.decanonicalize(cfg.bundles[p][i]); + if (defaultJSExtension && normalizedBundleDep.substr(normalizedBundleDep.length - 3, 3) == '.js') + normalizedBundleDep = normalizedBundleDep.substr(0, normalizedBundleDep.length - 3); + bundle.push(normalizedBundleDep); + } loader.bundles[p] = bundle; } } @@ -1509,38 +1822,21 @@ SystemJSLoader.prototype.config = function(cfg) { if (p.match(/^([^\/]+:)?\/\/$/)) throw new TypeError('"' + p + '" is not a valid package name.'); - // trailing slash allows paths matches here - // NB deprecate this to just remove trailing / - // as decanonicalize doesn't respond to trailing / - // and paths wildcards should deprecate - var prop = loader.decanonicalize(p + (p[p.length - 1] != '/' ? '/' : '')); + var prop = coreResolve.call(loader, p); - // allow trailing '/' in package config + // allow trailing slash in packages if (prop[prop.length - 1] == '/') prop = prop.substr(0, prop.length - 1); - loader.packages[prop] = loader.packages[prop] || {}; - - // meta backwards compatibility - if (cfg.packages[p].modules) { - warn.call(loader, 'Package ' + p + ' is configured with "modules", which is deprecated as it has been renamed to "meta".'); - cfg.packages[p].meta = cfg.packages[p].modules; - delete cfg.packages[p].modules; - } - - for (var q in cfg.packages[p]) - if (indexOf.call(packageProperties, q) == -1) - warn.call(loader, '"' + q + '" is not a valid package configuration option in package ' + p); - - extendMeta(loader.packages[prop], cfg.packages[p]); + setPkgConfig(loader, prop, cfg.packages[p], false); } } for (var c in cfg) { var v = cfg[c]; - var normalizeProp = false; - if (c == 'baseURL' || c == 'map' || c == 'packages' || c == 'bundles' || c == 'paths' || c == 'warnings' || c == 'packageConfigPaths') + if (indexOf.call(['baseURL', 'map', 'packages', 'bundles', 'paths', 'warnings', 'packageConfigPaths', + 'loaderErrorStack', 'browserConfig', 'nodeConfig', 'devConfig', 'buildConfig', 'productionConfig'], c) != -1) continue; if (typeof v != 'object' || v instanceof Array) { @@ -1549,20 +1845,35 @@ SystemJSLoader.prototype.config = function(cfg) { else { loader[c] = loader[c] || {}; - if (c == 'meta' || c == 'depCache') - normalizeProp = true; - for (var p in v) { // base-level wildcard meta does not normalize to retain catch-all quality - if (c == 'meta' && p[0] == '*') - loader[c][p] = v[p]; - else if (normalizeProp) - loader[c][loader.decanonicalize(p)] = v[p]; - else + if (c == 'meta' && p[0] == '*') { + extend(loader[c][p] = loader[c][p] || {}, v[p]); + } + else if (c == 'meta') { + // meta can go through global map, with defaultJSExtensions adding + var resolved = coreResolve.call(loader, p); + if (loader.defaultJSExtensions && resolved.substr(resolved.length - 3, 3) != '.js' && !isPlain(resolved)) + resolved += '.js'; + extend(loader[c][resolved] = loader[c][resolved] || {}, v[p]); + } + else if (c == 'depCache') { + var defaultJSExtension = loader.defaultJSExtensions && p.substr(p.length - 3, 3) != '.js'; + var prop = loader.decanonicalize(p); + if (defaultJSExtension && prop.substr(prop.length - 3, 3) == '.js') + prop = prop.substr(0, prop.length - 3); + loader[c][prop] = [].concat(v[p]); + } + else { loader[c][p] = v[p]; + } } } } + + envSet(loader, cfg, function(cfg) { + loader.config(cfg, true); + }); };/* * Package Configuration Extension * @@ -1570,7 +1881,6 @@ SystemJSLoader.prototype.config = function(cfg) { * * SystemJS.packages = { * jquery: { - * basePath: 'lib', // optionally only use a subdirectory within the package * main: 'index.js', // when not set, package name is requested directly * format: 'amd', * defaultExtension: 'ts', // defaults to 'js', can be set to false @@ -1592,7 +1902,8 @@ SystemJSLoader.prototype.config = function(cfg) { * * // environment-specific map configurations * './index.js': { - * '~browser': './index-node.js' + * '~browser': './index-node.js', + * './custom-condition.js|~export': './index-custom.js' * } * }, * // allows for setting package-prefixed depCache @@ -1623,13 +1934,6 @@ SystemJSLoader.prototype.config = function(cfg) { * - map targets support conditional interpolation ('./x': './x.#{|env}.js') * - internal package map targets cannot use boolean conditionals * - * In addition, the following modules properties will be allowed to be package - * -relative as well in the package module config: - * - * - loader - * - alias - * - * * Package Configuration Loading * * Not all packages may already have their configuration present in the System config @@ -1666,7 +1970,7 @@ SystemJSLoader.prototype.config = function(cfg) { return function() { constructor.call(this); this.packages = {}; - this.packageConfigPaths = {}; + this.packageConfigPaths = []; }; }); @@ -1685,28 +1989,11 @@ SystemJSLoader.prototype.config = function(cfg) { return curPkg; } - function getBasePath(pkg) { - // sanitize basePath - var basePath = pkg.basePath && pkg.basePath != '.' ? pkg.basePath : ''; - if (basePath) { - if (basePath.substr(0, 2) == './') - basePath = basePath.substr(2); - if (basePath[basePath.length - 1] != '/') - basePath += '/'; - } - return basePath; - } - - function addDefaultExtension(loader, pkg, pkgName, basePath, subPath, skipExtensions) { + function addDefaultExtension(loader, pkg, pkgName, subPath, skipExtensions) { // don't apply extensions to folders or if defaultExtension = false if (!subPath || subPath[subPath.length - 1] == '/' || skipExtensions || pkg.defaultExtension === false) return subPath; - // NB are you sure about this? - // skip if we have interpolation conditional syntax in subPath? - if (subPath.match(interpolationRegEx)) - return subPath; - var metaMatch = false; // exact meta or meta with any content after the last wildcard skips extension @@ -1718,7 +2005,7 @@ SystemJSLoader.prototype.config = function(cfg) { // exact global meta or meta with any content after the last wildcard skips extension if (!metaMatch && loader.meta) - getMetaMatches(loader.meta, pkgName + '/' + basePath + subPath, function(metaPattern, matchMeta, matchDepth) { + getMetaMatches(loader.meta, pkgName + '/' + subPath, function(metaPattern, matchMeta, matchDepth) { if (matchDepth == 0 || metaPattern.lastIndexOf('*') != metaPattern.length - 1) return metaMatch = true; }); @@ -1747,8 +2034,6 @@ SystemJSLoader.prototype.config = function(cfg) { return pkgName + (loader.defaultJSExtensions ? '.js' : ''); } - var basePath = getBasePath(pkg); - // map config checking without then with extensions if (pkg.map) { var mapPath = './' + subPath; @@ -1757,24 +2042,44 @@ SystemJSLoader.prototype.config = function(cfg) { // we then check map with the default extension adding if (!mapMatch) { - mapPath = './' + addDefaultExtension(loader, pkg, pkgName, basePath, subPath, skipExtensions); + mapPath = './' + addDefaultExtension(loader, pkg, pkgName, subPath, skipExtensions); if (mapPath != './' + subPath) mapMatch = getMapMatch(pkg.map, mapPath); } - if (mapMatch) - return doMapSync(loader, pkg, pkgName, basePath, mapMatch, mapPath, skipExtensions); + if (mapMatch) { + var mapped = doMapSync(loader, pkg, pkgName, mapMatch, mapPath, skipExtensions); + if (mapped) + return mapped; + } } // normal package resolution - return pkgName + '/' + basePath + addDefaultExtension(loader, pkg, pkgName, basePath, subPath, skipExtensions); + return pkgName + '/' + addDefaultExtension(loader, pkg, pkgName, subPath, skipExtensions); + } + + function validMapping(mapMatch, mapped, pkgName, path) { + // disallow internal to subpath maps + if (mapMatch == '.') + throw new Error('Package ' + pkgName + ' has a map entry for "." which is not permitted.'); + + // allow internal ./x -> ./x/y or ./x/ -> ./x/y recursive maps + // but only if the path is exactly ./x and not ./x/z + if (mapped.substr(0, mapMatch.length) == mapMatch && path.length > mapMatch.length) + return false; + + return true; } - function doMapSync(loader, pkg, pkgName, basePath, mapMatch, path, skipExtensions) { + function doMapSync(loader, pkg, pkgName, mapMatch, path, skipExtensions) { + if (path[path.length - 1] == '/') + path = path.substr(0, path.length - 1); var mapped = pkg.map[mapMatch]; - // ignore conditionals in sync - if (typeof mapped != 'string') - mapped = mapMatch = path; + if (typeof mapped == 'object') + throw new Error('Synchronous conditional normalization not supported sync normalizing ' + mapMatch + ' in ' + pkgName); + + if (!validMapping(mapMatch, mapped, pkgName, path) || typeof mapped != 'string') + return; // package map to main / base-level if (mapped == '.') @@ -1782,7 +2087,7 @@ SystemJSLoader.prototype.config = function(cfg) { // internal package map else if (mapped.substr(0, 2) == './') - return pkgName + '/' + basePath + addDefaultExtension(loader, pkg, pkgName, basePath, mapped.substr(2) + path.substr(mapMatch.length), skipExtensions); + return pkgName + '/' + addDefaultExtension(loader, pkg, pkgName, mapped.substr(2) + path.substr(mapMatch.length), skipExtensions); // external map reference return loader.normalizeSync(mapped + path.substr(mapMatch.length), pkgName + '/'); @@ -1800,8 +2105,6 @@ SystemJSLoader.prototype.config = function(cfg) { return Promise.resolve(pkgName + (loader.defaultJSExtensions ? '.js' : '')); } - var basePath = getBasePath(pkg); - // map config checking without then with extensions var mapPath, mapMatch; @@ -1811,67 +2114,84 @@ SystemJSLoader.prototype.config = function(cfg) { // we then check map with the default extension adding if (!mapMatch) { - mapPath = './' + addDefaultExtension(loader, pkg, pkgName, basePath, subPath, skipExtensions); + mapPath = './' + addDefaultExtension(loader, pkg, pkgName, subPath, skipExtensions); if (mapPath != './' + subPath) mapMatch = getMapMatch(pkg.map, mapPath); } } - return (mapMatch ? doMap(loader, pkg, pkgName, basePath, mapMatch, mapPath, skipExtensions) : Promise.resolve()) + return (mapMatch ? doMap(loader, pkg, pkgName, mapMatch, mapPath, skipExtensions) : Promise.resolve()) .then(function(mapped) { if (mapped) return Promise.resolve(mapped); // normal package resolution / fallback resolution for no conditional match - return Promise.resolve(pkgName + '/' + basePath + addDefaultExtension(loader, pkg, pkgName, basePath, subPath, skipExtensions)); + return Promise.resolve(pkgName + '/' + addDefaultExtension(loader, pkg, pkgName, subPath, skipExtensions)); }); } - function doStringMap(loader, pkg, pkgName, basePath, mapMatch, mapped, path, skipExtensions) { + function doStringMap(loader, pkg, pkgName, mapMatch, mapped, path, skipExtensions) { // NB the interpolation cases should strictly skip subsequent interpolation - // package map to main / base-level if (mapped == '.') mapped = pkgName; // internal package map else if (mapped.substr(0, 2) == './') - return Promise.resolve(pkgName + '/' + basePath + addDefaultExtension(loader, pkg, pkgName, basePath, mapped.substr(2) + path.substr(mapMatch.length), skipExtensions)) + return Promise.resolve(pkgName + '/' + addDefaultExtension(loader, pkg, pkgName, mapped.substr(2) + path.substr(mapMatch.length), skipExtensions)) .then(function(name) { return interpolateConditional.call(loader, name, pkgName + '/'); }); // external map reference - // NB deprecate the use of the second argument here -> should be fully global reference return loader.normalize(mapped + path.substr(mapMatch.length), pkgName + '/'); } - function doMap(loader, pkg, pkgName, basePath, mapMatch, path, skipExtensions) { + function doMap(loader, pkg, pkgName, mapMatch, path, skipExtensions) { + if (path[path.length - 1] == '/') + path = path.substr(0, path.length - 1); + var mapped = pkg.map[mapMatch]; - if (typeof mapped == 'string') - return doStringMap(loader, pkg, pkgName, basePath, mapMatch, mapped, path, skipExtensions); + if (typeof mapped == 'string') { + if (!validMapping(mapMatch, mapped, pkgName, path)) + return Promise.resolve(); + return doStringMap(loader, pkg, pkgName, mapMatch, mapped, path, skipExtensions); + } // we use a special conditional syntax to allow the builder to handle conditional branch points further if (loader.builder) return Promise.resolve(pkgName + '/#:' + path); + // we load all conditions upfront + var conditionPromises = []; + var conditions = []; + for (var e in mapped) { + var c = parseCondition(e); + conditions.push({ + condition: c, + map: mapped[e] + }); + conditionPromises.push(loader['import'](c.module, pkgName)); + } + // map object -> conditional map - return loader['import'](pkg.map['@env'] || '@system-env', pkgName) - .then(function(env) { + return Promise.all(conditionPromises) + .then(function(conditionValues) { // first map condition to match is used - for (var e in mapped) { - var negate = e[0] == '~'; - - var value = readMemberExpression(negate ? e.substr(1) : e, env); - - if (!negate && value || negate && !value) - return mapped[e]; + for (var i = 0; i < conditions.length; i++) { + var c = conditions[i].condition; + var value = readMemberExpression(c.prop, conditionValues[i]); + if (!c.negate && value || c.negate && !value) + return conditions[i].map; } }) .then(function(mapped) { - if (mapped) - return doStringMap(loader, pkg, pkgName, basePath, mapMatch, mapped, path, skipExtensions); + if (mapped) { + if (!validMapping(mapMatch, mapped, pkgName, path)) + return; + return doStringMap(loader, pkg, pkgName, mapMatch, mapped, path, skipExtensions); + } // no environment match -> fallback to original subPath by returning undefined }); @@ -1884,14 +2204,26 @@ SystemJSLoader.prototype.config = function(cfg) { // to be deprecated! hook('decanonicalize', function(decanonicalize) { return function(name, parentName) { - var decanonicalized = decanonicalize.call(this, name, parentName); + if (this.builder) + return decanonicalize.call(this, name, parentName, true); + + var decanonicalized = decanonicalize.call(this, name, parentName, false); if (!this.defaultJSExtensions) return decanonicalized; var pkgName = getPackage(this, decanonicalized); - var defaultExtension = name[name.length - 1] == '/' ? false : pkgName && this.packages[pkgName].defaultExtension; + var pkg = this.packages[pkgName]; + var defaultExtension = pkg && pkg.defaultExtension; + + if (defaultExtension == undefined && pkg && pkg.meta) + getMetaMatches(pkg.meta, decanonicalized.substr(pkgName), function(metaPattern, matchMeta, matchDepth) { + if (matchDepth == 0 || metaPattern.lastIndexOf('*') != metaPattern.length - 1) { + defaultExtension = false; + return true; + } + }); if ((defaultExtension === false || defaultExtension && defaultExtension != '.js') && name.substr(name.length - 3, 3) != '.js' && decanonicalized.substr(decanonicalized.length - 3, 3) == '.js') decanonicalized = decanonicalized.substr(0, decanonicalized.length - 3); @@ -1902,8 +2234,6 @@ SystemJSLoader.prototype.config = function(cfg) { hook('normalizeSync', function(normalizeSync) { return function(name, parentName, isPlugin) { - warn.call(this, 'SystemJS.normalizeSync has been deprecated for SystemJS.decanonicalize.'); - var loader = this; isPlugin = isPlugin === true; @@ -1916,26 +2246,22 @@ SystemJSLoader.prototype.config = function(cfg) { var parentPackage = parentPackageName && loader.packages[parentPackageName]; - // remove any parent basePath from parentName - if (parentPackage) { - var parentBasePath = getBasePath(parentPackage); - if (parentBasePath && parentName.substr(parentPackageName.length + 1, parentBasePath.length) == parentBasePath) - parentName = parentPackageName + parentName.substr(parentPackageName.length + parentBasePath.length); - } - // ignore . since internal maps handled by standard package resolution if (parentPackage && name[0] != '.') { var parentMap = parentPackage.map; var parentMapMatch = parentMap && getMapMatch(parentMap, name); - if (parentMapMatch && typeof parentMap[parentMapMatch] == 'string') - return doMapSync(loader, parentPackage, parentPackageName, getBasePath(parentPackage), parentMapMatch, name, isPlugin); + if (parentMapMatch && typeof parentMap[parentMapMatch] == 'string') { + var mapped = doMapSync(loader, parentPackage, parentPackageName, parentMapMatch, name, isPlugin); + if (mapped) + return mapped; + } } var defaultJSExtension = loader.defaultJSExtensions && name.substr(name.length - 3, 3) != '.js'; // apply map, core, paths, contextual package map - var normalized = normalizeSync.call(loader, name, parentName); + var normalized = normalizeSync.call(loader, name, parentName, false); // undo defaultJSExtension if (defaultJSExtension && normalized.substr(normalized.length - 3, 3) != '.js') @@ -1971,20 +2297,13 @@ SystemJSLoader.prototype.config = function(cfg) { var parentPackage = parentPackageName && loader.packages[parentPackageName]; - // remove any parent basePath from parentName - if (parentPackage) { - var parentBasePath = getBasePath(parentPackage); - if (parentBasePath && parentName.substr(parentPackageName.length + 1, parentBasePath.length) == parentBasePath) - parentName = parentPackageName + parentName.substr(parentPackageName.length + parentBasePath.length); - } - // ignore . since internal maps handled by standard package resolution if (parentPackage && name.substr(0, 2) != './') { var parentMap = parentPackage.map; var parentMapMatch = parentMap && getMapMatch(parentMap, name); if (parentMapMatch) - return doMap(loader, parentPackage, parentPackageName, parentBasePath, parentMapMatch, name, isPlugin); + return doMap(loader, parentPackage, parentPackageName, parentMapMatch, name, isPlugin); } return Promise.resolve(); @@ -1996,7 +2315,7 @@ SystemJSLoader.prototype.config = function(cfg) { var defaultJSExtension = loader.defaultJSExtensions && name.substr(name.length - 3, 3) != '.js'; // apply map, core, paths, contextual package map - var normalized = normalize.call(loader, name, parentName); + var normalized = normalize.call(loader, name, parentName, false); // undo defaultJSExtension if (defaultJSExtension && normalized.substr(normalized.length - 3, 3) != '.js') @@ -2034,8 +2353,7 @@ SystemJSLoader.prototype.config = function(cfg) { var length = Math.max(lastWildcard + 1, path.lastIndexOf('/')); return { length: length, - // NB handle regex control character escapes or simply create a test function here - regEx: new RegExp('^(' + path.substr(0, length).replace(/\*/g, '[^\\/]+') + ')(\\/|$)'), + regEx: new RegExp('^(' + path.substr(0, length).replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '[^\\/]+') + ')(\\/|$)'), wildcard: lastWildcard != -1 }; } @@ -2070,12 +2388,11 @@ SystemJSLoader.prototype.config = function(cfg) { // NB remove this when json is default (configLoader.meta[pkgConfigPath] = configLoader.meta[pkgConfigPath] || {}).format = 'json'; + configLoader.meta[pkgConfigPath].loader = null; return configLoader.load(pkgConfigPath) .then(function() { - pkgConfig = configLoader.get(pkgConfigPath); - - var cfg = pkgConfig['default']; + var cfg = configLoader.get(pkgConfigPath)['default']; // support "systemjs" prefixing if (cfg.systemjs) @@ -2087,32 +2404,7 @@ SystemJSLoader.prototype.config = function(cfg) { warn.call(loader, 'Package config file ' + pkgConfigPath + ' is configured with "modules", which is deprecated as it has been renamed to "meta".'); } - // remove any non-system properties if generic config file (eg package.json) - for (var p in cfg) { - if (indexOf.call(packageProperties, p) == -1) - delete cfg[p]; - } - - // deeply-merge (to first level) config with any existing package config - var pkg = loader.packages[pkgName] = loader.packages[pkgName] || {}; - extendMeta(pkg, cfg, true); - - // support external depCache - var basePath = getBasePath(pkg); - if (cfg.depCache) { - for (var d in cfg.depCache) { - var dNormalized; - - if (d.substr(0, 2) == './') - dNormalized = pkgName + '/' + basePath + d.substr(2); - else - dNormalized = coreResolve.call(loader, d); - loader.depCache[dNormalized] = (loader.depCache[dNormalized] || []).concat(cfg.depCache[d]); - } - delete cfg.depCache; - } - - return pkg; + return setPkgConfig(loader, pkgName, cfg, true); }); } @@ -2138,7 +2430,7 @@ SystemJSLoader.prototype.config = function(cfg) { } } // exact meta - var exactMeta = pkgMeta[subPath] || pkgMeta['./' + subPath]; + var exactMeta = pkgMeta[subPath] && pkgMeta.hasOwnProperty && pkgMeta.hasOwnProperty(subPath) ? pkgMeta[subPath] : pkgMeta['./' + subPath]; if (exactMeta) matchFn(exactMeta, exactMeta, 0); } @@ -2151,12 +2443,7 @@ SystemJSLoader.prototype.config = function(cfg) { var pkgName = getPackage(loader, load.name); if (pkgName) { var pkg = loader.packages[pkgName]; - var basePath = getBasePath(pkg); - var subPath = load.name.substr(pkgName.length + basePath.length + 1); - - // format - if (pkg.format) - load.metadata.format = load.metadata.format || pkg.format; + var subPath = load.name.substr(pkgName.length + 1); var meta = {}; if (pkg.meta) { @@ -2169,13 +2456,12 @@ SystemJSLoader.prototype.config = function(cfg) { extendMeta(meta, matchMeta, matchDepth && bestDepth > matchDepth); }); - // allow alias and loader to be package-relative - if (meta.alias && meta.alias.substr(0, 2) == './') - meta.alias = pkgName + meta.alias.substr(1); - if (meta.loader && meta.loader.substr(0, 2) == './') - meta.loader = pkgName + meta.loader.substr(1); extendMeta(load.metadata, meta); } + + // format + if (pkg.format && !load.metadata.loader) + load.metadata.format = load.metadata.format || pkg.format; } return address; @@ -2195,6 +2481,7 @@ SystemJSLoader.prototype.config = function(cfg) { var head = document.getElementsByTagName('head')[0]; var curSystem; + var curRequire; // if doing worker executing, this is set to the load record being executed var workerLoad = null; @@ -2276,7 +2563,7 @@ SystemJSLoader.prototype.config = function(cfg) { // if nothing registered, then something went wrong if (!load.metadata.entry) - reject(new Error(load.address + ' did not call System.register or AMD define')); + reject(new Error(load.address + ' did not call System.register or AMD define. If loading a global, ensure the meta format is set to global.')); resolve(''); }); @@ -2287,7 +2574,7 @@ SystemJSLoader.prototype.config = function(cfg) { return function(load) { var loader = this; - if (!load.metadata.scriptLoad || (!isBrowser && !isWorker)) + if (load.metadata.format == 'json' || !load.metadata.scriptLoad || (!isBrowser && !isWorker)) return fetch.call(this, load); if (isWorker) @@ -2297,7 +2584,10 @@ SystemJSLoader.prototype.config = function(cfg) { var s = document.createElement('script'); s.async = true; - + + if (load.metadata.crossOrigin) + s.crossOrigin = load.metadata.crossOrigin; + if (load.metadata.integrity) s.setAttribute('integrity', load.metadata.integrity); @@ -2316,6 +2606,7 @@ SystemJSLoader.prototype.config = function(cfg) { loadingCnt++; curSystem = __global.System; + curRequire = __global.require; s.src = load.address; head.appendChild(s); @@ -2353,6 +2644,7 @@ SystemJSLoader.prototype.config = function(cfg) { function cleanup() { __global.System = curSystem; + __global.require = curRequire; if (s.detachEvent) { s.detachEvent('onreadystatechange', complete); @@ -2427,7 +2719,7 @@ SystemJSLoader.prototype.config = function(cfg) { * */ -var leadingCommentAndMetaRegEx = /^\s*(\/\*[^\*]*(\*(?!\/)[^\*]*)*\*\/|\s*\/\/[^\n]*|\s*"[^"]+"\s*;?|\s*'[^']+'\s*;?)*\s*/; +var leadingCommentAndMetaRegEx = /^(\s*\/\*[^\*]*(\*(?!\/)[^\*]*)*\*\/|\s*\/\/[^\n]*|\s*"[^"]+"\s*;?|\s*'[^']+'\s*;?)*\s*/; function detectRegisterFormat(source) { var leadingCommentAndMeta = source.match(leadingCommentAndMetaRegEx); return leadingCommentAndMeta && source.substr(leadingCommentAndMeta[0].length, 15) == 'System.register'; @@ -2528,9 +2820,9 @@ function createEntry() { curMeta.bundle = true; } // anonymous register - if (!entry.name || load && entry.name == load.name) { + if (!entry.name || load && !curMeta.entry && entry.name == load.name) { if (!curMeta) - throw new TypeError('Unexpected anonymous System.register call.'); + throw new TypeError('Invalid System.register call. Anonymous System.register calls can only be made by modules loaded by SystemJS.import and not via script tags.'); if (curMeta.entry) { if (curMeta.format == 'register') throw new Error('Multiple anonymous System.register calls in module ' + load.name + '. If loading a bundle, ensure all the System.register calls are named.'); @@ -2591,9 +2883,7 @@ function createEntry() { } } - function link(name, loader) { - var startEntry = loader.defined[name]; - + function link(name, startEntry, loader) { // skip if already linked if (startEntry.module) return; @@ -2621,8 +2911,8 @@ function createEntry() { } // module binding records - function Module() {} - defineProperty(Module, 'toString', { + function ModuleRecord() {} + defineProperty(ModuleRecord, 'toString', { value: function() { return 'Module'; } @@ -2632,7 +2922,7 @@ function createEntry() { return moduleRecords[name] || (moduleRecords[name] = { name: name, dependencies: [], - exports: new Module(), // start from an empty module and extend + exports: new ModuleRecord(), // start from an empty module and extend importers: [] }); } @@ -2661,13 +2951,21 @@ function createEntry() { var importerModule = module.importers[i]; if (!importerModule.locked) { var importerIndex = indexOf.call(importerModule.dependencies, module); - importerModule.setters[importerIndex](exports); + var setter = importerModule.setters[importerIndex]; + if (setter) + setter(exports); } } module.locked = false; return value; - }, entry.name); + }, { id: entry.name }); + + if (typeof declaration == 'function') + declaration = { setters: [], execute: declaration }; + + // allowing undefined declaration was a mistake! To be deprecated. + declaration = declaration || { setters: [], execute: function() {} }; module.setters = declaration.setters; module.execute = declaration.execute; @@ -2736,7 +3034,7 @@ function createEntry() { else { if (entry.declarative) - ensureEvaluated(name, [], loader); + ensureEvaluated(name, entry, [], loader); else if (!entry.evaluated) linkDynamicModule(entry, loader); @@ -2777,24 +3075,29 @@ function createEntry() { continue; return getModule(entry.normalizedDeps[i], loader); } - throw new Error('Module ' + name + ' not declared as a dependency.'); + // try and normalize the dependency to see if we have another form + var nameNormalized = loader.normalizeSync(name, entry.name); + if (indexOf.call(entry.normalizedDeps, nameNormalized) != -1) + return getModule(nameNormalized, loader); + + throw new Error('Module ' + name + ' not declared as a dependency of ' + entry.name); }, exports, module); - if (output) + if (output !== undefined) module.exports = output; // create the esModule object, which allows ES6 named imports of dynamics exports = module.exports; // __esModule flag treats as already-named - if (exports && exports.__esModule) - entry.esModule = exports; + if (exports && (exports.__esModule || exports instanceof Module)) + entry.esModule = loader.newModule(exports); // set module as 'default' export, then fake named exports by iterating properties else if (entry.esmExports && exports !== __global) - entry.esModule = getESModule(exports); + entry.esModule = loader.newModule(getESModule(exports)); // just use the 'default' export else - entry.esModule = { 'default': exports }; + entry.esModule = loader.newModule({ 'default': exports, __useDefault: true }); } /* @@ -2806,9 +3109,7 @@ function createEntry() { * Then we evaluate the module itself depth-first left to right * execution to match ES6 modules */ - function ensureEvaluated(moduleName, seen, loader) { - var entry = loader.defined[moduleName]; - + function ensureEvaluated(moduleName, entry, seen, loader) { // if already seen, that means it's an already-evaluated non circular dependency if (!entry || entry.evaluated || !entry.declarative) return; @@ -2823,7 +3124,7 @@ function createEntry() { if (!loader.defined[depName]) loader.get(depName); else - ensureEvaluated(depName, seen, loader); + ensureEvaluated(depName, loader.defined[depName], seen, loader); } } @@ -2849,9 +3150,6 @@ function createEntry() { load.metadata.format = 'defined'; return ''; } - - if (load.metadata.format == 'register' && !load.metadata.authorization && load.metadata.scriptLoad !== false) - load.metadata.scriptLoad = true; load.metadata.deps = load.metadata.deps || []; @@ -2863,7 +3161,7 @@ function createEntry() { // we run the meta detection here (register is after meta) return function(load) { load.metadata.deps = load.metadata.deps || []; - return Promise.resolve(translate.call(this, load)).then(function(source) { + return Promise.resolve(translate.apply(this, arguments)).then(function(source) { // run detection for register format if (load.metadata.format == 'register' || !load.metadata.format && detectRegisterFormat(load.source)) load.metadata.format = 'register'; @@ -2872,6 +3170,37 @@ function createEntry() { }; }); + // implement a perforance shortpath for System.load with no deps + hook('load', function(doLoad) { + return function(normalized) { + var loader = this; + var entry = loader.defined[normalized]; + + if (!entry || entry.deps.length) + return doLoad.apply(this, arguments); + + entry.originalIndices = entry.normalizedDeps = []; + + // recursively ensure that the module and all its + // dependencies are linked (with dependency group handling) + link(normalized, entry, loader); + + // now handle dependency execution in correct order + ensureEvaluated(normalized, entry, [], loader); + if (!entry.esModule) + entry.esModule = loader.newModule(entry.module.exports); + + // remove from the registry + if (!loader.trace) + loader.defined[normalized] = undefined; + + // return the defined module object + loader.set(normalized, entry.esModule); + + return Promise.resolve(); + }; + }); + hook('instantiate', function(instantiate) { return function(load) { if (load.metadata.format == 'detect') @@ -2891,6 +3220,7 @@ function createEntry() { // don't support deps for ES modules if (!entry.declarative) entry.deps = entry.deps.concat(load.metadata.deps); + entry.deps = entry.deps.concat(load.metadata.deps); } // picked up already by an anonymous System.register script injection @@ -2949,31 +3279,57 @@ function createEntry() { execute: function() { // recursively ensure that the module and all its // dependencies are linked (with dependency group handling) - link(load.name, loader); + link(load.name, entry, loader); // now handle dependency execution in correct order - ensureEvaluated(load.name, [], loader); + ensureEvaluated(load.name, entry, [], loader); + + if (!entry.esModule) + entry.esModule = loader.newModule(entry.module.exports); // remove from the registry - loader.defined[load.name] = undefined; + if (!loader.trace) + loader.defined[load.name] = undefined; // return the defined module object - return loader.newModule(entry.declarative ? entry.module.exports : entry.esModule); + return entry.esModule; } }; }); }; }); })(); + + +function getGlobalValue(exports) { + if (typeof exports == 'string') + return readMemberExpression(exports, __global); + + if (!(exports instanceof Array)) + throw new Error('Global exports must be a string or array.'); + + var globalValue = {}; + var first = true; + for (var i = 0; i < exports.length; i++) { + var val = readMemberExpression(exports[i], __global); + if (first) { + globalValue['default'] = val; + first = false; + } + globalValue[exports[i].split('.').pop()] = val; + } + return globalValue; +} + hook('reduceRegister_', function(reduceRegister) { return function(load, register) { - if (register || !load.metadata.exports) + if (register || (!load.metadata.exports && !(isWorker && load.metadata.format == 'global'))) return reduceRegister.call(this, load, register); load.metadata.format = 'global'; var entry = load.metadata.entry = createEntry(); entry.deps = load.metadata.deps; - var globalValue = readMemberExpression(load.metadata.exports, __global); + var globalValue = getGlobalValue(load.metadata.exports); entry.execute = function() { return globalValue; }; @@ -2987,7 +3343,7 @@ hookConstructor(function(constructor) { var hasOwnProperty = Object.prototype.hasOwnProperty; - // bare minimum ignores for IE8 + // bare minimum ignores var ignoredGlobalProps = ['_g', 'sessionStorage', 'localStorage', 'clipboardData', 'frames', 'frameElement', 'external', 'mozAnimationStartTime', 'webkitStorageInfo', 'webkitIndexedDB', 'mozInnerScreenY', 'mozInnerScreenX']; @@ -3019,14 +3375,11 @@ hookConstructor(function(constructor) { } loader.set('@@global-helpers', loader.newModule({ - prepareGlobal: function(moduleName, exportName, globals) { + prepareGlobal: function(moduleName, exports, globals, encapsulate) { // disable module detection var curDefine = __global.define; __global.define = undefined; - __global.exports = undefined; - if (__global.module && __global.module.exports) - __global.module = undefined; // set globals var oldGlobals; @@ -3039,7 +3392,7 @@ hookConstructor(function(constructor) { } // store a complete copy of the global object in order to detect changes - if (!exportName) { + if (!exports) { globalSnapshot = {}; forEachGlobalValue(function(name, value) { @@ -3049,33 +3402,36 @@ hookConstructor(function(constructor) { // return function to retrieve global return function() { - var globalValue; + var globalValue = exports ? getGlobalValue(exports) : {}; - if (exportName) { - globalValue = readMemberExpression(exportName, __global); - } - else { - var singleGlobal; - var multipleExports; - var exports = {}; + var singleGlobal; + var multipleExports = !!exports; + if (!exports || encapsulate) forEachGlobalValue(function(name, value) { if (globalSnapshot[name] === value) return; if (typeof value == 'undefined') return; - exports[name] = value; - - if (typeof singleGlobal != 'undefined') { - if (!multipleExports && singleGlobal !== value) - multipleExports = true; - } - else { - singleGlobal = value; + + // allow global encapsulation where globals are removed + if (encapsulate) + __global[name] = undefined; + + if (!exports) { + globalValue[name] = value; + + if (typeof singleGlobal != 'undefined') { + if (!multipleExports && singleGlobal !== value) + multipleExports = true; + } + else { + singleGlobal = value; + } } }); - globalValue = multipleExports ? exports : singleGlobal; - } + + globalValue = multipleExports ? globalValue : singleGlobal; // revert globals if (oldGlobals) { @@ -3098,7 +3454,20 @@ hookConstructor(function(constructor) { if (typeof window != 'undefined' && typeof document != 'undefined' && window.location) var windowOrigin = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : ''); + function stripOrigin(path) { + if (path.substr(0, 8) == 'file:///') + return path.substr(7 + !!isWindows); + + if (windowOrigin && path.substr(0, windowOrigin.length) == windowOrigin) + return path.substr(windowOrigin.length); + + return path; + } + loader.set('@@cjs-helpers', loader.newModule({ + requireResolve: function(request, parentId) { + return stripOrigin(loader.normalizeSync(request, parentId)); + }, getPathVars: function(moduleId) { // remove any plugin syntax var pluginIndex = moduleId.lastIndexOf('!'); @@ -3112,24 +3481,9 @@ hookConstructor(function(constructor) { dirname.pop(); dirname = dirname.join('/'); - if (filename.substr(0, 8) == 'file:///') { - filename = filename.substr(7); - dirname = dirname.substr(7); - - // on windows remove leading '/' - if (isWindows) { - filename = filename.substr(1); - dirname = dirname.substr(1); - } - } - else if (windowOrigin && filename.substr(0, windowOrigin.length) === windowOrigin) { - filename = filename.substr(windowOrigin.length); - dirname = dirname.substr(windowOrigin.length); - } - return { - filename: filename, - dirname: dirname + filename: stripOrigin(filename), + dirname: stripOrigin(dirname) }; } })) @@ -3139,6 +3493,16 @@ hookConstructor(function(constructor) { * Separated into its own file as this is the part needed for full AMD support in SFX builds * NB since implementations have now diverged this can be merged back with amd.js */ + +hook('fetch', function(fetch) { + return function(load) { + // script load implies define global leak + if (load.metadata.scriptLoad && isBrowser) + __global.define = this.amdDefine; + return fetch.call(this, load); + }; +}); + hookConstructor(function(constructor) { return function() { var loader = this; @@ -3199,9 +3563,13 @@ hookConstructor(function(constructor) { // commonjs require else if (typeof names == 'string') { - var module = loader.get(loader.decanonicalize(names, referer)); + var defaultJSExtension = loader.defaultJSExtensions && names.substr(names.length - 3, 3) != '.js'; + var normalized = loader.decanonicalize(names, referer); + if (defaultJSExtension && normalized.substr(normalized.length - 3, 3) == '.js') + normalized = normalized.substr(0, normalized.length - 3); + var module = loader.get(normalized); if (!module) - throw new Error('Module not already loaded loading "' + names + '" from "' + referer + '".'); + throw new Error('Module not already loaded loading "' + names + '" as ' + normalized + (referer ? ' from "' + referer + '".' : '.')); return module.__useDefault ? module['default'] : module; } @@ -3318,17 +3686,20 @@ hookConstructor(function(constructor) { var curMeta = load && load.metadata; var entry = register.entry; - if (curMeta) - curMeta.format = 'amd'; + if (curMeta) { + if (!curMeta.format || curMeta.format == 'detect') + curMeta.format = 'amd'; + else if (!entry.name && curMeta.format != 'amd') + throw new Error('AMD define called while executing ' + curMeta.format + ' module ' + load.name); + } // anonymous define if (!entry.name) { if (!curMeta) throw new TypeError('Unexpected anonymous AMD define.'); - // already defined anonymously -> throw - if (curMeta.entry) - throw new TypeError('Multiple defines for anonymous module ' + load.name); + if (curMeta.entry && !curMeta.entry.name) + throw new Error('Multiple anonymous defines in module ' + load.name); curMeta.entry = entry; } @@ -3344,7 +3715,7 @@ hookConstructor(function(constructor) { if (curMeta) { if (!curMeta.entry && !curMeta.bundle) curMeta.entry = entry; - else + else if (curMeta.entry && curMeta.entry.name && curMeta.entry.name != load.name) curMeta.entry = undefined; // note this is now a bundle @@ -3358,29 +3729,6 @@ hookConstructor(function(constructor) { }; }); - // adds define as a global (potentially just temporarily) - function createDefine() { - // ensure no NodeJS environment detection - var oldModule = __global.module; - var oldExports = __global.exports; - var oldDefine = __global.define; - - __global.module = undefined; - __global.exports = undefined; - __global.define = define; - - return function() { - __global.define = oldDefine; - __global.module = oldModule; - __global.exports = oldExports; - }; - } - - loader.set('@@amd-helpers', loader.newModule({ - createDefine: createDefine, - require: require, - define: define - })); loader.amdDefine = define; loader.amdRequire = require; }; @@ -3459,8 +3807,8 @@ hookConstructor(function(constructor) { return function(name, parentName, isPlugin) { var loader = this; - parentName = getParentName(this, parentName); var parsed = parsePlugin(loader, name); + parentName = getParentName(this, parentName); if (!parsed) return normalizeSync.call(this, name, parentName, isPlugin); @@ -3488,7 +3836,7 @@ hookConstructor(function(constructor) { return Promise.all([ loader.normalize(parsed.argument, parentName, true), - loader.normalize(parsed.plugin, parentName, true) + loader.normalize(parsed.plugin, parentName, false) ]) .then(function(normalized) { return combinePluginParts(loader, normalized[0], normalized[1], checkDefaultExtension(loader, parsed.argument)); @@ -3519,11 +3867,27 @@ hookConstructor(function(constructor) { return locate.call(loader, load) .then(function(address) { + if (pluginSyntaxIndex != -1 || !load.metadata.loader) + return address; + + // normalize plugin relative to parent in locate here when + // using plugin via loader metadata + return (loader.pluginLoader || loader).normalize(load.metadata.loader, load.name) + .then(function(loaderNormalized) { + load.metadata.loader = loaderNormalized; + return address; + }); + }) + .then(function(address) { var plugin = load.metadata.loader; if (!plugin) return address; + // don't allow a plugin to load itself + if (load.name == plugin) + throw new Error('Plugin ' + plugin + ' cannot load itself, make sure it is excluded from any wildcard meta configuration via a custom loader: false rule.'); + // only fetch the plugin itself if this name isn't defined if (loader.defined && loader.defined[name]) return address; @@ -3563,41 +3927,41 @@ hookConstructor(function(constructor) { hook('translate', function(translate) { return function(load) { - - /* - * Source map sanitization for load.metadata.sourceMap - * Used to set browser and build-level source maps for - * translated sources in a general way. - * - * This isn't plugin-specific, but can't go anywhere else for now - * As it is post-translate - */ - var sourceMap = load.metadata.sourceMap; - - // if an object not a JSON string do sanitizing - if (sourceMap && typeof sourceMap == 'object') { - var originalName = load.name.split('!')[0]; - - // force set the filename of the original file - sourceMap.file = originalName + '!transpiled'; - - // force set the sources list if only one source - if (!sourceMap.sources || sourceMap.sources.length == 1) - sourceMap.sources = [originalName]; - load.metadata.sourceMap = JSON.stringify(sourceMap); - } - var loader = this; + var args = arguments; if (load.metadata.loaderModule && load.metadata.loaderModule.translate && load.metadata.format != 'defined') { - return Promise.resolve(load.metadata.loaderModule.translate.call(loader, load)).then(function(result) { - // NB we should probably enforce a string output + return Promise.resolve(load.metadata.loaderModule.translate.apply(loader, args)).then(function(result) { + var sourceMap = load.metadata.sourceMap; + + // sanitize sourceMap if an object not a JSON string + if (sourceMap) { + if (typeof sourceMap != 'object') + throw new Error('load.metadata.sourceMap must be set to an object.'); + + var originalName = load.address.split('!')[0]; + + // force set the filename of the original file + if (!sourceMap.file || sourceMap.file == load.address) + sourceMap.file = originalName + '!transpiled'; + + // force set the sources list if only one source + if (!sourceMap.sources || sourceMap.sources.length <= 1 && (!sourceMap.sources[0] || sourceMap.sources[0] == load.address)) + sourceMap.sources = [originalName]; + } + + // if running on file:/// URLs, sourcesContent is necessary + // load.metadata.sourceMap.sourcesContent = [load.source]; + if (typeof result == 'string') load.source = result; - return translate.call(loader, load); + else + warn.call(this, 'Plugin ' + load.metadata.loader + ' should return the source in translate, instead of setting load.source directly. This support will be deprecated.'); + + return translate.apply(loader, args); }); } else { - return translate.call(loader, load); + return translate.apply(loader, args); } }; }); @@ -3605,9 +3969,18 @@ hookConstructor(function(constructor) { hook('instantiate', function(instantiate) { return function(load) { var loader = this; + var calledInstantiate = false; if (load.metadata.loaderModule && load.metadata.loaderModule.instantiate && !loader.builder && load.metadata.format != 'defined') - return Promise.resolve(load.metadata.loaderModule.instantiate.call(loader, load)).then(function(result) { + return Promise.resolve(load.metadata.loaderModule.instantiate.call(loader, load, function(load) { + if (calledInstantiate) + throw new Error('Instantiate must only be called once.'); + calledInstantiate = true; + return instantiate.call(loader, load); + })).then(function(result) { + if (calledInstantiate) + return result; + load.metadata.entry = createEntry(); load.metadata.entry.execute = function() { return result; @@ -3657,10 +4030,12 @@ hookConstructor(function(constructor) { * * These conditions can also be negated via: * - * import 'es5-shim#?~./conditions.js|es6' + * import 'es5-shim#?./conditions.js|~es6' * */ + var sysConditions = ['browser', 'node', 'dev', 'build', 'production', 'default']; + function parseCondition(condition) { var conditionExport, conditionModule, negation; @@ -3668,33 +4043,49 @@ hookConstructor(function(constructor) { var conditionExportIndex = condition.lastIndexOf('|'); if (conditionExportIndex != -1) { conditionExport = condition.substr(conditionExportIndex + 1); - conditionModule = condition.substr(negation, conditionExportIndex - negation) || '@system-env'; + conditionModule = condition.substr(negation, conditionExportIndex - negation); + + if (negation) + warn.call(this, 'Condition negation form "' + condition + '" is deprecated for "' + conditionModule + '|~' + conditionExport + '"'); + + if (conditionExport[0] == '~') { + negation = true; + conditionExport = conditionExport.substr(1); + } } else { - conditionExport = null; + conditionExport = 'default'; conditionModule = condition.substr(negation); + if (sysConditions.indexOf(conditionModule) != -1) { + conditionExport = conditionModule; + conditionModule = null; + } } return { - module: conditionModule, + module: conditionModule || '@system-env', prop: conditionExport, negate: negation }; } function serializeCondition(conditionObj) { - return (conditionObj.negate ? '~' : '') + conditionObj.module + (conditionObj.prop ? '|' + conditionObj.prop : ''); + return conditionObj.module + '|' + (conditionObj.negate ? '~' : '') + conditionObj.prop; } function resolveCondition(conditionObj, parentName, bool) { - return this['import'](conditionObj.module, parentName) - .then(function(m) { - if (conditionObj.prop) - m = readMemberExpression(conditionObj.prop, m); - else if (typeof m == 'object' && m + '' == 'Module') - m = m['default']; - - return conditionObj.negate ? !m : m; + var self = this; + return this.normalize(conditionObj.module, parentName) + .then(function(normalizedCondition) { + return self.load(normalizedCondition) + .then(function(q) { + var m = readMemberExpression(conditionObj.prop, self.get(normalizedCondition)); + + if (bool && typeof m != 'boolean') + throw new TypeError('Condition ' + serializeCondition(conditionObj) + ' did not resolve to a boolean.'); + + return conditionObj.negate ? !m : m; + }); }); } @@ -3706,7 +4097,7 @@ hookConstructor(function(constructor) { if (!conditionalMatch) return Promise.resolve(name); - var conditionObj = parseCondition(conditionalMatch[0].substr(2, conditionalMatch[0].length - 3)); + var conditionObj = parseCondition.call(this, conditionalMatch[0].substr(2, conditionalMatch[0].length - 3)); // in builds, return normalized conditional if (this.builder) @@ -3735,7 +4126,7 @@ hookConstructor(function(constructor) { if (booleanIndex == -1) return Promise.resolve(name); - var conditionObj = parseCondition(name.substr(booleanIndex + 2)); + var conditionObj = parseCondition.call(this, name.substr(booleanIndex + 2)); // in builds, return normalized conditional if (this.builder) @@ -3753,11 +4144,11 @@ hookConstructor(function(constructor) { // normalizeSync does not parse conditionals at all although it could hook('normalize', function(normalize) { - return function(name, parentName, parentAddress) { + return function(name, parentName, skipExt) { var loader = this; return booleanConditional.call(loader, name, parentName) .then(function(name) { - return normalize.call(loader, name, parentName, parentAddress); + return normalize.call(loader, name, parentName, skipExt); }) .then(function(normalized) { return interpolateConditional.call(loader, normalized, parentName); @@ -3904,6 +4295,12 @@ hookConstructor(function(constructor) { hook('translate', function(translate) { return function(load) { + // shortpath for bundled + if (load.metadata.format == 'defined') { + load.metadata.deps = load.metadata.deps || []; + return Promise.resolve(load.source); + } + // NB meta will be post-translate pending transpiler conversion to plugins var meta = load.source.match(metaRegEx); if (meta) { @@ -3946,7 +4343,7 @@ hookConstructor(function(constructor) { } } - return translate.call(this, load); + return translate.apply(this, arguments); }; }); })(); @@ -4074,10 +4471,7 @@ hookConstructor(function(constructor) { hookConstructor(function(constructor) { return function() { constructor.apply(this, arguments); - - // prepare amd define - if (this.has('@@amd-helpers')) - this.get('@@amd-helpers').createDefine(); + __global.define = this.amdDefine; }; }); @@ -4089,40 +4483,24 @@ hook('fetch', function(fetch) { });System = new SystemJSLoader(); __global.SystemJS = System; -System.version = '0.19.17 CSP'; - // -- exporting -- - - if (typeof exports === 'object') - module.exports = Loader; - - __global.Reflect = __global.Reflect || {}; - __global.Reflect.Loader = __global.Reflect.Loader || Loader; - __global.Reflect.global = __global.Reflect.global || __global; - __global.LoaderPolyfill = Loader; - - if (!System) { - System = new SystemLoader(); - System.constructor = SystemLoader; - } - - if (typeof exports === 'object') +System.version = '0.19.39 CSP'; + if (typeof module == 'object' && module.exports && typeof exports == 'object') module.exports = System; __global.System = System; })(typeof self != 'undefined' ? self : global);} -// auto-load Promise and URL polyfills if needed in the browser -try { - var hasURL = typeof URLPolyfill != 'undefined' || new URL('test:///').protocol == 'test:'; -} -catch(e) {} +// auto-load Promise polyfill if needed in the browser +var doPolyfill = typeof Promise === 'undefined'; -if (typeof Promise === 'undefined' || !hasURL) { - // document.write - if (typeof document !== 'undefined') { - var scripts = document.getElementsByTagName('script'); - $__curScript = scripts[scripts.length - 1]; +// document.write +if (typeof document !== 'undefined') { + var scripts = document.getElementsByTagName('script'); + $__curScript = scripts[scripts.length - 1]; + if (document.currentScript && ($__curScript.defer || $__curScript.async)) + $__curScript = document.currentScript; + if (doPolyfill) { var curPath = $__curScript.src; var basePath = curPath.substr(0, curPath.lastIndexOf('/') + 1); window.systemJSBootstrap = bootstrap; @@ -4130,24 +4508,27 @@ if (typeof Promise === 'undefined' || !hasURL) { '<' + 'script type="text/javascript" src="' + basePath + 'system-polyfills.js">' + '<' + '/script>' ); } - // importScripts - else if (typeof importScripts !== 'undefined') { - var basePath = ''; - try { - throw new Error('_'); - } catch (e) { - e.stack.replace(/(?:at|@).*(http.+):[\d]+:[\d]+/, function(m, url) { - basePath = url.replace(/\/[^\/]*$/, '/'); - }); - } - importScripts(basePath + 'system-polyfills.js'); - bootstrap(); - } else { bootstrap(); } } +// importScripts +else if (typeof importScripts !== 'undefined') { + var basePath = ''; + try { + throw new Error('_'); + } catch (e) { + e.stack.replace(/(?:at|@).*(http.+):[\d]+:[\d]+/, function(m, url) { + $__curScript = { src: url }; + basePath = url.replace(/\/[^\/]*$/, '/'); + }); + } + if (doPolyfill) + importScripts(basePath + 'system-polyfills.js'); + bootstrap(); +} else { + $__curScript = typeof __filename != 'undefined' ? { src: __filename } : null; bootstrap(); } diff --git a/lib/wallet/chromeBadge.ts b/lib/wallet/chromeBadge.ts index 6586f7e6e..df12fba83 100644 --- a/lib/wallet/chromeBadge.ts +++ b/lib/wallet/chromeBadge.ts @@ -86,6 +86,9 @@ export class ChromeBadge implements Badge { constructor(window?: Window) { // Allow injecting another window for testing let bg = window || chrome.extension.getBackgroundPage(); + if (!bg) { + throw Error("no window available"); + } this.canvas = bg.document.createElement("canvas"); // Note: changing the width here means changing the font // size in draw() as well! @@ -221,4 +224,4 @@ export class ChromeBadge implements Badge { stopBusy() { this.isBusy = false; } -}
\ No newline at end of file +} diff --git a/lib/wallet/wallet.ts b/lib/wallet/wallet.ts index 32b85e7b0..ffd57e201 100644 --- a/lib/wallet/wallet.ts +++ b/lib/wallet/wallet.ts @@ -612,8 +612,7 @@ export class Wallet { * First fetch information requred to withdraw from the reserve, * then deplete the reserve, withdrawing coins until it is empty. */ - private processReserve(reserveRecord: any): void { - let retryDelayMs = 100; + private processReserve(reserveRecord: any, retryDelayMs: number = 250): void { const opId = "reserve-" + reserveRecord.reserve_pub; this.startOperation(opId); this.updateExchangeFromUrl(reserveRecord.exchange_base_url) @@ -633,11 +632,10 @@ export class Wallet { return Query(this.db).put("history", depleted).finish(); }) .catch((e) => { - console.error("Failed to deplete reserve"); - console.error(e); - setTimeout(() => this.processReserve(reserveRecord), retryDelayMs); - // exponential backoff truncated at one minute - retryDelayMs = Math.min(retryDelayMs * 2, 1000 * 60); + // random, exponential backoff truncated at 3 minutes + let nextDelay = Math.min(2 * retryDelayMs + retryDelayMs * Math.random(), 3000 * 60); + console.warn(`Failed to deplete reserve, trying again in ${retryDelayMs} ms`); + setTimeout(() => this.processReserve(reserveRecord, nextDelay), retryDelayMs); }); } |