mirror of
https://github.com/systemjs/systemjs.git
synced 2026-01-25 14:57:38 +00:00
package config adjustments
This commit is contained in:
parent
f5791c79ca
commit
686f65cd35
4
Makefile
4
Makefile
@ -70,9 +70,9 @@ dist/system.src.js: lib/*.js $(ESML)/*.js
|
||||
lib/cjs.js \
|
||||
lib/amd.js \
|
||||
lib/map.js \
|
||||
lib/package.js \
|
||||
lib/plugins.js \
|
||||
lib/alias.js \
|
||||
lib/package.js \
|
||||
lib/bundles.js \
|
||||
lib/depCache.js \
|
||||
lib/conditionals.js \
|
||||
@ -97,9 +97,9 @@ dist/system-prod.src.js: lib/*.js $(ESML)/*.js
|
||||
lib/register.js \
|
||||
lib/global-helpers.js \
|
||||
lib/map.js \
|
||||
lib/package.js \
|
||||
lib/plugins.js \
|
||||
lib/alias.js \
|
||||
lib/package.js \
|
||||
lib/bundles.js \
|
||||
lib/depCache.js \
|
||||
lib/conditionals.js \
|
||||
|
||||
144
lib/map.js
144
lib/map.js
@ -4,134 +4,46 @@
|
||||
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
|
||||
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
|
||||
The most specific map is always taken, as longest path length
|
||||
*/
|
||||
(function() {
|
||||
hookConstructor(function(constructor) {
|
||||
return function() {
|
||||
constructor.call(this);
|
||||
this.map = {};
|
||||
};
|
||||
});
|
||||
|
||||
hookConstructor(function(constructor) {
|
||||
return function() {
|
||||
constructor.call(this);
|
||||
this.map = {};
|
||||
};
|
||||
});
|
||||
hook('normalize', function(normalize) {
|
||||
return function(name, parentName, parentAddress) {
|
||||
var loader = this;
|
||||
return Promise.resolve(normalize.call(loader, name, parentName, parentAddress))
|
||||
.then(function(name) {
|
||||
var bestMatch, bestMatchLength = 0;
|
||||
|
||||
// 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) {
|
||||
// now do the global map
|
||||
for (var p in loader.map) {
|
||||
var curMap = loader.map[p];
|
||||
if (typeof curMap != 'object')
|
||||
continue;
|
||||
if (typeof loader.map[p] != 'string')
|
||||
throw new TypeError('Map configuration no longer permits object submaps. Use package map instead (`System.packages[name].map`).');
|
||||
|
||||
// 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))
|
||||
if (name.substr(0, p.length) == p && (name.length == p.length || name[p.length] == '/')) {
|
||||
var curMatchLength = p.split('/').length;
|
||||
if (curMatchLength <= bestMatchLength)
|
||||
continue;
|
||||
tmpPrefixLength = pathLen(q);
|
||||
if (tmpPrefixLength <= curMatchLength)
|
||||
continue;
|
||||
|
||||
curMatch = q;
|
||||
curMatchLength = tmpPrefixLength;
|
||||
curParent = p;
|
||||
curParentMatchLength = tmpParentLength;
|
||||
bestMatch = p;
|
||||
bestMatchLength = curMatchLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we found a contextual match, apply it now
|
||||
if (curMatch)
|
||||
return doMap(name, curMatch.length, loader.map[curParent][curMatch]);
|
||||
if (bestMatch)
|
||||
return loader.map[bestMatch] + name.substr(bestMatch.length);
|
||||
|
||||
// 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);
|
||||
});
|
||||
};
|
||||
});
|
||||
})();
|
||||
return name;
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
230
lib/package.js
230
lib/package.js
@ -7,47 +7,35 @@
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* System.package('jquery', {
|
||||
* main: 'index.js',
|
||||
* format: 'amd',
|
||||
* defaultJSExtension: true,
|
||||
* modules: {
|
||||
* 'vendor/sizzle.js': {
|
||||
* format: 'global'
|
||||
* }
|
||||
* },
|
||||
* map: {
|
||||
* // map internal require('sizzle') to local require('./vendor/sizzle')
|
||||
* sizzle: './vendor/sizzle.js',
|
||||
*
|
||||
* // map external require of 'jquery/vendor/another.js' to 'another/index.js'
|
||||
* './vendor/another.js': 'another/index.js'
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* Is equivalent to:
|
||||
*
|
||||
* System.config({
|
||||
* meta: {
|
||||
* 'jquery/*': {
|
||||
* format: 'amd',
|
||||
* }
|
||||
* 'jquery/vendor/sizzle.js': {
|
||||
* format: 'global'
|
||||
* }
|
||||
* },
|
||||
* map: {
|
||||
* 'jquery/vendor/another.js': 'another/index.js'
|
||||
* packages: {
|
||||
* jquery: {
|
||||
* sizzle: 'jquery/vendor/sizzle.js'
|
||||
* main: 'index.js', // this main is actually set by default
|
||||
* format: 'amd',
|
||||
* defaultExtension: 'js',
|
||||
* meta: {
|
||||
* '*.ts': {
|
||||
* plugin: 'typescript'
|
||||
* },
|
||||
* 'vendor/sizzle.js': {
|
||||
* format: 'global'
|
||||
* }
|
||||
* },
|
||||
* map: {
|
||||
* // map internal require('sizzle') to local require('./vendor/sizzle')
|
||||
* sizzle: './vendor/sizzle.js',
|
||||
*
|
||||
* // map any internal or external require of 'jquery/vendor/another' to 'another/index.js'
|
||||
* './vendor/another': 'another/index.js'
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* With normalization hooks providing main and defaultExtension support
|
||||
* so that:
|
||||
* import 'jquery' => import 'jquery/index.js'
|
||||
* import 'jquery/module' => import 'jquery/module.js'
|
||||
* Then:
|
||||
* import 'jquery' -> jquery/index.js
|
||||
* import 'jquery/submodule' -> jquery/submodule.js
|
||||
* import 'jquery/vendor/another' -> jquery/another/index.js
|
||||
*
|
||||
* In addition, the following meta properties will be allowed to be package
|
||||
* -relative as well in the package meta config:
|
||||
@ -61,86 +49,136 @@
|
||||
hookConstructor(function(constructor) {
|
||||
return function() {
|
||||
constructor.call(this);
|
||||
this.packageMains = {};
|
||||
this.packageDefaultJSExtensions = {};
|
||||
this.packages = {};
|
||||
};
|
||||
});
|
||||
|
||||
function getPackage(name) {
|
||||
for (var p in this.packages) {
|
||||
if (name.substr(0, p.length) === p && (name.length === p.length || name[p.length] === '/'))
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
function applyMap(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;
|
||||
}
|
||||
}
|
||||
if (bestMatch)
|
||||
name = map[bestMatch] + name.substr(bestMatch.length);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
hook('normalize', function(normalize) {
|
||||
return function(name, parentName, parentAddress) {
|
||||
var loader = this;
|
||||
|
||||
// apply contextual package map first
|
||||
if (parentName)
|
||||
var parentPackage = getPackage.call(loader, parentName);
|
||||
|
||||
if (parentPackage && name[0] !== '.') {
|
||||
var parentMap = loader.packages[parentPackage].map;
|
||||
if (parentMap) {
|
||||
name = applyMap(parentMap, name);
|
||||
|
||||
// relative maps are package-relative
|
||||
if (name[0] === '.')
|
||||
parentName = parentPackage;
|
||||
}
|
||||
}
|
||||
|
||||
// apply global map, relative normalization
|
||||
return normalize.call(loader, name, parentName, parentAddress)
|
||||
.then(function(normalized) {
|
||||
// main
|
||||
if (loader.packageMains[normalized])
|
||||
normalized = normalized + '/' + loader.packageMains[normalized];
|
||||
// check if we are inside a package
|
||||
var pkgName = getPackage.call(loader, normalized);
|
||||
|
||||
// defaultJSExtension
|
||||
if (normalized.split('/').pop().indexOf('.') == -1) {
|
||||
for (var d in loader.packageDefaultExtensions) {
|
||||
if (normalized.substr(0, d.length + 1) == d + '/') {
|
||||
normalized += '.js';
|
||||
break;
|
||||
}
|
||||
if (pkgName) {
|
||||
var pkg = loader.packages[pkgName];
|
||||
|
||||
// main
|
||||
if (pkgName === normalized)
|
||||
normalized += '/' + (pkg.main || 'index.js');
|
||||
|
||||
// relative maps
|
||||
if (pkg.map) {
|
||||
normalized = pkgName + applyMap(pkg.map, '.' + normalized.substr(pkgName.length)).substr(1);
|
||||
|
||||
// normalize package-relative maps
|
||||
if (normalized.substr(0, 2) == './')
|
||||
normalized = pkgName + normalized.substr(1);
|
||||
}
|
||||
|
||||
// defaultExtension
|
||||
if (pkg.defaultExtension
|
||||
&& (!pkg.meta || !pkg.meta[normalized.substr(pkgName.length + 1)])
|
||||
&& normalized.split('/').pop().indexOf('.') == -1)
|
||||
normalized += '.' + pkg.defaultExtension;
|
||||
}
|
||||
|
||||
return normalized;
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
SystemJSLoader.prototype.package = function(p, pkgConfig) {
|
||||
// main
|
||||
var main = pkgCfg.main;
|
||||
if (main)
|
||||
this.packageMains[p] = main.substr(0, 2) == './' ? main.substr(2) : main;
|
||||
|
||||
// defaultJSExtension
|
||||
if (pkgCfg.defaultJSExtension)
|
||||
this.packageDefaultJSExtensions[p] = true;
|
||||
|
||||
// format
|
||||
if (pkgCfg.format) {
|
||||
var formatMeta = this.meta[p + '/*'] || {};
|
||||
formatMeta.format = pkgCfg.format;
|
||||
this.meta[p + '/*'] = formatMeta;
|
||||
function extend(a, b, overwrite) {
|
||||
for (var p in b) {
|
||||
if (overwrite || !(p in a))
|
||||
a[p] = b[p];
|
||||
}
|
||||
}
|
||||
|
||||
// meta
|
||||
for (var m in pkgCfg.modules) {
|
||||
var meta = this.meta[p + '/' + m] || {};
|
||||
var pkgMeta = pkgCfg.modules[m];
|
||||
// alias shorthand
|
||||
if (typeof pkgMeta === 'string')
|
||||
pkgMeta = { alias: pkgMeta };
|
||||
for (var p in pkgMeta) {
|
||||
// plugin and alias can be package-relative
|
||||
if ((p === 'plugin' || p === 'alias')
|
||||
&& pkgMeta[p].substr(0, 2) == './')
|
||||
meta[p] = p + pkgMeta[p].substr(1);
|
||||
else
|
||||
meta[p] = pkgMeta[p];
|
||||
}
|
||||
this.meta[p + '/' + m] = meta;
|
||||
}
|
||||
hook('locate', function(locate) {
|
||||
return function(load) {
|
||||
var loader = this;
|
||||
return Promise.resolve(locate.call(this, load))
|
||||
.then(function(address) {
|
||||
var pkgName = getPackage.call(loader, load.name);
|
||||
if (pkgName) {
|
||||
var pkg = loader.packages[pkgName];
|
||||
|
||||
// format
|
||||
if (pkg.format)
|
||||
load.metadata.format = load.metadata.format || pkg.format;
|
||||
|
||||
// map
|
||||
for (var m in pkgCfg.map) {
|
||||
var target = pkgCfg.map[m];
|
||||
if (target.substr(0, 2) == './')
|
||||
target = p + target.substr(1);
|
||||
if (pkg.meta) {
|
||||
// wildcard meta
|
||||
var meta = {};
|
||||
var bestDepth = 0;
|
||||
var wildcardIndex;
|
||||
for (var module in pkg.meta) {
|
||||
wildcardIndex = indexOf.call(module, '*');
|
||||
if (wildcardIndex === -1)
|
||||
continue;
|
||||
if (module.substr(0, wildcardIndex) === load.name.substr(0, wildcardIndex)
|
||||
&& module.substr(wildcardIndex + 1) === load.name.substr(load.name.length - module.length + wildcardIndex + 1)) {
|
||||
var depth = module.split('/').length;
|
||||
if (depth > bestDepth)
|
||||
bestDetph = depth;
|
||||
extend(meta, pkg.meta[module], bestDepth == depth);
|
||||
}
|
||||
}
|
||||
// exact meta
|
||||
if (pkg.meta[load.name])
|
||||
extend(meta, meta[load.name], true);
|
||||
|
||||
extend(load.metadata, meta);
|
||||
}
|
||||
}
|
||||
|
||||
// package-relative base map
|
||||
if (m.substr(0, 2) == './') {
|
||||
this.map[p + m.substr(1)] = target;
|
||||
}
|
||||
|
||||
// package-contextual map
|
||||
else {
|
||||
this.map[p] = this.map[p] || {};
|
||||
this.map[p][m] = target;
|
||||
}
|
||||
}
|
||||
};
|
||||
return address;
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
})();
|
||||
39
test/test.js
39
test/test.js
@ -155,34 +155,31 @@ asyncTest('Map configuration subpath', function() {
|
||||
}, err);
|
||||
});
|
||||
|
||||
asyncTest('Contextual map configuration', function() {
|
||||
System.map['tests/contextual-map.js'] = {
|
||||
maptest: 'tests/contextual-map-dep.js'
|
||||
asyncTest('Package map configuration', function() {
|
||||
System.packages['tests/contextual-test'] = {
|
||||
main: 'contextual-map.js',
|
||||
map: {
|
||||
maptest: 'tests/contextual-map-dep.js'
|
||||
}
|
||||
};
|
||||
System['import']('tests/contextual-map.js').then(function(m) {
|
||||
System['import']('tests/contextual-test').then(function(m) {
|
||||
ok(m.mapdep == 'mapdep', 'Contextual map dep not loaded');
|
||||
start();
|
||||
}, err);
|
||||
});
|
||||
|
||||
asyncTest('Submodule contextual map configuration', function() {
|
||||
System.map['tests/subcontextual-map'] = {
|
||||
dep: 'tests/subcontextual-mapdep.js'
|
||||
asyncTest('Package map with shim', function() {
|
||||
System.packages['tests/shim-package'] = {
|
||||
meta: {
|
||||
'*': {
|
||||
deps: ['shim-map-dep']
|
||||
}
|
||||
},
|
||||
map: {
|
||||
'shim-map-dep': 'tests/shim-map-test-dep.js'
|
||||
}
|
||||
};
|
||||
System['import']('tests/subcontextual-map/submodule.js').then(function(m) {
|
||||
ok(m == 'submapdep', 'Submodule contextual map not loaded');
|
||||
start();
|
||||
}, err);
|
||||
});
|
||||
|
||||
asyncTest('Contextual map with shim', function() {
|
||||
System.meta['tests/shim-map-test.js'] = {
|
||||
deps: ['shim-map-dep']
|
||||
};
|
||||
System.map['tests/shim-map-test.js'] = {
|
||||
'shim-map-dep': 'tests/shim-map-test-dep.js'
|
||||
};
|
||||
System['import']('tests/shim-map-test.js').then(function(m) {
|
||||
System['import']('tests/shim-package/shim-map-test.js').then(function(m) {
|
||||
ok(m == 'depvalue', 'shim dep not loaded');
|
||||
start();
|
||||
}, err);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user