systemjs/lib/extension-plugins.js
2014-09-25 22:41:06 +02:00

152 lines
5.1 KiB
JavaScript

/*
SystemJS Plugin Support
Supports plugin syntax with "!"
The plugin name is loaded as a module itself, and can override standard loader hooks
for the plugin resource. See the plugin section of the systemjs readme.
*/
function plugins(loader) {
if (typeof indexOf == 'undefined')
indexOf = Array.prototype.indexOf;
var loaderNormalize = loader.normalize;
loader.normalize = function(name, parentName, parentAddress) {
var loader = this;
// if parent is a plugin, normalize against the parent plugin argument only
var parentPluginIndex;
if (parentName && (parentPluginIndex = parentName.indexOf('!')) != -1)
parentName = parentName.substr(0, parentPluginIndex);
return Promise.resolve(loaderNormalize.call(loader, name, parentName, parentAddress))
.then(function(name) {
// if this is a plugin, normalize the plugin name and the argument
var pluginIndex = name.lastIndexOf('!');
if (pluginIndex != -1) {
var argumentName = name.substr(0, pluginIndex);
// plugin name is part after "!" or the extension itself
var pluginName = name.substr(pluginIndex + 1) || argumentName.substr(argumentName.lastIndexOf('.') + 1);
// normalize the plugin name relative to the same parent
return new Promise(function(resolve) {
resolve(loader.normalize(pluginName, parentName, parentAddress));
})
// normalize the plugin argument
.then(function(_pluginName) {
pluginName = _pluginName;
return loader.normalize(argumentName, parentName, parentAddress);
})
.then(function(argumentName) {
return argumentName + '!' + pluginName;
});
}
// standard normalization
return name;
});
}
var loaderLocate = loader.locate;
loader.locate = function(load) {
var loader = this;
var name = load.name;
// only fetch the plugin itself if this name isn't defined
if (this.defined && this.defined[name])
return loaderLocate.call(this, load);
// plugin
var pluginIndex = name.lastIndexOf('!');
if (pluginIndex != -1) {
var pluginName = name.substr(pluginIndex + 1);
// the name to locate is the plugin argument only
load.name = name.substr(0, pluginIndex);
var pluginLoader = loader.pluginLoader || loader;
// load the plugin module
// NB ideally should use pluginLoader.load for normalized,
// but not currently working for some reason
return pluginLoader['import'](pluginName)
.then(function() {
var plugin = pluginLoader.get(pluginName);
plugin = plugin['default'] || plugin;
// allow plugins to opt-out of build
if (plugin.build === false && loader.pluginLoader)
load.metadata.build = false;
// store the plugin module itself on the metadata
load.metadata.plugin = plugin;
load.metadata.pluginName = pluginName;
load.metadata.pluginArgument = load.name;
// run plugin locate if given
if (plugin.locate)
return plugin.locate.call(loader, load);
// otherwise use standard locate without '.js' extension adding
else
return Promise.resolve(loader.locate(load))
.then(function(address) {
return address.substr(0, address.length - 3);
});
});
}
return loaderLocate.call(this, load);
}
var loaderFetch = loader.fetch;
loader.fetch = function(load) {
var loader = this;
if (load.metadata.build === false)
return '';
else if (load.metadata.plugin && load.metadata.plugin.fetch && !load.metadata.pluginFetchCalled) {
load.metadata.pluginFetchCalled = true;
return load.metadata.plugin.fetch.call(loader, load, loaderFetch);
}
else
return loaderFetch.call(loader, load);
}
var loaderTranslate = loader.translate;
loader.translate = function(load) {
var loader = this;
if (load.metadata.plugin && load.metadata.plugin.translate)
return Promise.resolve(load.metadata.plugin.translate.call(loader, load)).then(function(result) {
if (result)
load.source = result;
return loaderTranslate.call(loader, load);
});
else
return loaderTranslate.call(loader, load);
}
var loaderInstantiate = loader.instantiate;
loader.instantiate = function(load) {
var loader = this;
if (load.metadata.plugin && load.metadata.plugin.instantiate)
return Promise.resolve(load.metadata.plugin.instantiate.call(loader, load)).then(function(result) {
load.metadata.format = 'defined';
load.metadata.execute = function() {
return result;
};
return loaderInstantiate.call(loader, load);
});
else if (load.metadata.plugin && load.metadata.plugin.build === false) {
load.metadata.format = 'defined';
load.metadata.deps.push(load.metadata.pluginName);
load.metadata.execute = function() {
return loader.newModule({});
};
return loaderInstantiate.call(loader, load);
}
else
return loaderInstantiate.call(loader, load);
}
}