systemjs/lib/extension-map.js
2014-05-05 15:56:44 -07:00

115 lines
3.3 KiB
JavaScript

/*
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 map(loader) {
loader.map = loader.map || {};
// return the number of prefix parts (separated by '/') matching the name
// eg prefixMatchLength('jquery/some/thing', 'jquery') -> 1
function prefixMatchLength(name, prefix) {
var prefixParts = prefix.split('/');
var nameParts = name.split('/');
if (prefixParts.length > nameParts.length)
return 0;
for (var i = 0; i < prefixParts.length; i++)
if (nameParts[i] != prefixParts[i])
return 0;
return prefixParts.length;
}
// 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 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 (prefixMatchLength(parentName, p) <= curParentMatchLength)
continue;
for (var q in curMap) {
// most specific name match wins
if (prefixMatchLength(name, q) <= curMatchLength)
continue;
curMatch = q;
curMatchLength = q.split('/').length;
curParent = p;
curParentMatchLength = p.split('/').length;
}
}
}
// if we found a contextual match, apply it now
if (curMatch) {
nameParts = name.split('/');
subPath = nameParts.splice(curMatchLength, nameParts.length - curMatchLength).join('/');
name = loader.map[curParent][curMatch] + (subPath ? '/' + subPath : '');
curMatchLength = 0;
}
// now do the global map
for (var p in loader.map) {
var curMap = loader.map[p];
if (typeof curMap != 'string')
continue;
if (prefixMatchLength(name, p) <= curMatchLength)
continue;
curMatch = p;
curMatchLength = p.split('/').length;
}
// return a match if any
if (!curMatchLength)
return name;
nameParts = name.split('/');
subPath = nameParts.splice(curMatchLength, nameParts.length - curMatchLength).join('/');
return loader.map[curMatch] + (subPath ? '/' + subPath : '');
}
var loaderNormalize = loader.normalize;
loader.normalize = function(name, parentName, parentAddress) {
var loader = this;
if (!loader.map)
loader.map = {};
return Promise.resolve(loaderNormalize.call(loader, name, parentName, parentAddress))
.then(function(name) {
return applyMap(name, parentName, loader);
});
}
}