amdefine.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /** vim: et:ts=4:sw=4:sts=4
  2. * @license amdefine 0.0.2 Copyright (c) 2011, The Dojo Foundation All Rights Reserved.
  3. * Available via the MIT or new BSD license.
  4. * see: http://github.com/jrburke/amdefine for details
  5. */
  6. /*jslint node: true */
  7. /*global module, process */
  8. 'use strict';
  9. var path = require('path'),
  10. loaderCache = {},
  11. makeRequire;
  12. /**
  13. * Given a relative module name, like ./something, normalize it to
  14. * a real name that can be mapped to a path.
  15. * @param {String} name the relative name
  16. * @param {String} baseName a real name that the name arg is relative
  17. * to.
  18. * @returns {String} normalized name
  19. */
  20. function normalize(name, baseName) {
  21. return path.normalize(path.join(baseName, name));
  22. }
  23. /**
  24. * Create the normalize() function passed to a loader plugin's
  25. * normalize method.
  26. */
  27. function makeNormalize(relName) {
  28. return function (name) {
  29. return normalize(name, relName);
  30. };
  31. }
  32. function makeLoad(id) {
  33. function load(value) {
  34. loaderCache[id] = value;
  35. }
  36. load.fromText = function (id, text) {
  37. //This one is difficult because the text can/probably uses
  38. //define, and any relative paths and requires should be relative
  39. //to that id was it would be found on disk. But this would require
  40. //bootstrapping a module/require fairly deeply from node core.
  41. //Not sure how best to go about that yet.
  42. throw new Error('amdefine does not implement load.fromText');
  43. };
  44. return load;
  45. }
  46. function stringRequire(module, require, id) {
  47. //Split the ID by a ! so that
  48. var index = id.indexOf('!'),
  49. relId = path.dirname(module.filename),
  50. prefix, plugin;
  51. if (index === -1) {
  52. //Straight module lookup. If it is one of the special dependencies,
  53. //deal with it, otherwise, delegate to node.
  54. if (id === 'require') {
  55. return makeRequire(module, require);
  56. } else if (id === 'exports') {
  57. return module.exports;
  58. } else if (id === 'module') {
  59. return module;
  60. } else {
  61. return require(id);
  62. }
  63. } else {
  64. //There is a plugin in play.
  65. prefix = id.substring(0, index);
  66. id = id.substring(index + 1, id.length);
  67. plugin = require(prefix);
  68. if (plugin.normalize) {
  69. id = plugin.normalize(id, makeNormalize(relId));
  70. } else {
  71. //Normalize the ID normally.
  72. id = normalize(id, relId);
  73. }
  74. if (loaderCache[id]) {
  75. return loaderCache[id];
  76. } else {
  77. plugin.load(id, makeRequire(module, require), makeLoad(id), {});
  78. return loaderCache[id];
  79. }
  80. }
  81. }
  82. makeRequire = function (module, require) {
  83. function amdRequire(deps, callback) {
  84. if (typeof deps === 'string') {
  85. //Synchronous, single module require('')
  86. return stringRequire(module, require, deps);
  87. } else {
  88. //Array of dependencies with a callback.
  89. //Convert the dependencies to modules.
  90. deps = deps.map(function (depName) {
  91. return stringRequire(module, require, depName);
  92. });
  93. //Wait for next tick to call back the require call.
  94. process.nextTick(function () {
  95. callback.apply(null, deps);
  96. });
  97. //Keeps strict checking in komodo happy.
  98. return undefined;
  99. }
  100. }
  101. amdRequire.toUrl = function (filePath) {
  102. if (filePath.indexOf('.') === 0) {
  103. return normalize(filePath, path.dirname(module.filename));
  104. } else {
  105. return filePath;
  106. }
  107. };
  108. return amdRequire;
  109. };
  110. /**
  111. * Creates a define for node.
  112. * @param {Object} module the "module" object that is defined by Node for the
  113. * current module.
  114. * @param {Function} [require]. Node's require function for the current module.
  115. * It only needs to be passed in Node versions before 0.5, when module.require
  116. * did not exist.
  117. * @returns {Function} a define function that is usable for the current node
  118. * module.
  119. */
  120. function amdefine(module, require) {
  121. var alreadyCalled = false;
  122. //Favor explicit value, passed in if the module wants to support Node 0.4.
  123. require = require || function req() {
  124. return module.require.apply(module, arguments);
  125. };
  126. //Create a define function specific to the module asking for amdefine.
  127. function define() {
  128. var args = arguments,
  129. factory = args[args.length - 1],
  130. isFactoryFunction = (typeof factory === 'function'),
  131. deps, result;
  132. //Only support one define call per file
  133. if (alreadyCalled) {
  134. throw new Error('amdefine cannot be called more than once per file.');
  135. }
  136. alreadyCalled = true;
  137. //Grab array of dependencies if it is there.
  138. if (args.length > 1) {
  139. deps = args[args.length - 2];
  140. if (!Array.isArray(deps)) {
  141. //deps is not an array, may be an ID. Discard it.
  142. deps = null;
  143. }
  144. }
  145. //If there are dependencies, they are strings, so need
  146. //to convert them to dependency values.
  147. if (deps) {
  148. deps = deps.map(function (depName) {
  149. return stringRequire(module, require, depName);
  150. });
  151. } else if (isFactoryFunction) {
  152. //Pass in the standard require, exports, module
  153. deps = [makeRequire(module, require), module.exports, module];
  154. }
  155. if (!isFactoryFunction) {
  156. //Factory is an object that should just be used for the define call.
  157. module.exports = factory;
  158. } else {
  159. //Call the factory with the right dependencies.
  160. result = factory.apply(module.exports, deps);
  161. if (result !== undefined) {
  162. module.exports = result;
  163. }
  164. }
  165. }
  166. define.amd = {};
  167. return define;
  168. }
  169. module.exports = amdefine;