Skip to content
This repository has been archived by the owner on Jul 13, 2020. It is now read-only.

Commit

Permalink
ES6 module handling update for deferred execution
Browse files Browse the repository at this point in the history
  • Loading branch information
guybedford committed Mar 3, 2014
1 parent 80e94b9 commit 4f915f4
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 146 deletions.
4 changes: 2 additions & 2 deletions dist/es6-module-loader.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions lib/index.js
@@ -1,5 +1,5 @@
module.exports = {
Loader: require('./loader.js'),
Module: require('./module.js'),
System: require('./system.js')
Loader: require('./loader'),
Module: require('./module'),
System: require('./system')
};
198 changes: 132 additions & 66 deletions lib/loader.js
Expand Up @@ -10,15 +10,15 @@
- Abstract functions have been combined where possible, and their associated functions
commented
- Declarative Module Support is entirely disabled, and an error will be thrown if
the instantiate loader hook returns undefined
- When the traceur global is detected, declarative modules are transformed by Traceur
before execution. The Traceur parse tree is stored as load.body, analogously to the
spec
- With this assumption, instead of Link, LinkDynamicModules is run directly
- Link and EnsureEvaluated have been customised from the spec
- ES6 support is thus provided through the translate function of the System loader
- Module Linkage records are stored as: { module: (actual module), dependencies, body, name, address }
- EnsureEvaluated is removed, but may in future implement dynamic execution pending
issue - https://github.com/jorendorff/js-loaders/issues/63
- Cycles are not supported at all and will throw an error
- Realm implementation is entirely omitted. As such, Loader.global and Loader.realm
accessors will throw errors, as well as Loader.eval
Expand Down Expand Up @@ -54,8 +54,7 @@ function logloads(loads) {
} */

