Bladeren bron

Doing basic test of plugin support, using text plugin, needed fixes in amdefine.js

jrburke 13 jaren geleden
bovenliggende
commit
62673ee24d

+ 23 - 49
amdefine.js

@@ -1,10 +1,15 @@
 
 /*jslint strict: false, nomen: false, plusplus: false */
-/*global require, module, process */
+/*global module, process, require: true */
 
-var loaderCache = {},
+var path = require('path'),
+    loaderCache = {},
     makeRequire;
 
+// Null out require for this file so that it is not accidentally used
+// below, where module.require should be used instead.
+require = null;
+
 /**
  * Given a relative module name, like ./something, normalize it to
  * a real name that can be mapped to a path.
@@ -14,53 +19,12 @@ var loaderCache = {},
  * @returns {String} normalized name
  */
 function normalize(name, baseName) {
-    //Adjust any relative paths.
-    if (name && name.charAt(0) === ".") {
-        //If have a base name, try to normalize against it,
-        //otherwise, assume it is a top-level require that will
-        //be relative to baseUrl in the end.
-        if (baseName) {
-            //Convert baseName to array, and lop off the last part,
-            //so that . matches that "directory" and not name of the baseName's
-            //module. For instance, baseName of "one/two/three", maps to
-            //"one/two/three.js", but we want the directory, "one/two" for
-            //this normalization.
-            baseName = baseName.split("/");
-            baseName = baseName.slice(0, baseName.length - 1);
-
-            name = baseName.concat(name.split("/"));
-
-            //start trimDots
-            var i, part;
-            for (i = 0; (part = name[i]); i++) {
-                if (part === ".") {
-                    name.splice(i, 1);
-                    i -= 1;
-                } else if (part === "..") {
-                    if (i === 1 && (name[2] === '..' || name[0] === '..')) {
-                        //End of the line. Keep at least one non-dot
-                        //path segment at the front so it can be mapped
-                        //correctly to disk. Otherwise, there is likely
-                        //no path mapping for a path starting with '..'.
-                        //This can still fail, but catches the most reasonable
-                        //uses of ..
-                        break;
-                    } else if (i > 0) {
-                        name.splice(i - 1, 2);
-                        i -= 2;
-                    }
-                }
-            }
-            //end trimDots
-
-            name = name.join("/");
-        }
-    }
-    return name;
+    return path.normalize(path.join(baseName, name));
 }
 
 function makeNormalize(relName) {
     return function (name) {
+debugger;
         return normalize(name, relName);
     };
 }
