1 | /**
|
2 | * almond 0.1.1 Copyright (c) 2011, 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 |
|
11 | var requirejs, require, define;
|
12 | (function (undef) {
|
13 | var defined = {},
|
14 | waiting = {},
|
15 | config = {},
|
16 | defining = {},
|
17 | aps = [].slice,
|
18 | main, req;
|
19 |
|
20 | /**
|
21 | * Given a relative module name, like ./something, normalize it to
|
22 | * a real name that can be mapped to a path.
|
23 | * @param {String} name the relative name
|
24 | * @param {String} baseName a real name that the name arg is relative
|
25 | * to.
|
26 | * @returns {String} normalized name
|
27 | */
|
28 | function normalize(name, baseName) {
|
29 | var baseParts = baseName && baseName.split("/"),
|
30 | map = config.map,
|
31 | starMap = (map && map['*']) || {},
|
32 | nameParts, nameSegment, mapValue, foundMap, i, j, part;
|
33 |
|
34 | //Adjust any relative paths.
|
35 | if (name && name.charAt(0) === ".") {
|
36 | //If have a base name, try to normalize against it,
|
37 | //otherwise, assume it is a top-level require that will
|
38 | //be relative to baseUrl in the end.
|
39 | if (baseName) {
|
40 | //Convert baseName to array, and lop off the last part,
|
41 | //so that . matches that "directory" and not name of the baseName's
|
42 | //module. For instance, baseName of "one/two/three", maps to
|
43 | //"one/two/three.js", but we want the directory, "one/two" for
|
44 | //this normalization.
|
45 | baseParts = baseParts.slice(0, baseParts.length - 1);
|
46 |
|
47 | name = baseParts.concat(name.split("/"));
|
48 |
|
49 | //start trimDots
|
50 | for (i = 0; (part = name[i]); i++) {
|
51 | if (part === ".") {
|
52 | name.splice(i, 1);
|
53 | i -= 1;
|
54 | } else if (part === "..") {
|
55 | if (i === 1 && (name[2] === '..' || name[0] === '..')) {
|
56 | //End of the line. Keep at least one non-dot
|
57 | //path segment at the front so it can be mapped
|
58 | //correctly to disk. Otherwise, there is likely
|
59 | //no path mapping for a path starting with '..'.
|
60 | //This can still fail, but catches the most reasonable
|
61 | //uses of ..
|
62 | return true;
|
63 | } else if (i > 0) {
|
64 | name.splice(i - 1, 2);
|
65 | i -= 2;
|
66 | }
|
67 | }
|
68 | }
|
69 | //end trimDots
|
70 |
|
71 | name = name.join("/");
|
72 | }
|
73 | }
|
74 |
|
75 | //Apply map config if available.
|
76 | if ((baseParts || starMap) && map) {
|
77 | nameParts = name.split('/');
|
78 |
|
79 | for (i = nameParts.length; i > 0; i -= 1) {
|
80 | nameSegment = nameParts.slice(0, i).join("/");
|
81 |
|
82 | if (baseParts) {
|
83 | //Find the longest baseName segment match in the config.
|
84 | //So, do joins on the biggest to smallest lengths of baseParts.
|
85 | for (j = baseParts.length; j > 0; j -= 1) {
|
86 | mapValue = map[baseParts.slice(0, j).join('/')];
|
87 |
|
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 | break;
|
96 | }
|
97 | }
|
98 | }
|
99 | }
|
100 |
|
101 | foundMap = foundMap || starMap[nameSegment];
|
102 |
|
103 | if (foundMap) {
|
104 | nameParts.splice(0, i, foundMap);
|
105 | name = nameParts.join('/');
|
106 | break;
|
107 | }
|
108 | }
|
109 | }
|
110 |
|
111 | return name;
|
112 | }
|
113 |
|
114 | function makeRequire(relName, forceSync) {
|
115 | return function () {
|
116 | //A version of a require function that passes a moduleName
|
117 | //value for items that may need to
|
118 | //look up paths relative to the moduleName
|
119 | return req.apply(undef, aps.call(arguments, 0).concat([relName, forceSync]));
|
120 | };
|
121 | }
|
122 |
|
123 | function makeNormalize(relName) {
|
124 | return function (name) {
|
125 | return normalize(name, relName);
|
126 | };
|
127 | }
|
128 |
|
129 | function makeLoad(depName) {
|
130 | return function (value) {
|
131 | defined[depName] = value;
|
132 | };
|
133 | }
|
134 |
|
135 | function callDep(name) {
|
136 | if (waiting.hasOwnProperty(name)) {
|
137 | var args = waiting[name];
|
138 | delete waiting[name];
|
139 | defining[name] = true;
|
140 | main.apply(undef, args);
|
141 | }
|
142 |
|
143 | if (!defined.hasOwnProperty(name)) {
|
144 | throw new Error('No ' + name);
|
145 | }
|
146 | return defined[name];
|
147 | }
|
148 |
|
149 | /**
|
150 | * Makes a name map, normalizing the name, and using a plugin
|
151 | * for normalization if necessary. Grabs a ref to plugin
|
152 | * too, as an optimization.
|
153 | */
|
154 | function makeMap(name, relName) {
|
155 | var prefix, plugin,
|
156 | index = name.indexOf('!');
|
157 |
|
158 | if (index !== -1) {
|
159 | prefix = normalize(name.slice(0, index), relName);
|
160 | name = name.slice(index + 1);
|
161 | plugin = callDep(prefix);
|
162 |
|
163 | //Normalize according
|
164 | if (plugin && plugin.normalize) {
|
165 | name = plugin.normalize(name, makeNormalize(relName));
|
166 | } else {
|
167 | name = normalize(name, relName);
|
168 | }
|
169 | } else {
|
170 | name = normalize(name, relName);
|
171 | }
|
172 |
|
173 | //Using ridiculous property names for space reasons
|
174 | return {
|
175 | f: prefix ? prefix + '!' + name : name, //fullName
|
176 | n: name,
|
177 | p: plugin
|
178 | };
|
179 | }
|
180 |
|
181 | function makeConfig(name) {
|
182 | return function () {
|
183 | return (config && config.config && config.config[name]) || {};
|
184 | };
|
185 | }
|
186 |
|
187 | main = function (name, deps, callback, relName) {
|
188 | var args = [],
|
189 | usingExports,
|
190 | cjsModule, depName, ret, map, i;
|
191 |
|
192 | //Use name if no relName
|
193 | relName = relName || name;
|
194 |
|
195 | //Call the callback to define the module, if necessary.
|
196 | if (typeof callback === 'function') {
|
197 |
|
198 | //Pull out the defined dependencies and pass the ordered
|
199 | //values to the callback.
|
200 | //Default to [require, exports, module] if no deps
|
201 | deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
|
202 | for (i = 0; i < deps.length; i++) {
|
203 | map = makeMap(deps[i], relName);
|
204 | depName = map.f;
|
205 |
|
206 | //Fast path CommonJS standard dependencies.
|
207 | if (depName === "require") {
|
208 | args[i] = makeRequire(name);
|
209 | } else if (depName === "exports") {
|
210 | //CommonJS module spec 1.1
|
211 | args[i] = defined[name] = {};
|
212 | usingExports = true;
|
213 | } else if (depName === "module") {
|
214 | //CommonJS module spec 1.1
|
215 | cjsModule = args[i] = {
|
216 | id: name,
|
217 | uri: '',
|
218 | exports: defined[name],
|
219 | config: makeConfig(name)
|
220 | };
|
221 | } else if (defined.hasOwnProperty(depName) || waiting.hasOwnProperty(depName)) {
|
222 | args[i] = callDep(depName);
|
223 | } else if (map.p) {
|
224 | map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
|
225 | args[i] = defined[depName];
|
226 | } else if (!defining[depName]) {
|
227 | throw new Error(name + ' missing ' + depName);
|
228 | }
|
229 | }
|
230 |
|
231 | ret = callback.apply(defined[name], args);
|
232 |
|
233 | if (name) {
|
234 | //If setting exports via "module" is in play,
|
235 | //favor that over return value and exports. After that,
|
236 | //favor a non-undefined return value over exports use.
|
237 | if (cjsModule && cjsModule.exports !== undef &&
|
238 | cjsModule.exports !== defined[name]) {
|
239 | defined[name] = cjsModule.exports;
|
240 | } else if (ret !== undef || !usingExports) {
|
241 | //Use the return value from the function.
|
242 | defined[name] = ret;
|
243 | }
|
244 | }
|
245 | } else if (name) {
|
246 | //May just be an object definition for the module. Only
|
247 | //worry about defining if have a module name.
|
248 | defined[name] = callback;
|
249 | }
|
250 | };
|
251 |
|
252 | requirejs = require = req = function (deps, callback, relName, forceSync) {
|
253 | if (typeof deps === "string") {
|
254 | //Just return the module wanted. In this scenario, the
|
255 | //deps arg is the module name, and second arg (if passed)
|
256 | //is just the relName.
|
257 | //Normalize module name, if it contains . or ..
|
258 | return callDep(makeMap(deps, callback).f);
|
259 | } else if (!deps.splice) {
|
260 | //deps is a config object, not an array.
|
261 | config = deps;
|
262 | if (callback.splice) {
|
263 | //callback is an array, which means it is a dependency list.
|
264 | //Adjust args if there are dependencies
|
265 | deps = callback;
|
266 | callback = relName;
|
267 | relName = null;
|
268 | } else {
|
269 | deps = undef;
|
270 | }
|
271 | }
|
272 |
|
273 | //Support require(['a'])
|
274 | callback = callback || function () {};
|
275 |
|
276 | //Simulate async callback;
|
277 | if (forceSync) {
|
278 | main(undef, deps, callback, relName);
|
279 | } else {
|
280 | setTimeout(function () {
|
281 | main(undef, deps, callback, relName);
|
282 | }, 15);
|
283 | }
|
284 |
|
285 | return req;
|
286 | };
|
287 |
|
288 | /**
|
289 | * Just drops the config on the floor, but returns req in case
|
290 | * the config return value is used.
|
291 | */
|
292 | req.config = function (cfg) {
|
293 | config = cfg;
|
294 | return req;
|
295 | };
|
296 |
|
297 | define = function (name, deps, callback) {
|
298 |
|
299 | //This module may not have dependencies
|
300 | if (!deps.splice) {
|
301 | //deps is not an array, so probably means
|
302 | //an object literal or factory function for
|
303 | //the value. Adjust args.
|
304 | callback = deps;
|
305 | deps = [];
|
306 | }
|
307 |
|
308 | waiting[name] = [name, deps, callback];
|
309 | };
|
310 |
|
311 | define.amd = {
|
312 | jQuery: true
|
313 | };
|
314 | }());
|