| /** vim: et:ts=4:sw=4:sts=4 |
| * @license amdefine 1.0.1 Copyright (c) 2011-2016, The Dojo Foundation All Rights Reserved. |
| * Available via the MIT or new BSD license. |
| * see: http://github.com/jrburke/amdefine for details |
| */ |
| |
| /*jslint node: true */ |
| /*global module, process */ |
| 'use strict'; |
| |
| /** |
| * Creates a define for node. |
| * @param {Object} module the "module" object that is defined by Node for the |
| * current module. |
| * @param {Function} [requireFn]. 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, requireFn) { |
| 'use strict'; |
| var defineCache = {}, |
| loaderCache = {}, |
| alreadyCalled = false, |
| path = require('path'), |
| makeRequire, stringRequire; |
| |
| /** |
| * 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; |
| } |
| } |
| } |
| } |
| |
| function normalize(name, baseName) { |
| var baseParts; |
| |
| //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('/'); |
| } |
| } |
| |
| return name; |
| } |
| |
| /** |
| * Create the normalize() function passed to a loader plugin's |
| * normalize method. |
| */ |
| function makeNormalize(relName) { |
| return function (name) { |
| return normalize(name, relName); |
| }; |
| } |
| |
| function makeLoad(id) { |
| function load(value) { |
| loaderCache[id] = value; |
| } |
| |
| 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; |
| } |
| |
| 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. |
| |
| //Convert the dependencies to modules. |
| deps = deps.map(function (depName) { |
| return stringRequire(systemRequire, exports, module, depName, relId); |
| }); |
| |
| //Wait for next tick to call back the require call. |
| if (callback) { |
| process.nextTick(function () { |
| callback.apply(null, deps); |
| }); |
| } |
| } |
| } |
| |
| amdRequire.toUrl = function (filePath) { |
| if (filePath.indexOf('.') === 0) { |
| return normalize(filePath, path.dirname(module.filename)); |
| } else { |
| return filePath; |
| } |
| }; |
| |
| return amdRequire; |
| }; |
| |
| //Favor explicit value, passed in if the module wants to support Node 0.4. |
| requireFn = requireFn || function req() { |
| return module.require.apply(module, arguments); |
| }; |
| |
| function runFactory(id, deps, factory) { |
| var r, e, m, result; |
| |
| if (id) { |
| e = loaderCache[id] = {}; |
| m = { |
| id: id, |
| uri: __filename, |
| exports: e |
| }; |
| r = makeRequire(requireFn, 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(requireFn, e, m, module.id); |
| } |
| |
| //If there are dependencies, they are strings, so need |
| //to convert them to dependency values. |
| if (deps) { |
| deps = deps.map(function (depName) { |
| return r(depName); |
| }); |
| } |
| |
| //Call the factory with the right dependencies. |
| if (typeof factory === 'function') { |
| result = factory.apply(m.exports, deps); |
| } else { |
| result = factory; |
| } |
| |
| 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 = {}; |
| |
| return define; |
| } |
| |
| module.exports = amdefine; |