var absURLRegEx = /^[^\/]+:\/\//; function readMemberExpression(p, value) { var pParts = p.split('.'); while (pParts.length) value = value[pParts.shift()]; return value; } var baseURLCache = {}; function getBaseURLObj() { if (baseURLCache[this.baseURL]) return baseURLCache[this.baseURL]; // normalize baseURL if not already if (this.baseURL[this.baseURL.length - 1] != '/') this.baseURL += '/'; var baseURL = new URL(this.baseURL, baseURI); this.baseURL = baseURL.href; return (baseURLCache[this.baseURL] = baseURL); } function getMapMatch(map, name) { var bestMatch, bestMatchLength = 0; for (var p in map) { if (name.substr(0, p.length) == p && (name.length == p.length || name[p.length] == '/')) { var curMatchLength = p.split('/').length; if (curMatchLength <= bestMatchLength) continue; bestMatch = p; bestMatchLength = curMatchLength; } } return bestMatch; } function setProduction(isProduction) { this.set('@system-env', this.newModule({ browser: isBrowser, node: !!this._nodeRequire, production: isProduction, '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); // support map and paths this.map = {}; this.paths = {}; // global behaviour flags this.warnings = false; this.defaultJSExtensions = false; 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' }; // support the empty module, as a concept this.set('@empty', this.newModule({})); setProduction.call(this, false); }; }); // include the node require since we're overriding it 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 If a name is relative, we apply URL normalization to the page If a name is an absolute URL, we leave it as-is Plain names (neither of the above) run through the map and paths normalization phases. The paths normalization phase applies last (paths extension), which defines the `decanonicalize` function and normalizes everything into a URL. */ function isPlain(name) { return (name[0] != '.' || (!!name[1] && name[1] != '/' && name[1] != '.')) && name[0] != '/' && !name.match(absURLRegEx); } function urlResolve(name, parent) { if (parent) parent = parent.replace(/#/g, '%05'); return new URL(name, parent || baseURIObj).href.replace(/%05/g, '#'); } // only applies to plain names function baseURLResolve(loader, name) { return new URL(name, getBaseURLObj.call(loader)).href; } function coreResolve(name, parentName) { // standard URL resolution if (!isPlain(name)) return urlResolve(name, parentName); // plain names not starting with './', '://' and '/' go through custom resolution var mapMatch = getMapMatch(this.map, name); if (mapMatch) { name = this.map[mapMatch] + name.substr(mapMatch.length); if (!isPlain(name)) return urlResolve(name); } if (this.has(name)) return name; // 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))))); return name; } var pathed = applyPaths(this.paths, name); if (pathed && !isPlain(pathed)) return urlResolve(pathed); return baseURLResolve(this, pathed || name); } hook('normalize', function(normalize) { return function(name, parentName, skipExt) { var resolved = coreResolve.call(this, name, parentName); if (!skipExt && this.defaultJSExtensions && resolved.substr(resolved.length - 3, 3) != '.js' && !isPlain(resolved)) resolved += '.js'; return resolved; }; }); // percent encode just '#' in urls if using HTTP requests var httpRequest = typeof XMLHttpRequest != 'undefined'; hook('locate', function(locate) { return function(load) { return Promise.resolve(locate.call(this, load)) .then(function(address) { if (httpRequest) return address.replace(/#/g, '%23'); return address; }); }; }); /* * Fetch with authorization */ hook('fetch', function() { return function(load) { return new Promise(function(resolve, reject) { fetchTextFromURL(load.address, load.metadata.authorization, resolve, reject); }); }; }); /* __useDefault When a module object looks like: newModule( __useDefault: true, default: 'some-module' }) Then importing that module provides the 'some-module' result directly instead of the full module. Useful for eg module.exports = function() {} */ hook('import', function(systemImport) { return function(name, parentName, parentAddress) { if (parentName && parentName.name) warn.call(this, 'SystemJS.import(name, { name: parentName }) is deprecated for SystemJS.import(name, parentName), while importing ' + name + ' from ' + parentName.name); return systemImport.call(this, name, parentName, parentAddress).then(function(module) { return module.__useDefault ? module['default'] : module; }); }; }); /* * Allow format: 'detect' meta to enable format detection */ hook('translate', function(systemTranslate) { return function(load) { if (load.metadata.format == 'detect') load.metadata.format = undefined; return systemTranslate.call(this, load); }; }); /* * JSON format support * * Supports loading JSON files as a module format itself * * Usage: * * SystemJS.config({ * meta: { * '*.json': { format: 'json' } * } * }); * * Module is returned as if written: * * export default {JSON} * * No named exports are provided * * Files ending in ".json" are treated as json automatically by SystemJS */ hook('instantiate', function(instantiate) { return function(load) { if (load.metadata.format == 'json' && !this.builder) { var entry = load.metadata.entry = createEntry(); entry.deps = []; entry.execute = function() { try { return JSON.parse(load.source); } catch(e) { throw new Error("Invalid JSON file " + load.name); } }; } }; }) /* Extend config merging one deep only loader.config({ some: 'random', config: 'here', deep: { config: { too: 'too' } } }); <=> loader.some = 'random'; loader.config = 'here' loader.deep = loader.deep || {}; loader.deep.config = { too: 'too' }; Normalizes meta and package configs allowing for: SystemJS.config({ meta: { './index.js': {} } }); To become SystemJS.meta['https://thissite.com/index.js'] = {}; For easy normalization canonicalization with latest URL support. */ SystemJSLoader.prototype.env = 'development'; var curCurScript; SystemJSLoader.prototype.config = function(cfg) { 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; // transpiler deprecation path 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) if (hasOwnProperty.call(obj, 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.'); loader.baseURL = cfg.baseURL; // sanitize baseURL getBaseURLObj.call(loader); } if (cfg.defaultJSExtensions) { loader.defaultJSExtensions = cfg.defaultJSExtensions; warn.call(loader, 'The defaultJSExtensions configuration option is deprecated, use packages configuration instead.'); } 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) { var v = cfg.map[p]; // object map backwards-compat into packages configuration if (typeof v !== 'string') { objMaps += (objMaps.length ? ', ' : '') + '"' + p + '"'; 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 = ''; for (var pkg in loader.packages) { if (prop.substr(0, pkg.length) == pkg && (!prop[pkg.length] || prop[pkg.length] == '/') && pkgMatch.split('/').length < pkg.split('/').length) pkgMatch = pkg; } if (pkgMatch && loader.packages[pkgMatch].main) prop = prop.substr(0, prop.length - loader.packages[pkgMatch].main.length - 1); var pkg = loader.packages[prop] = loader.packages[prop] || {}; pkg.map = v; } else { loader.map[p] = v; } } if (objMaps) warn.call(loader, 'The map configuration for ' + objMaps + ' uses object submaps, which is deprecated in global map.\nUpdate this to use package contextual map with configs like SystemJS.config({ packages: { "' + p + '": { map: {...} } } }).'); } if (cfg.packageConfigPaths) { var packageConfigPaths = []; for (var i = 0; i < cfg.packageConfigPaths.length; i++) { var path = cfg.packageConfigPaths[i]; var packageLength = Math.max(path.lastIndexOf('*') + 1, path.lastIndexOf('/')); var defaultJSExtension = loader.defaultJSExtensions && path.substr(packageLength - 3, 3) != '.js'; var normalized = loader.decanonicalize(path.substr(0, packageLength)); if (defaultJSExtension && normalized.substr(normalized.length - 3, 3) == '.js') normalized = normalized.substr(0, normalized.length - 3); packageConfigPaths[i] = normalized + path.substr(packageLength); } loader.packageConfigPaths = packageConfigPaths; } if (cfg.bundles) { for (var p in cfg.bundles) { var bundle = []; 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; } } if (cfg.packages) { for (var p in cfg.packages) { if (p.match(/^([^\/]+:)?\/\/$/)) throw new TypeError('"' + p + '" is not a valid package name.'); var prop = coreResolve.call(loader, p); // allow trailing slash in packages if (prop[prop.length - 1] == '/') prop = prop.substr(0, prop.length - 1); loader.packages[prop] = loader.packages[prop] || {}; var pkg = cfg.packages[p]; // meta backwards compatibility if (pkg.modules) { warn.call(loader, 'Package ' + p + ' is configured with "modules", which is deprecated as it has been renamed to "meta".'); pkg.meta = pkg.modules; delete pkg.modules; } if (typeof pkg.main == 'object') { pkg.map = pkg.map || {}; pkg.map['./@main'] = pkg.main; pkg.main['default'] = pkg.main['default'] || './'; pkg.main = '@main'; } for (var q in pkg) if (indexOf.call(packageProperties, q) == -1) warn.call(loader, '"' + q + '" is not a valid package configuration option in package ' + p); extendMeta(loader.packages[prop], pkg); } } for (var c in cfg) { var v = cfg[c]; if (c == 'baseURL' || c == 'map' || c == 'packages' || c == 'bundles' || c == 'paths' || c == 'warnings' || c == 'packageConfigPaths' || c == 'loaderErrorStack') continue; if (typeof v != 'object' || v instanceof Array) { loader[c] = v; } else { loader[c] = loader[c] || {}; 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 (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'; 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] = v[p]; } else { loader[c][p] = v[p]; } } } } };