almond.js 15 KB

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