Last active
September 27, 2015 15:17
-
-
Save guybedford/11164189 to your computer and use it in GitHub Desktop.
System.register ES6 form loader hooks implementation for https://github.com/google/traceur-compiler/issues/953#issuecomment-40969512
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// our side table | |
// registry = { deps, declare ; normalizedDeps, depMap ; execute, exports } | |
// Lifecycle: | |
// 1. before instantiate, just deps, declare | |
// 2. after instantiate, normalizedDeps and depMap | |
// 3. after linking, execute, exports | |
// 4. after partial tree execution just exports | |
// 5. after full tree execution, removed from registry | |
var registry = {}; | |
loader.register = function(name, deps, declare) { | |
registry[name] = { | |
deps: deps, | |
declare: declare | |
}; | |
} | |
// recursively ensure that a module and all its dependencies are declared | |
// that is either in the loader registry or have registry.exports in the | |
// side table registry | |
// returns the exports object for convenience in recursion | |
function ensureDeclared(moduleName) { | |
var registryEntry = registry[moduleName]; | |
// no registry entry -> already executed or ES6. | |
// Run a System.get for ES6 modules to work with loader.register | |
// (a complete edge case, but makes it consistent) | |
if (!registryEntry) | |
return System.get(moduleName); | |
// exports already declared | |
if (registryEntry.exports) | |
return registryEntry.exports; | |
// not yet declared | |
// -> declare this module | |
// -> then declare its dependencies, populating the depMap | |
// top-down order avoids issues of cirularity | |
var declared = registryEntry.declare(registryEntry.depMap); | |
registryEntry.exports = declared.exports; | |
registryEntry.execute = declared.execute; | |
for (var i = 0; i < registryEntry.normalizedDeps.length; i++) { | |
var depName = registryEntry.normalizedDeps[i]; | |
registryEntry.depMap[registryEntry.deps[i]] = ensureDeclared(depName); | |
} | |
return registryEntry.exports; | |
} | |
// 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) { | |
var registryEntry = registry[moduleName]; | |
// if already seen, that means it's an already-evaluated non circular dependency | |
if (seen.indexOf(moduleName) != -1) | |
return; | |
seen.push(moduleName); | |
for (var i = 0; i < registryEntry.normalizedDeps.length; i++) { | |
var depName = registryEntry.normalizedDeps[i]; | |
// circular -> execute now if not already executed | |
if (seen.indexOf(depName) != -1) { | |
var depEntry = registry[depName]; | |
if (depEntry && depEntry.execute) | |
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 | |
registryEntry.execute.call(loader.global); | |
} | |
var loaderInstantiate = loader.instantiate; | |
loader.instantiate = function(load) { | |
var registryEntry = registry[load.name]; | |
if (!registryEntry) | |
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) { | |
registryEntry.normalizedDeps = normalizedDeps; | |
// create the empty dep map - this is our key deferred dependency binding object passed into declare | |
registryEntry.depMap = {}; | |
return { | |
deps: registryEntry.deps, | |
execute: function() { | |
// recursively ensure that the module and all its dependencies are declared | |
ensureDeclared(load.name); | |
// now handle dependency execution in correct order | |
ensureEvaluated(load.name, []); | |
// remove from the registry | |
delete registry[load.name]; | |
// return the defined module object | |
return Module(registryEntry.exports); | |
} | |
}; | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment