From 3cb9b6f657190dcba8541cccd9ff71fa66d5ac8a Mon Sep 17 00:00:00 2001 From: guybedford Date: Fri, 2 May 2014 22:17:50 -0700 Subject: [PATCH] spec update rewrite, wip --- Makefile | 13 +- dist/system-production-amd.js | 933 +++++++++++----- dist/system-production-amd.min.js | 2 +- dist/system.js | 1619 +++++++++++++++++----------- dist/system.min.js | 1 - lib/extension-amd.js | 170 +++ lib/extension-bundles.js | 29 +- lib/extension-cjs.js | 115 ++ lib/extension-core.js | 227 ++-- lib/extension-formatAMD.js | 199 ---- lib/extension-formatCJS.js | 88 -- lib/extension-formatGlobal.js | 102 -- lib/extension-formats.js | 126 --- lib/extension-global.js | 82 ++ lib/extension-map.js | 10 +- lib/extension-meta.js | 93 ++ lib/extension-plugins.js | 47 +- lib/extension-productionAMD.js | 109 -- lib/extension-register.js | 371 ++++++- lib/extension-scriptLoader.js | 26 + lib/extension-versions.js | 12 +- lib/polyfill-wrapper-end.js | 53 +- lib/polyfill-wrapper-start.js | 8 + lib/polyfills.js | 17 - test/test.html | 2 +- test/test.js | 12 +- test/tests/global-inline-dep.js | 4 +- test/tests/global-inline-export.js | 4 +- 28 files changed, 2707 insertions(+), 1767 deletions(-) create mode 100644 lib/extension-amd.js create mode 100644 lib/extension-cjs.js delete mode 100644 lib/extension-formatAMD.js delete mode 100644 lib/extension-formatCJS.js delete mode 100644 lib/extension-formatGlobal.js delete mode 100644 lib/extension-formats.js create mode 100644 lib/extension-global.js create mode 100644 lib/extension-meta.js delete mode 100644 lib/extension-productionAMD.js create mode 100644 lib/extension-scriptLoader.js delete mode 100644 lib/polyfills.js diff --git a/Makefile b/Makefile index ec1b1f48..6e210c10 100755 --- a/Makefile +++ b/Makefile @@ -1,15 +1,10 @@ -START = \ - cat lib/banner.js \ - lib/polyfill-wrapper-start.js \ - lib/polyfills.js > dist/$@.js; +START = cat lib/banner.js lib/polyfill-wrapper-start.js > dist/$@.js; -END = \ - cat lib/polyfill-wrapper-end.js >> dist/$@.js; - +END = cat lib/polyfill-wrapper-end.js >> dist/$@.js; -SystemJS = core formats formatAMD formatCJS formatGlobal map plugins bundles register versions -SystemProductionAMD = core productionAMD bundles register versions +SystemJS = core meta register global cjs amd map plugins bundles versions +SystemProductionAMD = core register scriptLoader map bundles versions all: system system-production-amd uglify diff --git a/dist/system-production-amd.js b/dist/system-production-amd.js index 6c4d8a92..8d8bdfeb 100644 --- a/dist/system-production-amd.js +++ b/dist/system-production-amd.js @@ -7,78 +7,180 @@ (function(__$global) { -__$global.upgradeSystemLoader = function() { - __$global.upgradeSystemLoader = undefined;// Define an IE-friendly shim good-enough for purposes -var indexOf = Array.prototype.indexOf || function(item) { - for (var i = 0, thisLen = this.length; i < thisLen; i++) { +// 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 lastIndexOf = Array.prototype.lastIndexOf || function(c) { - for (var i = this.length - 1; i >= 0; i--) { - if (this[i] === c) { - return i; - } - } - return -i; -}/* - SystemJS Core - Adds normalization to the import function, as well as __useDefault support -*/ +__$global.upgradeSystemLoader = function() { + __$global.upgradeSystemLoader = undefined;/* + * SystemJS Core + * Code should be vaguely readable + * + */ function core(loader) { (function() { - var curSystem = System; - /* __useDefault When a module object looks like: - new Module({ + Module({ __useDefault: true, default: 'some-module' }) - Then the import of that module is taken to be the 'default' export and not the module object itself. + Then importing that module provides the 'some-module' + result directly instead of the full module. - Useful for module.exports = function() {} handling + Useful for eg module.exports = function() {} */ - var checkUseDefault = function(module) { - if (!(module instanceof Module)) { - var out = []; - for (var i = 0; i < module.length; i++) - out[i] = checkUseDefault(module[i]); - return out; - } - return module.__useDefault ? module['default'] : module; - } - - // a variation on System.get that does the __useDefault check - loader.getModule = function(key) { - return checkUseDefault(loader.get(key)); + var loaderImport = loader['import']; + loader['import'] = function(name, options) { + return loaderImport.call(this, name, options).then(function(module) { + return module.__useDefault ? module['default'] : module; + }); } // support the empty module, as a concept loader.set('@empty', Module({})); - - - var loaderImport = loader['import']; - loader['import'] = function(name, options) { - // patch loader.import to do normalization - return new Promise(function(resolve) { - resolve(loader.normalize.call(this, name, options && options.name, options && options.address)) - }) - // add useDefault support - .then(function(name) { - return Promise.resolve(loaderImport.call(loader, name, options)).then(function(module) { - return checkUseDefault(module); - }); + + /* + Config + Extends config merging one deep only + + loader.config({ + some: 'random', + config: 'here', + deep: { + config: { too: 'too' } + } }); + + <=> + + loader.some = 'random'; + loader.config = 'here' + loader.deep = loader.deep || {}; + loader.deep.config = { too: 'too' }; + */ + loader.config = function(cfg) { + for (var c in cfg) { + var v = cfg[c]; + if (typeof v == 'object') { + this[c] = this[c] || {}; + for (var p in v) + this[c][p] = v[p]; + } + else + this[c] = v; + } } + // override locate to allow baseURL to be document-relative + var baseURI; + if (typeof window == 'undefined') { + baseURI = __dirname + '/'; + } + else { + baseURI = document.baseURI; + if (!baseURI) { + var bases = document.getElementsByTagName('base'); + baseURI = bases[0] && bases[0].href || window.location.href; + } + } + var loaderLocate = loader.locate; + var normalizedBaseURL; + loader.locate = function(load) { + if (this.baseURL != normalizedBaseURL) { + normalizedBaseURL = toAbsoluteURL(baseURI, this.baseURL); + + if (normalizedBaseURL.substr(normalizedBaseURL.length - 1, 1) != '/') + normalizedBaseURL += '/'; + + this.baseURL = normalizedBaseURL; + } + + return Promise.resolve(loaderLocate.call(this, load)); + } + + + // Traceur conveniences + var aliasRegEx = /^\s*export\s*\*\s*from\s*(?:'([^']+)'|"([^"]+)")/; + var es6RegEx = /(?:^\s*|[}{\(\);,\n]\s*)(import\s+['"]|(import|module)\s+[^"'\(\)\n;]+\s+from\s+['"]|export\s+(\*|\{|default|function|var|const|let|[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*))/; + + var loaderTranslate = loader.translate; + loader.translate = function(load) { + var loader = this; + + loader.__exec = exec; + + // support ES6 alias modules ("export * from 'module';") without needing Traceur + var match; + if (!loader.global.traceur && (load.metadata.format == 'es6' || !load.metadata.format) && (match = load.source.match(aliasRegEx))) { + var depName = match[1] || match[2]; + load.metadata.deps = [depName]; + load.metadata.execute = function(require) { + return require(depName); + } + } + + // detect ES6 + if (load.metadata.format == 'es6' || !load.metadata.format && load.source.match(es6RegEx)) { + load.metadata.format = 'es6'; + + // dynamically load Traceur for ES6 if necessary + if (!loader.global.traceur) + return loader['import']('@traceur').then(function() { + return loaderTranslate.call(loader, load); + }); + } + + return loaderTranslate.call(loader, load); + } + + // always load Traceur as a global + var loaderInstantiate = loader.instantiate; + loader.instantiate = function(load) { + var loader = this; + if (load.name == '@traceur') { + loader.__exec(load); + return { + deps: [], + execute: function() {} + }; + } + return loaderInstantiate.call(loader, load); + } + + + // define exec for easy evaluation of a load record (load.name, load.source, load.address) + // main feature is source maps support handling + var curSystem + function exec(load) { + if (load.name == '@traceur') + curSystem = System; + // support sourceMappingURL (efficiently) + var sourceMappingURL; + var lastLineIndex = load.source.lastIndexOf('\n'); + if (lastLineIndex != -1) { + if (load.source.substr(lastLineIndex + 1, 21) == '//# sourceMappingURL=') + sourceMappingURL = toAbsoluteURL(load.address, load.source.substr(lastLineIndex + 22)); + } + + __eval(load.source, this.global, load.address, sourceMappingURL); + + // traceur overwrites System - write it back + if (load.name == '@traceur') { + this.global.traceurSystem = this.global.System; + this.global.System = curSystem; + } + } + loader.__exec = exec; + // 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]*)?/); @@ -119,54 +221,6 @@ function core(loader) { (href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) + href.hash; } - var baseURI; - if (typeof window == 'undefined') { - baseURI = __dirname + '/'; - } - else { - baseURI = document.baseURI; - if (!baseURI) { - var bases = document.getElementsByTagName('base'); - baseURI = bases[0] && bases[0].href || window.location.href; - } - } - - // System.meta provides default metadata - System.meta = {}; - - // override locate to allow baseURL to be document-relative - var loaderLocate = loader.locate; - var normalizedBaseURL; - loader.locate = function(load) { - if (this.baseURL != normalizedBaseURL) - this.baseURL = normalizedBaseURL = toAbsoluteURL(baseURI, this.baseURL); - - var meta = System.meta[load.name]; - for (var p in meta) - load.metadata[p] = meta[p]; - - return Promise.resolve(loaderLocate.call(this, load)); - } - - // define exec for custom instantiations - loader.__exec = function(load) { - - // support sourceMappingURL (efficiently) - var sourceMappingURL; - var lastLineIndex = load.source.lastIndexOf('\n'); - if (lastLineIndex != -1) { - if (load.source.substr(lastLineIndex + 1, 21) == '//# sourceMappingURL=') - sourceMappingURL = toAbsoluteURL(load.address, load.source.substr(lastLineIndex + 22)); - } - - __eval(load.source, loader.global, load.address, sourceMappingURL); - - // traceur overwrites System - write it back - if (load.name == '@traceur') { - loader.global.traceurSystem = loader.global.System; - loader.global.System = curSystem; - } - } })(); @@ -184,24 +238,370 @@ function core(loader) { } } } -function amdScriptLoader(loader) { +/* + * Instantiate registry extension + * + * Supports Traceur System.register 'instantiate' output for loading ES6 as ES5. + * + * - Creates the loader.register function + * - Also supports metadata.format = 'register' in instantiate for anonymous register modules + * - Also supports metadata.deps, metadata.execute and metadata.executingRequire + * for handling dynamic modules alongside register-transformed ES6 modules + * + * Works as a standalone extension provided there is a + * loader.__exec(load) like the one set in SystemJS core + * + */ + +function register(loader) { + if (typeof indexOf == 'undefined') + indexOf = Array.prototype.indexOf; + if (!loader.__exec) + throw "loader.__exec(load) needs to be provided for loader.register. See SystemJS core for an implementation example."; + + function dedupe(deps) { + var newDeps = []; + for (var i = 0; i < deps.length) + if (indexOf.call(newDeps, deps[i]) == -1) + newDeps.push(deps[i]) + return newDeps; + } + + // Registry side table + // Registry Entry Contains: + // - deps + // - declare for register modules + // - execute for dynamic modules, also after declare for register modules + // - declarative boolean indicating which of the above + // - normalizedDeps derived from deps, created in instantiate + // - depMap array derived from deps, populated gradually in link + // - groupIndex used by group linking algorithm + // - module a raw module exports object with no wrapper + // - evaluated indiciating whether evaluation has happend for declarative modules + // After linked and evaluated, entries are removed + var lastRegister; + function register(name, deps, declare) { + if (declare.length == 0) + throw 'Invalid System.register form. Ensure setting --modules=instantiate if using Traceur.'; + + loader.defined = loader.defined || {}; + + if (typeof name != 'string') { + declare = deps; + deps = name; + name = null; + } + + lastRegister = { + deps: deps, + declare: declare, + declarative: true + }; + + if (name) + loader.defined[name] = lastRegister; + } + loader.register = register; + + function buildGroups(entry, loader, groups) { + + groups[entry.groupIndex] = groups[entry.groupIndex] || []; + + if (indexOf.call(groups[entry.groupIndex], entry) != -1) + return; + + groups[entry.groupIndex].push(entry); + + for (var i = 0; i < entry.normalizedDeps.length; i++) { + var depName = entry.normalizedDeps[i]; + var depEntry = loader.defined[depName]; + + // not in the registry means already linked / ES6 + if (!depEntry) + continue; + + // now we know the entry is in our unlinked linkage group + var depGroupIndex = entry.groupIndex + (depEntry.declarative != entry.declarative); + + if (depEntry.groupIndex === undefined) { + depEntry.groupIndex = depGroupIndex; + } + else if (depEntry.groupIndex != depGroupIndex) { + throw new TypeError('System.register mixed dependency cycle'); + } + + buildGroups(entry, loader, groups); + } + } + + function link(name, loader) { + var startEntry = loader.defined[name]; + + startEntry.groupIndex = 0; + + var groups = buildGroups(name, loader, []); + + var curGroupDeclarative = startEntry.declarative == groups.length % 2; + for (var i = groups.length - 1; i >= 0; i--) { + var group = groups[i]; + for (var j = 0; j < group.length; j++) { + var entry = group[j]; + + // link each group + if (curGroupDeclarative) + linkDeclarativeModule(entry, loader); + else + linkDynamicModule(entry, loader); + } + curGroupDeclarative = !curGroupDeclarative; + } + } + + function linkDeclarativeModule(entry, loader) { + // only link if already not already started linking (stops at circular) + if (entry.module) + return; + + // declare the module with an empty depMap + var depMap = []; + + var declaration = load.declare.call(loader.global, depMap); + + entry.module = declaration.exports; + entry.exportStar = declaration.exportStar; + entry.execute = declaration.execute; + + var module = entry.module; + + // now link all the module dependencies + // amending the depMap as we go + for (var i = 0; i < entry.normalizedDeps.length; i++) { + var depName = entry.normalizedDeps[i]; + var depEntry = loader.defined[depName]; + + // part of another linking group - use loader.get + if (!depEntry) { + depModule = loader.get(depName); + } + // if dependency already linked, use that + else if (depEntry.module) { + depModule = depEntry.module; + } + // otherwise we need to link the dependency + else { + linkDeclarativeModule(depEntry, loader); + depModule = depEntry.module; + } + + if (entry.exportStar && indexOf.call(entry.exportStar, entry.normalizedDeps[i]) != -1) { + // we are exporting * from this dependency + (function(depModule) { + for (var p in depModule) (function(p) { + // if the property is already defined throw? + Object.defineProperty(module, p, { + enumerable: true, + get: function() { + return depModule[p]; + }, + set: function(value) { + depModule[p] = value; + } + }); + })(p); + })(depModule); + } + + depMap[i] = depModule; + } + } + + // An analog to loader.get covering execution of all three layers (real declarative, simulated declarative, simulated dynamic) + function getModule(name, loader) { + var entry = loader.defined[name]; + + if (!entry) + return loader.get(name); + + if (entry.declarative) + ensureEvaluated(name, [], loader); + + else if (!entry.evaluated) + linkDynamicModule(entry, loader); + + return entry.module; + } + + function linkDynamicModule(entry, loader) { + if (entry.module) + return; + + entry.module = {}; + + // AMD requires execute the tree first + if (!entry.executingRequire) { + for (var i = 0; i < entry.normalizedDeps.length; i++) { + var depName = entry.normalizedDeps[i]; + var depEntry = loader.defined[depName]; + linkDynamicModule(depEntry, loader); + } + } + + // now execute + entry.evaluated = true; + var output = entry.execute(function(name) { + for (var i = 0; i < entry.deps.length; i++) { + if (entry.deps[i] != name) + continue; + return getModule(entry.normalizedDeps[i], loader); + } + }, entry.module, name); + + if (output) + entry.module = output; + } + + // given a module, and the list of modules for this current branch, + // ensure that each of the dependencies of this module is evaluated + // (unless one is a circular dependency already in the list of seen + // modules, in which case we execute it) + // then evaluate the module itself + // depth-first left to right execution to match ES6 modules + function ensureEvaluated(moduleName, seen, loader) { + var entry = loader.defined[moduleName]; + + // if already seen, that means it's an already-evaluated non circular dependency + if (!entry.declarative || entry.evaluated || indexOf.call(seen, moduleName) != -1) + return; + + seen.push(moduleName); + + for (var i = 0; i < entry.normalizedDeps.length; i++) { + var depName = entry.normalizedDeps[i]; + + // circular -> execute now if not already executed + if (indexOf.call(seen, depName) != -1) { + var depEntry = loader.defined[depName]; + if (depEntry && !depEntry.evaluated) { + depEntry.execute.call(loader.global); + delete depEntry.execute; + } + } + // in turn ensure dependencies are evaluated + else + ensureEvaluated(depName, seen); + } + + // we've evaluated all dependencies so evaluate this module now + entry.execute.call(loader.global); + entry.evaluated = true; + } + + var registerRegEx = /asdf/; + + + var loaderTranslate = loader.translate; + loader.translate = function(load) { + loader.register = register; + + // run detection for register format here + if (load.metadata.format == 'register' || !load.metadata.format && load.source.match(registerRegEx)) + load.metadata.format = 'register'; + + load.metadata.deps = []; + return loaderTranslate.call(this, load); + } + + + var loaderInstantiate = loader.instantiate; + loader.instantiate = function(load) { + var loader = this; + + var entry; + + if (loader.defined[load.name]) + entry = loader.defined[load.name]; + + else if (load.metadata.execute) { + entry = { + deps: load.metadata.deps || [], + execute: load.metadata.execute, + executingRequire: load.metadata.executingRequire // NodeJS-style requires or not + }; + } + else if (load.metadata.format == 'register') { + lastRegister = null; + loader.__exec(load); + + // for a bundle, take the last defined module + // in the bundle to be the bundle itself + if (lastRegister) + entry = lastRegister; + } + + if (!entry) + return loaderInstantiate.call(this, load); + + + // first, normalize all dependencies + var normalizePromises = []; + for (var i = 0; i < deps.length; i++) + normalizePromises.push(Promise.resolve(loader.normalize(deps[i], load.name))); + + return Promise.all(normalizePromises).then(function(normalizedDeps) { + + entry.normalizedDeps = normalizedDeps; + + // create the empty dep map - this is our key deferred dependency binding object passed into declare + entry.depMap = []; + + entry.deps = dedupe(entry.deps); + + return { + deps: entry.deps, + execute: function() { + // recursively ensure that the module and all its + // dependencies are linked (with dependency group handling) + link(load.name, loader); + + // now handle dependency execution in correct order + ensureEvaluated(load.name, [], loader); + + // remove from the registry + delete loader.defined[load.name]; + + var module = Module(entry.module); + + // if the entry is an alias, set the alias too + for (var name in loader.defined) { + if (loader.defined[name].execute != entry.execute) + continue; + if (!loader.has(name)) + loader.set(name, module); + } + + // return the defined module object + return module; + } + }; + }); + } +} +/* + * Script tag fetch + */ + +function scriptLoader(loader) { + if (typeof indexOf == 'undefined') + indexOf = Array.prototype.indexOf; var head = document.getElementsByTagName('head')[0]; // override fetch to use script injection loader.fetch = function(load) { - // if already defined, skip - if (loader.defined[load.name]) - return ''; - - // script injection fetch system return new Promise(function(resolve, reject) { var s = document.createElement('script'); s.async = true; s.addEventListener('load', function(evt) { - if (lastAnonymous) - loader.defined[load.name] = lastAnonymous; - lastAnonymous = null; resolve(''); }, false); s.addEventListener('error', function(err) { @@ -211,87 +611,121 @@ function amdScriptLoader(loader) { head.appendChild(s); }); } - var lastAnonymous = null; - loader.global.define = function(name, deps, factory) { - // anonymous define - if (typeof name != 'string') { - factory = deps; - deps = name; - name = null; +} +/* + 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' } - if (!(deps instanceof Array)) { - factory = deps; - deps = []; + 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 (typeof factory != 'function') - factory = (function(factory) { - return function() { return factory; } - })(factory); + // 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; + } - for (var i = 0; i < deps.length; i++) - if (lastIndexOf.call(deps, deps[i]) != i) - deps.splice(i--, 1); + // now do the global map + for (var p in loader.map) { + var curMap = loader.map[p]; + if (typeof curMap != 'string') + continue; - var instantiate = { - deps: deps, - execute: function() { - var args = []; - for (var i = 0; i < arguments.length; i++) - args.push(loader.getModule(arguments[i])); + if (prefixMatchLength(name, p) <= curMatchLength) + continue; - var output = factory.apply(this, args); - return new loader.global.Module(output && output.__esModule ? output : { __useDefault: true, 'default': output }); - } - }; - - if (name) - loader.defined[name] = instantiate; - else - lastAnonymous = instantiate; - } - loader.global.define.amd = {}; - - // no translate at all - loader.translate = function() {} - - // instantiate defaults to null - loader.instantiate = function() { - return { - deps: [], - execute: function() { - return new Module({}); - } - }; + 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 : ''); } - - /* - AMD-compatible require - To copy RequireJS, set window.require = window.requirejs = loader.requirejs - */ - var require = loader.requirejs = function(names, callback, errback, referer) { - // in amd, first arg can be a config object... we just ignore - if (typeof names == 'object' && !(names instanceof Array)) - return require.apply(null, Array.prototype.splice.call(arguments, 1, arguments.length - 1)); - - // amd require - if (names instanceof Array) - Promise.all(names.map(function(name) { - return loader['import'](name, referer); - })).then(function(mods) { - return callback.apply(this, mods); - }, errback); - - // commonjs require - else if (typeof names == 'string') - return loader.getModule(names); - - else - throw 'Invalid require'; + 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); + }); } - } /* System bundles @@ -309,6 +743,9 @@ function amdScriptLoader(loader) { */ function bundles(loader) { + if (typeof indexOf == 'undefined') + indexOf = Array.prototype.indexOf; + // bundles support (just like RequireJS) // bundle name is module name of bundle itself // bundle is array of modules defined by the bundle @@ -318,6 +755,9 @@ function bundles(loader) { var loaderFetch = loader.fetch; loader.fetch = function(load) { + if (!loader.bundles) + loader.bundles = {}; + // if this module is in a bundle, load the bundle first then for (var b in loader.bundles) { if (indexOf.call(loader.bundles[b], load.name) == -1) @@ -335,80 +775,7 @@ function bundles(loader) { } return loaderFetch.apply(this, arguments); } - - var loaderLocate = loader.locate; - loader.locate = function(load) { - if (loader.bundles[load.name]) - load.metadata.bundle = true; - return loaderLocate.call(this, load); - } - - var loaderInstantiate = loader.instantiate; - loader.instantiate = function(load) { - // if it is a bundle itself, it doesn't define anything - if (load.metadata.bundle) - return { - deps: [], - execute: function() { - loader.__exec(load); - return new Module({}); - } - }; - - return loaderInstantiate.apply(this, arguments); - } - }/* - Implementation of the loader.register bundling method - - This allows the output of Traceur to populate the - module registry of the loader loader -*/ - -function register(loader) { - - // instantiation cache for loader.register - loader.defined = {}; - - // register a new module for instantiation - loader.register = function(name, deps, execute) { - loader.defined[name] = { - deps: deps, - execute: function() { - return Module(execute.apply(this, arguments)); - } - }; - } - - var loaderLocate = loader.locate; - loader.locate = function(load) { - if (loader.defined[load.name]) - return ''; - return loaderLocate.apply(this, arguments); - } - - var loaderFetch = loader.fetch; - loader.fetch = function(load) { - // if the module is already defined, skip fetch - if (loader.defined[load.name]) - return ''; - return loaderFetch.apply(this, arguments); - } - - var loaderInstantiate = loader.instantiate; - loader.instantiate = function(load) { - // if the module has been defined by a bundle, use that - if (loader.defined[load.name]) { - var instantiateResult = loader.defined[load.name]; - delete loader.defined[load.name]; - return instantiateResult; - } - - return loaderInstantiate.apply(this, arguments); - } - -} -/* SystemJS Semver Version Addon 1. Uses Semver convention for major and minor forms @@ -466,6 +833,9 @@ function register(loader) { */ function versions(loader) { + if (typeof indexOf == 'undefined') + indexOf = Array.prototype.indexOf; + // match x, x.y, x.y.z, x.y.z-prerelease.1 var semverRegEx = /^(\d+)(?:\.(\d+)(?:\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?)?)?$/; @@ -486,15 +856,16 @@ function versions(loader) { return parseInt(v1Parts[i]) > parseInt(v2Parts[i]) ? 1 : -1; } return 0; - } + } - var loaderNormalize = loader.normalize; loader.versions = loader.versions || {}; - // hook normalize and store a record of all versioned packages + var loaderNormalize = loader.normalize; loader.normalize = function(name, parentName, parentAddress) { - var packageVersions = loader.versions; + if (!loader.versions) + loader.versions = {}; + var packageVersions = this.versions; // run all other normalizers first return Promise.resolve(loaderNormalize.call(this, name, parentName, parentAddress)).then(function(normalized) { @@ -626,46 +997,62 @@ function versions(loader) { } } core(System); -productionAMD(System); -bundles(System); register(System); +scriptLoader(System); +map(System); +bundles(System); versions(System); + System.baseURL = __$curScript.getAttribute('data-baseurl') || System.baseURL; + + var configPath = __$curScript.getAttribute('data-config'); + if (configPath === '') + configPath = System.baseURL + 'config.json'; + + var main = __$curScript.getAttribute('data-main'); + + (!configPath ? Promise.resolve() : + Promise.resolve(System.fetch.call(System, { address: configPath, metadata: {} })) + .then(JSON.parse) + .then(System.config) + ).then(function() { + if (main) + return System['import'](main); + }) + ['catch'](function(e) { + setTimeout(function() { + throw e; + }) + }); - if (__$global.systemMainEntryPoint) - System['import'](__$global.systemMainEntryPoint); }; -(function() { +var __$curScript; + +(function(global) { if (typeof window != 'undefined') { var scripts = document.getElementsByTagName('script'); - var curScript = scripts[scripts.length - 1]; - __$global.systemMainEntryPoint = curScript.getAttribute('data-main'); + __$curScript = scripts[scripts.length - 1]; - if (!__$global.System || __$global.System.registerModule) { + if (!global.System || global.System.registerModule) { // determine the current script path as the base path - var curPath = curScript.src; + var curPath = __$curScript.src; var basePath = curPath.substr(0, curPath.lastIndexOf('/') + 1); document.write( '<' + 'script type="text/javascript" src="' + basePath + 'es6-module-loader.js" data-init="upgradeSystemLoader">' + '<' + '/script>' ); } else { - __$global.upgradeSystemLoader(); + global.upgradeSystemLoader(); } - - var configPath = curScript.getAttribute('data-config'); - if (configPath) - document.write('<' + 'script type="text/javascript src="' + configPath + '">' + '<' + '/script>'); } else { var es6ModuleLoader = require('es6-module-loader'); - __$global.System = es6ModuleLoader.System; - __$global.Loader = es6ModuleLoader.Loader; - __$global.Module = es6ModuleLoader.Module; - module.exports = __$global.System; - __$global.upgradeSystemLoader(); + global.System = es6ModuleLoader.System; + global.Loader = es6ModuleLoader.Loader; + global.Module = es6ModuleLoader.Module; + module.exports = global.System; + global.upgradeSystemLoader(); } -})(); - +})(__$global); })(typeof window != 'undefined' ? window : global); \ No newline at end of file diff --git a/dist/system-production-amd.min.js b/dist/system-production-amd.min.js index ae5edee2..6ea6f45d 100644 --- a/dist/system-production-amd.min.js +++ b/dist/system-production-amd.min.js @@ -5,4 +5,4 @@ * MIT License */ -!function(__$global){__$global.upgradeSystemLoader=function(){function core(loader){function __eval(__source,__global,__address,__sourceMap){try{__source="with(__global) { (function() { "+__source+" \n }).call(__global); }\n//# sourceURL="+__address+(__sourceMap?"\n//# sourceMappingURL="+__sourceMap:""),eval(__source)}catch(e){throw"SyntaxError"==e.name&&(e.message="Evaluating "+__address+"\n "+e.message),e}}!function(){function e(e){var t=String(e).replace(/^\s+|\s+$/g,"").match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);return t?{href:t[0]||"",protocol:t[1]||"",authority:t[2]||"",host:t[3]||"",hostname:t[4]||"",port:t[5]||"",pathname:t[6]||"",search:t[7]||"",hash:t[8]||""}:null}function t(t,n){function r(e){var t=[];return e.replace(/^(\.\.?(\/|$))+/,"").replace(/\/(\.(\/|$))+/g,"/").replace(/\/\.\.$/,"/../").replace(/\/?[^\/]*/g,function(e){"/.."===e?t.pop():t.push(e)}),t.join("").replace(/^\//,"/"===e.charAt(0)?"/":"")}return n=e(n||""),t=e(t||""),n&&t?(n.protocol||t.protocol)+(n.protocol||n.authority?n.authority:t.authority)+r(n.protocol||n.authority||"/"===n.pathname.charAt(0)?n.pathname:n.pathname?(t.authority&&!t.pathname?"/":"")+t.pathname.slice(0,t.pathname.lastIndexOf("/")+1)+n.pathname:t.pathname)+(n.protocol||n.authority||n.pathname?n.search:n.search||t.search)+n.hash:null}var n=System,r=function(e){if(!(e instanceof Module)){for(var t=[],n=0;nparseInt(a[o])?1:-1}return 0},r=e.normalize;e.versions=e.versions||{},e.normalize=function(a,o,s){var l=e.versions;return Promise.resolve(r.call(this,a,o,s)).then(function(e){var r,a,o,s,i=e.indexOf("@");if(-1==i){for(var u in l)if(s=l[u],e.substr(0,u.length)==u&&(o=e.substr(u.length,1),!o||"/"==o))return u+"@"+("string"==typeof s?s:s[s.length-1])+e.substr(u.length);return e}r=e.substr(i+1).split("/")[0];var c,d=r.length;if("^"==r.substr(0,1)&&(r=r.substr(1),c=!0),a=r.match(t),!a)return e;c&&(a[2]||(c=!1),a[3]||(a[2]>0?a[3]="0":c=!1)),c&&(a[1]>0?(a[2]||(r=a[1]+".0.0"),a[3]||(r=a[1]+".0"),c=r,a=[a[1]]):a[2]>0?(c=r,a=[0,a[2]]):(c=!1,a=[0,0,a[3]]),r=a.join("."));var f=e.substr(0,i);if(s=l[f]||[],"string"==typeof s&&(s=[s]),!a[3]||c)for(var p=s.length-1;p>=0;p--){var m=s[p];if(m.substr(0,r.length)==r&&m.substr(r.length,1).match(/^[\.\-]?$/)&&(!c||c&&-1!=n(m,c)))return f+"@"+m+e.substr(f.length+d+1)}return-1==indexOf.call(s,r)&&(s.push(r),s.sort(n),e=f+"@"+r+e.substr(f.length+d+1),a[3]&&-1!=(i=indexOf.call(s,a[1]+"."+a[2]))&&s.splice(i,1),a[2]&&-1!=(i=indexOf.call(s,a[1]))&&s.splice(i,1),l[f]=1==s.length?s[0]:s),e})}}__$global.upgradeSystemLoader=void 0;var indexOf=Array.prototype.indexOf||function(e){for(var t=0,n=this.length;n>t;t++)if(this[t]===e)return t;return-1},lastIndexOf=Array.prototype.lastIndexOf||function(e){for(var t=this.length-1;t>=0;t--)if(this[t]===e)return t;return-t};core(System),productionAMD(System),bundles(System),register(System),versions(System),__$global.systemMainEntryPoint&&System["import"](__$global.systemMainEntryPoint)},function(){if("undefined"!=typeof window){var e=document.getElementsByTagName("script"),t=e[e.length-1];if(__$global.systemMainEntryPoint=t.getAttribute("data-main"),!__$global.System||__$global.System.registerModule){var n=t.src,r=n.substr(0,n.lastIndexOf("/")+1);document.write('')}else __$global.upgradeSystemLoader();var a=t.getAttribute("data-config");a&&document.write('')}else{var o=require("es6-module-loader");__$global.System=o.System,__$global.Loader=o.Loader,__$global.Module=o.Module,module.exports=__$global.System,__$global.upgradeSystemLoader()}}()}("undefined"!=typeof window?window:global); \ No newline at end of file +!function(__$global){__$global.upgradeSystemLoader=function(){function core(loader){function __eval(__source,__global,__address,__sourceMap){try{__source="with(__global) { (function() { "+__source+" \n }).call(__global); }\n//# sourceURL="+__address+(__sourceMap?"\n//# sourceMappingURL="+__sourceMap:""),eval(__source)}catch(e){throw"SyntaxError"==e.name&&(e.message="Evaluating "+__address+"\n "+e.message),e}}!function(){function e(e){var t=String(e).replace(/^\s+|\s+$/g,"").match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);return t?{href:t[0]||"",protocol:t[1]||"",authority:t[2]||"",host:t[3]||"",hostname:t[4]||"",port:t[5]||"",pathname:t[6]||"",search:t[7]||"",hash:t[8]||""}:null}function t(t,n){function r(e){var t=[];return e.replace(/^(\.\.?(\/|$))+/,"").replace(/\/(\.(\/|$))+/g,"/").replace(/\/\.\.$/,"/../").replace(/\/?[^\/]*/g,function(e){"/.."===e?t.pop():t.push(e)}),t.join("").replace(/^\//,"/"===e.charAt(0)?"/":"")}return n=e(n||""),t=e(t||""),n&&t?(n.protocol||t.protocol)+(n.protocol||n.authority?n.authority:t.authority)+r(n.protocol||n.authority||"/"===n.pathname.charAt(0)?n.pathname:n.pathname?(t.authority&&!t.pathname?"/":"")+t.pathname.slice(0,t.pathname.lastIndexOf("/")+1)+n.pathname:t.pathname)+(n.protocol||n.authority||n.pathname?n.search:n.search||t.search)+n.hash:null}var n=System,r=function(e){if(!(e instanceof Module)){for(var t=[],n=0;nparseInt(a[o])?1:-1}return 0},r=e.normalize;e.versions=e.versions||{},e.normalize=function(a,o,s){var i=e.versions;return Promise.resolve(r.call(this,a,o,s)).then(function(e){var r,a,o,s,u=e.indexOf("@");if(-1==u){for(var l in i)if(s=i[l],e.substr(0,l.length)==l&&(o=e.substr(l.length,1),!o||"/"==o))return l+"@"+("string"==typeof s?s:s[s.length-1])+e.substr(l.length);return e}r=e.substr(u+1).split("/")[0];var c,d=r.length;if("^"==r.substr(0,1)&&(r=r.substr(1),c=!0),a=r.match(t),!a)return e;c&&(a[2]||(c=!1),a[3]||(a[2]>0?a[3]="0":c=!1)),c&&(a[1]>0?(a[2]||(r=a[1]+".0.0"),a[3]||(r=a[1]+".0"),c=r,a=[a[1]]):a[2]>0?(c=r,a=[0,a[2]]):(c=!1,a=[0,0,a[3]]),r=a.join("."));var f=e.substr(0,u);if(s=i[f]||[],"string"==typeof s&&(s=[s]),!a[3]||c)for(var m=s.length-1;m>=0;m--){var p=s[m];if(p.substr(0,r.length)==r&&p.substr(r.length,1).match(/^[\.\-]?$/)&&(!c||c&&-1!=n(p,c)))return f+"@"+p+e.substr(f.length+d+1)}return-1==indexOf.call(s,r)&&(s.push(r),s.sort(n),e=f+"@"+r+e.substr(f.length+d+1),a[3]&&-1!=(u=indexOf.call(s,a[1]+"."+a[2]))&&s.splice(u,1),a[2]&&-1!=(u=indexOf.call(s,a[1]))&&s.splice(u,1),i[f]=1==s.length?s[0]:s),e})}}__$global.upgradeSystemLoader=void 0;var indexOf=Array.prototype.indexOf||function(e){for(var t=0,n=this.length;n>t;t++)if(this[t]===e)return t;return-1},lastIndexOf=Array.prototype.lastIndexOf||function(e){for(var t=this.length-1;t>=0;t--)if(this[t]===e)return t;return-t};core(System),productionAMD(System),bundles(System),register(System),versions(System),(__$config?System.fetch({address:__$config}).then(JSON.parse).then(System.config):Promise.resolve()).then(function(){System["import"](__$main)})["catch"](function(e){setTimeout(function(){throw e})})};var __$main,__$config;!function(){if("undefined"!=typeof window){var e=document.getElementsByTagName("script"),t=e[e.length-1];if(__$config=t.getAttribute("config")||t.getAttribute("data-config"),__$main=t.getAttribute("main")||t.getAttribute("data-main"),!__$global.System||__$global.System.registerModule){var n=t.src,r=n.substr(0,n.lastIndexOf("/")+1);document.write('')}else __$global.upgradeSystemLoader()}else{var a=require("es6-module-loader");__$global.System=a.System,__$global.Loader=a.Loader,__$global.Module=a.Module,module.exports=__$global.System,__$global.upgradeSystemLoader()}}()}("undefined"!=typeof window?window:global); \ No newline at end of file diff --git a/dist/system.js b/dist/system.js index 974859c6..22a0ca3a 100644 --- a/dist/system.js +++ b/dist/system.js @@ -7,78 +7,181 @@ (function(__$global) { -__$global.upgradeSystemLoader = function() { - __$global.upgradeSystemLoader = undefined;// Define an IE-friendly shim good-enough for purposes -var indexOf = Array.prototype.indexOf || function(item) { - for (var i = 0, thisLen = this.length; i < thisLen; i++) { +// 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 lastIndexOf = Array.prototype.lastIndexOf || function(c) { - for (var i = this.length - 1; i >= 0; i--) { - if (this[i] === c) { - return i; - } - } - return -i; -}/* - SystemJS Core - Adds normalization to the import function, as well as __useDefault support -*/ +__$global.upgradeSystemLoader = function() { + __$global.upgradeSystemLoader = undefined;/* + * SystemJS Core + * Code should be vaguely readable + * + */ function core(loader) { (function() { - var curSystem = System; - /* __useDefault When a module object looks like: - new Module({ + Module({ __useDefault: true, default: 'some-module' }) - Then the import of that module is taken to be the 'default' export and not the module object itself. + Then importing that module provides the 'some-module' + result directly instead of the full module. - Useful for module.exports = function() {} handling + Useful for eg module.exports = function() {} */ - var checkUseDefault = function(module) { - if (!(module instanceof Module)) { - var out = []; - for (var i = 0; i < module.length; i++) - out[i] = checkUseDefault(module[i]); - return out; - } - return module.__useDefault ? module['default'] : module; - } - - // a variation on System.get that does the __useDefault check - loader.getModule = function(key) { - return checkUseDefault(loader.get(key)); + var loaderImport = loader['import']; + loader['import'] = function(name, options) { + return loaderImport.call(this, name, options).then(function(module) { + return module.__useDefault ? module['default'] : module; + }); } // support the empty module, as a concept loader.set('@empty', Module({})); - - - var loaderImport = loader['import']; - loader['import'] = function(name, options) { - // patch loader.import to do normalization - return new Promise(function(resolve) { - resolve(loader.normalize.call(this, name, options && options.name, options && options.address)) - }) - // add useDefault support - .then(function(name) { - return Promise.resolve(loaderImport.call(loader, name, options)).then(function(module) { - return checkUseDefault(module); - }); + + /* + Config + Extends config merging one deep only + + loader.config({ + some: 'random', + config: 'here', + deep: { + config: { too: 'too' } + } }); + + <=> + + loader.some = 'random'; + loader.config = 'here' + loader.deep = loader.deep || {}; + loader.deep.config = { too: 'too' }; + */ + loader.config = function(cfg) { + for (var c in cfg) { + var v = cfg[c]; + if (typeof v == 'object') { + this[c] = this[c] || {}; + for (var p in v) + this[c][p] = v[p]; + } + else + this[c] = v; + } } + // override locate to allow baseURL to be document-relative + var baseURI; + if (typeof window == 'undefined') { + baseURI = __dirname + '/'; + } + else { + baseURI = document.baseURI; + if (!baseURI) { + var bases = document.getElementsByTagName('base'); + baseURI = bases[0] && bases[0].href || window.location.href; + } + } + var loaderLocate = loader.locate; + var normalizedBaseURL; + loader.locate = function(load) { + if (this.baseURL != normalizedBaseURL) { + normalizedBaseURL = toAbsoluteURL(baseURI, this.baseURL); + + if (normalizedBaseURL.substr(normalizedBaseURL.length - 1, 1) != '/') + normalizedBaseURL += '/'; + + this.baseURL = normalizedBaseURL; + } + + return Promise.resolve(loaderLocate.call(this, load)); + } + + + // Traceur conveniences + var aliasRegEx = /^\s*export\s*\*\s*from\s*(?:'([^']+)'|"([^"]+)")/; + var es6RegEx = /(?:^\s*|[}{\(\);,\n]\s*)(import\s+['"]|(import|module)\s+[^"'\(\)\n;]+\s+from\s+['"]|export\s+(\*|\{|default|function|var|const|let|[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*))/; + + var loaderTranslate = loader.translate; + loader.translate = function(load) { + var loader = this; + + loader.__exec = exec; + + // support ES6 alias modules ("export * from 'module';") without needing Traceur + var match; + if (!loader.global.traceur && (load.metadata.format == 'es6' || !load.metadata.format) && (match = load.source.match(aliasRegEx))) { + var depName = match[1] || match[2]; + load.metadata.deps = [depName]; + load.metadata.execute = function(require) { + return require(depName); + } + } + + // detect ES6 + if (load.metadata.format == 'es6' || !load.metadata.format && load.source.match(es6RegEx)) { + console.log('load traceur'); + load.metadata.format = 'es6'; + + // dynamically load Traceur for ES6 if necessary + if (!loader.global.traceur) + return loader['import']('@traceur').then(function() { + return loaderTranslate.call(loader, load); + }); + } + + return loaderTranslate.call(loader, load); + } + + // always load Traceur as a global + var loaderInstantiate = loader.instantiate; + loader.instantiate = function(load) { + var loader = this; + if (load.name == '@traceur') { + loader.__exec(load); + return { + deps: [], + execute: function() {} + }; + } + return loaderInstantiate.call(loader, load); + } + + + // define exec for easy evaluation of a load record (load.name, load.source, load.address) + // main feature is source maps support handling + var curSystem + function exec(load) { + if (load.name == '@traceur') + curSystem = System; + // support sourceMappingURL (efficiently) + var sourceMappingURL; + var lastLineIndex = load.source.lastIndexOf('\n'); + if (lastLineIndex != -1) { + if (load.source.substr(lastLineIndex + 1, 21) == '//# sourceMappingURL=') + sourceMappingURL = toAbsoluteURL(load.address, load.source.substr(lastLineIndex + 22)); + } + + __eval(load.source, this.global, load.address, sourceMappingURL); + + // traceur overwrites System - write it back + if (load.name == '@traceur') { + this.global.traceurSystem = this.global.System; + this.global.System = curSystem; + } + } + loader.__exec = exec; + // 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]*)?/); @@ -119,54 +222,6 @@ function core(loader) { (href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) + href.hash; } - var baseURI; - if (typeof window == 'undefined') { - baseURI = __dirname + '/'; - } - else { - baseURI = document.baseURI; - if (!baseURI) { - var bases = document.getElementsByTagName('base'); - baseURI = bases[0] && bases[0].href || window.location.href; - } - } - - // System.meta provides default metadata - System.meta = {}; - - // override locate to allow baseURL to be document-relative - var loaderLocate = loader.locate; - var normalizedBaseURL; - loader.locate = function(load) { - if (this.baseURL != normalizedBaseURL) - this.baseURL = normalizedBaseURL = toAbsoluteURL(baseURI, this.baseURL); - - var meta = System.meta[load.name]; - for (var p in meta) - load.metadata[p] = meta[p]; - - return Promise.resolve(loaderLocate.call(this, load)); - } - - // define exec for custom instantiations - loader.__exec = function(load) { - - // support sourceMappingURL (efficiently) - var sourceMappingURL; - var lastLineIndex = load.source.lastIndexOf('\n'); - if (lastLineIndex != -1) { - if (load.source.substr(lastLineIndex + 1, 21) == '//# sourceMappingURL=') - sourceMappingURL = toAbsoluteURL(load.address, load.source.substr(lastLineIndex + 22)); - } - - __eval(load.source, loader.global, load.address, sourceMappingURL); - - // traceur overwrites System - write it back - if (load.name == '@traceur') { - loader.global.traceurSystem = loader.global.System; - loader.global.System = curSystem; - } - } })(); @@ -185,138 +240,653 @@ function core(loader) { } } /* - SystemJS Formats + * Meta Extension + * + * Sets default metadata on a load record (load.metadata) from + * loader.meta[moduleName]. + * Also provides an inline meta syntax for module meta in source. + * + * Eg: + * + * loader.meta['my/module'] = { some: 'meta' }; + * + * load.metadata.some = 'meta' will now be set on the load record. + * + * The same meta could be set with a my/module.js file containing: + * + * my/module.js + * "some meta"; + * "another meta"; + * console.log('this is my/module'); + * + * The benefit of inline meta is that coniguration doesn't need + * to be known in advanced, which is useful for modularising + * configuration and avoiding the need for configuration injection. + * + * + * Example + * ------- + * + * The simplest meta example is setting the module format: + * + * System.meta['my/module'] = { format: 'amd' }; + * + * or inside 'my/module.js': + * + * "format amd"; + * define(...); + * + */ - Provides modular support for format detections. +function meta(loader) { + var metaRegEx = /^(\s*\/\*.*\*\/|\s*\/\/[^\n]*|\s*"[^"]+"\s*;?|\s*'[^']+'\s*;?)+/; + var metaPartRegEx = /\/\*.*\*\/|\/\/[^\n]*|"[^"]+"\s*;?|'[^']+'\s*;?/g; - Also dynamically loads Traceur if ES6 syntax is found. + loader.meta = {}; - Add a format with: - System.formats.push('myformatname'); - System.format.myformat = { - detect: function(source, load) { - return false / depArray; - }, - execute: function(load, deps) { - return moduleObj; // (doesnt have to be a Module instance) + function setConfigMeta(loader, load) { + var meta = loader.meta && loader.meta[load.name]; + if (meta) { + for (var p in meta) + load.metadata[p] = load.metadata[p] || meta[p]; + } + } + + var loaderLocate = loader.locate; + loader.locate = function(load) { + setConfigMeta(this, load); + return loaderLocate.call(this, load); + } + + var loaderTranslate = loader.translate; + loader.translate = function(load) { + setConfigMeta(this, load); + + // detect any meta header syntax + var meta = load.source.match(metaRegEx); + if (meta) { + var metaParts = meta[0].match(metaPartRegEx); + for (var i = 0; i < metaParts.length; i++) { + var len = metaParts[i].length; + + var firstChar = metaParts[i].substr(0, 1); + if (metaParts[i].substr(len - 1, 1) == ';') + len--; + + if (firstChar != '"' && firstChar != "'") + continue; + + var metaString = metaParts[i].substr(1, metaParts[i].length - 3); + + var metaName = metaString.substr(0, metaString.indexOf(' ')); + if (metaName) { + var metaValue = metaString.substr(metaName.length + 1, metaString.length - metaName.length - 1); + + if (load.metadata[metaName] instanceof Array) + load.metadata[metaName].push(metaValue); + else + load.metadata[metaName] = load.metadata[metaName] || metaValue; + } + } + } + return loaderTranslate.call(this, load); + } +}/* + * Instantiate registry extension + * + * Supports Traceur System.register 'instantiate' output for loading ES6 as ES5. + * + * - Creates the loader.register function + * - Also supports metadata.format = 'register' in instantiate for anonymous register modules + * - Also supports metadata.deps, metadata.execute and metadata.executingRequire + * for handling dynamic modules alongside register-transformed ES6 modules + * + * Works as a standalone extension provided there is a + * loader.__exec(load) like the one set in SystemJS core + * + */ + +function register(loader) { + if (typeof indexOf == 'undefined') + indexOf = Array.prototype.indexOf; + if (!loader.__exec) + throw "loader.__exec(load) needs to be provided for loader.register. See SystemJS core for an implementation example."; + + function dedupe(deps) { + var newDeps = []; + for (var i = 0; i < deps.length; i++) + if (indexOf.call(newDeps, deps[i]) == -1) + newDeps.push(deps[i]) + return newDeps; + } + + // Registry side table + // Registry Entry Contains: + // - deps + // - declare for register modules + // - execute for dynamic modules, also after declare for register modules + // - declarative boolean indicating which of the above + // - normalizedDeps derived from deps, created in instantiate + // - depMap array derived from deps, populated gradually in link + // - groupIndex used by group linking algorithm + // - module a raw module exports object with no wrapper + // - evaluated indiciating whether evaluation has happend for declarative modules + // After linked and evaluated, entries are removed + var lastRegister; + function register(name, deps, declare) { + if (declare.length == 0) + throw 'Invalid System.register form. Ensure setting --modules=instantiate if using Traceur.'; + + if (!loader.defined) + loader.defined = {}; + + if (typeof name != 'string') { + declare = deps; + deps = name; + name = null; + } + + lastRegister = { + deps: deps, + declare: declare, + declarative: true + }; + + if (name) + loader.defined[name] = lastRegister; + } + loader.defined = loader.defined || {}; + loader.register = register; + + function buildGroups(entry, loader, groups) { + + groups[entry.groupIndex] = groups[entry.groupIndex] || []; + + if (indexOf.call(groups[entry.groupIndex], entry) != -1) + return; + + groups[entry.groupIndex].push(entry); + + for (var i = 0; i < entry.normalizedDeps.length; i++) { + var depName = entry.normalizedDeps[i]; + var depEntry = loader.defined[depName]; + + // not in the registry means already linked / ES6 + if (!depEntry) + continue; + + // now we know the entry is in our unlinked linkage group + var depGroupIndex = entry.groupIndex + (depEntry.declarative != entry.declarative); + + if (depEntry.groupIndex === undefined) { + depEntry.groupIndex = depGroupIndex; + } + else if (depEntry.groupIndex != depGroupIndex) { + throw new TypeError('System.register mixed dependency cycle'); + } + + buildGroups(entry, loader, groups); + } + } + + function link(name, loader) { + var startEntry = loader.defined[name]; + + startEntry.groupIndex = 0; + + var groups = []; + + buildGroups(startEntry, loader, groups); + + var curGroupDeclarative = startEntry.declarative == groups.length % 2; + for (var i = groups.length - 1; i >= 0; i--) { + var group = groups[i]; + for (var j = 0; j < group.length; j++) { + var entry = group[j]; + + // link each group + if (curGroupDeclarative) + linkDeclarativeModule(entry, loader); + else + linkDynamicModule(entry, loader); + } + curGroupDeclarative = !curGroupDeclarative; + } + } + + function linkDeclarativeModule(entry, loader) { + // only link if already not already started linking (stops at circular) + if (entry.module) + return; + + // declare the module with an empty depMap + var depMap = []; + + var declaration = load.declare.call(loader.global, depMap); + + entry.module = declaration.exports; + entry.exportStar = declaration.exportStar; + entry.execute = declaration.execute; + + var module = entry.module; + + // now link all the module dependencies + // amending the depMap as we go + for (var i = 0; i < entry.normalizedDeps.length; i++) { + var depName = entry.normalizedDeps[i]; + var depEntry = loader.defined[depName]; + + // part of another linking group - use loader.get + if (!depEntry) { + depModule = loader.get(depName); + } + // if dependency already linked, use that + else if (depEntry.module) { + depModule = depEntry.module; + } + // otherwise we need to link the dependency + else { + linkDeclarativeModule(depEntry, loader); + depModule = depEntry.module; + } + + if (entry.exportStar && indexOf.call(entry.exportStar, entry.normalizedDeps[i]) != -1) { + // we are exporting * from this dependency + (function(depModule) { + for (var p in depModule) (function(p) { + // if the property is already defined throw? + Object.defineProperty(module, p, { + enumerable: true, + get: function() { + return depModule[p]; + }, + set: function(value) { + depModule[p] = value; + } + }); + })(p); + })(depModule); + } + + depMap[i] = depModule; + } + } + + // An analog to loader.get covering execution of all three layers (real declarative, simulated declarative, simulated dynamic) + function getModule(name, loader) { + var entry = loader.defined[name]; + + if (!entry) + return loader.get(name); + + if (entry.declarative) + ensureEvaluated(name, [], loader); + + else if (!entry.evaluated) + linkDynamicModule(entry, loader); + + return entry.module; + } + + function linkDynamicModule(entry, loader) { + if (entry.module) + return; + + entry.module = {}; + + // AMD requires execute the tree first + if (!entry.executingRequire) { + for (var i = 0; i < entry.normalizedDeps.length; i++) { + var depName = entry.normalizedDeps[i]; + var depEntry = loader.defined[depName]; + linkDynamicModule(depEntry, loader); } } - The System.formats array sets the format detection order. - - See the AMD, global and CommonJS format extensions for examples. -*/ -function formats(loader) { - - loader.format = {}; - loader.formats = []; - - if (typeof window != 'undefined') { - var curScript = document.getElementsByTagName('script'); - curScript = curScript[curScript.length - 1]; - // set the path to traceur - loader.paths['@traceur'] = curScript.getAttribute('data-traceur-src') || curScript.src.substr(0, curScript.src.lastIndexOf('/') + 1) + 'traceur.js'; + // now execute + try { + entry.evaluated = true; + var output = entry.execute(function(name) { + for (var i = 0; i < entry.deps.length; i++) { + if (entry.deps[i] != name) + continue; + return getModule(entry.normalizedDeps[i], loader); + } + }, entry.module, name); + } + catch(e) { + throw e; + } + + if (output) + entry.module = output; } - // also in ESML, build.js - var es6RegEx = /(?:^\s*|[}{\(\);,\n]\s*)(import\s+['"]|(import|module)\s+[^"'\(\)\n;]+\s+from\s+['"]|export\s+(\*|\{|default|function|var|const|let|[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*))/; - - // es6 module forwarding - allow detecting without Traceur - var aliasRegEx = /^\s*export\s*\*\s*from\s*(?:'([^']+)'|"([^"]+)")/; + // given a module, and the list of modules for this current branch, + // ensure that each of the dependencies of this module is evaluated + // (unless one is a circular dependency already in the list of seen + // modules, in which case we execute it) + // then evaluate the module itself + // depth-first left to right execution to match ES6 modules + function ensureEvaluated(moduleName, seen, loader) { + var entry = loader.defined[moduleName]; + + // if already seen, that means it's an already-evaluated non circular dependency + if (!entry.declarative || entry.evaluated || indexOf.call(seen, moduleName) != -1) + return; + + seen.push(moduleName); + + for (var i = 0; i < entry.normalizedDeps.length; i++) { + var depName = entry.normalizedDeps[i]; + + // circular -> execute now if not already executed + if (indexOf.call(seen, depName) != -1) { + var depEntry = loader.defined[depName]; + if (depEntry && !depEntry.evaluated) { + depEntry.execute.call(loader.global); + delete depEntry.execute; + } + } + // in turn ensure dependencies are evaluated + else + ensureEvaluated(depName, seen); + } + + // we've evaluated all dependencies so evaluate this module now + entry.execute.call(loader.global); + entry.evaluated = true; + } + + var registerRegEx = /System\.register/; + + var loaderTranslate = loader.translate; + loader.translate = function(load) { + loader.register = register; + + load.metadata.deps = load.metadata.deps || []; + + // run detection for register format here + if (load.metadata.format == 'register' || !load.metadata.format && load.source.match(registerRegEx)) + load.metadata.format = 'register'; + + return loaderTranslate.call(this, load); + } - // module format hint regex - var formatHintRegEx = /^(\s*(\/\*.*\*\/)|(\/\/[^\n]*))*(["']use strict["'];?)?["']([^'"]+)["'][;\n]/; var loaderInstantiate = loader.instantiate; loader.instantiate = function(load) { - var name = load.name || ''; + var loader = this; - load.source = load.source || ''; + var entry; + + if (loader.defined[load.name]) + loader.defined[load.name] = entry = loader.defined[load.name]; - // set load.metadata.format from metadata or format hints in the source - var format = load.metadata.format; - if (!format) { - var formatMatch = load.source.match(formatHintRegEx); - if (formatMatch) - format = load.metadata.format = formatMatch[5]; - } - - if (name == '@traceur') - format = 'global'; - - // es6 handled by core - - // support alias modules without needing Traceur - var match; - if (!loader.global.traceur && (format == 'es6' || !format) && (match = load.source.match(aliasRegEx))) { - return { - deps: [match[1] || match[2]], - execute: function(depName) { - return loader.get(depName); - } + else if (load.metadata.execute) { + loader.defined[load.name] = entry = { + deps: load.metadata.deps || [], + execute: load.metadata.execute, + executingRequire: load.metadata.executingRequire // NodeJS-style requires or not }; } + else if (load.metadata.format == 'register') { + lastRegister = null; + loader.__exec(load); - if (format == 'es6' || !format && load.source.match(es6RegEx)) { - // dynamically load Traceur if necessary - if (!loader.global.traceur) - return loader['import']('@traceur').then(function() { - return loaderInstantiate.call(loader, load); - }); - else - return loaderInstantiate.call(loader, load); + // for a bundle, take the last defined module + // in the bundle to be the bundle itself + if (lastRegister) + loader.defined[load.name] = entry = lastRegister; } - // if it is shimmed, assume it is a global script - if (load.metadata.exports || load.metadata.deps) - format = 'global'; + if (!entry) + return loaderInstantiate.call(this, load); - // if we don't know the format, run detection first - if (!format || !this.format[format]) - for (var i = 0; i < this.formats.length; i++) { - var f = this.formats[i]; - var curFormat = this.format[f]; - if (curFormat.detect(load)) { - format = f; - break; + entry.deps = dedupe(entry.deps); + + // first, normalize all dependencies + var normalizePromises = []; + for (var i = 0; i < entry.deps.length; i++) + normalizePromises.push(Promise.resolve(loader.normalize(entry.deps[i], load.name))); + + return Promise.all(normalizePromises).then(function(normalizedDeps) { + + entry.normalizedDeps = normalizedDeps; + + // create the empty dep map - this is our key deferred dependency binding object passed into declare + entry.depMap = []; + + return { + deps: entry.deps, + execute: function() { + // recursively ensure that the module and all its + // dependencies are linked (with dependency group handling) + link(load.name, loader); + + // now handle dependency execution in correct order + ensureEvaluated(load.name, [], loader); + + // remove from the registry + delete loader.defined[load.name]; + + var module = Module(entry.module); + + // if the entry is an alias, set the alias too + for (var name in loader.defined) { + if (loader.defined[name].execute != entry.execute) + continue; + if (!loader.has(name)) + loader.set(name, module); + } + // return the defined module object + return module; } - } - - var curFormat = this.format[format]; - - // if we don't have a format or format rule, throw - if (!format || !curFormat) - throw new TypeError('No format found for ' + (format ? format : load.address)); - - // now invoke format instantiation - var deps = curFormat.deps(load); - - // remove duplicates from deps first - for (var i = 0; i < deps.length; i++) - if (lastIndexOf.call(deps, deps[i]) != i) - deps.splice(i--, 1); - - return { - deps: deps, - execute: function() { - var output = curFormat.execute.call(this, Array.prototype.splice.call(arguments, 0, arguments.length), load); - - if (output instanceof loader.global.Module) - return output; - else - return new loader.global.Module(output && output.__esModule ? output : { __useDefault: true, 'default': output }); - } - }; + }; + }); } - } /* + SystemJS Global Format + + Supports + metadata.deps + metadata.init + metadata.exports + + Also detects writes to the global object avoiding global collisions. + See the SystemJS readme global support section for further information. +*/ +function global(loader) { + var loaderInstantiate = loader.instantiate; + loader.instantiate = function(load) { + var loader = this; + + // global is a fallback module format + if (load.metadata.format == 'global' || !load.metadata.format) { + load.metadata.deps = load.metadata.deps || []; + var deps = load.metadata.deps; + + var moduleGlobals = loader.moduleGlobals = loader.moduleGlobals || {}; + var globalExport = load.metadata.exports; + var init = load.metadata.init; + + load.metadata.execute = function(require, exports, moduleName) { + var hasOwnProperty = loader.global.hasOwnProperty; + + // first, we add all the dependency modules to the global + for (var i = 0; i < deps.length; i++) { + var moduleGlobal = moduleGlobals[deps[i]]; + if (moduleGlobal) + for (var m in moduleGlobal) + loader.global[m] = moduleGlobal[m]; + } + + // now store a complete copy of the global object + // in order to detect changes + var globalObj = {}; + for (var g in loader.global) + if (!hasOwnProperty || loader.global.hasOwnProperty(g)) + globalObj[g] = loader.global[g]; + + if (globalExport) + load.source += '\nthis["' + globalExport + '"] = ' + globalExport; + + loader.__exec(load); + + // check for global changes, creating the globalObject for the module + // if many globals, then a module object for those is created + // if one global, then that is the module directly + var singleGlobal; + if (globalExport) { + var firstPart = globalExport.split('.')[0]; + singleGlobal = eval.call(loader.global, globalExport); + exports[firstPart] = loader.global[firstPart]; + } + else { + for (var g in loader.global) { + if (!hasOwnProperty && (g == 'sessionStorage' || g == 'localStorage' || g == 'clipboardData' || g == 'frames')) + continue; + if ((!hasOwnProperty || loader.global.hasOwnProperty(g)) && g != loader.global && globalObj[g] != loader.global[g]) { + exports[g] = loader.global[g]; + if (singleGlobal) { + if (singleGlobal !== loader.global[g]) + singleGlobal = false; + } + else if (singleGlobal !== false) + singleGlobal = loader.global[g]; + } + } + } + moduleGlobals[load.name] = exports; + + var module = singleGlobal ? singleGlobal : exports; + + return { __useDefault: true, 'default': module }; + } + } + return loaderInstantiate.call(loader, load); + } +}/* + SystemJS CommonJS Format +*/ +function cjs(loader) { + + // CJS Module Format + // require('...') || exports[''] = ... || exports.asd = ... || module.exports = ... + var cjsExportsRegEx = /(?:^\s*|[}{\(\);,\n=:\?\&]\s*|module\.)(exports\s*\[\s*('[^']+'|"[^"]+")\s*\]|\exports\s*\.\s*[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*|exports\s*\=)/; + var cjsRequireRegEx = /(?:^\s*|[}{\(\);,\n=:\?\&]\s*)require\s*\(\s*("([^"]+)"|'([^']+)')\s*\)/g; + var commentRegEx = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg; + + function getCJSDeps(source) { + cjsExportsRegEx.lastIndex = 0; + cjsRequireRegEx.lastIndex = 0; + + var deps = []; + + // remove comments from the source first + var source = source.replace(commentRegEx, ''); + + var match; + + while (match = cjsRequireRegEx.exec(source)) + deps.push(match[2] || match[3]); + + return deps; + } + + var loaderTranslate = loader.translate; + loader.translate = function(load) { + load.metadata.getCJSDeps = getCJSDeps; + return loaderTranslate.call(this, load); + } + + + var noop = function() {} + var nodeProcess = { + nextTick: function(f) { + setTimeout(f, 7); + }, + browser: typeof window != 'undefined', + env: {}, + argv: [], + on: noop, + once: noop, + off: noop, + emit: noop, + cwd: function() { return '/' } + }; + loader.set('@@nodeProcess', Module(nodeProcess)); + + var loaderInstantiate = loader.instantiate; + loader.instantiate = function(load) { + + if (!load.metadata.format) { + cjsExportsRegEx.lastIndex = 0; + cjsRequireRegEx.lastIndex = 0; + if (cjsRequireRegEx.exec(load.source) || cjsExportsRegEx.exec(load.source)) + load.metadata.format = 'cjs'; + } + + if (load.metadata.format == 'cjs') { + load.metadata.deps = load.metadata.deps ? load.metadata.deps.concat(getCJSDeps(load.source)) : load.metadata.deps; + + load.metadata.execute = function(require, exports, moduleName) { + var dirname = load.address.split('/'); + dirname.pop(); + dirname = dirname.join('/'); + + var globals = loader.global._g = { + global: loader.global, + exports: exports, + module: { exports: exports }, + process: nodeProcess, + require: function(name) { + var module = require(name); + if (module.__useDefault) { + module = module['default']; + } + else if (!module.__esModule) { + // compatibility -> ES6 modules must have a __esModule flag + // we clone the module object to handle this + var moduleClone = { __esModule: true }; + for (var p in module) + moduleClone[p] = module[p]; + module = moduleClone; + } + return module; + }, + __filename: load.address, + __dirname: dirname + }; + + var glString = ''; + for (var _g in globals) + glString += 'var ' + _g + ' = _g.' + _g + ';'; + + load.source = glString + load.source; + + loader.__exec(load); + + loader.global._g = undefined; + + var output = globals.module.exports; + + if (output && output.__esModule) + return output; + else if (output !== undefined) + return { __useDefault: true, 'default': output }; + } + } + + return loaderInstantiate.call(this, load); + }; +}/* SystemJS AMD Format Provides the AMD module format definition at System.format.amd as well as a RequireJS-style require on System.require */ -function formatAMD(loader) { - loader.formats.push('amd'); +function amd(loader) { // AMD Module Format Detection RegEx // define([.., .., ..], ...) @@ -327,7 +897,10 @@ function formatAMD(loader) { AMD-compatible require To copy RequireJS, set window.require = window.requirejs = loader.require */ - var require = loader.require = function(names, callback, errback, referer) { + function require(names, callback, errback, referer) { + // 'this' is bound to the loader + var loader = this; + // in amd, first arg can be a config object... we just ignore if (typeof names == 'object' && !(names instanceof Array)) return require.apply(null, Array.prototype.splice.call(arguments, 1, arguments.length - 1)); @@ -341,361 +914,142 @@ function formatAMD(loader) { }, errback); // commonjs require - else if (typeof names == 'string') - return loader.getModule(names); + else if (typeof names == 'string') { + var module = loader.get(names); + return module.__useDefault ? module['default'] : module; + } else throw 'Invalid require'; }; - function makeRequire(parentName, deps, depsNormalized) { + loader.require = require; + + function makeRequire(parentName, staticRequire, loader) { return function(names, callback, errback) { - if (typeof names == 'string' && indexOf.call(deps, names) != -1) - return loader.getModule(depsNormalized[indexOf.call(deps, names)]); - return require(names, callback, errback, { name: parentName }); + if (typeof names == 'string') + return staticRequire(names); + return require.call(loader, names, callback, errback, { name: parentName }); } } - function prepareDeps(deps, meta) { - for (var i = 0; i < deps.length; i++) - if (lastIndexOf.call(deps, deps[i]) != i) - deps.splice(i--, 1); + var lastDefine; + function createDefine(loader, getCJSDeps) { + if (loader.global.define && loader.global.define.loader == loader) + return; - // remove system dependencies - var index; - if ((index = indexOf.call(deps, 'require')) != -1) { - meta.requireIndex = index; - deps.splice(index, 1); - } - if ((index = indexOf.call(deps, 'exports')) != -1) { - meta.exportsIndex = index; - deps.splice(index, 1); - } - if ((index = indexOf.call(deps, 'module')) != -1) { - meta.moduleIndex = index; - deps.splice(index, 1); - } - - return deps; - } - - function prepareExecute(depNames, load) { - var meta = load.metadata; - var deps = []; - for (var i = 0; i < depNames.length; i++) { - var module = loader.get(depNames[i]); - if (module.__useDefault) { - module = module['default']; + loader.global.define = function(name, deps, factory) { + if (typeof name != 'string') { + factory = deps; + deps = name; + name = null; } - else if (!module.__esModule) { - // compatibility -> ES6 modules must have a __esModule flag - // we clone the module object to handle this - var moduleClone = { __esModule: true }; - for (var p in module) - moduleClone[p] = module[p]; - module = moduleClone; + if (!(deps instanceof Array)) { + factory = deps; + // CommonJS AMD form + if (!getCJSDeps) + throw "AMD extension needs CJS extension for AMD CJS support"; + deps = ['require', 'exports', 'module'].concat(getCJSDeps(factory.toString())); } - deps[i] = module; - } - var module, exports; + if (typeof factory != 'function') + factory = (function(factory) { + return function() { return factory; } + })(factory); - // add back in system dependencies - if (meta.moduleIndex !== undefined) - deps.splice(meta.moduleIndex, 0, exports = {}, module = { id: load.name, uri: load.address, config: function() { return {}; }, exports: exports }); - if (meta.exportsIndex !== undefined) - deps.splice(meta.exportsIndex, 0, exports = exports || {}); - if (meta.requireIndex !== undefined) - deps.splice(meta.requireIndex, 0, makeRequire(load.name, meta.deps, depNames)); + // a module file can only define one anonymous module + if (!name && lastDefine) + throw "Multiple defines for anonymous module"; - return { - deps: deps, - module: module || exports && { exports: exports } - }; - } + // remove system dependencies + var requireIndex, exportsIndex, moduleIndex + if ((requireIndex = indexOf.call(deps, 'require')) != -1) + deps.splice(requireIndex, 1); - loader.format.amd = { - detect: function(load) { - return !!load.source.match(amdRegEx); - }, - deps: function(load) { + if ((exportsIndex = indexOf.call(deps, 'exports')) != -1) + deps.splice(exportsIndex, 1); + + if ((moduleIndex = indexOf.call(deps, 'module')) != -1) + deps.splice(moduleIndex, 1); - var global = loader.global; + lastDefine = { + deps: deps, + execute: function(require, exports, moduleName) { - var deps; - var meta = load.metadata; - var defined = false; - global.define = function(name, _deps, factory) { - - if (typeof name != 'string') { - factory = _deps; - _deps = name; - name = null; - } - - // anonymous modules must only call define once - if (!name && defined) { - throw "Multiple anonymous defines for module " + load.name; - } - if (!name) { - defined = true; - } - - if (!(_deps instanceof Array)) { - factory = _deps; - // CommonJS AMD form - var src = load.source; - load.source = factory.toString(); - _deps = ['require', 'exports', 'module'].concat(loader.format.cjs.deps(load, global)); - load.source = src; - } - - if (typeof factory != 'function') - factory = (function(factory) { - return function() { return factory; } - })(factory); - - if (name && name != load.name) { - // named define for a bundle describing another module - var _load = { - name: name, - address: name, - metadata: {} - }; - _deps = prepareDeps(_deps, _load.metadata); - loader.defined[name] = { - deps: _deps, - execute: function() { - var execs = prepareExecute(Array.prototype.splice.call(arguments, 0, arguments.length), _load); - var output = factory.apply(global, execs.deps) || execs.module && execs.module.exports; - - if (output instanceof global.Module) - return output; - else - return new global.Module(output && output.__esModule ? output : { __useDefault: true, 'default': output }); + var depValues = []; + for (var i = 0; i < deps.length; i++) { + var module = require(deps[i]); + if (module.__useDefault) { + module = module['default']; } - }; - } - else { - // we are defining this module - deps = _deps; - meta.factory = factory; + else if (!module.__esModule) { + // compatibility -> ES6 modules must have a __esModule flag + // we clone the module object to handle this + var moduleClone = { __esModule: true }; + for (var p in module) + moduleClone[p] = module[p]; + module = moduleClone; + } + depValues.push(module); + } + + var module; + + // add back in system dependencies + if (moduleIndex != -1) + depValues.splice(moduleIndex, 0, exports, module = { id: moduleName, uri: loader.baseURL + moduleName, config: function() { return {}; }, exports: exports }); + + if (exportsIndex != -1) + depValues.splice(exportsIndex, 0, exports); + + if (requireIndex != -1) + depValues.splice(requireIndex, 0, makeRequire(moduleName, require, loader)); + + var output = factory.apply(loader.global, depValues); + + output = output || module && module.exports; + + if (output && output.__esModule) + return output; + else if (output !== undefined) + return { __useDefault: true, 'default': output }; } }; - global.define.amd = {}; + + // attaches to loader.defined as dynamic + if (name) + loader.defined[name] = lastDefine; + }; + + loader.global.define.amd = {}; + loader.global.define.loader = loader; + } + + + var loaderInstantiate = loader.instantiate; + loader.instantiate = function(load) { + var loader = this; + + if (load.metadata.format == 'amd' || !load.metadata.format && load.source.match(amdRegEx)) { + load.metadata.format = 'amd'; + createDefine(loader, load.metadata.getCJSDeps); + + lastDefine = null; // ensure no NodeJS environment detection - global.module = undefined; - global.exports = undefined; + loader.global.module = undefined; + loader.global.exports = undefined; loader.__exec(load); - // deps not defined for an AMD module that defines a different name - deps = deps || []; + if (!lastDefine) + throw "AMD module " + load.name + " did not define"; - deps = prepareDeps(deps, meta); - - global.define = undefined; - - meta.deps = deps; - - return deps; - - }, - execute: function(depNames, load) { - if (!load.metadata.factory) - return; - var execs = prepareExecute(depNames, load); - return load.metadata.factory.apply(loader.global, execs.deps) || execs.module && execs.module.exports; + load.metadata.deps = load.metadata.deps ? load.metadata.deps.concat(lastDefine.deps) : lastDefine.deps; + load.metadata.execute = lastDefine.execute; } - }; -}/* - SystemJS CommonJS Format - Provides the CommonJS module format definition at System.format.cjs -*/ -function formatCJS(loader) { - loader.formats.push('cjs'); - // CJS Module Format - // require('...') || exports[''] = ... || exports.asd = ... || module.exports = ... - var cjsExportsRegEx = /(?:^\s*|[}{\(\);,\n=:\?\&]\s*|module\.)(exports\s*\[\s*('[^']+'|"[^"]+")\s*\]|\exports\s*\.\s*[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*|exports\s*\=)/; - var cjsRequireRegEx = /(?:^\s*|[}{\(\);,\n=:\?\&]\s*)require\s*\(\s*("([^"]+)"|'([^']+)')\s*\)/g; - var commentRegEx = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg; - - var noop = function() {} - var nodeProcess = { - nextTick: function(f) { - setTimeout(f, 7); - }, - browser: true, - env: {}, - argv: [], - on: noop, - once: noop, - off: noop, - emit: noop, - cwd: function() { return '/' } - }; - loader.set('@@nodeProcess', Module(nodeProcess)); - - loader.format.cjs = { - detect: function(load) { - cjsExportsRegEx.lastIndex = 0; - cjsRequireRegEx.lastIndex = 0; - return !!(cjsRequireRegEx.exec(load.source) || cjsExportsRegEx.exec(load.source)); - }, - deps: function(load) { - cjsExportsRegEx.lastIndex = 0; - cjsRequireRegEx.lastIndex = 0; - - var deps = []; - - // remove comments from the source first - var source = load.source.replace(commentRegEx, ''); - - var match; - - while (match = cjsRequireRegEx.exec(source)) - deps.push(match[2] || match[3]); - - load.metadata.deps = deps; - - return deps; - }, - execute: function(depNames, load) { - var dirname = load.address.split('/'); - dirname.pop(); - dirname = dirname.join('/'); - - var deps = load.metadata.deps; - - var globals = loader.global._g = { - global: loader.global, - exports: {}, - process: nodeProcess, - require: function(d) { - var index = indexOf.call(deps, d); - if (index != -1) - return loader.getModule(depNames[index]); - }, - __filename: load.address, - __dirname: dirname, - }; - globals.module = { exports: globals.exports }; - - var glString = ''; - for (var _g in globals) - glString += 'var ' + _g + ' = _g.' + _g + ';'; - - load.source = glString + load.source; - - loader.__exec(load); - - loader.global._g = undefined; - - return globals.module.exports; - } - }; -}/* - SystemJS Global Format - Provides the global support at System.format.global - Supports inline shim syntax with: - "global"; - "import jquery"; - "export my.Global"; - - Also detects writes to the global object avoiding global collisions. - See the SystemJS readme global support section for further information. -*/ -function formatGlobal(loader) { - loader.formats.push('global'); - - // Global - var globalShimRegEx = /(["']global["'];\s*)((['"]import [^'"]+['"];\s*)*)(['"]export ([^'"]+)["'])?/; - var globalImportRegEx = /(["']import [^'"]+)+/g; - - // given a module's global dependencies, prepare the global object - // to contain the union of the defined properties of its dependent modules - var moduleGlobals = {}; - - // also support a loader.shim system - loader.shim = {}; - - loader.format.global = { - detect: function() { - return true; - }, - deps: function(load) { - var match, deps; - if (match = load.source.match(globalShimRegEx)) { - deps = match[2].match(globalImportRegEx); - if (deps) - for (var i = 0; i < deps.length; i++) - deps[i] = deps[i].substr(8); - load.metadata.exports = match[5]; - } - deps = deps || []; - if (load.metadata.deps) - deps = deps.concat(load.metadata.deps); - return deps; - }, - execute: function(depNames, load) { - var hasOwnProperty = loader.global.hasOwnProperty; - var globalExport = load.metadata.exports; - - // first, we add all the dependency module properties to the global - for (var i = 0; i < depNames.length; i++) { - var moduleGlobal = moduleGlobals[depNames[i]]; - if (moduleGlobal) - for (var m in moduleGlobal) - loader.global[m] = moduleGlobal[m]; - } - - // now store a complete copy of the global object - // in order to detect changes - var globalObj = {}; - for (var g in loader.global) - if (!hasOwnProperty || loader.global.hasOwnProperty(g)) - globalObj[g] = loader.global[g]; - - if (globalExport) - load.source += '\nthis["' + globalExport + '"] = ' + globalExport; - - loader.__exec(load); - - // check for global changes, creating the globalObject for the module - // if many globals, then a module object for those is created - // if one global, then that is the module directly - var singleGlobal, moduleGlobal; - if (globalExport) { - var firstPart = globalExport.split('.')[0]; - singleGlobal = eval.call(loader.global, globalExport); - moduleGlobal = {}; - moduleGlobal[firstPart] = loader.global[firstPart]; - } - else { - moduleGlobal = {}; - for (var g in loader.global) { - if (!hasOwnProperty && (g == 'sessionStorage' || g == 'localStorage' || g == 'clipboardData' || g == 'frames')) - continue; - if ((!hasOwnProperty || loader.global.hasOwnProperty(g)) && g != loader.global && globalObj[g] != loader.global[g]) { - moduleGlobal[g] = loader.global[g]; - if (singleGlobal) { - if (singleGlobal !== loader.global[g]) - singleGlobal = false; - } - else if (singleGlobal !== false) - singleGlobal = loader.global[g]; - } - } - } - moduleGlobals[load.name] = moduleGlobal; - - if (singleGlobal) - return singleGlobal; - else - return new Module(moduleGlobal); - } - }; + return loaderInstantiate.call(loader, load); + } }/* SystemJS map support @@ -720,10 +1074,8 @@ function formatGlobal(loader) { 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) { @@ -740,7 +1092,7 @@ function map(loader) { // given a relative-resolved module name and normalized parent name, // apply the map configuration - function applyMap(name, parentName) { + function applyMap(name, parentName, loader) { var curMatch, curMatchLength = 0; var curParent, curParentMatchLength = 0; @@ -802,11 +1154,13 @@ function map(loader) { } var loaderNormalize = loader.normalize; - var mapped = {}; 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); + return applyMap(name, parentName, loader); }); } } @@ -819,14 +1173,18 @@ function map(loader) { 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(name, parentName, parentAddress)) + 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('!'); @@ -857,6 +1215,8 @@ function plugins(loader) { var loaderLocate = loader.locate; loader.locate = function(load) { + var loader = this; + var name = load.name; // plugin @@ -867,10 +1227,12 @@ function plugins(loader) { // the name to locate is the plugin argument only load.name = name.substr(0, pluginIndex); + var pluginLoader = loader.pluginLoader || loader; + // load the plugin module - return loader.load(pluginName) + return pluginLoader.load(pluginName) .then(function() { - var plugin = loader.get(pluginName); + var plugin = pluginLoader.get(pluginName); plugin = plugin['default'] || plugin; // store the plugin module itself on the metadata @@ -898,25 +1260,32 @@ function plugins(loader) { var loaderFetch = loader.fetch; loader.fetch = function(load) { - // support legacy plugins - var self = this; - if (typeof load.metadata.plugin == 'function') { - return new Promise(function(fulfill, reject) { - load.metadata.plugin(load.metadata.pluginArgument, load.address, function(url, callback, errback) { - loaderFetch.call(self, { name: load.name, address: url, metadata: {} }).then(callback, errback); - }, fulfill, reject); + if (load.metadata.plugin && load.metadata.plugin.fetch) + return load.metadata.plugin.fetch.call(this, load, function(load) { + return loaderFetch.call(this, load); }); - } - return (load.metadata.plugin && load.metadata.plugin.fetch || loaderFetch).call(this, load); + else + return loaderFetch.call(this, load); } var loaderTranslate = loader.translate; loader.translate = function(load) { - var plugin = load.metadata.plugin; - if (plugin && plugin.translate) - return plugin.translate.call(this, load); + if (load.metadata.plugin && load.metadata.plugin.translate) + return load.metadata.plugin.translate.call(this, load, function(load) { + return loaderTranslate.call(this, load); + }); + else + return loaderTranslate.call(this, load); + } - return loaderTranslate.call(this, load); + var loaderInstantiate = loader.instantiate; + loader.instantiate = function(load) { + if (load.metadata.plugin && load.metadata.plugin.instantiate) + return load.metadata.plugin.instantiate.call(this, load, function(load) { + return loaderInstantiate.call(this, load); + }); + else + return loaderInstantiate.call(this, load); } }/* @@ -935,6 +1304,9 @@ function plugins(loader) { */ function bundles(loader) { + if (typeof indexOf == 'undefined') + indexOf = Array.prototype.indexOf; + // bundles support (just like RequireJS) // bundle name is module name of bundle itself // bundle is array of modules defined by the bundle @@ -944,6 +1316,9 @@ function bundles(loader) { var loaderFetch = loader.fetch; loader.fetch = function(load) { + if (!loader.bundles) + loader.bundles = {}; + // if this module is in a bundle, load the bundle first then for (var b in loader.bundles) { if (indexOf.call(loader.bundles[b], load.name) == -1) @@ -961,80 +1336,7 @@ function bundles(loader) { } return loaderFetch.apply(this, arguments); } - - var loaderLocate = loader.locate; - loader.locate = function(load) { - if (loader.bundles[load.name]) - load.metadata.bundle = true; - return loaderLocate.call(this, load); - } - - var loaderInstantiate = loader.instantiate; - loader.instantiate = function(load) { - // if it is a bundle itself, it doesn't define anything - if (load.metadata.bundle) - return { - deps: [], - execute: function() { - loader.__exec(load); - return new Module({}); - } - }; - - return loaderInstantiate.apply(this, arguments); - } - }/* - Implementation of the loader.register bundling method - - This allows the output of Traceur to populate the - module registry of the loader loader -*/ - -function register(loader) { - - // instantiation cache for loader.register - loader.defined = {}; - - // register a new module for instantiation - loader.register = function(name, deps, execute) { - loader.defined[name] = { - deps: deps, - execute: function() { - return Module(execute.apply(this, arguments)); - } - }; - } - - var loaderLocate = loader.locate; - loader.locate = function(load) { - if (loader.defined[load.name]) - return ''; - return loaderLocate.apply(this, arguments); - } - - var loaderFetch = loader.fetch; - loader.fetch = function(load) { - // if the module is already defined, skip fetch - if (loader.defined[load.name]) - return ''; - return loaderFetch.apply(this, arguments); - } - - var loaderInstantiate = loader.instantiate; - loader.instantiate = function(load) { - // if the module has been defined by a bundle, use that - if (loader.defined[load.name]) { - var instantiateResult = loader.defined[load.name]; - delete loader.defined[load.name]; - return instantiateResult; - } - - return loaderInstantiate.apply(this, arguments); - } - -} -/* SystemJS Semver Version Addon 1. Uses Semver convention for major and minor forms @@ -1092,6 +1394,9 @@ function register(loader) { */ function versions(loader) { + if (typeof indexOf == 'undefined') + indexOf = Array.prototype.indexOf; + // match x, x.y, x.y.z, x.y.z-prerelease.1 var semverRegEx = /^(\d+)(?:\.(\d+)(?:\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?)?)?$/; @@ -1112,15 +1417,16 @@ function versions(loader) { return parseInt(v1Parts[i]) > parseInt(v2Parts[i]) ? 1 : -1; } return 0; - } + } - var loaderNormalize = loader.normalize; loader.versions = loader.versions || {}; - // hook normalize and store a record of all versioned packages + var loaderNormalize = loader.normalize; loader.normalize = function(name, parentName, parentAddress) { - var packageVersions = loader.versions; + if (!loader.versions) + loader.versions = {}; + var packageVersions = this.versions; // run all other normalizers first return Promise.resolve(loaderNormalize.call(this, name, parentName, parentAddress)).then(function(normalized) { @@ -1252,51 +1558,66 @@ function versions(loader) { } } core(System); -formats(System); -formatAMD(System); -formatCJS(System); -formatGlobal(System); +meta(System); +register(System); +global(System); +cjs(System); +amd(System); map(System); plugins(System); bundles(System); -register(System); versions(System); + System.baseURL = __$curScript.getAttribute('data-baseurl') || System.baseURL; + + var configPath = __$curScript.getAttribute('data-config'); + if (configPath === '') + configPath = System.baseURL + 'config.json'; + + var main = __$curScript.getAttribute('data-main'); + + (!configPath ? Promise.resolve() : + Promise.resolve(System.fetch.call(System, { address: configPath, metadata: {} })) + .then(JSON.parse) + .then(System.config) + ).then(function() { + if (main) + return System['import'](main); + }) + ['catch'](function(e) { + setTimeout(function() { + throw e; + }) + }); - if (__$global.systemMainEntryPoint) - System['import'](__$global.systemMainEntryPoint); }; -(function() { +var __$curScript; + +(function(global) { if (typeof window != 'undefined') { var scripts = document.getElementsByTagName('script'); - var curScript = scripts[scripts.length - 1]; - __$global.systemMainEntryPoint = curScript.getAttribute('data-main'); + __$curScript = scripts[scripts.length - 1]; - if (!__$global.System || __$global.System.registerModule) { + if (!global.System || global.System.registerModule) { // determine the current script path as the base path - var curPath = curScript.src; + var curPath = __$curScript.src; var basePath = curPath.substr(0, curPath.lastIndexOf('/') + 1); document.write( '<' + 'script type="text/javascript" src="' + basePath + 'es6-module-loader.js" data-init="upgradeSystemLoader">' + '<' + '/script>' ); } else { - __$global.upgradeSystemLoader(); + global.upgradeSystemLoader(); } - - var configPath = curScript.getAttribute('data-config'); - if (configPath) - document.write('<' + 'script type="text/javascript src="' + configPath + '">' + '<' + '/script>'); } else { var es6ModuleLoader = require('es6-module-loader'); - __$global.System = es6ModuleLoader.System; - __$global.Loader = es6ModuleLoader.Loader; - __$global.Module = es6ModuleLoader.Module; - module.exports = __$global.System; - __$global.upgradeSystemLoader(); + global.System = es6ModuleLoader.System; + global.Loader = es6ModuleLoader.Loader; + global.Module = es6ModuleLoader.Module; + module.exports = global.System; + global.upgradeSystemLoader(); } -})(); - +})(__$global); })(typeof window != 'undefined' ? window : global); \ No newline at end of file diff --git a/dist/system.min.js b/dist/system.min.js index d1fac06f..5f479da8 100644 --- a/dist/system.min.js +++ b/dist/system.min.js @@ -5,4 +5,3 @@ * MIT License */ -!function(__$global){__$global.upgradeSystemLoader=function(){function core(loader){function __eval(__source,__global,__address,__sourceMap){try{__source="with(__global) { (function() { "+__source+" \n }).call(__global); }\n//# sourceURL="+__address+(__sourceMap?"\n//# sourceMappingURL="+__sourceMap:""),eval(__source)}catch(e){throw"SyntaxError"==e.name&&(e.message="Evaluating "+__address+"\n "+e.message),e}}!function(){function e(e){var t=String(e).replace(/^\s+|\s+$/g,"").match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);return t?{href:t[0]||"",protocol:t[1]||"",authority:t[2]||"",host:t[3]||"",hostname:t[4]||"",port:t[5]||"",pathname:t[6]||"",search:t[7]||"",hash:t[8]||""}:null}function t(t,r){function a(e){var t=[];return e.replace(/^(\.\.?(\/|$))+/,"").replace(/\/(\.(\/|$))+/g,"/").replace(/\/\.\.$/,"/../").replace(/\/?[^\/]*/g,function(e){"/.."===e?t.pop():t.push(e)}),t.join("").replace(/^\//,"/"===e.charAt(0)?"/":"")}return r=e(r||""),t=e(t||""),r&&t?(r.protocol||t.protocol)+(r.protocol||r.authority?r.authority:t.authority)+a(r.protocol||r.authority||"/"===r.pathname.charAt(0)?r.pathname:r.pathname?(t.authority&&!t.pathname?"/":"")+t.pathname.slice(0,t.pathname.lastIndexOf("/")+1)+r.pathname:t.pathname)+(r.protocol||r.authority||r.pathname?r.search:r.search||t.search)+r.hash:null}var r=System,a=function(e){if(!(e instanceof Module)){for(var t=[],r=0;ra.length)return 0;for(var n=0;nparseInt(n[o])?1:-1}return 0},a=e.normalize;e.versions=e.versions||{},e.normalize=function(n,o,s){var l=e.versions;return Promise.resolve(a.call(this,n,o,s)).then(function(e){var a,n,o,s,u=e.indexOf("@");if(-1==u){for(var i in l)if(s=l[i],e.substr(0,i.length)==i&&(o=e.substr(i.length,1),!o||"/"==o))return i+"@"+("string"==typeof s?s:s[s.length-1])+e.substr(i.length);return e}a=e.substr(u+1).split("/")[0];var c,f=a.length;if("^"==a.substr(0,1)&&(a=a.substr(1),c=!0),n=a.match(t),!n)return e;c&&(n[2]||(c=!1),n[3]||(n[2]>0?n[3]="0":c=!1)),c&&(n[1]>0?(n[2]||(a=n[1]+".0.0"),n[3]||(a=n[1]+".0"),c=a,n=[n[1]]):n[2]>0?(c=a,n=[0,n[2]]):(c=!1,n=[0,0,n[3]]),a=n.join("."));var d=e.substr(0,u);if(s=l[d]||[],"string"==typeof s&&(s=[s]),!n[3]||c)for(var m=s.length-1;m>=0;m--){var p=s[m];if(p.substr(0,a.length)==a&&p.substr(a.length,1).match(/^[\.\-]?$/)&&(!c||c&&-1!=r(p,c)))return d+"@"+p+e.substr(d.length+f+1)}return-1==indexOf.call(s,a)&&(s.push(a),s.sort(r),e=d+"@"+a+e.substr(d.length+f+1),n[3]&&-1!=(u=indexOf.call(s,n[1]+"."+n[2]))&&s.splice(u,1),n[2]&&-1!=(u=indexOf.call(s,n[1]))&&s.splice(u,1),l[d]=1==s.length?s[0]:s),e})}}__$global.upgradeSystemLoader=void 0;var indexOf=Array.prototype.indexOf||function(e){for(var t=0,r=this.length;r>t;t++)if(this[t]===e)return t;return-1},lastIndexOf=Array.prototype.lastIndexOf||function(e){for(var t=this.length-1;t>=0;t--)if(this[t]===e)return t;return-t};core(System),formats(System),formatAMD(System),formatCJS(System),formatGlobal(System),map(System),plugins(System),bundles(System),register(System),versions(System),__$global.systemMainEntryPoint&&System["import"](__$global.systemMainEntryPoint)},function(){if("undefined"!=typeof window){var e=document.getElementsByTagName("script"),t=e[e.length-1];if(__$global.systemMainEntryPoint=t.getAttribute("data-main"),!__$global.System||__$global.System.registerModule){var r=t.src,a=r.substr(0,r.lastIndexOf("/")+1);document.write('')}else __$global.upgradeSystemLoader();var n=t.getAttribute("data-config");n&&document.write('')}else{var o=require("es6-module-loader");__$global.System=o.System,__$global.Loader=o.Loader,__$global.Module=o.Module,module.exports=__$global.System,__$global.upgradeSystemLoader()}}()}("undefined"!=typeof window?window:global); \ No newline at end of file diff --git a/lib/extension-amd.js b/lib/extension-amd.js new file mode 100644 index 00000000..113c7398 --- /dev/null +++ b/lib/extension-amd.js @@ -0,0 +1,170 @@ +/* + SystemJS AMD Format + Provides the AMD module format definition at System.format.amd + as well as a RequireJS-style require on System.require +*/ +function amd(loader) { + + // AMD Module Format Detection RegEx + // define([.., .., ..], ...) + // define(varName); || define(function(require, exports) {}); || define({}) + var amdRegEx = /(?:^\s*|[}{\(\);,\n\?\&]\s*)define\s*\(\s*("[^"]+"\s*,\s*|'[^']+'\s*,\s*)?(\[(\s*("[^"]+"|'[^']+')\s*,)*(\s*("[^"]+"|'[^']+')\s*)?\]|function\s*|{|[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*\))/; + + /* + AMD-compatible require + To copy RequireJS, set window.require = window.requirejs = loader.require + */ + function require(names, callback, errback, referer) { + // 'this' is bound to the loader + var loader = this; + + // in amd, first arg can be a config object... we just ignore + if (typeof names == 'object' && !(names instanceof Array)) + return require.apply(null, Array.prototype.splice.call(arguments, 1, arguments.length - 1)); + + // amd require + if (names instanceof Array) + Promise.all(names.map(function(name) { + return loader['import'](name, referer); + })).then(function(modules) { + callback.apply(null, modules); + }, errback); + + // commonjs require + else if (typeof names == 'string') { + var module = loader.get(names); + return module.__useDefault ? module['default'] : module; + } + + else + throw 'Invalid require'; + }; + loader.require = require; + + function makeRequire(parentName, staticRequire, loader) { + return function(names, callback, errback) { + if (typeof names == 'string') + return staticRequire(names); + return require.call(loader, names, callback, errback, { name: parentName }); + } + } + + var lastDefine; + function createDefine(loader, getCJSDeps) { + if (loader.global.define && loader.global.define.loader == loader) + return; + + loader.global.define = function(name, deps, factory) { + if (typeof name != 'string') { + factory = deps; + deps = name; + name = null; + } + if (!(deps instanceof Array)) { + factory = deps; + // CommonJS AMD form + if (!getCJSDeps) + throw "AMD extension needs CJS extension for AMD CJS support"; + deps = ['require', 'exports', 'module'].concat(getCJSDeps(factory.toString())); + } + + if (typeof factory != 'function') + factory = (function(factory) { + return function() { return factory; } + })(factory); + + // a module file can only define one anonymous module + if (!name && lastDefine) + throw "Multiple defines for anonymous module"; + + // remove system dependencies + var requireIndex, exportsIndex, moduleIndex + if ((requireIndex = indexOf.call(deps, 'require')) != -1) + deps.splice(requireIndex, 1); + + if ((exportsIndex = indexOf.call(deps, 'exports')) != -1) + deps.splice(exportsIndex, 1); + + if ((moduleIndex = indexOf.call(deps, 'module')) != -1) + deps.splice(moduleIndex, 1); + + lastDefine = { + deps: deps, + execute: function(require, exports, moduleName) { + + var depValues = []; + for (var i = 0; i < deps.length; i++) { + var module = require(deps[i]); + if (module.__useDefault) { + module = module['default']; + } + else if (!module.__esModule) { + // compatibility -> ES6 modules must have a __esModule flag + // we clone the module object to handle this + var moduleClone = { __esModule: true }; + for (var p in module) + moduleClone[p] = module[p]; + module = moduleClone; + } + depValues.push(module); + } + + var module; + + // add back in system dependencies + if (moduleIndex != -1) + depValues.splice(moduleIndex, 0, exports, module = { id: moduleName, uri: loader.baseURL + moduleName, config: function() { return {}; }, exports: exports }); + + if (exportsIndex != -1) + depValues.splice(exportsIndex, 0, exports); + + if (requireIndex != -1) + depValues.splice(requireIndex, 0, makeRequire(moduleName, require, loader)); + + var output = factory.apply(loader.global, depValues); + + output = output || module && module.exports; + + if (output && output.__esModule) + return output; + else if (output !== undefined) + return { __useDefault: true, 'default': output }; + } + }; + + // attaches to loader.defined as dynamic + if (name) + loader.defined[name] = lastDefine; + }; + + loader.global.define.amd = {}; + loader.global.define.loader = loader; + } + + + var loaderInstantiate = loader.instantiate; + loader.instantiate = function(load) { + var loader = this; + + if (load.metadata.format == 'amd' || !load.metadata.format && load.source.match(amdRegEx)) { + load.metadata.format = 'amd'; + createDefine(loader, load.metadata.getCJSDeps); + + lastDefine = null; + + // ensure no NodeJS environment detection + loader.global.module = undefined; + loader.global.exports = undefined; + + loader.__exec(load); + + if (!lastDefine) + throw "AMD module " + load.name + " did not define"; + + load.metadata.deps = load.metadata.deps ? load.metadata.deps.concat(lastDefine.deps) : lastDefine.deps; + load.metadata.execute = lastDefine.execute; + } + + return loaderInstantiate.call(loader, load); + } +} \ No newline at end of file diff --git a/lib/extension-bundles.js b/lib/extension-bundles.js index aac4e5c3..79035f4d 100644 --- a/lib/extension-bundles.js +++ b/lib/extension-bundles.js @@ -14,6 +14,9 @@ */ function bundles(loader) { + if (typeof indexOf == 'undefined') + indexOf = Array.prototype.indexOf; + // bundles support (just like RequireJS) // bundle name is module name of bundle itself // bundle is array of modules defined by the bundle @@ -23,6 +26,9 @@ function bundles(loader) { var loaderFetch = loader.fetch; loader.fetch = function(load) { + if (!loader.bundles) + loader.bundles = {}; + // if this module is in a bundle, load the bundle first then for (var b in loader.bundles) { if (indexOf.call(loader.bundles[b], load.name) == -1) @@ -40,27 +46,4 @@ function bundles(loader) { } return loaderFetch.apply(this, arguments); } - - var loaderLocate = loader.locate; - loader.locate = function(load) { - if (loader.bundles[load.name]) - load.metadata.bundle = true; - return loaderLocate.call(this, load); - } - - var loaderInstantiate = loader.instantiate; - loader.instantiate = function(load) { - // if it is a bundle itself, it doesn't define anything - if (load.metadata.bundle) - return { - deps: [], - execute: function() { - loader.__exec(load); - return new Module({}); - } - }; - - return loaderInstantiate.apply(this, arguments); - } - } \ No newline at end of file diff --git a/lib/extension-cjs.js b/lib/extension-cjs.js new file mode 100644 index 00000000..9ea45f2b --- /dev/null +++ b/lib/extension-cjs.js @@ -0,0 +1,115 @@ +/* + SystemJS CommonJS Format +*/ +function cjs(loader) { + + // CJS Module Format + // require('...') || exports[''] = ... || exports.asd = ... || module.exports = ... + var cjsExportsRegEx = /(?:^\s*|[}{\(\);,\n=:\?\&]\s*|module\.)(exports\s*\[\s*('[^']+'|"[^"]+")\s*\]|\exports\s*\.\s*[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*|exports\s*\=)/; + var cjsRequireRegEx = /(?:^\s*|[}{\(\);,\n=:\?\&]\s*)require\s*\(\s*("([^"]+)"|'([^']+)')\s*\)/g; + var commentRegEx = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg; + + function getCJSDeps(source) { + cjsExportsRegEx.lastIndex = 0; + cjsRequireRegEx.lastIndex = 0; + + var deps = []; + + // remove comments from the source first + var source = source.replace(commentRegEx, ''); + + var match; + + while (match = cjsRequireRegEx.exec(source)) + deps.push(match[2] || match[3]); + + return deps; + } + + var loaderTranslate = loader.translate; + loader.translate = function(load) { + load.metadata.getCJSDeps = getCJSDeps; + return loaderTranslate.call(this, load); + } + + + var noop = function() {} + var nodeProcess = { + nextTick: function(f) { + setTimeout(f, 7); + }, + browser: typeof window != 'undefined', + env: {}, + argv: [], + on: noop, + once: noop, + off: noop, + emit: noop, + cwd: function() { return '/' } + }; + loader.set('@@nodeProcess', Module(nodeProcess)); + + var loaderInstantiate = loader.instantiate; + loader.instantiate = function(load) { + + if (!load.metadata.format) { + cjsExportsRegEx.lastIndex = 0; + cjsRequireRegEx.lastIndex = 0; + if (cjsRequireRegEx.exec(load.source) || cjsExportsRegEx.exec(load.source)) + load.metadata.format = 'cjs'; + } + + if (load.metadata.format == 'cjs') { + load.metadata.deps = load.metadata.deps ? load.metadata.deps.concat(getCJSDeps(load.source)) : load.metadata.deps; + + load.metadata.execute = function(require, exports, moduleName) { + var dirname = load.address.split('/'); + dirname.pop(); + dirname = dirname.join('/'); + + var globals = loader.global._g = { + global: loader.global, + exports: exports, + module: { exports: exports }, + process: nodeProcess, + require: function(name) { + var module = require(name); + if (module.__useDefault) { + module = module['default']; + } + else if (!module.__esModule) { + // compatibility -> ES6 modules must have a __esModule flag + // we clone the module object to handle this + var moduleClone = { __esModule: true }; + for (var p in module) + moduleClone[p] = module[p]; + module = moduleClone; + } + return module; + }, + __filename: load.address, + __dirname: dirname + }; + + var glString = ''; + for (var _g in globals) + glString += 'var ' + _g + ' = _g.' + _g + ';'; + + load.source = glString + load.source; + + loader.__exec(load); + + loader.global._g = undefined; + + var output = globals.module.exports; + + if (output && output.__esModule) + return output; + else if (output !== undefined) + return { __useDefault: true, 'default': output }; + } + } + + return loaderInstantiate.call(this, load); + }; +} \ No newline at end of file diff --git a/lib/extension-core.js b/lib/extension-core.js index 06c9fa71..ea78c9c1 100644 --- a/lib/extension-core.js +++ b/lib/extension-core.js @@ -1,58 +1,169 @@ /* - SystemJS Core - Adds normalization to the import function, as well as __useDefault support -*/ + * SystemJS Core + * Code should be vaguely readable + * + */ function core(loader) { (function() { - var curSystem = System; - /* __useDefault When a module object looks like: - new Module({ + Module({ __useDefault: true, default: 'some-module' }) - Then the import of that module is taken to be the 'default' export and not the module object itself. + Then importing that module provides the 'some-module' + result directly instead of the full module. - Useful for module.exports = function() {} handling + Useful for eg module.exports = function() {} */ - var checkUseDefault = function(module) { - if (!(module instanceof Module)) { - var out = []; - for (var i = 0; i < module.length; i++) - out[i] = checkUseDefault(module[i]); - return out; - } - return module.__useDefault ? module['default'] : module; - } - - // a variation on System.get that does the __useDefault check - loader.getModule = function(key) { - return checkUseDefault(loader.get(key)); + var loaderImport = loader['import']; + loader['import'] = function(name, options) { + return loaderImport.call(this, name, options).then(function(module) { + return module.__useDefault ? module['default'] : module; + }); } // support the empty module, as a concept loader.set('@empty', Module({})); - - - var loaderImport = loader['import']; - loader['import'] = function(name, options) { - // patch loader.import to do normalization - return new Promise(function(resolve) { - resolve(loader.normalize.call(this, name, options && options.name, options && options.address)) - }) - // add useDefault support - .then(function(name) { - return Promise.resolve(loaderImport.call(loader, name, options)).then(function(module) { - return checkUseDefault(module); - }); + + /* + Config + Extends config merging one deep only + + loader.config({ + some: 'random', + config: 'here', + deep: { + config: { too: 'too' } + } }); + + <=> + + loader.some = 'random'; + loader.config = 'here' + loader.deep = loader.deep || {}; + loader.deep.config = { too: 'too' }; + */ + loader.config = function(cfg) { + for (var c in cfg) { + var v = cfg[c]; + if (typeof v == 'object') { + this[c] = this[c] || {}; + for (var p in v) + this[c][p] = v[p]; + } + else + this[c] = v; + } } + // override locate to allow baseURL to be document-relative + var baseURI; + if (typeof window == 'undefined') { + baseURI = __dirname + '/'; + } + else { + baseURI = document.baseURI; + if (!baseURI) { + var bases = document.getElementsByTagName('base'); + baseURI = bases[0] && bases[0].href || window.location.href; + } + } + var loaderLocate = loader.locate; + var normalizedBaseURL; + loader.locate = function(load) { + if (this.baseURL != normalizedBaseURL) { + normalizedBaseURL = toAbsoluteURL(baseURI, this.baseURL); + + if (normalizedBaseURL.substr(normalizedBaseURL.length - 1, 1) != '/') + normalizedBaseURL += '/'; + + this.baseURL = normalizedBaseURL; + } + + return Promise.resolve(loaderLocate.call(this, load)); + } + + + // Traceur conveniences + var aliasRegEx = /^\s*export\s*\*\s*from\s*(?:'([^']+)'|"([^"]+)")/; + var es6RegEx = /(?:^\s*|[}{\(\);,\n]\s*)(import\s+['"]|(import|module)\s+[^"'\(\)\n;]+\s+from\s+['"]|export\s+(\*|\{|default|function|var|const|let|[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*))/; + + var loaderTranslate = loader.translate; + loader.translate = function(load) { + var loader = this; + + loader.__exec = exec; + + // support ES6 alias modules ("export * from 'module';") without needing Traceur + var match; + if (!loader.global.traceur && (load.metadata.format == 'es6' || !load.metadata.format) && (match = load.source.match(aliasRegEx))) { + var depName = match[1] || match[2]; + load.metadata.deps = [depName]; + load.metadata.execute = function(require) { + return require(depName); + } + } + + // detect ES6 + if (load.metadata.format == 'es6' || !load.metadata.format && load.source.match(es6RegEx)) { + console.log('load traceur'); + load.metadata.format = 'es6'; + + // dynamically load Traceur for ES6 if necessary + if (!loader.global.traceur) + return loader['import']('@traceur').then(function() { + return loaderTranslate.call(loader, load); + }); + } + + return loaderTranslate.call(loader, load); + } + + // always load Traceur as a global + var loaderInstantiate = loader.instantiate; + loader.instantiate = function(load) { + var loader = this; + if (load.name == '@traceur') { + loader.__exec(load); + return { + deps: [], + execute: function() {} + }; + } + return loaderInstantiate.call(loader, load); + } + + + // define exec for easy evaluation of a load record (load.name, load.source, load.address) + // main feature is source maps support handling + var curSystem + function exec(load) { + if (load.name == '@traceur') + curSystem = System; + // support sourceMappingURL (efficiently) + var sourceMappingURL; + var lastLineIndex = load.source.lastIndexOf('\n'); + if (lastLineIndex != -1) { + if (load.source.substr(lastLineIndex + 1, 21) == '//# sourceMappingURL=') + sourceMappingURL = toAbsoluteURL(load.address, load.source.substr(lastLineIndex + 22)); + } + + __eval(load.source, this.global, load.address, sourceMappingURL); + + // traceur overwrites System - write it back + if (load.name == '@traceur') { + this.global.traceurSystem = this.global.System; + this.global.System = curSystem; + } + } + loader.__exec = exec; + // 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]*)?/); @@ -93,54 +204,6 @@ function core(loader) { (href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) + href.hash; } - var baseURI; - if (typeof window == 'undefined') { - baseURI = __dirname + '/'; - } - else { - baseURI = document.baseURI; - if (!baseURI) { - var bases = document.getElementsByTagName('base'); - baseURI = bases[0] && bases[0].href || window.location.href; - } - } - - // System.meta provides default metadata - System.meta = {}; - - // override locate to allow baseURL to be document-relative - var loaderLocate = loader.locate; - var normalizedBaseURL; - loader.locate = function(load) { - if (this.baseURL != normalizedBaseURL) - this.baseURL = normalizedBaseURL = toAbsoluteURL(baseURI, this.baseURL); - - var meta = System.meta[load.name]; - for (var p in meta) - load.metadata[p] = meta[p]; - - return Promise.resolve(loaderLocate.call(this, load)); - } - - // define exec for custom instantiations - loader.__exec = function(load) { - - // support sourceMappingURL (efficiently) - var sourceMappingURL; - var lastLineIndex = load.source.lastIndexOf('\n'); - if (lastLineIndex != -1) { - if (load.source.substr(lastLineIndex + 1, 21) == '//# sourceMappingURL=') - sourceMappingURL = toAbsoluteURL(load.address, load.source.substr(lastLineIndex + 22)); - } - - __eval(load.source, loader.global, load.address, sourceMappingURL); - - // traceur overwrites System - write it back - if (load.name == '@traceur') { - loader.global.traceurSystem = loader.global.System; - loader.global.System = curSystem; - } - } })(); diff --git a/lib/extension-formatAMD.js b/lib/extension-formatAMD.js deleted file mode 100644 index 8889c628..00000000 --- a/lib/extension-formatAMD.js +++ /dev/null @@ -1,199 +0,0 @@ -/* - SystemJS AMD Format - Provides the AMD module format definition at System.format.amd - as well as a RequireJS-style require on System.require -*/ -function formatAMD(loader) { - loader.formats.push('amd'); - - // AMD Module Format Detection RegEx - // define([.., .., ..], ...) - // define(varName); || define(function(require, exports) {}); || define({}) - var amdRegEx = /(?:^\s*|[}{\(\);,\n\?\&]\s*)define\s*\(\s*("[^"]+"\s*,\s*|'[^']+'\s*,\s*)?(\[(\s*("[^"]+"|'[^']+')\s*,)*(\s*("[^"]+"|'[^']+')\s*)?\]|function\s*|{|[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*\))/; - - /* - AMD-compatible require - To copy RequireJS, set window.require = window.requirejs = loader.require - */ - var require = loader.require = function(names, callback, errback, referer) { - // in amd, first arg can be a config object... we just ignore - if (typeof names == 'object' && !(names instanceof Array)) - return require.apply(null, Array.prototype.splice.call(arguments, 1, arguments.length - 1)); - - // amd require - if (names instanceof Array) - Promise.all(names.map(function(name) { - return loader['import'](name, referer); - })).then(function(modules) { - callback.apply(null, modules); - }, errback); - - // commonjs require - else if (typeof names == 'string') - return loader.getModule(names); - - else - throw 'Invalid require'; - }; - function makeRequire(parentName, deps, depsNormalized) { - return function(names, callback, errback) { - if (typeof names == 'string' && indexOf.call(deps, names) != -1) - return loader.getModule(depsNormalized[indexOf.call(deps, names)]); - return require(names, callback, errback, { name: parentName }); - } - } - - function prepareDeps(deps, meta) { - for (var i = 0; i < deps.length; i++) - if (lastIndexOf.call(deps, deps[i]) != i) - deps.splice(i--, 1); - - // remove system dependencies - var index; - if ((index = indexOf.call(deps, 'require')) != -1) { - meta.requireIndex = index; - deps.splice(index, 1); - } - if ((index = indexOf.call(deps, 'exports')) != -1) { - meta.exportsIndex = index; - deps.splice(index, 1); - } - if ((index = indexOf.call(deps, 'module')) != -1) { - meta.moduleIndex = index; - deps.splice(index, 1); - } - - return deps; - } - - function prepareExecute(depNames, load) { - var meta = load.metadata; - var deps = []; - for (var i = 0; i < depNames.length; i++) { - var module = loader.get(depNames[i]); - if (module.__useDefault) { - module = module['default']; - } - else if (!module.__esModule) { - // compatibility -> ES6 modules must have a __esModule flag - // we clone the module object to handle this - var moduleClone = { __esModule: true }; - for (var p in module) - moduleClone[p] = module[p]; - module = moduleClone; - } - deps[i] = module; - } - - var module, exports; - - // add back in system dependencies - if (meta.moduleIndex !== undefined) - deps.splice(meta.moduleIndex, 0, exports = {}, module = { id: load.name, uri: load.address, config: function() { return {}; }, exports: exports }); - if (meta.exportsIndex !== undefined) - deps.splice(meta.exportsIndex, 0, exports = exports || {}); - if (meta.requireIndex !== undefined) - deps.splice(meta.requireIndex, 0, makeRequire(load.name, meta.deps, depNames)); - - return { - deps: deps, - module: module || exports && { exports: exports } - }; - } - - loader.format.amd = { - detect: function(load) { - return !!load.source.match(amdRegEx); - }, - deps: function(load) { - - var global = loader.global; - - var deps; - var meta = load.metadata; - var defined = false; - global.define = function(name, _deps, factory) { - - if (typeof name != 'string') { - factory = _deps; - _deps = name; - name = null; - } - - // anonymous modules must only call define once - if (!name && defined) { - throw "Multiple anonymous defines for module " + load.name; - } - if (!name) { - defined = true; - } - - if (!(_deps instanceof Array)) { - factory = _deps; - // CommonJS AMD form - var src = load.source; - load.source = factory.toString(); - _deps = ['require', 'exports', 'module'].concat(loader.format.cjs.deps(load, global)); - load.source = src; - } - - if (typeof factory != 'function') - factory = (function(factory) { - return function() { return factory; } - })(factory); - - if (name && name != load.name) { - // named define for a bundle describing another module - var _load = { - name: name, - address: name, - metadata: {} - }; - _deps = prepareDeps(_deps, _load.metadata); - loader.defined[name] = { - deps: _deps, - execute: function() { - var execs = prepareExecute(Array.prototype.splice.call(arguments, 0, arguments.length), _load); - var output = factory.apply(global, execs.deps) || execs.module && execs.module.exports; - - if (output instanceof global.Module) - return output; - else - return new global.Module(output && output.__esModule ? output : { __useDefault: true, 'default': output }); - } - }; - } - else { - // we are defining this module - deps = _deps; - meta.factory = factory; - } - }; - global.define.amd = {}; - - // ensure no NodeJS environment detection - global.module = undefined; - global.exports = undefined; - - loader.__exec(load); - - // deps not defined for an AMD module that defines a different name - deps = deps || []; - - deps = prepareDeps(deps, meta); - - global.define = undefined; - - meta.deps = deps; - - return deps; - - }, - execute: function(depNames, load) { - if (!load.metadata.factory) - return; - var execs = prepareExecute(depNames, load); - return load.metadata.factory.apply(loader.global, execs.deps) || execs.module && execs.module.exports; - } - }; -} \ No newline at end of file diff --git a/lib/extension-formatCJS.js b/lib/extension-formatCJS.js deleted file mode 100644 index 433129e4..00000000 --- a/lib/extension-formatCJS.js +++ /dev/null @@ -1,88 +0,0 @@ -/* - SystemJS CommonJS Format - Provides the CommonJS module format definition at System.format.cjs -*/ -function formatCJS(loader) { - loader.formats.push('cjs'); - - // CJS Module Format - // require('...') || exports[''] = ... || exports.asd = ... || module.exports = ... - var cjsExportsRegEx = /(?:^\s*|[}{\(\);,\n=:\?\&]\s*|module\.)(exports\s*\[\s*('[^']+'|"[^"]+")\s*\]|\exports\s*\.\s*[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*|exports\s*\=)/; - var cjsRequireRegEx = /(?:^\s*|[}{\(\);,\n=:\?\&]\s*)require\s*\(\s*("([^"]+)"|'([^']+)')\s*\)/g; - var commentRegEx = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg; - - var noop = function() {} - var nodeProcess = { - nextTick: function(f) { - setTimeout(f, 7); - }, - browser: true, - env: {}, - argv: [], - on: noop, - once: noop, - off: noop, - emit: noop, - cwd: function() { return '/' } - }; - loader.set('@@nodeProcess', Module(nodeProcess)); - - loader.format.cjs = { - detect: function(load) { - cjsExportsRegEx.lastIndex = 0; - cjsRequireRegEx.lastIndex = 0; - return !!(cjsRequireRegEx.exec(load.source) || cjsExportsRegEx.exec(load.source)); - }, - deps: function(load) { - cjsExportsRegEx.lastIndex = 0; - cjsRequireRegEx.lastIndex = 0; - - var deps = []; - - // remove comments from the source first - var source = load.source.replace(commentRegEx, ''); - - var match; - - while (match = cjsRequireRegEx.exec(source)) - deps.push(match[2] || match[3]); - - load.metadata.deps = deps; - - return deps; - }, - execute: function(depNames, load) { - var dirname = load.address.split('/'); - dirname.pop(); - dirname = dirname.join('/'); - - var deps = load.metadata.deps; - - var globals = loader.global._g = { - global: loader.global, - exports: {}, - process: nodeProcess, - require: function(d) { - var index = indexOf.call(deps, d); - if (index != -1) - return loader.getModule(depNames[index]); - }, - __filename: load.address, - __dirname: dirname, - }; - globals.module = { exports: globals.exports }; - - var glString = ''; - for (var _g in globals) - glString += 'var ' + _g + ' = _g.' + _g + ';'; - - load.source = glString + load.source; - - loader.__exec(load); - - loader.global._g = undefined; - - return globals.module.exports; - } - }; -} \ No newline at end of file diff --git a/lib/extension-formatGlobal.js b/lib/extension-formatGlobal.js deleted file mode 100644 index 7f19144a..00000000 --- a/lib/extension-formatGlobal.js +++ /dev/null @@ -1,102 +0,0 @@ -/* - SystemJS Global Format - Provides the global support at System.format.global - Supports inline shim syntax with: - "global"; - "import jquery"; - "export my.Global"; - - Also detects writes to the global object avoiding global collisions. - See the SystemJS readme global support section for further information. -*/ -function formatGlobal(loader) { - loader.formats.push('global'); - - // Global - var globalShimRegEx = /(["']global["'];\s*)((['"]import [^'"]+['"];\s*)*)(['"]export ([^'"]+)["'])?/; - var globalImportRegEx = /(["']import [^'"]+)+/g; - - // given a module's global dependencies, prepare the global object - // to contain the union of the defined properties of its dependent modules - var moduleGlobals = {}; - - // also support a loader.shim system - loader.shim = {}; - - loader.format.global = { - detect: function() { - return true; - }, - deps: function(load) { - var match, deps; - if (match = load.source.match(globalShimRegEx)) { - deps = match[2].match(globalImportRegEx); - if (deps) - for (var i = 0; i < deps.length; i++) - deps[i] = deps[i].substr(8); - load.metadata.exports = match[5]; - } - deps = deps || []; - if (load.metadata.deps) - deps = deps.concat(load.metadata.deps); - return deps; - }, - execute: function(depNames, load) { - var hasOwnProperty = loader.global.hasOwnProperty; - var globalExport = load.metadata.exports; - - // first, we add all the dependency module properties to the global - for (var i = 0; i < depNames.length; i++) { - var moduleGlobal = moduleGlobals[depNames[i]]; - if (moduleGlobal) - for (var m in moduleGlobal) - loader.global[m] = moduleGlobal[m]; - } - - // now store a complete copy of the global object - // in order to detect changes - var globalObj = {}; - for (var g in loader.global) - if (!hasOwnProperty || loader.global.hasOwnProperty(g)) - globalObj[g] = loader.global[g]; - - if (globalExport) - load.source += '\nthis["' + globalExport + '"] = ' + globalExport; - - loader.__exec(load); - - // check for global changes, creating the globalObject for the module - // if many globals, then a module object for those is created - // if one global, then that is the module directly - var singleGlobal, moduleGlobal; - if (globalExport) { - var firstPart = globalExport.split('.')[0]; - singleGlobal = eval.call(loader.global, globalExport); - moduleGlobal = {}; - moduleGlobal[firstPart] = loader.global[firstPart]; - } - else { - moduleGlobal = {}; - for (var g in loader.global) { - if (!hasOwnProperty && (g == 'sessionStorage' || g == 'localStorage' || g == 'clipboardData' || g == 'frames')) - continue; - if ((!hasOwnProperty || loader.global.hasOwnProperty(g)) && g != loader.global && globalObj[g] != loader.global[g]) { - moduleGlobal[g] = loader.global[g]; - if (singleGlobal) { - if (singleGlobal !== loader.global[g]) - singleGlobal = false; - } - else if (singleGlobal !== false) - singleGlobal = loader.global[g]; - } - } - } - moduleGlobals[load.name] = moduleGlobal; - - if (singleGlobal) - return singleGlobal; - else - return new Module(moduleGlobal); - } - }; -} \ No newline at end of file diff --git a/lib/extension-formats.js b/lib/extension-formats.js deleted file mode 100644 index 1bbe94f6..00000000 --- a/lib/extension-formats.js +++ /dev/null @@ -1,126 +0,0 @@ -/* - SystemJS Formats - - Provides modular support for format detections. - - Also dynamically loads Traceur if ES6 syntax is found. - - Add a format with: - System.formats.push('myformatname'); - System.format.myformat = { - detect: function(source, load) { - return false / depArray; - }, - execute: function(load, deps) { - return moduleObj; // (doesnt have to be a Module instance) - } - } - - The System.formats array sets the format detection order. - - See the AMD, global and CommonJS format extensions for examples. -*/ -function formats(loader) { - - loader.format = {}; - loader.formats = []; - - if (typeof window != 'undefined') { - var curScript = document.getElementsByTagName('script'); - curScript = curScript[curScript.length - 1]; - // set the path to traceur - loader.paths['@traceur'] = curScript.getAttribute('data-traceur-src') || curScript.src.substr(0, curScript.src.lastIndexOf('/') + 1) + 'traceur.js'; - } - - // also in ESML, build.js - var es6RegEx = /(?:^\s*|[}{\(\);,\n]\s*)(import\s+['"]|(import|module)\s+[^"'\(\)\n;]+\s+from\s+['"]|export\s+(\*|\{|default|function|var|const|let|[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*))/; - - // es6 module forwarding - allow detecting without Traceur - var aliasRegEx = /^\s*export\s*\*\s*from\s*(?:'([^']+)'|"([^"]+)")/; - - // module format hint regex - var formatHintRegEx = /^(\s*(\/\*.*\*\/)|(\/\/[^\n]*))*(["']use strict["'];?)?["']([^'"]+)["'][;\n]/; - - var loaderInstantiate = loader.instantiate; - loader.instantiate = function(load) { - var name = load.name || ''; - - load.source = load.source || ''; - - // set load.metadata.format from metadata or format hints in the source - var format = load.metadata.format; - if (!format) { - var formatMatch = load.source.match(formatHintRegEx); - if (formatMatch) - format = load.metadata.format = formatMatch[5]; - } - - if (name == '@traceur') - format = 'global'; - - // es6 handled by core - - // support alias modules without needing Traceur - var match; - if (!loader.global.traceur && (format == 'es6' || !format) && (match = load.source.match(aliasRegEx))) { - return { - deps: [match[1] || match[2]], - execute: function(depName) { - return loader.get(depName); - } - }; - } - - if (format == 'es6' || !format && load.source.match(es6RegEx)) { - // dynamically load Traceur if necessary - if (!loader.global.traceur) - return loader['import']('@traceur').then(function() { - return loaderInstantiate.call(loader, load); - }); - else - return loaderInstantiate.call(loader, load); - } - - // if it is shimmed, assume it is a global script - if (load.metadata.exports || load.metadata.deps) - format = 'global'; - - // if we don't know the format, run detection first - if (!format || !this.format[format]) - for (var i = 0; i < this.formats.length; i++) { - var f = this.formats[i]; - var curFormat = this.format[f]; - if (curFormat.detect(load)) { - format = f; - break; - } - } - - var curFormat = this.format[format]; - - // if we don't have a format or format rule, throw - if (!format || !curFormat) - throw new TypeError('No format found for ' + (format ? format : load.address)); - - // now invoke format instantiation - var deps = curFormat.deps(load); - - // remove duplicates from deps first - for (var i = 0; i < deps.length; i++) - if (lastIndexOf.call(deps, deps[i]) != i) - deps.splice(i--, 1); - - return { - deps: deps, - execute: function() { - var output = curFormat.execute.call(this, Array.prototype.splice.call(arguments, 0, arguments.length), load); - - if (output instanceof loader.global.Module) - return output; - else - return new loader.global.Module(output && output.__esModule ? output : { __useDefault: true, 'default': output }); - } - }; - } - -} diff --git a/lib/extension-global.js b/lib/extension-global.js new file mode 100644 index 00000000..778bde2b --- /dev/null +++ b/lib/extension-global.js @@ -0,0 +1,82 @@ +/* + SystemJS Global Format + + Supports + metadata.deps + metadata.init + metadata.exports + + Also detects writes to the global object avoiding global collisions. + See the SystemJS readme global support section for further information. +*/ +function global(loader) { + var loaderInstantiate = loader.instantiate; + loader.instantiate = function(load) { + var loader = this; + + // global is a fallback module format + if (load.metadata.format == 'global' || !load.metadata.format) { + load.metadata.deps = load.metadata.deps || []; + var deps = load.metadata.deps; + + var moduleGlobals = loader.moduleGlobals = loader.moduleGlobals || {}; + var globalExport = load.metadata.exports; + var init = load.metadata.init; + + load.metadata.execute = function(require, exports, moduleName) { + var hasOwnProperty = loader.global.hasOwnProperty; + + // first, we add all the dependency modules to the global + for (var i = 0; i < deps.length; i++) { + var moduleGlobal = moduleGlobals[deps[i]]; + if (moduleGlobal) + for (var m in moduleGlobal) + loader.global[m] = moduleGlobal[m]; + } + + // now store a complete copy of the global object + // in order to detect changes + var globalObj = {}; + for (var g in loader.global) + if (!hasOwnProperty || loader.global.hasOwnProperty(g)) + globalObj[g] = loader.global[g]; + + if (globalExport) + load.source += '\nthis["' + globalExport + '"] = ' + globalExport; + + loader.__exec(load); + + // check for global changes, creating the globalObject for the module + // if many globals, then a module object for those is created + // if one global, then that is the module directly + var singleGlobal; + if (globalExport) { + var firstPart = globalExport.split('.')[0]; + singleGlobal = eval.call(loader.global, globalExport); + exports[firstPart] = loader.global[firstPart]; + } + else { + for (var g in loader.global) { + if (!hasOwnProperty && (g == 'sessionStorage' || g == 'localStorage' || g == 'clipboardData' || g == 'frames')) + continue; + if ((!hasOwnProperty || loader.global.hasOwnProperty(g)) && g != loader.global && globalObj[g] != loader.global[g]) { + exports[g] = loader.global[g]; + if (singleGlobal) { + if (singleGlobal !== loader.global[g]) + singleGlobal = false; + } + else if (singleGlobal !== false) + singleGlobal = loader.global[g]; + } + } + } + moduleGlobals[load.name] = exports; + + var module = singleGlobal ? singleGlobal : exports; + + return { __useDefault: true, 'default': module }; + } + } + return loaderInstantiate.call(loader, load); + } +} \ No newline at end of file diff --git a/lib/extension-map.js b/lib/extension-map.js index 1ec7d275..1670fe29 100644 --- a/lib/extension-map.js +++ b/lib/extension-map.js @@ -22,10 +22,8 @@ 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) { @@ -42,7 +40,7 @@ function map(loader) { // given a relative-resolved module name and normalized parent name, // apply the map configuration - function applyMap(name, parentName) { + function applyMap(name, parentName, loader) { var curMatch, curMatchLength = 0; var curParent, curParentMatchLength = 0; @@ -104,11 +102,13 @@ function map(loader) { } var loaderNormalize = loader.normalize; - var mapped = {}; 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); + return applyMap(name, parentName, loader); }); } } diff --git a/lib/extension-meta.js b/lib/extension-meta.js new file mode 100644 index 00000000..fb324330 --- /dev/null +++ b/lib/extension-meta.js @@ -0,0 +1,93 @@ +/* + * Meta Extension + * + * Sets default metadata on a load record (load.metadata) from + * loader.meta[moduleName]. + * Also provides an inline meta syntax for module meta in source. + * + * Eg: + * + * loader.meta['my/module'] = { some: 'meta' }; + * + * load.metadata.some = 'meta' will now be set on the load record. + * + * The same meta could be set with a my/module.js file containing: + * + * my/module.js + * "some meta"; + * "another meta"; + * console.log('this is my/module'); + * + * The benefit of inline meta is that coniguration doesn't need + * to be known in advanced, which is useful for modularising + * configuration and avoiding the need for configuration injection. + * + * + * Example + * ------- + * + * The simplest meta example is setting the module format: + * + * System.meta['my/module'] = { format: 'amd' }; + * + * or inside 'my/module.js': + * + * "format amd"; + * define(...); + * + */ + +function meta(loader) { + var metaRegEx = /^(\s*\/\*.*\*\/|\s*\/\/[^\n]*|\s*"[^"]+"\s*;?|\s*'[^']+'\s*;?)+/; + var metaPartRegEx = /\/\*.*\*\/|\/\/[^\n]*|"[^"]+"\s*;?|'[^']+'\s*;?/g; + + loader.meta = {}; + + function setConfigMeta(loader, load) { + var meta = loader.meta && loader.meta[load.name]; + if (meta) { + for (var p in meta) + load.metadata[p] = load.metadata[p] || meta[p]; + } + } + + var loaderLocate = loader.locate; + loader.locate = function(load) { + setConfigMeta(this, load); + return loaderLocate.call(this, load); + } + + var loaderTranslate = loader.translate; + loader.translate = function(load) { + setConfigMeta(this, load); + + // detect any meta header syntax + var meta = load.source.match(metaRegEx); + if (meta) { + var metaParts = meta[0].match(metaPartRegEx); + for (var i = 0; i < metaParts.length; i++) { + var len = metaParts[i].length; + + var firstChar = metaParts[i].substr(0, 1); + if (metaParts[i].substr(len - 1, 1) == ';') + len--; + + if (firstChar != '"' && firstChar != "'") + continue; + + var metaString = metaParts[i].substr(1, metaParts[i].length - 3); + + var metaName = metaString.substr(0, metaString.indexOf(' ')); + if (metaName) { + var metaValue = metaString.substr(metaName.length + 1, metaString.length - metaName.length - 1); + + if (load.metadata[metaName] instanceof Array) + load.metadata[metaName].push(metaValue); + else + load.metadata[metaName] = load.metadata[metaName] || metaValue; + } + } + } + return loaderTranslate.call(this, load); + } +} \ No newline at end of file diff --git a/lib/extension-plugins.js b/lib/extension-plugins.js index a639bf95..f419360f 100644 --- a/lib/extension-plugins.js +++ b/lib/extension-plugins.js @@ -7,14 +7,18 @@ 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(name, parentName, parentAddress)) + 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('!'); @@ -45,6 +49,8 @@ function plugins(loader) { var loaderLocate = loader.locate; loader.locate = function(load) { + var loader = this; + var name = load.name; // plugin @@ -55,10 +61,12 @@ function plugins(loader) { // the name to locate is the plugin argument only load.name = name.substr(0, pluginIndex); + var pluginLoader = loader.pluginLoader || loader; + // load the plugin module - return loader.load(pluginName) + return pluginLoader.load(pluginName) .then(function() { - var plugin = loader.get(pluginName); + var plugin = pluginLoader.get(pluginName); plugin = plugin['default'] || plugin; // store the plugin module itself on the metadata @@ -86,25 +94,32 @@ function plugins(loader) { var loaderFetch = loader.fetch; loader.fetch = function(load) { - // support legacy plugins - var self = this; - if (typeof load.metadata.plugin == 'function') { - return new Promise(function(fulfill, reject) { - load.metadata.plugin(load.metadata.pluginArgument, load.address, function(url, callback, errback) { - loaderFetch.call(self, { name: load.name, address: url, metadata: {} }).then(callback, errback); - }, fulfill, reject); + if (load.metadata.plugin && load.metadata.plugin.fetch) + return load.metadata.plugin.fetch.call(this, load, function(load) { + return loaderFetch.call(this, load); }); - } - return (load.metadata.plugin && load.metadata.plugin.fetch || loaderFetch).call(this, load); + else + return loaderFetch.call(this, load); } var loaderTranslate = loader.translate; loader.translate = function(load) { - var plugin = load.metadata.plugin; - if (plugin && plugin.translate) - return plugin.translate.call(this, load); + if (load.metadata.plugin && load.metadata.plugin.translate) + return load.metadata.plugin.translate.call(this, load, function(load) { + return loaderTranslate.call(this, load); + }); + else + return loaderTranslate.call(this, load); + } - return loaderTranslate.call(this, load); + var loaderInstantiate = loader.instantiate; + loader.instantiate = function(load) { + if (load.metadata.plugin && load.metadata.plugin.instantiate) + return load.metadata.plugin.instantiate.call(this, load, function(load) { + return loaderInstantiate.call(this, load); + }); + else + return loaderInstantiate.call(this, load); } } \ No newline at end of file diff --git a/lib/extension-productionAMD.js b/lib/extension-productionAMD.js deleted file mode 100644 index d9b9b6f4..00000000 --- a/lib/extension-productionAMD.js +++ /dev/null @@ -1,109 +0,0 @@ -function amdScriptLoader(loader) { - - var head = document.getElementsByTagName('head')[0]; - - // override fetch to use script injection - loader.fetch = function(load) { - // if already defined, skip - if (loader.defined[load.name]) - return ''; - - // script injection fetch system - return new Promise(function(resolve, reject) { - var s = document.createElement('script'); - s.async = true; - s.addEventListener('load', function(evt) { - if (lastAnonymous) - loader.defined[load.name] = lastAnonymous; - lastAnonymous = null; - resolve(''); - }, false); - s.addEventListener('error', function(err) { - reject(err); - }, false); - s.src = load.address; - head.appendChild(s); - }); - } - var lastAnonymous = null; - loader.global.define = function(name, deps, factory) { - // anonymous define - if (typeof name != 'string') { - factory = deps; - deps = name; - name = null; - } - - if (!(deps instanceof Array)) { - factory = deps; - deps = []; - } - - if (typeof factory != 'function') - factory = (function(factory) { - return function() { return factory; } - })(factory); - - for (var i = 0; i < deps.length; i++) - if (lastIndexOf.call(deps, deps[i]) != i) - deps.splice(i--, 1); - - var instantiate = { - deps: deps, - execute: function() { - var args = []; - for (var i = 0; i < arguments.length; i++) - args.push(loader.getModule(arguments[i])); - - var output = factory.apply(this, args); - return new loader.global.Module(output && output.__esModule ? output : { __useDefault: true, 'default': output }); - } - }; - - if (name) - loader.defined[name] = instantiate; - else - lastAnonymous = instantiate; - } - loader.global.define.amd = {}; - - // no translate at all - loader.translate = function() {} - - // instantiate defaults to null - loader.instantiate = function() { - return { - deps: [], - execute: function() { - return new Module({}); - } - }; - } - - - /* - AMD-compatible require - To copy RequireJS, set window.require = window.requirejs = loader.requirejs - */ - var require = loader.requirejs = function(names, callback, errback, referer) { - // in amd, first arg can be a config object... we just ignore - if (typeof names == 'object' && !(names instanceof Array)) - return require.apply(null, Array.prototype.splice.call(arguments, 1, arguments.length - 1)); - - // amd require - if (names instanceof Array) - Promise.all(names.map(function(name) { - return loader['import'](name, referer); - })).then(function(mods) { - return callback.apply(this, mods); - }, errback); - - // commonjs require - else if (typeof names == 'string') - return loader.getModule(names); - - else - throw 'Invalid require'; - } - -} diff --git a/lib/extension-register.js b/lib/extension-register.js index f3838a71..0e74dc50 100644 --- a/lib/extension-register.js +++ b/lib/extension-register.js @@ -1,50 +1,355 @@ /* - Implementation of the loader.register bundling method - - This allows the output of Traceur to populate the - module registry of the loader loader -*/ + * Instantiate registry extension + * + * Supports Traceur System.register 'instantiate' output for loading ES6 as ES5. + * + * - Creates the loader.register function + * - Also supports metadata.format = 'register' in instantiate for anonymous register modules + * - Also supports metadata.deps, metadata.execute and metadata.executingRequire + * for handling dynamic modules alongside register-transformed ES6 modules + * + * Works as a standalone extension provided there is a + * loader.__exec(load) like the one set in SystemJS core + * + */ function register(loader) { + if (typeof indexOf == 'undefined') + indexOf = Array.prototype.indexOf; + if (!loader.__exec) + throw "loader.__exec(load) needs to be provided for loader.register. See SystemJS core for an implementation example."; - // instantiation cache for loader.register - loader.defined = {}; + function dedupe(deps) { + var newDeps = []; + for (var i = 0; i < deps.length; i++) + if (indexOf.call(newDeps, deps[i]) == -1) + newDeps.push(deps[i]) + return newDeps; + } - // register a new module for instantiation - loader.register = function(name, deps, execute) { - loader.defined[name] = { + // Registry side table + // Registry Entry Contains: + // - deps + // - declare for register modules + // - execute for dynamic modules, also after declare for register modules + // - declarative boolean indicating which of the above + // - normalizedDeps derived from deps, created in instantiate + // - depMap array derived from deps, populated gradually in link + // - groupIndex used by group linking algorithm + // - module a raw module exports object with no wrapper + // - evaluated indiciating whether evaluation has happend for declarative modules + // After linked and evaluated, entries are removed + var lastRegister; + function register(name, deps, declare) { + if (declare.length == 0) + throw 'Invalid System.register form. Ensure setting --modules=instantiate if using Traceur.'; + + if (!loader.defined) + loader.defined = {}; + + if (typeof name != 'string') { + declare = deps; + deps = name; + name = null; + } + + lastRegister = { deps: deps, - execute: function() { - return Module(execute.apply(this, arguments)); - } + declare: declare, + declarative: true }; + + if (name) + loader.defined[name] = lastRegister; } - - var loaderLocate = loader.locate; - loader.locate = function(load) { - if (loader.defined[load.name]) - return ''; - return loaderLocate.apply(this, arguments); + loader.defined = loader.defined || {}; + loader.register = register; + + function buildGroups(entry, loader, groups) { + + groups[entry.groupIndex] = groups[entry.groupIndex] || []; + + if (indexOf.call(groups[entry.groupIndex], entry) != -1) + return; + + groups[entry.groupIndex].push(entry); + + for (var i = 0; i < entry.normalizedDeps.length; i++) { + var depName = entry.normalizedDeps[i]; + var depEntry = loader.defined[depName]; + + // not in the registry means already linked / ES6 + if (!depEntry) + continue; + + // now we know the entry is in our unlinked linkage group + var depGroupIndex = entry.groupIndex + (depEntry.declarative != entry.declarative); + + if (depEntry.groupIndex === undefined) { + depEntry.groupIndex = depGroupIndex; + } + else if (depEntry.groupIndex != depGroupIndex) { + throw new TypeError('System.register mixed dependency cycle'); + } + + buildGroups(entry, loader, groups); + } } - - var loaderFetch = loader.fetch; - loader.fetch = function(load) { - // if the module is already defined, skip fetch - if (loader.defined[load.name]) - return ''; - return loaderFetch.apply(this, arguments); + + function link(name, loader) { + var startEntry = loader.defined[name]; + + startEntry.groupIndex = 0; + + var groups = []; + + buildGroups(startEntry, loader, groups); + + var curGroupDeclarative = startEntry.declarative == groups.length % 2; + for (var i = groups.length - 1; i >= 0; i--) { + var group = groups[i]; + for (var j = 0; j < group.length; j++) { + var entry = group[j]; + + // link each group + if (curGroupDeclarative) + linkDeclarativeModule(entry, loader); + else + linkDynamicModule(entry, loader); + } + curGroupDeclarative = !curGroupDeclarative; + } } + function linkDeclarativeModule(entry, loader) { + // only link if already not already started linking (stops at circular) + if (entry.module) + return; + + // declare the module with an empty depMap + var depMap = []; + + var declaration = load.declare.call(loader.global, depMap); + + entry.module = declaration.exports; + entry.exportStar = declaration.exportStar; + entry.execute = declaration.execute; + + var module = entry.module; + + // now link all the module dependencies + // amending the depMap as we go + for (var i = 0; i < entry.normalizedDeps.length; i++) { + var depName = entry.normalizedDeps[i]; + var depEntry = loader.defined[depName]; + + // part of another linking group - use loader.get + if (!depEntry) { + depModule = loader.get(depName); + } + // if dependency already linked, use that + else if (depEntry.module) { + depModule = depEntry.module; + } + // otherwise we need to link the dependency + else { + linkDeclarativeModule(depEntry, loader); + depModule = depEntry.module; + } + + if (entry.exportStar && indexOf.call(entry.exportStar, entry.normalizedDeps[i]) != -1) { + // we are exporting * from this dependency + (function(depModule) { + for (var p in depModule) (function(p) { + // if the property is already defined throw? + Object.defineProperty(module, p, { + enumerable: true, + get: function() { + return depModule[p]; + }, + set: function(value) { + depModule[p] = value; + } + }); + })(p); + })(depModule); + } + + depMap[i] = depModule; + } + } + + // An analog to loader.get covering execution of all three layers (real declarative, simulated declarative, simulated dynamic) + function getModule(name, loader) { + var entry = loader.defined[name]; + + if (!entry) + return loader.get(name); + + if (entry.declarative) + ensureEvaluated(name, [], loader); + + else if (!entry.evaluated) + linkDynamicModule(entry, loader); + + return entry.module; + } + + function linkDynamicModule(entry, loader) { + if (entry.module) + return; + + entry.module = {}; + + // AMD requires execute the tree first + if (!entry.executingRequire) { + for (var i = 0; i < entry.normalizedDeps.length; i++) { + var depName = entry.normalizedDeps[i]; + var depEntry = loader.defined[depName]; + linkDynamicModule(depEntry, loader); + } + } + + // now execute + try { + entry.evaluated = true; + var output = entry.execute(function(name) { + for (var i = 0; i < entry.deps.length; i++) { + if (entry.deps[i] != name) + continue; + return getModule(entry.normalizedDeps[i], loader); + } + }, entry.module, name); + } + catch(e) { + throw e; + } + + if (output) + entry.module = output; + } + + // given a module, and the list of modules for this current branch, + // ensure that each of the dependencies of this module is evaluated + // (unless one is a circular dependency already in the list of seen + // modules, in which case we execute it) + // then evaluate the module itself + // depth-first left to right execution to match ES6 modules + function ensureEvaluated(moduleName, seen, loader) { + var entry = loader.defined[moduleName]; + + // if already seen, that means it's an already-evaluated non circular dependency + if (!entry.declarative || entry.evaluated || indexOf.call(seen, moduleName) != -1) + return; + + seen.push(moduleName); + + for (var i = 0; i < entry.normalizedDeps.length; i++) { + var depName = entry.normalizedDeps[i]; + + // circular -> execute now if not already executed + if (indexOf.call(seen, depName) != -1) { + var depEntry = loader.defined[depName]; + if (depEntry && !depEntry.evaluated) { + depEntry.execute.call(loader.global); + delete depEntry.execute; + } + } + // in turn ensure dependencies are evaluated + else + ensureEvaluated(depName, seen); + } + + // we've evaluated all dependencies so evaluate this module now + entry.execute.call(loader.global); + entry.evaluated = true; + } + + var registerRegEx = /System\.register/; + + var loaderTranslate = loader.translate; + loader.translate = function(load) { + loader.register = register; + + load.metadata.deps = load.metadata.deps || []; + + // run detection for register format here + if (load.metadata.format == 'register' || !load.metadata.format && load.source.match(registerRegEx)) + load.metadata.format = 'register'; + + return loaderTranslate.call(this, load); + } + + var loaderInstantiate = loader.instantiate; loader.instantiate = function(load) { - // if the module has been defined by a bundle, use that - if (loader.defined[load.name]) { - var instantiateResult = loader.defined[load.name]; - delete loader.defined[load.name]; - return instantiateResult; + var loader = this; + + var entry; + + if (loader.defined[load.name]) + loader.defined[load.name] = entry = loader.defined[load.name]; + + else if (load.metadata.execute) { + loader.defined[load.name] = entry = { + deps: load.metadata.deps || [], + execute: load.metadata.execute, + executingRequire: load.metadata.executingRequire // NodeJS-style requires or not + }; + } + else if (load.metadata.format == 'register') { + lastRegister = null; + loader.__exec(load); + + // for a bundle, take the last defined module + // in the bundle to be the bundle itself + if (lastRegister) + loader.defined[load.name] = entry = lastRegister; } - return loaderInstantiate.apply(this, arguments); - } + if (!entry) + return loaderInstantiate.call(this, load); + entry.deps = dedupe(entry.deps); + + // first, normalize all dependencies + var normalizePromises = []; + for (var i = 0; i < entry.deps.length; i++) + normalizePromises.push(Promise.resolve(loader.normalize(entry.deps[i], load.name))); + + return Promise.all(normalizePromises).then(function(normalizedDeps) { + + entry.normalizedDeps = normalizedDeps; + + // create the empty dep map - this is our key deferred dependency binding object passed into declare + entry.depMap = []; + + return { + deps: entry.deps, + execute: function() { + // recursively ensure that the module and all its + // dependencies are linked (with dependency group handling) + link(load.name, loader); + + // now handle dependency execution in correct order + ensureEvaluated(load.name, [], loader); + + // remove from the registry + delete loader.defined[load.name]; + + var module = Module(entry.module); + + // if the entry is an alias, set the alias too + for (var name in loader.defined) { + if (loader.defined[name].execute != entry.execute) + continue; + if (!loader.has(name)) + loader.set(name, module); + } + // return the defined module object + return module; + } + }; + }); + } } diff --git a/lib/extension-scriptLoader.js b/lib/extension-scriptLoader.js new file mode 100644 index 00000000..3c123aec --- /dev/null +++ b/lib/extension-scriptLoader.js @@ -0,0 +1,26 @@ +/* + * Script tag fetch + */ + +function scriptLoader(loader) { + if (typeof indexOf == 'undefined') + indexOf = Array.prototype.indexOf; + + var head = document.getElementsByTagName('head')[0]; + + // override fetch to use script injection + loader.fetch = function(load) { + return new Promise(function(resolve, reject) { + var s = document.createElement('script'); + s.async = true; + s.addEventListener('load', function(evt) { + resolve(''); + }, false); + s.addEventListener('error', function(err) { + reject(err); + }, false); + s.src = load.address; + head.appendChild(s); + }); + } +} diff --git a/lib/extension-versions.js b/lib/extension-versions.js index e39b37f4..6321301f 100644 --- a/lib/extension-versions.js +++ b/lib/extension-versions.js @@ -56,6 +56,9 @@ */ function versions(loader) { + if (typeof indexOf == 'undefined') + indexOf = Array.prototype.indexOf; + // match x, x.y, x.y.z, x.y.z-prerelease.1 var semverRegEx = /^(\d+)(?:\.(\d+)(?:\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?)?)?$/; @@ -76,15 +79,16 @@ function versions(loader) { return parseInt(v1Parts[i]) > parseInt(v2Parts[i]) ? 1 : -1; } return 0; - } + } - var loaderNormalize = loader.normalize; loader.versions = loader.versions || {}; - // hook normalize and store a record of all versioned packages + var loaderNormalize = loader.normalize; loader.normalize = function(name, parentName, parentAddress) { - var packageVersions = loader.versions; + if (!loader.versions) + loader.versions = {}; + var packageVersions = this.versions; // run all other normalizers first return Promise.resolve(loaderNormalize.call(this, name, parentName, parentAddress)).then(function(normalized) { diff --git a/lib/polyfill-wrapper-end.js b/lib/polyfill-wrapper-end.js index eb681d54..1c820fb5 100644 --- a/lib/polyfill-wrapper-end.js +++ b/lib/polyfill-wrapper-end.js @@ -1,39 +1,54 @@ + System.baseURL = __$curScript.getAttribute('data-baseurl') || System.baseURL; + + var configPath = __$curScript.getAttribute('data-config'); + if (configPath === '') + configPath = System.baseURL + 'config.json'; + + var main = __$curScript.getAttribute('data-main'); + + (!configPath ? Promise.resolve() : + Promise.resolve(System.fetch.call(System, { address: configPath, metadata: {} })) + .then(JSON.parse) + .then(System.config) + ).then(function() { + if (main) + return System['import'](main); + }) + ['catch'](function(e) { + setTimeout(function() { + throw e; + }) + }); - if (__$global.systemMainEntryPoint) - System['import'](__$global.systemMainEntryPoint); }; -(function() { +var __$curScript; + +(function(global) { if (typeof window != 'undefined') { var scripts = document.getElementsByTagName('script'); - var curScript = scripts[scripts.length - 1]; - __$global.systemMainEntryPoint = curScript.getAttribute('data-main'); + __$curScript = scripts[scripts.length - 1]; - if (!__$global.System || __$global.System.registerModule) { + if (!global.System || global.System.registerModule) { // determine the current script path as the base path - var curPath = curScript.src; + var curPath = __$curScript.src; var basePath = curPath.substr(0, curPath.lastIndexOf('/') + 1); document.write( '<' + 'script type="text/javascript" src="' + basePath + 'es6-module-loader.js" data-init="upgradeSystemLoader">' + '<' + '/script>' ); } else { - __$global.upgradeSystemLoader(); + global.upgradeSystemLoader(); } - - var configPath = curScript.getAttribute('data-config'); - if (configPath) - document.write('<' + 'script type="text/javascript src="' + configPath + '">' + '<' + '/script>'); } else { var es6ModuleLoader = require('es6-module-loader'); - __$global.System = es6ModuleLoader.System; - __$global.Loader = es6ModuleLoader.Loader; - __$global.Module = es6ModuleLoader.Module; - module.exports = __$global.System; - __$global.upgradeSystemLoader(); + global.System = es6ModuleLoader.System; + global.Loader = es6ModuleLoader.Loader; + global.Module = es6ModuleLoader.Module; + module.exports = global.System; + global.upgradeSystemLoader(); } -})(); - +})(__$global); })(typeof window != 'undefined' ? window : global); \ No newline at end of file diff --git a/lib/polyfill-wrapper-start.js b/lib/polyfill-wrapper-start.js index 477634b7..6d079069 100644 --- a/lib/polyfill-wrapper-start.js +++ b/lib/polyfill-wrapper-start.js @@ -1,4 +1,12 @@ (function(__$global) { +// 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; +} + __$global.upgradeSystemLoader = function() { __$global.upgradeSystemLoader = undefined; \ No newline at end of file diff --git a/lib/polyfills.js b/lib/polyfills.js deleted file mode 100644 index 887018b3..00000000 --- a/lib/polyfills.js +++ /dev/null @@ -1,17 +0,0 @@ -// Define an IE-friendly shim good-enough for purposes -var indexOf = Array.prototype.indexOf || function(item) { - for (var i = 0, thisLen = this.length; i < thisLen; i++) { - if (this[i] === item) - return i; - } - return -1; -} - -var lastIndexOf = Array.prototype.lastIndexOf || function(c) { - for (var i = this.length - 1; i >= 0; i--) { - if (this[i] === c) { - return i; - } - } - return -i; -} \ No newline at end of file diff --git a/test/test.html b/test/test.html index 6a2970ef..4fba6c03 100644 --- a/test/test.html +++ b/test/test.html @@ -14,7 +14,7 @@
- + diff --git a/test/test.js b/test/test.js index 2f415d18..10b312ac 100644 --- a/test/test.js +++ b/test/test.js @@ -1,4 +1,4 @@ -"global"; +"format global"; QUnit.config.testTimeout = 2000; @@ -17,7 +17,7 @@ function err(e) { } asyncTest('Error handling', function() { - System['import']('tests/error').then(err, function() { + System['import']('tests/error').then(err, function(e) { ok(true); start(); }); @@ -139,7 +139,7 @@ asyncTest('Loading an AMD module', function() { }, err); }); -asyncTest('Loading an AMD named define', function() { +/*asyncTest('Loading an AMD named define', function() { System['import']('tests/nameddefine').then(function(m1){ ok(m1.converter, 'Showdown not loaded'); System['import']('another-define').then(function(m2) { @@ -236,13 +236,13 @@ asyncTest('Advanced compiler plugin', function() { }, err); }); -/* asyncTest('Loading from jspm', function() { +asyncTest('Loading from jspm', function() { System.paths['npm:*'] = 'https://npm.jspm.io/*.js'; System['import']('npm:underscore').then(function(m) { ok(m && typeof m.chain == 'function', 'Not loaded'); start(); }, err); -}); */ +}); asyncTest('Wrapper module support', function() { System['import']('tests/wrapper').then(function(m) { @@ -326,4 +326,4 @@ asyncTest('Relative dyanamic loading', function() { start(); }, err); }, err); -}); +}); */ diff --git a/test/tests/global-inline-dep.js b/test/tests/global-inline-dep.js index b4479f77..201aa84a 100644 --- a/test/tests/global-inline-dep.js +++ b/test/tests/global-inline-dep.js @@ -1,5 +1,5 @@ -'global'; -'import ./global-dep'; +'format global'; +'deps ./global-dep'; (function(window) { diff --git a/test/tests/global-inline-export.js b/test/tests/global-inline-export.js index c77e5e09..0fc07aea 100644 --- a/test/tests/global-inline-export.js +++ b/test/tests/global-inline-export.js @@ -1,5 +1,5 @@ -"global"; -"export p.r"; +"format global"; +"exports p.r"; (function(window) {