@@ -68,7 +32,7 @@ function makeNormalize(relName) {
 function stringRequire(module, id) {
     //Split the ID by a ! so that
     var index = id.indexOf('!'),
-        relId = module.id,
+        relId = path.dirname(module.filename),
         prefix, plugin;
 
     if (index === -1) {
@@ -86,9 +50,9 @@ function stringRequire(module, id) {
     } else {
         //There is a plugin in play.
         prefix = id.substring(0, index);
-        id = id.substring(index, id.length);
+        id = id.substring(index + 1, id.length);
 
-        plugin = require(prefix);
+        plugin = module.require(prefix);
 
         if (plugin.normalize) {
             id = plugin.normalize(id, makeNormalize(relId));
@@ -110,7 +74,7 @@ function stringRequire(module, id) {
 }
 
 makeRequire = function (module) {
-    return function (deps, callback) {
+    function amdRequire(deps, callback) {
         if (typeof deps === 'string') {
             //Synchronous, single module require('')
             return stringRequire(module, deps);
@@ -130,7 +94,17 @@ makeRequire = function (module) {
             //Keeps strict checking in komodo happy.
             return undefined;
         }
+    }
+
+    amdRequire.toUrl = function (filePath) {
+        if (filePath.indexOf('.') === 0) {
+            return normalize(filePath, path.dirname(module.filename));
+        } else {
+            return filePath;
+        }
     };
+
+    return amdRequire;
 };
 
 function amdefine(module) {

+ 0 - 0
tests/plugins/relative/multicall.js


+ 4 - 0
tests/plugins/relative/relative-test.js

@@ -0,0 +1,4 @@
+
+var branch = require('./sub/branch');
+
+console.log(branch);

+ 9 - 0
tests/plugins/relative/sub/another/leaf.js

@@ -0,0 +1,9 @@
+if (typeof define !== 'function') { var define = (require('../../../../../amdefine'))(module); }
+
+define(function (require) {
+debugger;
+    return {
+        name: 'leaf',
+        two: require('../../text!../templates/two.txt')
+    };
+});

+ 14 - 0
tests/plugins/relative/sub/branch.js

@@ -0,0 +1,14 @@
+if (typeof define !== 'function') { var define = (require('../../../../amdefine'))(module); }
+
+define(function (require) {
+    var leaf = require('./another/leaf'),
+        oneTemplate = require('../text!./templates/one.txt'),
+        twoTemplate = require('../text!./templates/two.txt');
+
+    return {
+        name: 'branch',
+        leaf: leaf,
+        one: oneTemplate,
+        two: twoTemplate
+    };
+});

+ 1 - 0
tests/plugins/relative/sub/templates/one.txt

@@ -0,0 +1 @@
+This is one

+ 3 - 0
tests/plugins/relative/sub/templates/two.txt

@@ -0,0 +1,3 @@
+<h1>This is two</h1>
+
+<h2>OK</h2>

+ 285 - 0
tests/plugins/relative/text.js

@@ -0,0 +1,285 @@
+if (typeof define !== 'function') { var define = (require('../../../amdefine'))(module); }
+
+/**
+ * @license RequireJS text 1.0.2 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
+ * Available via the MIT or new BSD license.
+ * see: http://github.com/jrburke/requirejs for details
+ */
+/*jslint regexp: false, nomen: false, plusplus: false, strict: false */
+/*global require: false, XMLHttpRequest: false, ActiveXObject: false,
+  define: false, window: false, process: false, Packages: false,
+  java: false, location: false */
+
+(function () {
+    var progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],
+        xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,
+        bodyRegExp = /<body[^>]*>\s*([\s\S]+)\s*<\/body>/im,
+        hasLocation = typeof location !== 'undefined' && location.href,
+        defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''),
+        defaultHostName = hasLocation && location.hostname,
+        defaultPort = hasLocation && (location.port || undefined),
+        buildMap = [];
+
+    define(function () {
+        var text, get, fs;
+
+        if (typeof window !== "undefined" && window.navigator && window.document) {
+            get = function (url, callback) {
+                var xhr = text.createXhr();
+                xhr.open('GET', url, true);
+                xhr.onreadystatechange = function (evt) {
+                    //Do not explicitly handle errors, those should be
+                    //visible via console output in the browser.
+                    if (xhr.readyState === 4) {
+                        callback(xhr.responseText);
+                    }
+                };
+                xhr.send(null);
+            };
+        } else if (typeof process !== "undefined" &&
+                 process.versions &&
+                 !!process.versions.node) {
+            //Using special require.nodeRequire, something added by r.js.
+            fs = (require.nodeRequire || require)('fs');
+
+            get = function (url, callback) {
+                callback(fs.readFileSync(url, 'utf8'));
+            };
+        } else if (typeof Packages !== 'undefined') {
+            //Why Java, why is this so awkward?
+            get = function (url, callback) {
+                var encoding = "utf-8",
+                    file = new java.io.File(url),
+                    lineSeparator = java.lang.System.getProperty("line.separator"),
+                    input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),
+                    stringBuffer, line,
+                    content = '';
+                try {
+                    stringBuffer = new java.lang.StringBuffer();
+                    line = input.readLine();
+
+                    // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
+                    // http://www.unicode.org/faq/utf_bom.html
+
+                    // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
+                    // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
+                    if (line && line.length() && line.charAt(0) === 0xfeff) {
+                        // Eat the BOM, since we've already found the encoding on this file,
+                        // and we plan to concatenating this buffer with others; the BOM should
+                        // only appear at the top of a file.
+                        line = line.substring(1);
+                    }
+
+                    stringBuffer.append(line);
+
+                    while ((line = input.readLine()) !== null) {
+                        stringBuffer.append(lineSeparator);
+                        stringBuffer.append(line);
+                    }
+                    //Make sure we return a JavaScript string and not a Java string.
+                    content = String(stringBuffer.toString()); //String
+                } finally {
+                    input.close();
+                }
+                callback(content);
+            };
+        }
+
+        text = {
+            version: '1.0.2',
+
+            strip: function (content) {
+                //Strips <?xml ...?> declarations so that external SVG and XML
+                //documents can be added to a document without worry. Also, if the string
+                //is an HTML document, only the part inside the body tag is returned.
+                if (content) {
+                    content = content.replace(xmlRegExp, "");
+                    var matches = content.match(bodyRegExp);
+                    if (matches) {
+                        content = matches[1];
+                    }
+                } else {
+                    content = "";
+                }
+                return content;
+            },
+
+            jsEscape: function (content) {
+                return content.replace(/(['\\])/g, '\\$1')
+                    .replace(/[\f]/g, "\\f")
+                    .replace(/[\b]/g, "\\b")
+                    .replace(/[\n]/g, "\\n")
+                    .replace(/[\t]/g, "\\t")
+                    .replace(/[\r]/g, "\\r");
+            },
+
+            createXhr: function () {
+                //Would love to dump the ActiveX crap in here. Need IE 6 to die first.
+                var xhr, i, progId;
+                if (typeof XMLHttpRequest !== "undefined") {
+                    return new XMLHttpRequest();
+                } else {
+                    for (i = 0; i < 3; i++) {
+                        progId = progIds[i];
+                        try {
+                            xhr = new ActiveXObject(progId);
+                        } catch (e) {}
+
+                        if (xhr) {
+                            progIds = [progId];  // so faster next time
+                            break;
+                        }
+                    }
+                }
+
+                if (!xhr) {
+                    throw new Error("createXhr(): XMLHttpRequest not available");
+                }
+
+                return xhr;
+            },
+
+            get: get,
+
+            /**
+             * Parses a resource name into its component parts. Resource names
+             * look like: module/name.ext!strip, where the !strip part is
+             * optional.
+             * @param {String} name the resource name
+             * @returns {Object} with properties "moduleName", "ext" and "strip"
+             * where strip is a boolean.
+             */
+            parseName: function (name) {
+                var strip = false, index = name.indexOf("."),
+                    modName = name.substring(0, index),
+                    ext = name.substring(index + 1, name.length);
+
+                index = ext.indexOf("!");
+                if (index !== -1) {
+                    //Pull off the strip arg.
+                    strip = ext.substring(index + 1, ext.length);
+                    strip = strip === "strip";
+                    ext = ext.substring(0, index);
+                }
+
+                return {
+                    moduleName: modName,
+                    ext: ext,
+                    strip: strip
+                };
+            },
+
+            xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/,
+
+            /**
+             * Is an URL on another domain. Only works for browser use, returns
+             * false in non-browser environments. Only used to know if an
+             * optimized .js version of a text resource should be loaded
+             * instead.
+             * @param {String} url
+             * @returns Boolean
+             */
+            useXhr: function (url, protocol, hostname, port) {
+                var match = text.xdRegExp.exec(url),
+                    uProtocol, uHostName, uPort;
+                if (!match) {
+                    return true;
+                }
+                uProtocol = match[2];
+                uHostName = match[3];
+
+                uHostName = uHostName.split(':');
+                uPort = uHostName[1];
+                uHostName = uHostName[0];
+
+                return (!uProtocol || uProtocol === protocol) &&
+                       (!uHostName || uHostName === hostname) &&
+                       ((!uPort && !uHostName) || uPort === port);
+            },
+
+            finishLoad: function (name, strip, content, onLoad, config) {
+                content = strip ? text.strip(content) : content;
+                if (config.isBuild) {
+                    buildMap[name] = content;
+                }
+                onLoad(content);
+            },
+
+            load: function (name, req, onLoad, config) {
+                //Name has format: some.module.filext!strip
+                //The strip part is optional.
+                //if strip is present, then that means only get the string contents
+                //inside a body tag in an HTML string. For XML/SVG content it means
+                //removing the <?xml ...?> declarations so the content can be inserted
+                //into the current doc without problems.
+
+                // Do not bother with the work if a build and text will
+                // not be inlined.
+                if (config.isBuild && !config.inlineText) {
+                    onLoad();
+                    return;
+                }
+
+                var parsed = text.parseName(name),
+                    nonStripName = parsed.moduleName + '.' + parsed.ext,
+                    url = req.toUrl(nonStripName),
+                    useXhr = (config && config.text && config.text.useXhr) ||
+                             text.useXhr;
+
+                //Load the text. Use XHR if possible and in a browser.
+                if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {
+                    text.get(url, function (content) {
+                        text.finishLoad(name, parsed.strip, content, onLoad, config);
+                    });
+                } else {
+                    //Need to fetch the resource across domains. Assume
+                    //the resource has been optimized into a JS module. Fetch
+                    //by the module name + extension, but do not include the
+                    //!strip part to avoid file system issues.
+                    req([nonStripName], function (content) {
+                        text.finishLoad(parsed.moduleName + '.' + parsed.ext,
+                                        parsed.strip, content, onLoad, config);
+                    });
+                }
+            },
+
+            write: function (pluginName, moduleName, write, config) {
+                if (moduleName in buildMap) {
+                    var content = text.jsEscape(buildMap[moduleName]);
+                    write.asModule(pluginName + "!" + moduleName,
+                                   "define(function () { return '" +
+                                       content +
+                                   "';});\n");
+                }
+            },
+
+            writeFile: function (pluginName, moduleName, req, write, config) {
+                var parsed = text.parseName(moduleName),
+                    nonStripName = parsed.moduleName + '.' + parsed.ext,
+                    //Use a '.js' file name so that it indicates it is a
+                    //script that can be loaded across domains.
+                    fileName = req.toUrl(parsed.moduleName + '.' +
+                                         parsed.ext) + '.js';
+
+                //Leverage own load() method to load plugin value, but only
+                //write out values that do not have the strip argument,
+                //to avoid any potential issues with ! in file names.
+                text.load(nonStripName, req, function (value) {
+                    //Use own write() method to construct full module value.
+                    //But need to create shell that translates writeFile's
+                    //write() to the right interface.
+                    var textWrite = function (contents) {
+                        return write(fileName, contents);
+                    };
+                    textWrite.asModule = function (moduleName, contents) {
+                        return write.asModule(moduleName, fileName, contents);
+                    };
+
+                    text.write(pluginName, nonStripName, textWrite, config);
+                }, config);
+            }
+        };
+
+        return text;
+    });
+}());