steal-tools
Version:
Futuristic build tools for ES6 Module applications.
1,820 lines (1,599 loc) • 118 kB
JavaScript
(function(global){
// helpers
var camelize = function(str){
return str.replace(/-+(.)?/g, function(match, chr){
return chr ? chr.toUpperCase() : ''
});
},
each = function( o, cb){
var i, len;
// weak array detection, but we only use this internally so don't
// pass it weird stuff
if ( typeof o.length == 'number' && (o.length - 1) in o) {
for ( i = 0, len = o.length; i < len; i++ ) {
cb.call(o[i], o[i], i, o);
}
} else {
for ( i in o ) {
if(o.hasOwnProperty(i)){
cb.call(o[i], o[i], i, o);
}
}
}
return o;
},
map = function(o, cb) {
var arr = [];
each(o, function(item, i){
arr[i] = cb(item, i);
});
return arr;
},
isString = function(o) {
return typeof o == "string";
},
extend = function(d,s){
each(s, function(v, p){
d[p] = v;
});
return d;
},
dir = function(uri){
var lastSlash = uri.lastIndexOf("/");
//if no / slashes, check for \ slashes since it might be a windows path
if(lastSlash === -1)
lastSlash = uri.lastIndexOf("\\");
if(lastSlash !== -1) {
return uri.substr(0, lastSlash);
} else {
return uri;
}
},
last = function(arr){
return arr[arr.length - 1];
},
parseURI = function(url) {
var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@\/]*(?::[^:@\/]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
// authority = '//' + user + ':' + pass '@' + hostname + ':' port
return (m ? {
href : m[0] || '',
protocol : m[1] || '',
authority: m[2] || '',
host : m[3] || '',
hostname : m[4] || '',
port : m[5] || '',
pathname : m[6] || '',
search : m[7] || '',
hash : m[8] || ''
} : null);
},
joinURIs = function(base, href) {
function removeDotSegments(input) {
var output = [];
input.replace(/^(\.\.?(\/|$))+/, '')
.replace(/\/(\.(\/|$))+/g, '/')
.replace(/\/\.\.$/, '/../')
.replace(/\/?[^\/]*/g, function (p) {
if (p === '/..') {
output.pop();
} else {
output.push(p);
}
});
return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
}
href = parseURI(href || '');
base = parseURI(base || '');
return !href || !base ? null : (href.protocol || base.protocol) +
(href.protocol || href.authority ? href.authority : base.authority) +
removeDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) +
(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
href.hash;
},
relativeURI = function(base, path) {
var uriParts = path.split("/"),
baseParts = base.split("/"),
result = [];
while ( uriParts.length && baseParts.length && uriParts[0] == baseParts[0] ) {
uriParts.shift();
baseParts.shift();
}
for(var i = 0 ; i< baseParts.length-1; i++) {
result.push("../");
}
return "./" + result.join("") + uriParts.join("/");
},
fBind = Function.prototype.bind,
isFunction = function(obj) {
return !!(obj && obj.constructor && obj.call && obj.apply);
},
isWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope,
isNode = typeof process === "object" && {}.toString.call(process) === "[object process]",
isBrowserWithWindow = !isNode && typeof window !== "undefined",
isNW = isNode && (function(){
try {
return require("nw.gui") !== "undefined";
} catch(e) {
return false;
}
})(),
isElectron = isNode && !!process.versions["electron"],
isNode = isNode && !isNW && !isElectron,
warn = typeof console === "object" ?
fBind.call(console.warn, console) : function(){};
var filename = function(uri){
var lastSlash = uri.lastIndexOf("/");
//if no / slashes, check for \ slashes since it might be a windows path
if(lastSlash === -1)
lastSlash = uri.lastIndexOf("\\");
var matches = ( lastSlash == -1 ? uri : uri.substr(lastSlash+1) ).match(/^[\w-\s\.!]+/);
return matches ? matches[0] : "";
};
var ext = function(uri){
var fn = filename(uri);
var dot = fn.lastIndexOf(".");
if(dot !== -1) {
return fn.substr(dot+1);
} else {
return "";
}
};
var pluginCache = {};
var normalize = function(unnormalizedName, loader){
var name = unnormalizedName;
// Detech if this name contains a plugin part like: app.less!steal/less
// and catch the plugin name so that when it is normalized we do not perform
// Steal's normalization against it.
var pluginIndex = name.lastIndexOf('!');
var pluginPart = "";
if (pluginIndex != -1) {
// argumentName is the part before the !
var argumentName = name.substr(0, pluginIndex);
var pluginName = name.substr(pluginIndex + 1);
pluginPart = "!" + pluginName;
// Set the name to the argument name so that we can normalize it alone.
name = argumentName;
}
var last = filename(name),
extension = ext(name);
// if the name ends with /
if( name[name.length -1] === "/" ) {
return name+filename( name.substr(0, name.length-1) ) + pluginPart;
} else if( !/^(\w+(?:s)?:\/\/|\.|file|\/)/.test(name) &&
// and doesn't end with a dot
last.indexOf(".") === -1
) {
return name+"/"+last + pluginPart;
} else {
if(extension === "js") {
return name.substr(0, name.lastIndexOf(".")) + pluginPart;
} else {
return name + pluginPart;
}
}
};
var cloneSteal = function(System){
var loader = System || this.System;
var steal = makeSteal(loader.clone());
steal.loader.set("@steal", steal.loader.newModule({
"default": steal,
__useDefault: true
}));
steal.clone = cloneSteal;
return steal;
};
var makeSteal = function(System){
var addStealExtension = function (extensionFn) {
if (typeof System !== "undefined" && isFunction(extensionFn)) {
if (System._extensions) {
System._extensions.push(extensionFn);
}
extensionFn(System);
}
};
System.set('@loader', System.newModule({
'default': System,
__useDefault: true
}));
System.set("less", System.newModule({
__useDefault: true,
default: {
fetch: function() {
throw new Error(
[
"steal-less plugin must be installed and configured properly",
"See https://stealjs.com/docs/steal-less.html"
].join("\n")
);
}
}
}));
System.config({
map: {
"@loader/@loader": "@loader",
"@steal/@steal": "@steal"
}
});
var configPromise,
devPromise,
appPromise;
var steal = function(){
var args = arguments;
var afterConfig = function(){
var imports = [];
var factory;
each(args, function(arg){
if(isString(arg)) {
imports.push( steal.System['import']( normalize(arg) ) );
} else if(typeof arg === "function") {
factory = arg;
}
});
var modules = Promise.all(imports);
if(factory) {
return modules.then(function(modules) {
return factory && factory.apply(null, modules);
});
} else {
return modules;
}
};
if(System.isEnv("production")) {
return afterConfig();
} else {
// wait until the config has loaded
return configPromise.then(afterConfig,afterConfig);
}
};
System.set("@steal", System.newModule({
"default": steal,
__useDefault:true
}));
var loaderClone = System.clone;
System.clone = function(){
var loader = loaderClone.apply(this, arguments);
loader.set("@loader", loader.newModule({
"default": loader,
__useDefault: true
}));
loader.set("@steal", loader.newModule({
"default": steal,
__useDefault: true
}));
return loader;
};
// steal.System remains for backwards compat only
steal.System = steal.loader = System;
steal.parseURI = parseURI;
steal.joinURIs = joinURIs;
steal.normalize = normalize;
steal.relativeURI = relativeURI;
steal.addExtension = addStealExtension;
// System-Ext
// This normalize-hook does 2 things.
// 1. with specify a extension in your config
// you can use the "!" (bang) operator to load
// that file with the extension
// System.ext = {bar: "path/to/bar"}
// foo.bar! -> foo.bar!path/to/bar
// 2. if you load a javascript file e.g. require("./foo.js")
// normalize will remove the ".js" to load the module
addStealExtension(function (loader) {
loader.ext = {};
var normalize = loader.normalize,
endingExtension = /\.(\w+)!?$/;
loader.normalize = function (name, parentName, parentAddress, pluginNormalize) {
if (pluginNormalize) {
return normalize.apply(this, arguments);
}
var matches = name.match(endingExtension);
var outName = name;
if (matches) {
var hasBang = name[name.length - 1] === "!",
ext = matches[1];
// load js-files nodd-like
if (parentName && loader.configMain !== name && matches[0] === '.js') {
outName = name.substr(0, name.lastIndexOf("."));
// matches ext mapping
} else if (loader.ext[ext]) {
outName = name + (hasBang ? "" : "!") + loader.ext[ext];
}
}
return normalize.call(this, outName, parentName, parentAddress);
};
});
// Steal Locate Extension
// normalize a given path e.g.
// "path/to/folder/" -> "path/to/folder/folder"
addStealExtension(function (loader) {
var normalize = loader.normalize;
var npmLike = /@.+#.+/;
loader.normalize = function (name, parentName, parentAddress, pluginNormalize) {
var lastPos = name.length - 1,
secondToLast,
folderName,
newName = name;
if (name[lastPos] === "/") {
secondToLast = name.substring(0, lastPos).lastIndexOf("/");
folderName = name.substring(secondToLast + 1, lastPos);
if (npmLike.test(folderName)) {
folderName = folderName.substr(folderName.lastIndexOf("#") + 1);
}
newName += folderName;
}
return normalize.call(this, newName, parentName, parentAddress, pluginNormalize);
};
});
// override loader.translate to rewrite 'locate://' & 'pkg://' path schemes found
// in resources loaded by supporting plugins
addStealExtension(function (loader) {
/**
* @hide
* @function normalizeAndLocate
* @description Run a module identifier through Normalize and Locate hooks.
* @param {String} moduleName The module to run through normalize and locate.
* @return {Promise} A promise to resolve when the address is found.
*/
var normalizeAndLocate = function(moduleName, parentName){
var loader = this;
return Promise.resolve(loader.normalize(moduleName, parentName))
.then(function(name){
return loader.locate({name: name, metadata: {}});
}).then(function(address){
var outAddress = address;
if(address.substr(address.length - 3) === ".js") {
outAddress = address.substr(0, address.length - 3);
}
return outAddress;
});
};
var relative = function(base, path){
var uriParts = path.split("/"),
baseParts = base.split("/"),
result = [];
while ( uriParts.length && baseParts.length && uriParts[0] == baseParts[0] ) {
uriParts.shift();
baseParts.shift();
}
for(var i = 0 ; i< baseParts.length-1; i++) {
result.push("../");
}
return result.join("") + uriParts.join("/");
};
var schemePattern = /(locate):\/\/([a-z0-9/._@-]*)/ig,
parsePathSchemes = function(source, parent) {
var locations = [];
source.replace(schemePattern, function(whole, scheme, path, index){
locations.push({
start: index,
end: index+whole.length,
name: path,
postLocate: function(address){
return relative(parent, address);
}
});
});
return locations;
};
var _translate = loader.translate;
loader.translate = function(load){
var loader = this;
// This only applies to plugin resources.
if(!load.metadata.plugin) {
return _translate.call(this, load);
}
// Use the translator if this file path scheme is supported by the plugin
var locateSupport = load.metadata.plugin.locateScheme;
if(!locateSupport) {
return _translate.call(this, load);
}
// Parse array of module names
var locations = parsePathSchemes(load.source, load.address);
// no locations found
if(!locations.length) {
return _translate.call(this, load);
}
// normalize and locate all of the modules found and then replace those instances in the source.
var promises = [];
for(var i = 0, len = locations.length; i < len; i++) {
promises.push(
normalizeAndLocate.call(this, locations[i].name, load.name)
);
}
return Promise.all(promises).then(function(addresses){
for(var i = locations.length - 1; i >= 0; i--) {
load.source = load.source.substr(0, locations[i].start)
+ locations[i].postLocate(addresses[i])
+ load.source.substr(locations[i].end, load.source.length);
}
return _translate.call(loader, load);
});
};
});
addStealExtension(function (loader) {
loader._contextualModules = {};
loader.setContextual = function(moduleName, definer){
this._contextualModules[moduleName] = definer;
};
var normalize = loader.normalize;
loader.normalize = function(name, parentName){
var loader = this;
var pluginLoader = loader.pluginLoader || loader;
if (parentName) {
var definer = this._contextualModules[name];
// See if `name` is a contextual module
if (definer) {
var localName = name + '/' + parentName;
if(!loader.has(localName)) {
// `definer` could be a function or could be a moduleName
if (typeof definer === 'string') {
definer = pluginLoader['import'](definer);
}
return Promise.resolve(definer)
.then(function(modDefiner) {
var definer = modDefiner;
if (definer['default']) {
definer = definer['default'];
}
var definePromise = Promise.resolve(
definer.call(loader, parentName)
);
return definePromise;
})
.then(function(moduleDef){
loader.set(localName, loader.newModule(moduleDef));
return localName;
});
}
return Promise.resolve(localName);
}
}
return normalize.apply(this, arguments);
};
});
/**
* Steal Script-Module Extension
*
* Add a steal-module script to the page and it will run after Steal has been
* configured, e.g:
*
* <script type="text/steal-module">...</script>
* <script type="steal-module">...</script>
*/
addStealExtension(function(loader) {
// taken from https://github.com/ModuleLoader/es6-module-loader/blob/master/src/module-tag.js
function completed() {
document.removeEventListener("DOMContentLoaded", completed, false);
window.removeEventListener("load", completed, false);
ready();
}
function ready() {
var scripts = document.getElementsByTagName("script");
for (var i = 0; i < scripts.length; i++) {
var script = scripts[i];
if (script.type == "steal-module" || script.type == "text/steal-module") {
var source = script.innerHTML;
if (/\S/.test(source)) {
loader.module(source)["catch"](function(err) {
setTimeout(function() {
throw err;
});
});
}
}
}
}
loader.loadScriptModules = function() {
if (isBrowserWithWindow) {
if (document.readyState === "complete") {
setTimeout(ready);
} else if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", completed, false);
window.addEventListener("load", completed, false);
}
}
};
});
// SystemJS Steal Format
// Provides the Steal module format definition.
addStealExtension(function (loader) {
// Steal Module Format Detection RegEx
// steal(module, ...)
var stealRegEx = /(?:^\s*|[}{\(\);,\n\?\&]\s*)steal\s*\(\s*((?:"[^"]+"\s*,|'[^']+'\s*,\s*)*)/;
// What we stole.
var stealInstantiateResult;
function createSteal(loader) {
stealInstantiateResult = null;
// ensure no NodeJS environment detection
loader.global.module = undefined;
loader.global.exports = undefined;
function steal() {
var deps = [];
var factory;
for( var i = 0; i < arguments.length; i++ ) {
if (typeof arguments[i] === 'string') {
deps.push( normalize(arguments[i]) );
} else {
factory = arguments[i];
}
}
if (typeof factory !== 'function') {
factory = (function(factory) {
return function() { return factory; };
})(factory);
}
stealInstantiateResult = {
deps: deps,
execute: function(require, exports, moduleName) {
var depValues = [];
for (var i = 0; i < deps.length; i++) {
depValues.push(require(deps[i]));
}
var output = factory.apply(loader.global, depValues);
if (typeof output !== 'undefined') {
return output;
}
}
};
}
loader.global.steal = steal;
}
var loaderInstantiate = loader.instantiate;
loader.instantiate = function(load) {
var loader = this;
if (load.metadata.format === 'steal' || !load.metadata.format && load.source.match(stealRegEx)) {
load.metadata.format = 'steal';
var oldSteal = loader.global.steal;
createSteal(loader);
loader.__exec(load);
loader.global.steal = oldSteal;
if (!stealInstantiateResult) {
throw "Steal module " + load.name + " did not call steal";
}
if (stealInstantiateResult) {
load.metadata.deps = load.metadata.deps ? load.metadata.deps.concat(stealInstantiateResult.deps) : stealInstantiateResult.deps;
load.metadata.execute = stealInstantiateResult.execute;
}
}
return loaderInstantiate.call(loader, load);
};
});
addStealExtension(function(loader) {
var superTranspile = loader.transpile;
var superDetermineFormat = loader._determineFormat;
function prependDeps (loader, load, callback) {
var meta = loader.meta[load.name];
if (meta && meta.deps && meta.deps.length) {
var imports = meta.deps.map(callback).join('\n');
load.source = imports + "\n" + load.source;
}
}
function createImport(dep) {
return "import \"" + dep + "\";";
}
function createRequire(dep) {
return "require(\"" + dep + "\");";
}
loader.transpile = function (load) {
prependDeps(this, load, createImport);
var result = superTranspile.apply(this, arguments);
return result;
}
loader._determineFormat = function (load) {
if(load.metadata.format === 'cjs') {
prependDeps(this, load, createRequire);
}
var result = superDetermineFormat.apply(this, arguments);
return result;
};
});
addStealExtension(function applyTraceExtension(loader) {
if(loader._extensions) {
loader._extensions.push(applyTraceExtension);
}
loader._traceData = {
loads: {},
parentMap: {}
};
loader.getDependencies = function(moduleName){
var load = this.getModuleLoad(moduleName);
return load ? load.metadata.dependencies : undefined;
};
loader.getDependants = function(moduleName){
var deps = [];
var pars = this._traceData.parentMap[moduleName] || {};
eachOf(pars, function(name) { deps.push(name); });
return deps;
};
loader.getModuleLoad = function(moduleName){
return this._traceData.loads[moduleName];
};
loader.getBundles = function(moduleName, argVisited){
var visited = argVisited || {};
visited[moduleName] = true;
var loader = this;
var parentMap = loader._traceData.parentMap;
var parents = parentMap[moduleName];
if(!parents) return [moduleName];
var bundles = [];
eachOf(parents, function(parentName, value){
if(!visited[parentName])
bundles = bundles.concat(loader.getBundles(parentName, visited));
});
return bundles;
};
loader._allowModuleExecution = {};
loader.allowModuleExecution = function(name){
var loader = this;
return loader.normalize(name).then(function(name){
loader._allowModuleExecution[name] = true;
});
};
function eachOf(obj, callback){
var name, val;
for(name in obj) {
callback(name, obj[name]);
}
}
var normalize = loader.normalize;
loader.normalize = function(name, parentName){
var normalizePromise = normalize.apply(this, arguments);
if(parentName) {
var parentMap = this._traceData.parentMap;
return normalizePromise.then(function(name){
if(!parentMap[name]) {
parentMap[name] = {};
}
parentMap[name][parentName] = true;
return name;
});
}
return normalizePromise;
};
var emptyExecute = function(){
return loader.newModule({});
};
var passThroughModules = {
traceur: true,
babel: true
};
var isAllowedToExecute = function(load){
return passThroughModules[load.name] || this._allowModuleExecution[load.name];
};
var map = [].map || function(callback){
var res = [];
for(var i = 0, len = this.length; i < len; i++) {
res.push(callback(this[i]));
}
return res;
};
var esImportDepsExp = /import [\s\S]*?["'](.+)["']/g;
var esExportDepsExp = /export .+ from ["'](.+)["']/g;
var commentRegEx = /(?:(?:^|\s)\/\/(.+?)$)|(?:\/\*([\S\s]*?)\*\/)/gm;
var stringRegEx = /(?:("|')[^\1\\\n\r]*(?:\\.[^\1\\\n\r]*)*\1|`[^`]*`)/g;
function getESDeps(source) {
var cleanSource = source.replace(commentRegEx, "");
esImportDepsExp.lastIndex = commentRegEx.lastIndex =
esExportDepsExp.lastIndex = stringRegEx.lastIndex = 0;
var match;
var deps = [];
var stringLocations = []; // track string for unminified source
function inLocation(locations, match) {
for (var i = 0; i < locations.length; i++)
if (locations[i][0] < match.index && locations[i][1] > match.index)
return true;
return false;
}
function addDeps(exp) {
while (match = exp.exec(cleanSource)) {
// ensure we're not within a string location
if (!inLocation(stringLocations, match)) {
var dep = match[1];
deps.push(dep);
}
}
}
if (source.length / source.split('\n').length < 200) {
while (match = stringRegEx.exec(cleanSource))
stringLocations.push([match.index, match.index + match[0].length]);
}
addDeps(esImportDepsExp);
addDeps(esExportDepsExp);
return deps;
}
var instantiate = loader.instantiate;
loader.instantiate = function(load){
this._traceData.loads[load.name] = load;
var loader = this;
var instantiatePromise = Promise.resolve(instantiate.apply(this, arguments));
function finalizeResult(result){
var preventExecution = loader.preventModuleExecution &&
!isAllowedToExecute.call(loader, load);
// deps either comes from the instantiate result, or if an
// es6 module it was found in the transpile hook.
var deps = result ? result.deps : load.metadata.deps;
return Promise.all(map.call(deps, function(depName){
return loader.normalize(depName, load.name);
})).then(function(dependencies){
load.metadata.deps = deps;
load.metadata.dependencies = dependencies;
if(preventExecution) {
return {
deps: deps,
execute: emptyExecute
};
}
return result;
});
}
return instantiatePromise.then(function(result){
// This must be es6
if(!result) {
var deps = getESDeps(load.source);
load.metadata.deps = deps;
}
return finalizeResult(result);
});
};
var transpile = loader.transpile;
// Allow transpile to be memoized, but only once
loader.transpile = function(load){
var transpiled = load.metadata.transpiledSource;
if(transpiled) {
delete load.metadata.transpiledSource;
return Promise.resolve(transpiled);
}
return transpile.apply(this, arguments);
};
loader.eachModule = function(cb){
for (var moduleName in this._loader.modules) {
cb.call(this, moduleName, this.get(moduleName));
}
};
});
// Steal JSON Format
// Provides the JSON module format definition.
addStealExtension(function (loader) {
var jsonExt = /\.json$/i;
var jsExt = /\.js$/i;
// taken from prototypejs
// https://github.com/sstephenson/prototype/blob/master/src/prototype/lang/string.js#L682-L706
function isJSON(json) {
var str = json;
if (!str) return false;
str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
return (/^[\],:{}\s]*$/).test(str);
}
// if someone has a moduleName that is .json, make sure it loads a json file
// no matter what paths might do
var loaderLocate = loader.locate;
loader.locate = function(load){
return loaderLocate.apply(this, arguments).then(function(address){
if(jsonExt.test(load.name)) {
return address.replace(jsExt, "");
}
return address;
});
};
var transform = function(loader, load, data){
var fn = loader.jsonOptions && loader.jsonOptions.transform;
if(!fn) return data;
return fn.call(loader, load, data);
};
// If we are in a build we should convert to CommonJS instead.
if(isNode) {
var loaderTranslate = loader.translate;
loader.translate = function(load){
var address = load.metadata.address || load.address;
if(jsonExt.test(address) && load.name.indexOf('!') === -1) {
var parsed = parse(load);
if(parsed) {
parsed = transform(this, load, parsed);
return "def" + "ine([], function(){\n" +
"\treturn " + JSON.stringify(parsed) + "\n});";
}
}
return loaderTranslate.call(this, load);
};
return;
}
var loaderInstantiate = loader.instantiate;
loader.instantiate = function(load) {
var loader = this,
parsed;
parsed = parse(load);
if(parsed) {
parsed = transform(loader, load, parsed);
load.metadata.format = 'json';
load.metadata.execute = function(){
return parsed;
};
}
return loaderInstantiate.call(loader, load);
};
return loader;
// Attempt to parse a load as json.
function parse(load){
if ((load.metadata.format === 'json' || !load.metadata.format) && isJSON(load.source)) {
try {
return JSON.parse(load.source);
} catch(e) {
warn("Error parsing " + load.address + ":", e);
return {};
}
}
}
});
// Steal Cache-Bust Extension
// if enabled, Steal Cache-Bust will add a
// cacheKey and cacheVersion to the required file address
addStealExtension(function (loader) {
var fetch = loader.fetch;
loader.fetch = function(load) {
var loader = this;
if(loader.isEnv("production") && loader.cacheVersion) {
var cacheVersion = loader.cacheVersion,
cacheKey = loader.cacheKey || "version",
cacheKeyVersion = cacheKey + "=" + cacheVersion;
load.address = load.address + (load.address.indexOf('?') === -1 ? '?' : '&') + cacheKeyVersion;
}
return fetch.call(this, load);
};
});
// Overwrites System.config with setter hooks
var setterConfig = function(loader, configOrder, configSpecial){
var oldConfig = loader.config;
loader.config = function(cfg){
var data = extend({},cfg);
// check each special
each(configOrder, function(name){
var special = configSpecial[name];
// if there is a setter and a value
if(special.set && data[name]){
// call the setter
var res = special.set.call(loader,data[name], cfg);
// if the setter returns a value
if(res !== undefined) {
// set that on the loader
loader[name] = res;
}
// delete the property b/c setting is done
delete data[name];
}
});
oldConfig.call(this, data);
};
};
var setIfNotPresent = function(obj, prop, value){
if(!obj[prop]) {
obj[prop] = value;
}
};
// steal.js's default configuration values
System.configMain = "@config";
System.devBundle = "@empty";
System.depsBundle = "@empty";
System.paths[System.configMain] = "stealconfig.js";
System.env = (isWebWorker ? "worker" : "window") + "-development";
System.ext = Object.create(null);
System.logLevel = 0;
var cssBundlesNameGlob = "bundles/*.css",
jsBundlesNameGlob = "bundles/*";
setIfNotPresent(System.paths,cssBundlesNameGlob, "dist/bundles/*css");
setIfNotPresent(System.paths,jsBundlesNameGlob, "dist/bundles/*.js");
var configSetter = function(order){
return {
order: order,
set: function(val){
var name = filename(val),
root = dir(val);
if(!isNode) {
System.configPath = joinURIs( location.href, val);
}
System.configMain = name;
System.paths[name] = name;
this.config({ baseURL: (root === val ? "." : root) + "/" });
}
}
},
valueSetter = function(prop, order) {
return {
order: order,
set: function(val) {
this[prop] = val;
}
}
},
booleanSetter = function(prop, order) {
return {
order: order,
set: function(val) {
this[prop] = !!val;
}
}
},
fileSetter = function(prop, order) {
return {
order: order,
set: function(val) {
this[prop] = envPath(val);
}
};
};
// checks if we're running in node, then prepends the "file:" protocol if we are
var envPath = function(pathVal) {
var val = pathVal;
if(isNode && !/^file:/.test(val)) {
// If relative join with the current working directory
if(val[0] === "." && (val[1] === "/" ||
(val[1] === "." && val[2] === "/"))) {
val = require("path").join(process.cwd(), val);
}
if(!val) return val;
return "file:" + val;
}
return val;
};
var setToSystem = function(prop){
return {
set: function(val){
if(typeof val === "object" && typeof steal.System[prop] === "object") {
this[prop] = extend(this[prop] || {},val || {});
} else {
this[prop] = val;
}
}
};
};
var pluginPart = function(name) {
var bang = name.lastIndexOf("!");
if(bang !== -1) {
return name.substr(bang+1);
}
};
var pluginResource = function(name){
var bang = name.lastIndexOf("!");
if(bang !== -1) {
return name.substr(0, bang);
}
};
var addProductionBundles = function(){
// we don't want add the main bundled module if steal is bundled inside!
if(this.loadBundles && this.main && !this.stealBundled) {
var main = this.main,
bundlesDir = this.bundlesName || "bundles/",
mainBundleName = bundlesDir+main;
setIfNotPresent(this.meta, mainBundleName, {format:"amd"});
// If the configMain has a plugin like package.json!npm,
// plugin has to be defined prior to importing.
var plugin = pluginPart(System.configMain);
var bundle = [main, System.configMain];
if(plugin){
System.set(plugin, System.newModule({}));
}
plugin = pluginPart(main);
if(plugin) {
var resource = pluginResource(main);
bundle.push(plugin);
bundle.push(resource);
mainBundleName = bundlesDir+resource.substr(0, resource.indexOf("."));
}
this.bundles[mainBundleName] = bundle;
}
};
var setEnvsConfig = function(){
if(this.envs) {
var envConfig = this.envs[this.env];
if(envConfig) {
this.config(envConfig);
}
}
};
var setupLiveReload = function(){
if(this.liveReloadInstalled) {
var loader = this;
this["import"]("live-reload", {
name: "@@steal"
}).then(function(reload){
reload(loader.configMain, function(){
setEnvsConfig.call(loader);
});
});
}
};
var specialConfigOrder = [];
var envsSpecial = { map: true, paths: true, meta: true };
var specialConfig = {
instantiated: {
order: 1,
set: function(val){
var loader = this;
each(val || {}, function(value, name){
loader.set(name, loader.newModule(value));
});
}
},
envs: {
order: 2,
set: function(val){
// envs should be set, deep
var envs = this.envs;
if(!envs) envs = this.envs = {};
each(val, function(cfg, name){
var env = envs[name];
if(!env) env = envs[name] = {};
each(cfg, function(val, name){
if(envsSpecial[name] && env[name]) {
extend(env[name], val);
} else {
env[name] = val;
}
});
});
}
},
env: {
order: 3,
set: function(val){
this.env = val;
if(this.isEnv("production")) {
this.loadBundles = true;
}
}
},
loadBundles: booleanSetter("loadBundles", 4),
stealBundled: booleanSetter("stealBundled", 5),
// System.config does not like being passed arrays.
bundle: {
order: 6,
set: function(val){
System.bundle = val;
}
},
bundlesPath: {
order: 7,
set: function(val){
this.paths[cssBundlesNameGlob] = val+"/*css";
this.paths[jsBundlesNameGlob] = val+"/*.js";
return val;
}
},
meta: {
order: 8,
set: function(cfg){
var loader = this;
each(cfg || {}, function(value, name){
if(typeof value !== "object") {
return;
}
var cur = loader.meta[name];
if(cur && cur.format === value.format) {
// Keep the deps, if we have any
var deps = value.deps;
extend(value, cur);
if(deps) {
value.deps = deps;
}
}
});
extend(this.meta, cfg);
}
},
configMain: valueSetter("configMain", 9),
config: configSetter(10),
configPath: configSetter(11),
baseURL: fileSetter("baseURL", 12),
main: valueSetter("main", 13),
// this gets called with the __dirname steal is in
// directly called from steal-tools
stealPath: {
order: 14,
set: function(identifier, cfg) {
var dirname = envPath(identifier);
var parts = dirname.split("/");
// steal keeps this around to make things easy no matter how you are using it.
setIfNotPresent(this.paths,"@dev", dirname+"/ext/dev.js");
setIfNotPresent(this.paths,"npm", dirname+"/ext/npm.js");
setIfNotPresent(this.paths,"npm-extension", dirname+"/ext/npm-extension.js");
setIfNotPresent(this.paths,"npm-utils", dirname+"/ext/npm-utils.js");
setIfNotPresent(this.paths,"npm-crawl", dirname+"/ext/npm-crawl.js");
setIfNotPresent(this.paths,"npm-load", dirname+"/ext/npm-load.js");
setIfNotPresent(this.paths,"npm-convert", dirname+"/ext/npm-convert.js");
setIfNotPresent(this.paths,"semver", dirname+"/ext/semver.js");
setIfNotPresent(this.paths,"bower", dirname+"/ext/bower.js");
setIfNotPresent(this.paths,"live-reload", dirname+"/ext/live-reload.js");
setIfNotPresent(this.paths,"steal-clone", dirname+"/ext/steal-clone.js");
this.paths["traceur"] = dirname+"/ext/traceur.js";
this.paths["traceur-runtime"] = dirname+"/ext/traceur-runtime.js";
this.paths["babel"] = dirname+"/ext/babel.js";
this.paths["babel-runtime"] = dirname+"/ext/babel-runtime.js";
setIfNotPresent(this.meta,"traceur",{"exports":"traceur"});
// steal-clone is contextual so it can override modules using relative paths
this.setContextual('steal-clone', 'steal-clone');
if(isNode) {
if(this.configMain === "@config" && last(parts) === "steal") {
parts.pop();
if(last(parts) === "node_modules") {
this.configMain = "package.json!npm";
parts.pop();
}
}
if(this.isEnv("production") || this.loadBundles) {
addProductionBundles.call(this);
}
} else {
// make sure we don't set baseURL if it already set
if(!cfg.baseURL && !cfg.config && !cfg.configPath) {
// if we loading steal.js and it is located in node_modules or bower_components
// we rewrite the baseURL relative to steal.js (one directory up!)
// we do this because, normaly our app is located as a sibling folder to
// node_modules or bower_components
if ( last(parts) === "steal" ) {
parts.pop();
var isFromPackage = false;
if ( last(parts) === cfg.bowerPath || last(parts) === "bower_components" ) {
System.configMain = "bower.json!bower";
addProductionBundles.call(this);
parts.pop();
isFromPackage = true;
}
if (last(parts) === "node_modules") {
System.configMain = "package.json!npm";
addProductionBundles.call(this);
parts.pop();
isFromPackage = true;
}
if(!isFromPackage) {
parts.push("steal");
}
}
this.config({ baseURL: parts.join("/")+"/"});
}
}
System.stealPath = dirname;
}
},
stealURL: {
order: 15,
// http://domain.com/steal/steal.js?moduleName,env&
set: function(url, cfg) {
var urlParts = url.split("?"),
path = urlParts.shift(),
paths = path.split("/"),
lastPart = paths.pop(),
stealPath = paths.join("/"),
platform = this.getPlatform() || (isWebWorker ? "worker" : "window");
System.stealURL = path;
// if steal is bundled or we are loading steal.production
// we always are in production environment
if((this.stealBundled && this.stealBundled === true) ||
((lastPart.indexOf("steal.production") > -1) ||
(lastPart.indexOf("steal-sans-promises.production") > -1)
&& !cfg.env)) {
this.config({ env: platform+"-production" });
}
if(this.isEnv("production") || this.loadBundles) {
addProductionBundles.call(this);
}
specialConfig.stealPath.set.call(this,stealPath, cfg);
}
},
devBundle: {
order: 16,
set: function(dirname, cfg) {
var path = (dirname === true) ? "dev-bundle" : dirname;
if (path) {
this.devBundle = path;
}
}
},
depsBundle: {
order: 17,
set: function(dirname, cfg) {
var path = (dirname === true) ? "dev-bundle" : dirname;
if (path) {
this.depsBundle = path;
}
}
}
};
/*
make a setter order
currently:
instantiated
envs
env
loadBundles
stealBundled
bundle
bundlesPath
meta
config
configPath
baseURL
main
stealPath
stealURL
*/
each(specialConfig, function(setter, name){
if(!setter.order) {
specialConfigOrder.push(name)
}else{
specialConfigOrder.splice(setter.order, 0, name);
}
});
// special setter config
setterConfig(System, specialConfigOrder, specialConfig);
steal.config = function(cfg){
if(typeof cfg === "string") {
return this.loader[cfg];
} else {
this.loader.config(cfg);
}
};
// Steal Env Extension
// adds some special environment functions to the loader
addStealExtension(function (loader) {
loader.getEnv = function(){
var envParts = (this.env || "").split("-");
// Fallback to this.env for legacy
return envParts[1] || this.env;
};
loader.getPlatform = function(){
var envParts = (this.env || "").split("-");
return envParts.length === 2 ? envParts[0] : undefined;
};
loader.isEnv = function(name){
return this.getEnv() === name;
};
loader.isPlatform = function(name){
return this.getPlatform() === name;
};
});
// get config by the URL query
// like ?main=foo&env=production
// formally used for Webworkers
var getQueryOptions = function(url) {
var queryOptions = {},
urlRegEx = /Url$/,
urlParts = url.split("?"),
path = urlParts.shift(),
search = urlParts.join("?"),
searchParts = search.split("&"),
paths = path.split("/"),
lastPart = paths.pop(),
stealPath = paths.join("/");
if(searchParts.length && searchParts[0].length) {
var searchPart;
for(var i =0; i < searchParts.length; i++) {
searchPart = searchParts[i];
var paramParts = searchPart.split("=");
if(paramParts.length > 1) {
var optionName = camelize(paramParts[0]);
// make options uniform e.g. baseUrl => baseURL
optionName = optionName.replace(urlRegEx, "URL")
queryOptions[optionName] = paramParts.slice(1).join("=");
}
}
}
return queryOptions;
};
// extract the script tag options
var getScriptOptions = function (script) {
var scriptOptions = {},
urlRegEx = /Url$/;
scriptOptions.stealURL = script.src;
each(script.attributes, function(attr){
var nodeName = attr.nodeName || attr.name;
// get option, remove "data" and camelize
var optionName =
camelize( nodeName.indexOf("data-") === 0 ?
nodeName.replace("data-","") :
nodeName );
// make options uniform e.g. baseUrl => baseURL
optionName = optionName.replace(urlRegEx, "URL")
scriptOptions[optionName] = (attr.value === "") ? true : attr.value;
});
// main source within steals script is deprecated
// and will be removed in future releases
var source = script.innerHTML;
if(/\S/.test(source)){
scriptOptions.mainSource = source;
}
// script config ever wins!
return extend(getQueryOptions(script.src), scriptOptions);
};
// get steal URL
// if we are in a browser, we need to know which script is steal
// to extract the script tag options => getScriptOptions()
var getUrlOptions = function (){
return new Promise(function(resolve, reject){
// for Workers get options from steal query
if (isWebWorker) {
resolve(extend({
stealURL: location.href
}, getQueryOptions(location.href)));
return;
} else if(isBrowserWithWindow || isNW || isElectron) {
// if the browser supports currentScript, use it!
if (document.currentScript) {
// get options from script tag and query
resolve(getScriptOptions(document.currentScript));
return;
}
// assume the last script on the page is the one loading steal.js
else {
var scripts = document.scripts;
if (scripts.length) {
resolve(getScriptOptions(scripts[scripts.length - 1]));
}
}
} else {
// or the only option is where steal is.
resolve({
stealPath: __dirname
});
}
})
};
// configure and startup steal
// load the main module(s) if everything is configured
steal.startup = function(startupConfig){
var steal = this;
var loader = this.loader;
var configResolve;
var configReject;
configPromise = new Promise(function(resolve, reject){
configResolve = resolve;
configReject = reject;
});
appPromise = getUrlOptions().then(function(urlOptions) {
var config;
if (typeof startupConfig === 'object') {
// the url options are the source of truth
config = extend(startupConfig, urlOptions);
} else {
config = urlOptions;
}
// set the config
loader.config(config);
setEnvsConfig.call(loader);
// we only load things with force = true
if (loader.loadBundles) {
if (!loader.main && loader.isEnv("production") &&
!loader.stealBundled) {
// prevent this warning from being removed by Uglify
warn("Attribute 'main' is required in production environment. Please add it to the script tag.");
}
loader["import"](loader.configMain)
.then(configResolve, configReject);
return configPromise.then(function (cfg) {
setEnvsConfig.call(loader);
loader._configLoaded = true;
return loader.main ? loader["import"](loader.main) : cfg;
});
} else {
// devBundle includes the same modules as "depsBundle and it also
// includes the @config graph, so it should be loaded before of
// configMain
loader["import"](loader.devBundle)
.then(function() {
return loader["import"](loader.configMain);
})
.then(function() {
// depsBundle includes the dependencies in the node_modules
// folder so it has to be loaded after configMain finished
// loading
return loader["import"](loader.depsBundle);
})
.then(configResolve, configReject);
devPromise = configPromise.then(function () {
setEnvsConfig.call(loader);
setupLiveReload.call(loader);
loader._configLoaded = true;
// If a configuration was passed to startup we'll use that to overwrite
// what was loaded in stealconfig.js
// This means we call it twice, but that's ok
if (config) {
loader.config(config);
}
return loader["import"]("@dev");
});
return devPromise.then(function () {
// if there's a main, get it, otherwise, we are just loading
// the config.
if (!loader.main || loader.localLoader) {
return configPromise;
}
var main = loader.main;
if (typeof main === "string") {
main = [main];
}
return Promise.all(map(main, function (main) {
return loader["import"](main);
}));
});
}
}).then(function(main){
if(loader.mainSource) {
return loader.module(loader.mainSource);
}
// load script modules they are tagged as
// text/steal-module
loader.loadScriptModules();
return main;
});
return appPromise;
};
steal.done = function(){
return appPromise;
};
System.setContextual("@node-require", function(name){
if(isNode) {
var nodeRequire = require;
var load = {name: name, metadata: {}};
return this.locate(load).then(function(address){
var url = address.replace("file:", "");
return {
"default": function(specifier){
var resolve = nodeRequire("resolve");
var res = resolve.sync(specifier, {
basedir: nodeRequire("path").dirname(url)
});
return nodeRequire(res);
},
__useDefault: true
};
});
} else {
return {
"default": function(){},
__useDefault: true
}
}
});
steal["import"] = function(){
var names = arguments;
var loader = this.System;
function afterConfig(){
var imports = [];
each(names, function(name){
imports.push(loader["import"](name));
});
if(imports.length > 1) {
return Promise.all(imports);
} else {
return imports[0];
}
}
if(!configPromise) {
// In Node a main isn't required, but we still want
// to call startup() to do autoconfiguration,
// so setting to empty allows this to work.
if(!loader.main) {
loader.main = "@empty";
}
steal.startup();
}
return configPromise.then(afterConfig);
};
steal.setContextual = fBind.call(System.setContextual, System);
steal.isEnv = fBind.call(System.isEnv, System);
steal.isPlatform = fBind.call(System.isPlatform, System);
return steal;
};
/*
* StealJS base extension
*
* **src/base/base.js** is an autogenerated file; any change should be
* made to the source files in **src/base/lib/*.js**
*/
(function($__global) {
$__global.upgradeSystemLoader = function() {
$__global.upgradeSystemLoader = undefined;
// indexOf polyfill for IE
var indexOf = Array.prototype.indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++)
if (this[i] === item)
return i;
return -1;
}
var isWindows = typeof process != 'undefined' && !!process.platform.match(/^win/);
// Absolute URL parsing, from https://gist.github.com/Yaffle/1088850
function parseURI(url) {
var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@\/?#]*(?::[^:@\/?#]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
// authority = '//' + user + ':' + pass '@' + hostname + ':' port
return (m ? {
href : m[0] || '',
protocol : m[1] || '',
authority: m[2] || '',
host : m[3] || '',
hostname : m[4] || '',
port : m[5] || '',
pathname : m[6] || '',
search : m[7] || '',
hash : m[8] || ''
} : null);
}
function toAbsoluteURL(inBase, inHref) {
var base = inBase;
var href = inHref;
function removeDotSegments(input) {
var output = [];
input.replace(/^(\.\.?(\/|$))+/, '')
.replace(/\/(\.(\/|$))+/g, '/')
.replace(/\/\.\.$/, '/../')
.replace(/\/?[^\/]*/g, function (p) {
if (p === '/..')
output.pop();
else
output.push(p);
});
return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
}
if (isWindows)
href = href.replace(/\\/g, '/');
href = parseURI(href || '');
base = parseURI(base || '');
return !href || !base ? null : (href.protocol || base.protocol) +
(href.protocol || href.authority ? href.authority : base.authority) +
removeDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) +
(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
href.hash;
}
// clone the original System loader
var System;
(function() {
var originalSystem = $__global.System;
System = $__global.System = new LoaderPolyfill(originalSystem);
System.baseURL = originalSystem.baseURL;
System.paths = { '*': '*.js' };
System.originalSystem = originalSystem;
})();
System.noConflict = function() {
$__global.SystemJS = System;
$__global.System = System.originalSystem;
}
var getOwnPropertyDescriptor = true;
try {
Object.getOwnPropertyDescriptor({ a: 0 }, 'a');
}
catch(e) {
getOwnPropertyDescriptor = false;
}
var defineProperty;
(function () {
try {
if (!!Object.defineProperty({}, 'a', {}))
defineProperty = Object.defineProperty;
}
catch (e) {
defineProperty = function(obj, prop, opt) {
try {
obj[prop] = opt.value || opt.get.call(obj);
}
catch(e) {}
}
}
})();
// 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;
definePrope