amdefine.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*jslint strict: false, nomen: false, plusplus: false */
  2. /*global module, process, require: true */
  3. var path = require('path'),
  4. loaderCache = {},
  5. makeRequire;
  6. // Null out require for this file so that it is not accidentally used
  7. // below, where module.require should be used instead.
  8. require = null;
  9. /**
  10. * Given a relative module name, like ./something, normalize it to
  11. * a real name that can be mapped to a path.
  12. * @param {String} name the relative name
  13. * @param {String} baseName a real name that the name arg is relative
  14. * to.
  15. * @returns {String} normalized name
  16. */
  17. function normalize(name, baseName) {
  18. return path.normalize(path.join(baseName, name));
  19. }
  20. function makeNormalize(relName) {
  21. return function (name) {
  22. return normalize(name, relName);
  23. };
  24. }
  25. function stringRequire(module, id) {
  26. //Split the ID by a ! so that
  27. var index = id.indexOf('!'),
  28. relId = path.dirname(module.filename),
  29. prefix, plugin;
  30. if (index === -1) {
  31. //Straight module lookup. If it is one of the special dependencies,
  32. //deal with it, otherwise, delegate to node.
  33. if (id === 'require') {
  34. return makeRequire(module);
  35. } else if (id === 'exports') {
  36. return module.exports;
  37. } else if (id === 'module') {
  38. return module;
  39. } else {
  40. return module.require(id);
  41. }
  42. } else {
  43. //There is a plugin in play.
  44. prefix = id.substring(0, index);
  45. id = id.substring(index + 1, id.length);
  46. plugin = module.require(prefix);
  47. if (plugin.normalize) {
  48. id = plugin.normalize(id, makeNormalize(relId));
  49. } else {
  50. //Normalize the ID normally.
  51. id = normalize(id, relId);
  52. }
  53. if (loaderCache[id]) {
  54. return loaderCache[id];
  55. } else {
  56. plugin.load(id, makeRequire(module), function (value) {
  57. loaderCache[id] = value;
  58. }, {});
  59. return loaderCache[id];
  60. }
  61. }
  62. }
  63. makeRequire = function (module) {
  64. function amdRequire(deps, callback) {
  65. if (typeof deps === 'string') {
  66. //Synchronous, single module require('')
  67. return stringRequire(module, deps);
  68. } else {
  69. //Array of dependencies with a callback.
  70. //Convert the dependencies to modules.
  71. deps = deps.map(function (depName) {
  72. return stringRequire(module, depName);
  73. });
  74. //Wait for next tick to call back the require call.
  75. process.nextTick(function () {
  76. callback.apply(null, deps);
  77. });
  78. //Keeps strict checking in komodo happy.
  79. return undefined;
  80. }
  81. }
  82. amdRequire.toUrl = function (filePath) {
  83. if (filePath.indexOf('.') === 0) {
  84. return normalize(filePath, path.dirname(module.filename));
  85. } else {
  86. return filePath;
  87. }
  88. };
  89. return amdRequire;
  90. };
  91. function amdefine(module) {
  92. var alreadyCalled = false;
  93. //Create a define function specific to the module asking for amdefine.
  94. function define() {
  95. var args = arguments,
  96. factory = args[args.length - 1],
  97. isFactoryFunction = (typeof factory === 'function'),
  98. deps, result;
  99. //Only support one define call per file
  100. if (alreadyCalled) {
  101. throw new Error('amdefine cannot be called more than once per file.');
  102. }
  103. alreadyCalled = true;
  104. //Grab array of dependencies if it is there.
  105. if (args.length > 1) {
  106. deps = args[args.length - 2];
  107. if (!Array.isArray(deps)) {
  108. //deps is not an array, may be an ID. Discard it.
  109. deps = null;
  110. }
  111. }
  112. //If there are dependencies, they are strings, so need
  113. //to convert them to dependency values.
  114. if (deps) {
  115. deps = deps.map(function (depName) {
  116. return stringRequire(module, depName);
  117. });
  118. } else if (isFactoryFunction) {
  119. //Pass in the standard require, exports, module
  120. deps = [makeRequire(module), module.exports, module];
  121. }
  122. if (!isFactoryFunction) {
  123. //Factory is an object that should just be used for the define call.
  124. module.exports = factory;
  125. } else {
  126. //Call the factory with the right dependencies.
  127. result = factory.apply(module.exports, deps);
  128. if (result !== undefined) {
  129. module.exports = result;
  130. }
  131. }
  132. }
  133. define.amd = {};
  134. return define;
  135. }
  136. module.exports = amdefine;