Skip to content

Instantly share code, notes, and snippets.

@lukehoban
Created March 30, 2012 05:17

Revisions

  1. lukehoban revised this gist Mar 30, 2012. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions gistfile1.js
    Original file line number Diff line number Diff line change
    @@ -121,8 +121,7 @@
    xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
    if (xhr.status === 200) {
    var sourceText = xhr.responseText;
    request.fulfill(sourceText);
    request.fulfill(xhr.responseText);
    } else {
    request.reject(xhr.statusText);
    }
  2. lukehoban created this gist Mar 30, 2012.
    148 changes: 148 additions & 0 deletions gistfile1.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,148 @@
    (function (global) {

    // TODO: Delegate to parent loader in various places
    // TODO: Canonicalization
    // TODO: Can we do better for 'eval'?

    /// Module loader constructor
    function Loader(parent, options) {

    // Initialization of loader state from options
    this._global = options.global || Object.create(null);
    this._baseURL = options.baseURL || this.global && this.global.baseURL;
    if (options.intrinsics === null || options.intrinsics) {
    throw new Error("Setting 'intrinsics' not yet supported.");
    }
    this._strict = options.string === undefined ? false : !!options.string;
    this._resolve = options.resolve || parent.resolve;
    this._fetch = options.fetch || parent.fetch;
    this._translate = options.translate || parent.translate;

    // The internal table of module instance objects
    this._mios = {}
    }

    Object.defineProperty(Loader.prototype, "global", { configurable: true, enumerable: true, get: function () {
    return this._global;
    }});

    Object.defineProperty(Loader.prototype, "baseURL", { configurable: true, enumerable: true, get: function () {
    return this._baseURL;
    }});

    Loader.prototype.load = function (url, callback, errback) {
    var key = this._resolve(url, this._baseURL);
    if (this._mios[key]) {
    callback(this._mios[key]);
    } else {
    var self = this;
    this._fetch(url, this._baseURL, {
    fulfill: function (src) {
    var actualSrc = self._translate(src, url, self._baseURL, key);
    if (self._strict) {
    actualSrc = "'use strict';\n" + actualSrc;
    }
    eval(actualSrc);
    callback(self._mios[key]);
    },
    redirect: function (url, baseURL) {
    throw new Error("'redirect' not yet implemented");
    },
    reject: function (msg) {
    errback(msg);
    }
    }, key);
    }
    }

    Loader.prototype.eval = function (sourceText) {
    with (this._global) {
    eval(sourceText);
    }
    }

    Loader.prototype.evalAsync = function () {
    throw new Error("'evalAsync' not yet implemented. Not needed until module syntax is available.");
    }

    Loader.prototype.get = function (url) {
    var key = this._resolve(url, this._baseURL);
    return this._mios[key];
    }

    Loader.prototype.set = function (url, mio) {
    var key = this._resolve(url, this._baseURL);
    if (typeof url == "string") {
    this._mios[key] = Module(mio);
    } else {
    for (var p in key) {
    this._mios[p] = Module(key[p]);
    }
    }
    }

    Loader.prototype.defineBuiltins = function (o) {
    if (typeof o != "object") throw new Error("Expected object");
    for (var globalProp in global) {
    o[globalProp] = global;
    }
    return o;
    }

    function Module(o) {
    if (o == null) throw new TypeError("Expected object");
    var obj = Object(o);
    if (obj instanceof Module) {
    return obj;
    } else {
    var mio = Object.create(null);
    for (var key in obj) {
    (function(key) {
    Object.defineProperty(mio, key, { configurable: false, enumerable: true, get: function () {
    return obj[key];
    }});
    })(key);
    }
    return mio;
    }
    }

    var defaultSystemLoader = new Loader(null, {
    global: window,
    baseURL: document.URL.substring(0, document.URL.lastIndexOf('\/') + 1),
    strict: false,
    resolve: function (relURL, baseURL) {
    var url = baseURL + relURL;
    return url;
    },
    fetch: function (relURL, baseURL, request, resolved) {
    var url = baseURL + relURL;
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
    if (xhr.status === 200) {
    var sourceText = xhr.responseText;
    request.fulfill(sourceText);
    } else {
    request.reject(xhr.statusText);
    }
    }
    };
    xhr.open("GET", url, true);
    xhr.send(null);
    },
    translate: function (src, relURL, baseURL, resolved) {
    return src;
    }
    });

    // Export the Loader class
    global.Loader = Loader;

    // Export the Module class
    global.Module = Module;

    // Export the System object
    global.System = defaultSystemLoader;

    })(this);