|
@@ -8,190 +8,289 @@
|
|
/*global module, process */
|
|
/*global module, process */
|
|
'use strict';
|
|
'use strict';
|
|
|
|
|
|
-var path = require('path'),
|
|
|
|
- loaderCache = {},
|
|
|
|
- makeRequire;
|
|
|
|
|
|
+var path = require('path');
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Given a relative module name, like ./something, normalize it to
|
|
|
|
- * a real name that can be mapped to a path.
|
|
|
|
- * @param {String} name the relative name
|
|
|
|
- * @param {String} baseName a real name that the name arg is relative
|
|
|
|
- * to.
|
|
|
|
- * @returns {String} normalized name
|
|
|
|
- */
|
|
|
|
-function normalize(name, baseName) {
|
|
|
|
- return path.normalize(path.join(baseName, name));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * Create the normalize() function passed to a loader plugin's
|
|
|
|
- * normalize method.
|
|
|
|
|
|
+ * Creates a define for node.
|
|
|
|
+ * @param {Object} module the "module" object that is defined by Node for the
|
|
|
|
+ * current module.
|
|
|
|
+ * @param {Function} [require]. Node's require function for the current module.
|
|
|
|
+ * It only needs to be passed in Node versions before 0.5, when module.require
|
|
|
|
+ * did not exist.
|
|
|
|
+ * @returns {Function} a define function that is usable for the current node
|
|
|
|
+ * module.
|
|
*/
|
|
*/
|
|
-function makeNormalize(relName) {
|
|
|
|
- return function (name) {
|
|
|
|
- return normalize(name, relName);
|
|
|
|
- };
|
|
|
|
-}
|
|
|
|
|
|
+function amdefine(module, require) {
|
|
|
|
+ var defineCache = {},
|
|
|
|
+ loaderCache = {},
|
|
|
|
+ alreadyCalled = false,
|
|
|
|
+ makeRequire, stringRequire;
|
|
|
|
|
|
-function makeLoad(id) {
|
|
|
|
- function load(value) {
|
|
|
|
- loaderCache[id] = value;
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Trims the . and .. from an array of path segments.
|
|
|
|
+ * It will keep a leading path segment if a .. will become
|
|
|
|
+ * the first path segment, to help with module name lookups,
|
|
|
|
+ * which act like paths, but can be remapped. But the end result,
|
|
|
|
+ * all paths that use this function should look normalized.
|
|
|
|
+ * NOTE: this method MODIFIES the input array.
|
|
|
|
+ * @param {Array} ary the array of path segments.
|
|
|
|
+ */
|
|
|
|
+ function trimDots(ary) {
|
|
|
|
+ var i, part;
|
|
|
|
+ for (i = 0; ary[i]; i+= 1) {
|
|
|
|
+ part = ary[i];
|
|
|
|
+ if (part === '.') {
|
|
|
|
+ ary.splice(i, 1);
|
|
|
|
+ i -= 1;
|
|
|
|
+ } else if (part === '..') {
|
|
|
|
+ if (i === 1 && (ary[2] === '..' || ary[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) {
|
|
|
|
+ ary.splice(i - 1, 2);
|
|
|
|
+ i -= 2;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- load.fromText = function (id, text) {
|
|
|
|
- //This one is difficult because the text can/probably uses
|
|
|
|
- //define, and any relative paths and requires should be relative
|
|
|
|
- //to that id was it would be found on disk. But this would require
|
|
|
|
- //bootstrapping a module/require fairly deeply from node core.
|
|
|
|
- //Not sure how best to go about that yet.
|
|
|
|
- throw new Error('amdefine does not implement load.fromText');
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- return load;
|
|
|
|
-}
|
|
|
|
|
|
+ function normalize(name, baseName) {
|
|
|
|
+ var baseParts;
|
|
|
|
|
|
-function stringRequire(module, require, id) {
|
|
|
|
- //Split the ID by a ! so that
|
|
|
|
- var index = id.indexOf('!'),
|
|
|
|
- relId = path.dirname(module.filename),
|
|
|
|
- prefix, plugin;
|
|
|
|
-
|
|
|
|
- if (index === -1) {
|
|
|
|
- //Straight module lookup. If it is one of the special dependencies,
|
|
|
|
- //deal with it, otherwise, delegate to node.
|
|
|
|
- if (id === 'require') {
|
|
|
|
- return makeRequire(module, require);
|
|
|
|
- } else if (id === 'exports') {
|
|
|
|
- return module.exports;
|
|
|
|
- } else if (id === 'module') {
|
|
|
|
- return module;
|
|
|
|
- } else {
|
|
|
|
- return require(id);
|
|
|
|
|
|
+ //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) {
|
|
|
|
+ baseParts = baseName.split('/');
|
|
|
|
+ baseParts = baseParts.slice(0, baseParts.length - 1);
|
|
|
|
+ baseParts = baseParts.concat(name.split('/'));
|
|
|
|
+ trimDots(baseParts);
|
|
|
|
+ name = baseParts.join('/');
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- } else {
|
|
|
|
- //There is a plugin in play.
|
|
|
|
- prefix = id.substring(0, index);
|
|
|
|
- id = id.substring(index + 1, id.length);
|
|
|
|
|
|
|
|
- plugin = require(prefix);
|
|
|
|
-
|
|
|
|
- if (plugin.normalize) {
|
|
|
|
- id = plugin.normalize(id, makeNormalize(relId));
|
|
|
|
- } else {
|
|
|
|
- //Normalize the ID normally.
|
|
|
|
- id = normalize(id, relId);
|
|
|
|
- }
|
|
|
|
|
|
+ return name;
|
|
|
|
+ }
|
|
|
|
|
|
- if (loaderCache[id]) {
|
|
|
|
- return loaderCache[id];
|
|
|
|
- } else {
|
|
|
|
- plugin.load(id, makeRequire(module, require), makeLoad(id), {});
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Create the normalize() function passed to a loader plugin's
|
|
|
|
+ * normalize method.
|
|
|
|
+ */
|
|
|
|
+ function makeNormalize(relName) {
|
|
|
|
+ return function (name) {
|
|
|
|
+ return normalize(name, relName);
|
|
|
|
+ };
|
|
|
|
+ }
|
|
|
|
|
|
- return loaderCache[id];
|
|
|
|
|
|
+ function makeLoad(id) {
|
|
|
|
+ function load(value) {
|
|
|
|
+ loaderCache[id] = value;
|
|
}
|
|
}
|
|
- }
|
|
|
|
-}
|
|
|
|
|
|
|
|
-makeRequire = function (module, require) {
|
|
|
|
- function amdRequire(deps, callback) {
|
|
|
|
- if (typeof deps === 'string') {
|
|
|
|
- //Synchronous, single module require('')
|
|
|
|
- return stringRequire(module, require, deps);
|
|
|
|
- } else {
|
|
|
|
- //Array of dependencies with a callback.
|
|
|
|
|
|
+ load.fromText = function (id, text) {
|
|
|
|
+ //This one is difficult because the text can/probably uses
|
|
|
|
+ //define, and any relative paths and requires should be relative
|
|
|
|
+ //to that id was it would be found on disk. But this would require
|
|
|
|
+ //bootstrapping a module/require fairly deeply from node core.
|
|
|
|
+ //Not sure how best to go about that yet.
|
|
|
|
+ throw new Error('amdefine does not implement load.fromText');
|
|
|
|
+ };
|
|
|
|
|
|
- //Convert the dependencies to modules.
|
|
|
|
- deps = deps.map(function (depName) {
|
|
|
|
- return stringRequire(module, require, depName);
|
|
|
|
- });
|
|
|
|
|
|
+ return load;
|
|
|
|
+ }
|
|
|
|
|
|
- //Wait for next tick to call back the require call.
|
|
|
|
- process.nextTick(function () {
|
|
|
|
- callback.apply(null, deps);
|
|
|
|
- });
|
|
|
|
|
|
+ makeRequire = function (systemRequire, exports, module, relId) {
|
|
|
|
+ function amdRequire(deps, callback) {
|
|
|
|
+ if (typeof deps === 'string') {
|
|
|
|
+ //Synchronous, single module require('')
|
|
|
|
+ return stringRequire(systemRequire, exports, module, deps, relId);
|
|
|
|
+ } else {
|
|
|
|
+ //Array of dependencies with a callback.
|
|
|
|
|
|
- //Keeps strict checking in komodo happy.
|
|
|
|
- return undefined;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ //Convert the dependencies to modules.
|
|
|
|
+ deps = deps.map(function (depName) {
|
|
|
|
+ return stringRequire(systemRequire, exports, module, depName, relId);
|
|
|
|
+ });
|
|
|
|
|
|
- amdRequire.toUrl = function (filePath) {
|
|
|
|
- if (filePath.indexOf('.') === 0) {
|
|
|
|
- return normalize(filePath, path.dirname(module.filename));
|
|
|
|
- } else {
|
|
|
|
- return filePath;
|
|
|
|
|
|
+ //Wait for next tick to call back the require call.
|
|
|
|
+ process.nextTick(function () {
|
|
|
|
+ callback.apply(null, deps);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- };
|
|
|
|
|
|
|
|
- return amdRequire;
|
|
|
|
-};
|
|
|
|
|
|
+ amdRequire.toUrl = function (filePath) {
|
|
|
|
+ if (filePath.indexOf('.') === 0) {
|
|
|
|
+ return normalize(filePath, path.dirname(module.filename));
|
|
|
|
+ } else {
|
|
|
|
+ return filePath;
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
|
|
-/**
|
|
|
|
- * Creates a define for node.
|
|
|
|
- * @param {Object} module the "module" object that is defined by Node for the
|
|
|
|
- * current module.
|
|
|
|
- * @param {Function} [require]. Node's require function for the current module.
|
|
|
|
- * It only needs to be passed in Node versions before 0.5, when module.require
|
|
|
|
- * did not exist.
|
|
|
|
- * @returns {Function} a define function that is usable for the current node
|
|
|
|
- * module.
|
|
|
|
- */
|
|
|
|
-function amdefine(module, require) {
|
|
|
|
- var alreadyCalled = false;
|
|
|
|
|
|
+ return amdRequire;
|
|
|
|
+ };
|
|
|
|
|
|
//Favor explicit value, passed in if the module wants to support Node 0.4.
|
|
//Favor explicit value, passed in if the module wants to support Node 0.4.
|
|
require = require || function req() {
|
|
require = require || function req() {
|
|
return module.require.apply(module, arguments);
|
|
return module.require.apply(module, arguments);
|
|
};
|
|
};
|
|
|
|
|
|
- //Create a define function specific to the module asking for amdefine.
|
|
|
|
- function define() {
|
|
|
|
-
|
|
|
|
- var args = arguments,
|
|
|
|
- factory = args[args.length - 1],
|
|
|
|
- isFactoryFunction = (typeof factory === 'function'),
|
|
|
|
- deps, result;
|
|
|
|
|
|
+ function runFactory(id, deps, factory) {
|
|
|
|
+ var r, e, m, result;
|
|
|
|
|
|
- //Only support one define call per file
|
|
|
|
- if (alreadyCalled) {
|
|
|
|
- throw new Error('amdefine cannot be called more than once per file.');
|
|
|
|
- }
|
|
|
|
- alreadyCalled = true;
|
|
|
|
-
|
|
|
|
- //Grab array of dependencies if it is there.
|
|
|
|
- if (args.length > 1) {
|
|
|
|
- deps = args[args.length - 2];
|
|
|
|
- if (!Array.isArray(deps)) {
|
|
|
|
- //deps is not an array, may be an ID. Discard it.
|
|
|
|
- deps = null;
|
|
|
|
|
|
+ if (id) {
|
|
|
|
+ e = loaderCache[id] = {};
|
|
|
|
+ m = {
|
|
|
|
+ id: id,
|
|
|
|
+ uri: __filename,
|
|
|
|
+ exports: e
|
|
|
|
+ };
|
|
|
|
+ r = makeRequire(undefined, e, m, id);
|
|
|
|
+ } else {
|
|
|
|
+ //Only support one define call per file
|
|
|
|
+ if (alreadyCalled) {
|
|
|
|
+ throw new Error('amdefine with no module ID cannot be called more than once per file.');
|
|
}
|
|
}
|
|
|
|
+ alreadyCalled = true;
|
|
|
|
+
|
|
|
|
+ //Use the real variables from node
|
|
|
|
+ //Use module.exports for exports, since
|
|
|
|
+ //the exports in here is amdefine exports.
|
|
|
|
+ e = module.exports;
|
|
|
|
+ m = module;
|
|
|
|
+ r = makeRequire(require, e, m, module.id);
|
|
}
|
|
}
|
|
|
|
|
|
//If there are dependencies, they are strings, so need
|
|
//If there are dependencies, they are strings, so need
|
|
//to convert them to dependency values.
|
|
//to convert them to dependency values.
|
|
if (deps) {
|
|
if (deps) {
|
|
deps = deps.map(function (depName) {
|
|
deps = deps.map(function (depName) {
|
|
- return stringRequire(module, require, depName);
|
|
|
|
|
|
+ return r(depName);
|
|
});
|
|
});
|
|
- } else if (isFactoryFunction) {
|
|
|
|
- //Pass in the standard require, exports, module
|
|
|
|
- deps = [makeRequire(module, require), module.exports, module];
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- if (!isFactoryFunction) {
|
|
|
|
- //Factory is an object that should just be used for the define call.
|
|
|
|
- module.exports = factory;
|
|
|
|
- } else {
|
|
|
|
- //Call the factory with the right dependencies.
|
|
|
|
|
|
+ //Call the factory with the right dependencies.
|
|
|
|
+ if (typeof factory === 'function') {
|
|
result = factory.apply(module.exports, deps);
|
|
result = factory.apply(module.exports, deps);
|
|
|
|
+ } else {
|
|
|
|
+ result = factory;
|
|
|
|
+ }
|
|
|
|
|
|
- if (result !== undefined) {
|
|
|
|
- module.exports = result;
|
|
|
|
|
|
+ if (result !== undefined) {
|
|
|
|
+ m.exports = result;
|
|
|
|
+ if (id) {
|
|
|
|
+ loaderCache[id] = m.exports;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ stringRequire = function (systemRequire, exports, module, id, relId) {
|
|
|
|
+ //Split the ID by a ! so that
|
|
|
|
+ var index = id.indexOf('!'),
|
|
|
|
+ originalId = id,
|
|
|
|
+ prefix, plugin;
|
|
|
|
+
|
|
|
|
+ if (index === -1) {
|
|
|
|
+ id = normalize(id, relId);
|
|
|
|
+
|
|
|
|
+ //Straight module lookup. If it is one of the special dependencies,
|
|
|
|
+ //deal with it, otherwise, delegate to node.
|
|
|
|
+ if (id === 'require') {
|
|
|
|
+ return makeRequire(systemRequire, exports, module, relId);
|
|
|
|
+ } else if (id === 'exports') {
|
|
|
|
+ return exports;
|
|
|
|
+ } else if (id === 'module') {
|
|
|
|
+ return module;
|
|
|
|
+ } else if (loaderCache.hasOwnProperty(id)) {
|
|
|
|
+ return loaderCache[id];
|
|
|
|
+ } else if (defineCache[id]) {
|
|
|
|
+ runFactory.apply(null, defineCache[id]);
|
|
|
|
+ return loaderCache[id];
|
|
|
|
+ } else {
|
|
|
|
+ if(systemRequire) {
|
|
|
|
+ return systemRequire(originalId);
|
|
|
|
+ } else {
|
|
|
|
+ throw new Error('No module with ID: ' + id);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ //There is a plugin in play.
|
|
|
|
+ prefix = id.substring(0, index);
|
|
|
|
+ id = id.substring(index + 1, id.length);
|
|
|
|
+
|
|
|
|
+ plugin = stringRequire(systemRequire, exports, module, prefix, relId);
|
|
|
|
+
|
|
|
|
+ if (plugin.normalize) {
|
|
|
|
+ id = plugin.normalize(id, makeNormalize(relId));
|
|
|
|
+ } else {
|
|
|
|
+ //Normalize the ID normally.
|
|
|
|
+ id = normalize(id, relId);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (loaderCache[id]) {
|
|
|
|
+ return loaderCache[id];
|
|
|
|
+ } else {
|
|
|
|
+ plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {});
|
|
|
|
+
|
|
|
|
+ return loaderCache[id];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ //Create a define function specific to the module asking for amdefine.
|
|
|
|
+ function define(id, deps, factory) {
|
|
|
|
+ if (Array.isArray(id)) {
|
|
|
|
+ factory = deps;
|
|
|
|
+ deps = id;
|
|
|
|
+ id = undefined;
|
|
|
|
+ } else if (typeof id !== 'string') {
|
|
|
|
+ factory = id;
|
|
|
|
+ id = deps = undefined;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (deps && !Array.isArray(deps)) {
|
|
|
|
+ factory = deps;
|
|
|
|
+ deps = undefined;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!deps) {
|
|
|
|
+ deps = ['require', 'exports', 'module'];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //Set up properties for this module. If an ID, then use
|
|
|
|
+ //internal cache. If no ID, then use the external variables
|
|
|
|
+ //for this node module.
|
|
|
|
+ if (id) {
|
|
|
|
+ //Put the module in deep freeze until there is a
|
|
|
|
+ //require call for it.
|
|
|
|
+ defineCache[id] = [id, deps, factory];
|
|
|
|
+ } else {
|
|
|
|
+ runFactory(id, deps, factory);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //define.require, which has access to all the values in the
|
|
|
|
+ //cache. Useful for AMD modules that all have IDs in the file,
|
|
|
|
+ //but need to finally export a value to node based on one of those
|
|
|
|
+ //IDs.
|
|
|
|
+ define.require = function (id) {
|
|
|
|
+ if (loaderCache[id]) {
|
|
|
|
+ return loaderCache[id];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (defineCache[id]) {
|
|
|
|
+ runFactory.apply(null, defineCache[id]);
|
|
|
|
+ return loaderCache[id];
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
define.amd = {};
|
|
define.amd = {};
|
|
|
|
|
|
return define;
|
|
return define;
|