269 lines
8.2 KiB
JavaScript
269 lines
8.2 KiB
JavaScript
|
// SystemJS Loader Class and Extension helpers
|
||
|
function SystemJSLoader() {
|
||
|
Loader.call(this);
|
||
|
|
||
|
this.paths = {};
|
||
|
this._loader.paths = {};
|
||
|
|
||
|
systemJSConstructor.call(this);
|
||
|
}
|
||
|
|
||
|
// inline Object.create-style class extension
|
||
|
function SystemProto() {};
|
||
|
SystemProto.prototype = Loader.prototype;
|
||
|
SystemJSLoader.prototype = new SystemProto();
|
||
|
SystemJSLoader.prototype.constructor = SystemJSLoader;
|
||
|
|
||
|
var systemJSConstructor;
|
||
|
|
||
|
function hook(name, hook) {
|
||
|
SystemJSLoader.prototype[name] = hook(SystemJSLoader.prototype[name] || function() {});
|
||
|
}
|
||
|
function hookConstructor(hook) {
|
||
|
systemJSConstructor = hook(systemJSConstructor || function() {});
|
||
|
}
|
||
|
|
||
|
|
||
|
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(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) {
|
||
|
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 (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] == '/' || 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] &&
|
||
|
name.substr(name.length - pathParts[1].length) == pathParts[1]) {
|
||
|
maxWildcardPrefixLen = wildcardPrefixLen;
|
||
|
pathMatch = p;
|
||
|
wildcard = name.substr(pathParts[0].length, name.length - pathParts[1].length - pathParts[0].length);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var outPath = paths[pathMatch];
|
||
|
if (typeof wildcard == 'string')
|
||
|
outPath = outPath.replace('*', wildcard);
|
||
|
|
||
|
return outPath;
|
||
|
}
|
||
|
|
||
|
function dedupe(deps) {
|
||
|
var newDeps = [];
|
||
|
for (var i = 0, l = deps.length; i < l; i++)
|
||
|
if (indexOf.call(newDeps, deps[i]) == -1)
|
||
|
newDeps.push(deps[i])
|
||
|
return newDeps;
|
||
|
}
|
||
|
|
||
|
function group(deps) {
|
||
|
var names = [];
|
||
|
var indices = [];
|
||
|
for (var i = 0, l = deps.length; i < l; i++) {
|
||
|
var index = indexOf.call(names, deps[i]);
|
||
|
if (index === -1) {
|
||
|
names.push(deps[i]);
|
||
|
indices.push([i]);
|
||
|
}
|
||
|
else {
|
||
|
indices[index].push(i);
|
||
|
}
|
||
|
}
|
||
|
return { names: names, indices: indices };
|
||
|
}
|
||
|
|
||
|
var getOwnPropertyDescriptor = true;
|
||
|
try {
|
||
|
Object.getOwnPropertyDescriptor({ a: 0 }, 'a');
|
||
|
}
|
||
|
catch(e) {
|
||
|
getOwnPropertyDescriptor = false;
|
||
|
}
|
||
|
|
||
|
// converts any module.exports object into an object ready for SystemJS.newModule
|
||
|
function getESModule(exports) {
|
||
|
var esModule = {};
|
||
|
// don't trigger getters/setters in environments that support them
|
||
|
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', {
|
||
|
value: true
|
||
|
});
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
// 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;
|
||
|
else if (val instanceof Array && a[p] instanceof Array)
|
||
|
a[p] = [].concat(prepend ? val : a[p]).concat(prepend ? a[p] : val);
|
||
|
else if (typeof val == 'object' && val !== null && typeof a[p] == 'object')
|
||
|
a[p] = extend(extend({}, a[p]), val, prepend);
|
||
|
else if (!prepend)
|
||
|
a[p] = val;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
}
|