(function (global) {
var Module = global.Module || require('./module.js');
var Promise = global.Promise || require('./promise.js');
var Promise = global.Promise || require('./promise');

var defineProperty;
try {
Expand All @@ -72,10 +71,6 @@ function logloads(loads) {
if (!expression)
console.log('Assertion Failed - ' + name);
}
function preventExtensions(obj) {
if (Object.preventExtensions)
Object.preventExtensions(obj);
}

// Define an IE-friendly shim good-enough for purposes
var indexOf = Array.prototype.indexOf || function (item) {
Expand All @@ -99,10 +94,10 @@ function logloads(loads) {
}

// promise for a load record, can be in registry, already loading, or not
function requestLoad(loader, request, refererName, refererAddress) {
function requestLoad(loader, request, referrerName, referrerAddress) {
return new Promise(function(resolve, reject) {
// CallNormalize
resolve(loader.normalize(request, refererName, refererAddress));
resolve(loader.normalize(request, referrerName, referrerAddress));
})

// GetOrCreateLoad
Expand Down Expand Up @@ -177,18 +172,11 @@ function logloads(loads) {
var depsList;
if (instantiateResult === undefined) {
if (traceur) {
var reporter = new traceur.util.ErrorReporter();

reporter.reportMessageInternal = function(location, kind, format, args) {
throw kind + '\n' + location;
}

load.address = load.address || 'anon' + ++anonCnt;
var parser = new traceur.syntax.Parser(new traceur.syntax.SourceFile(load.address, load.source));

var tree = parser.parseModule();

depsList = getImports(tree);
load.body = tree;
load.body = (new traceur.codegeneration.module.AttachModuleNameTransformer(load.name)).transformAny(tree);
}
else {
var match = load.source.match(aliasRegEx);
Expand Down Expand Up @@ -403,11 +391,64 @@ function logloads(loads) {
function evaluateLoadedModule(loader, load) {
assert('is linked ' + load.name, load.status == 'linked');

assert('is a module', load.module instanceof Module);
ensureEvaluated(load.module, loader);

// ensureEvaluated(load.module, [], loader);
assert('is a module', load.module.module instanceof Module);

return load.module;
return load.module.module;
}
function ensureEvaluated(module, loader) {

// if already executed or dynamic module exists
// dynamic modules are evaluated during linking
if (module.module)
return module.module;

// continue until all evaluated
var circular = true;

// ensure all dependencies are evaluated first
for (var m in module.dependencies) {
var depName = module.dependencies[m];
// no module object means it is not executed
if (!loader._modules[depName].module)
ensureEvaluated(loader._modules[depName], loader);
}

// now evaluate this module
traceur.options.sourceMaps = true;
traceur.options.modules = 'instantiate';

var reporter = new traceur.util.ErrorReporter();

reporter.reportMessageInternal = function(location, kind, format, args) {
throw kind + '\n' + location;
}

// transform
var transformer = new traceur.codegeneration.FromOptionsTransformer(reporter);
var tree = transformer.transform(module.body);
delete module.body;

// convert back to a source string
var sourceMapGenerator = new traceur.outputgeneration.SourceMapGenerator({ file: module.address });
var options = { sourceMapGenerator: sourceMapGenerator };

var source = traceur.outputgeneration.TreeWriter.write(tree, options);
if (global.btoa)
source += '\n//# sourceMappingURL=data:application/json;base64,' + btoa(unescape(encodeURIComponent(options.sourceMap))) + '\n';

var sysRegister = System.register;
System.register = function(name, deps, execute) {
for (var i = 0; i < deps.length; i++)
deps[i] = module.dependencies[deps[i]];

module.module = new Module(execute.apply(global, deps));
}

__eval(source, global, module.address, module.name);

System.register = sysRegister;
}

// Linking
Expand All @@ -433,36 +474,22 @@ function logloads(loads) {

circular = false;

// all dependencies linked now, so we can execute
// all dependencies linked now, so we can link

if (load.kind == 'declarative') {
traceur.options.sourceMaps = true;
traceur.options.modules = 'instantiate';

// transform
var transformer = new traceur.codegeneration.FromOptionsTransformer(reporter);
var tree = transformer.transform(load.body);

// convert back to a source string
var sourceMapGenerator = new traceur.outputgeneration.SourceMapGenerator({ file: load.address });
var options = { sourceMapGenerator: sourceMapGenerator };

var source = traceur.outputgeneration.TreeWriter.write(tree, options);
if (global.btoa)
source += '\n//# sourceMappingURL=data:application/json;base64,' + btoa(unescape(encodeURIComponent(options.sourceMap))) + '\n';

console.log(source);

__eval(source, global, load.address, load.name);

load.module = new Module(exports);
load.module = {
name: load.name,
dependencies: load.dependencies,
body: load.body
};
}
else {
// dynamic module
var module = load.execute.apply(null, depNames);
if (!(module instanceof Module))
throw new TypeError('Execution must define a Module instance');
load.module = module;
load.module = {
module: module
};
}

load.status = 'linked';
Expand All @@ -474,6 +501,7 @@ function logloads(loads) {
// console.log('linked');
}


// Loader
function Loader(options) {
if (typeof options != 'object')
Expand Down Expand Up @@ -515,8 +543,10 @@ function logloads(loads) {
return importPromises[name].then(function() { delete importPromises[name]; });
},
load: function(request, options) {
if (this._modules[request])
return Promise.resolve(this._modules[request]);
if (this._modules[request]) {
ensureEvaluated(this._modules[request], this);
return Promise.resolve(this._modules[request].module);
}
if (importPromises[request])
return importPromises[request];
importPromises[request] = loadModule(this, request, options);
Expand All @@ -527,35 +557,41 @@ function logloads(loads) {
load.address = options && options.address;
var linkSet = createLinkSet(this, load);
var sourcePromise = Promise.resolve(source);
var loader = this;
var p = linkSet.done.then(function() {
evaluateLoadedModule(this, load);
return evaluateLoadedModule(loader, load);
});
proceedToTranslate(this, load, sourcePromise);
return p;
},
'import': function(name, options) {
if (this._modules[name])
return Promise.resolve(this._modules[name]);
if (this._modules[name]) {
ensureEvaluated(this._modules[name], this);
return Promise.resolve(this._modules[name].module);
}
var loader = this;
return (importPromises[name] || (importPromises[name] = loadModule(this, name, options)))
.then(function(load) {
delete importPromises[name];
return evaluateLoadedModule(this, load);
return evaluateLoadedModule(loader, load);
});
},
eval: function(source) {
throw new TypeError('Eval not implemented in polyfill')
},
get: function(key) {
// NB run ensure evaluted here when implemented
return this._modules[key];
ensureEvaluated(this._modules[key], this);
return this._modules[key].module;
},
has: function(name) {
return !!this._modules[name];
},
set: function(name, module) {
if (!(module instanceof Module))
throw new TypeError('Set must be a module');
this._modules[name] = module;
this._modules[name] = {
module: module
};
},
'delete': function(name) {
return this._modules[name] ? delete this._modules[name] : false;
Expand All @@ -570,7 +606,7 @@ function logloads(loads) {
values: function() {
throw new TypeError('Iteration not yet implemented in the polyfill');
},
normalize: function(name, refererName, refererAddress) {
normalize: function(name, referrerName, referrerAddress) {
return name;
},
locate: function(load) {
Expand All @@ -586,13 +622,6 @@ function logloads(loads) {
}
};

if (typeof exports === 'object') {
module.exports = Loader;
}

global.Loader || (global.Loader = Loader);
global.LoaderPolyfill = Loader;


// es6 module forwarding - allow detecting without Traceur
var aliasRegEx = /^\s*export\s*\*\s*from\s*(?:'([^']+)'|"([^"]+)")/;
Expand All @@ -601,6 +630,9 @@ function logloads(loads) {
Use Traceur?
*/
var traceur = global.traceur;
$traceurRuntime.ModuleStore.get = $traceurRuntime.getModuleImpl = function(name) {
return System.get(name);
}

// tree traversal, NB should use visitor pattern here
function traverse(object, iterator, parent, parentProperty) {
Expand Down Expand Up @@ -643,6 +675,7 @@ function logloads(loads) {
});
return imports;
}
var anonCnt = 0;


function __eval(__source, global, __sourceURL, __moduleName) {
Expand All @@ -658,4 +691,37 @@ function logloads(loads) {
}
}

// Module Object
function Module(obj) {
if (typeof obj != 'object')
throw new TypeError('Expected object');

if (!(this instanceof Module))
return new Module(obj);

var self = this;
for (var key in obj) {
(function (key, value) {
defineProperty(self, key, {
configurable: false,
enumerable: true,
get: function () {
return value;
}
});
})(key, obj[key]);
}
if (Object.preventExtensions)
Object.preventExtensions(this);
}
// Module.prototype = null;


if (typeof exports === 'object')
module.exports = Loader;

global.Loader || (global.Loader = Loader);
global.LoaderPolyfill = Loader;
global.Module || (global.Module = Module);

})(typeof global !== 'undefined' ? global : this);
45 changes: 0 additions & 45 deletions lib/module.js
@@ -1,45 +0,0 @@
(function (global) {
var defineProperty;
try {
if (!!Object.defineProperty({}, 'a', {})) {
defineProperty = Object.defineProperty;
}
} catch (e) {
defineProperty = function (obj, prop, opt) {
obj[prop] = opt.value || opt.get.call(obj);
}
}

// Module Object
function Module(obj) {
if (typeof obj != 'object')
throw new TypeError('Expected object');

if (!(this instanceof Module))
return new Module(obj);

var self = this;
for (var key in obj) {
(function (key, value) {
defineProperty(self, key, {
configurable: false,
enumerable: true,
get: function () {
return value;
}
});
})(key, obj[key]);
}
if (Object.preventExtensions)
Object.preventExtensions(this);
}
// Module.prototype = null;

if (typeof exports === 'object') {
module.exports = Module;
}

global.Module || (global.Module = Module);
global.ModulePolyfill = Module;

})(typeof global !== 'undefined' ? global : this);

0 comments on commit 4f915f4

Please sign in to comment.