almond.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /**
  2. * almond 0.2.5 Copyright (c) 2011-2012, The Dojo Foundation All Rights Reserved.
  3. * Available via the MIT or new BSD license.
  4. * see: http://github.com/jrburke/almond for details
  5. */
  6. //Going sloppy to avoid 'use strict' string cost, but strict practices should
  7. //be followed.
  8. /*jslint sloppy: true */
  9. /*global setTimeout: false */
  10. var requirejs, require, define;
  11. (function (undef) {
  12. var main, req, makeMap, handlers,
  13. defined = {},
  14. waiting = {},
  15. config = {},
  16. defining = {},
  17. hasOwn = Object.prototype.hasOwnProperty,
  18. aps = [].slice;
  19. function hasProp(obj, prop) {
  20. return hasOwn.call(obj, prop);
  21. }
  22. /**
  23. * Given a relative module name, like ./something, normalize it to
  24. * a real name that can be mapped to a path.
  25. * @param {String} name the relative name
  26. * @param {String} baseName a real name that the name arg is relative
  27. * to.
  28. * @returns {String} normalized name
  29. */
  30. function normalize(name, baseName) {
  31. var nameParts, nameSegment, mapValue, foundMap,
  32. foundI, foundStarMap, starI, i, j, part,
  33. baseParts = baseName && baseName.split("/"),
  34. map = config.map,
  35. starMap = (map && map['*']) || {};
  36. //Adjust any relative paths.
  37. if (name && name.charAt(0) === ".") {
  38. //If have a base name, try to normalize against it,
  39. //otherwise, assume it is a top-level require that will
  40. //be relative to baseUrl in the end.
  41. if (baseName) {
  42. //Convert baseName to array, and lop off the last part,
  43. //so that . matches that "directory" and not name of the baseName's
  44. //module. For instance, baseName of "one/two/three", maps to
  45. //"one/two/three.js", but we want the directory, "one/two" for
  46. //this normalization.
  47. baseParts = baseParts.slice(0, baseParts.length - 1);
  48. name = baseParts.concat(name.split("/"));
  49. //start trimDots
  50. for (i = 0; i < name.length; i += 1) {
  51. part = name[i];
  52. if (part === ".") {
  53. name.splice(i, 1);
  54. i -= 1;
  55. } else if (part === "..") {
  56. if (i === 1 && (name[2] === '..' || name[0] === '..')) {
  57. //End of the line. Keep at least one non-dot
  58. //path segment at the front so it can be mapped
  59. //correctly to disk. Otherwise, there is likely
  60. //no path mapping for a path starting with '..'.
  61. //This can still fail, but catches the most reasonable
  62. //uses of ..
  63. break;
  64. } else if (i > 0) {
  65. name.splice(i - 1, 2);
  66. i -= 2;
  67. }
  68. }
  69. }
  70. //end trimDots
  71. name = name.join("/");
  72. } else if (name.indexOf('./') === 0) {
  73. // No baseName, so this is ID is resolved relative
  74. // to baseUrl, pull off the leading dot.
  75. name = name.substring(2);
  76. }
  77. }
  78. //Apply map config if available.
  79. if ((baseParts || starMap) && map) {
  80. nameParts = name.split('/');
  81. for (i = nameParts.length; i > 0; i -= 1) {
  82. nameSegment = nameParts.slice(0, i).join("/");
  83. if (baseParts) {
  84. //Find the longest baseName segment match in the config.
  85. //So, do joins on the biggest to smallest lengths of baseParts.
  86. for (j = baseParts.length; j > 0; j -= 1) {
  87. mapValue = map[baseParts.slice(0, j).join('/')];
  88. //baseName segment has config, find if it has one for
  89. //this name.
  90. if (mapValue) {
  91. mapValue = mapValue[nameSegment];
  92. if (mapValue) {
  93. //Match, update name to the new value.
  94. foundMap = mapValue;
  95. foundI = i;
  96. break;
  97. }
  98. }
  99. }
  100. }
  101. if (foundMap) {
  102. break;
  103. }
  104. //Check for a star map match, but just hold on to it,
  105. //if there is a shorter segment match later in a matching
  106. //config, then favor over this star map.
  107. if (!foundStarMap && starMap && starMap[nameSegment]) {
  108. foundStarMap = starMap[nameSegment];
  109. starI = i;
  110. }
  111. }
  112. if (!foundMap && foundStarMap) {
  113. foundMap = foundStarMap;
  114. foundI = starI;
  115. }
  116. if (foundMap) {
  117. nameParts.splice(0, foundI, foundMap);
  118. name = nameParts.join('/');
  119. }
  120. }
  121. return name;
  122. }
  123. function makeRequire(relName, forceSync) {
  124. return function () {
  125. //A version of a require function that passes a moduleName
  126. //value for items that may need to
  127. //look up paths relative to the moduleName
  128. return req.apply(undef, aps.call(arguments, 0).concat([relName, forceSync]));
  129. };
  130. }
  131. function makeNormalize(relName) {
  132. return function (name) {
  133. return normalize(name, relName);
  134. };
  135. }
  136. function makeLoad(depName) {
  137. return function (value) {
  138. defined[depName] = value;
  139. };
  140. }
  141. function callDep(name) {
  142. if (hasProp(waiting, name)) {
  143. var args = waiting[name];
  144. delete waiting[name];
  145. defining[name] = true;
  146. main.apply(undef, args);
  147. }
  148. if (!hasProp(defined, name) && !hasProp(defining, name)) {
  149. throw new Error('No ' + name);
  150. }
  151. return defined[name];
  152. }
  153. //Turns a plugin!resource to [plugin, resource]
  154. //with the plugin being undefined if the name
  155. //did not have a plugin prefix.
  156. function splitPrefix(name) {
  157. var prefix,
  158. index = name ? name.indexOf('!') : -1;
  159. if (index > -1) {
  160. prefix = name.substring(0, index);
  161. name = name.substring(index + 1, name.length);
  162. }
  163. return [prefix, name];
  164. }
  165. /**
  166. * Makes a name map, normalizing the name, and using a plugin
  167. * for normalization if necessary. Grabs a ref to plugin
  168. * too, as an optimization.
  169. */
  170. makeMap = function (name, relName) {
  171. var plugin,
  172. parts = splitPrefix(name),
  173. prefix = parts[0];
  174. name = parts[1];
  175. if (prefix) {
  176. prefix = normalize(prefix, relName);
  177. plugin = callDep(prefix);
  178. }
  179. //Normalize according
  180. if (prefix) {
  181. if (plugin && plugin.normalize) {
  182. name = plugin.normalize(name, makeNormalize(relName));
  183. } else {
  184. name = normalize(name, relName);
  185. }
  186. } else {
  187. name = normalize(name, relName);
  188. parts = splitPrefix(name);
  189. prefix = parts[0];
  190. name = parts[1];
  191. if (prefix) {
  192. plugin = callDep(prefix);
  193. }
  194. }
  195. //Using ridiculous property names for space reasons
  196. return {
  197. f: prefix ? prefix + '!' + name : name, //fullName
  198. n: name,
  199. pr: prefix,
  200. p: plugin
  201. };
  202. };
  203. function makeConfig(name) {
  204. return function () {
  205. return (config && config.config && config.config[name]) || {};
  206. };
  207. }
  208. handlers = {
  209. require: function (name) {
  210. return makeRequire(name);
  211. },
  212. exports: function (name) {
  213. var e = defined[name];
  214. if (typeof e !== 'undefined') {
  215. return e;
  216. } else {
  217. return (defined[name] = {});
  218. }
  219. },
  220. module: function (name) {
  221. return {
  222. id: name,
  223. uri: '',
  224. exports: defined[name],
  225. config: makeConfig(name)
  226. };
  227. }
  228. };
  229. main = function (name, deps, callback, relName) {
  230. var cjsModule, depName, ret, map, i,
  231. args = [],
  232. usingExports;
  233. //Use name if no relName
  234. relName = relName || name;
  235. //Call the callback to define the module, if necessary.
  236. if (typeof callback === 'function') {
  237. //Pull out the defined dependencies and pass the ordered
  238. //values to the callback.
  239. //Default to [require, exports, module] if no deps
  240. deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
  241. for (i = 0; i < deps.length; i += 1) {
  242. map = makeMap(deps[i], relName);
  243. depName = map.f;
  244. //Fast path CommonJS standard dependencies.
  245. if (depName === "require") {
  246. args[i] = handlers.require(name);
  247. } else if (depName === "exports") {
  248. //CommonJS module spec 1.1
  249. args[i] = handlers.exports(name);
  250. usingExports = true;
  251. } else if (depName === "module") {
  252. //CommonJS module spec 1.1
  253. cjsModule = args[i] = handlers.module(name);
  254. } else if (hasProp(defined, depName) ||
  255. hasProp(waiting, depName) ||
  256. hasProp(defining, depName)) {
  257. args[i] = callDep(depName);
  258. } else if (map.p) {
  259. map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
  260. args[i] = defined[depName];
  261. } else {
  262. throw new Error(name + ' missing ' + depName);
  263. }
  264. }
  265. ret = callback.apply(defined[name], args);
  266. if (name) {
  267. //If setting exports via "module" is in play,
  268. //favor that over return value and exports. After that,
  269. //favor a non-undefined return value over exports use.
  270. if (cjsModule && cjsModule.exports !== undef &&
  271. cjsModule.exports !== defined[name]) {
  272. defined[name] = cjsModule.exports;
  273. } else if (ret !== undef || !usingExports) {
  274. //Use the return value from the function.
  275. defined[name] = ret;
  276. }
  277. }
  278. } else if (name) {
  279. //May just be an object definition for the module. Only
  280. //worry about defining if have a module name.
  281. defined[name] = callback;
  282. }
  283. };
  284. requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
  285. if (typeof deps === "string") {
  286. if (handlers[deps]) {
  287. //callback in this case is really relName
  288. return handlers[deps](callback);
  289. }
  290. //Just return the module wanted. In this scenario, the
  291. //deps arg is the module name, and second arg (if passed)
  292. //is just the relName.
  293. //Normalize module name, if it contains . or ..
  294. return callDep(makeMap(deps, callback).f);
  295. } else if (!deps.splice) {
  296. //deps is a config object, not an array.
  297. config = deps;
  298. if (callback.splice) {
  299. //callback is an array, which means it is a dependency list.
  300. //Adjust args if there are dependencies
  301. deps = callback;
  302. callback = relName;
  303. relName = null;
  304. } else {
  305. deps = undef;
  306. }
  307. }
  308. //Support require(['a'])
  309. callback = callback || function () {};
  310. //If relName is a function, it is an errback handler,
  311. //so remove it.
  312. if (typeof relName === 'function') {
  313. relName = forceSync;
  314. forceSync = alt;
  315. }
  316. //Simulate async callback;
  317. if (forceSync) {
  318. main(undef, deps, callback, relName);
  319. } else {
  320. //Using a non-zero value because of concern for what old browsers
  321. //do, and latest browsers "upgrade" to 4 if lower value is used:
  322. //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
  323. //If want a value immediately, use require('id') instead -- something
  324. //that works in almond on the global level, but not guaranteed and
  325. //unlikely to work in other AMD implementations.
  326. setTimeout(function () {
  327. main(undef, deps, callback, relName);
  328. }, 4);
  329. }
  330. return req;
  331. };
  332. /**
  333. * Just drops the config on the floor, but returns req in case
  334. * the config return value is used.
  335. */
  336. req.config = function (cfg) {
  337. config = cfg;
  338. if (config.deps) {
  339. req(config.deps, config.callback);
  340. }
  341. return req;
  342. };
  343. define = function (name, deps, callback) {
  344. //This module may not have dependencies
  345. if (!deps.splice) {
  346. //deps is not an array, so probably means
  347. //an object literal or factory function for
  348. //the value. Adjust args.
  349. callback = deps;
  350. deps = [];
  351. }
  352. if (!hasProp(defined, name) && !hasProp(waiting, name)) {
  353. waiting[name] = [name, deps, callback];
  354. }
  355. };
  356. define.amd = {
  357. jQuery: true
  358. };
  359. }());