/* SystemJS map support Provides map configuration through System.map['jquery'] = 'some/module/map' As well as contextual map config through System.map['bootstrap'] = { jquery: 'some/module/map2' } Note that this applies for subpaths, just like RequireJS jquery -> 'some/module/map' jquery/path -> 'some/module/map/path' bootstrap -> 'bootstrap' Inside any module name of the form 'bootstrap' or 'bootstrap/*' jquery -> 'some/module/map2' jquery/p -> 'some/module/map2/p' Maps are carefully applied from most specific contextual map, to least specific global map */ (function() { hookConstructor(function(constructor) { return function() { constructor.call(this); this.map = {}; }; }); // return if prefix parts (separated by '/') match the name // eg prefixMatch('jquery/some/thing', 'jquery') -> true // prefixMatch('jqueryhere/', 'jquery') -> false function prefixMatch(name, prefix) { if (name.length < prefix.length) return false; if (name.substr(0, prefix.length) != prefix) return false; if (name[prefix.length] && name[prefix.length] != '/') return false; return true; } // get the depth of a given path // eg pathLen('some/name') -> 2 function pathLen(name) { var len = 1; for (var i = 0, l = name.length; i < l; i++) if (name[i] === '/') len++; return len; } function doMap(name, matchLen, map) { return map + name.substr(matchLen); } // given a relative-resolved module name and normalized parent name, // apply the map configuration function applyMap(name, parentName, loader) { var curMatch, curMatchLength = 0; var curParent, curParentMatchLength = 0; var tmpParentLength, tmpPrefixLength; var subPath; var nameParts; // first find most specific contextual match if (parentName) { for (var p in loader.map) { var curMap = loader.map[p]; if (typeof curMap != 'object') continue; // most specific parent match wins first if (!prefixMatch(parentName, p)) continue; tmpParentLength = pathLen(p); if (tmpParentLength <= curParentMatchLength) continue; for (var q in curMap) { // most specific name match wins if (!prefixMatch(name, q)) continue; tmpPrefixLength = pathLen(q); if (tmpPrefixLength <= curMatchLength) continue; curMatch = q; curMatchLength = tmpPrefixLength; curParent = p; curParentMatchLength = tmpParentLength; } } } // if we found a contextual match, apply it now if (curMatch) return doMap(name, curMatch.length, loader.map[curParent][curMatch]); // now do the global map for (var p in loader.map) { var curMap = loader.map[p]; if (typeof curMap != 'string') continue; if (!prefixMatch(name, p)) continue; var tmpPrefixLength = pathLen(p); if (tmpPrefixLength <= curMatchLength) continue; curMatch = p; curMatchLength = tmpPrefixLength; } if (curMatch) return doMap(name, curMatch.length, loader.map[curMatch]); return name; } hook('normalize', function(normalize) { return function(name, parentName, parentAddress) { var loader = this; return Promise.resolve(normalize.call(loader, name, parentName, parentAddress)) .then(function(name) { return applyMap(name, parentName, loader); }); }; }); })();