| OLD | NEW |
| (Empty) | |
| 1 /** @preserve |
| 2 * unrequire.js |
| 3 * |
| 4 * Copyright 2011 Sibblingz, Inc. |
| 5 * |
| 6 * Licensed under MIT |
| 7 */ |
| 8 |
| 9 // XXX Lines between comments with @{{{ and @}}} are removed when building |
| 10 |
| 11 //@{{{ |
| 12 (function () { |
| 13 //@}}} |
| 14 |
| 15 // MIT: http://trac.webkit.org/wiki/DetectingWebKit |
| 16 var IS_WEBKIT = typeof navigator !== 'undefined' && navigator && / AppleWebK
it\//.test(navigator.userAgent); |
| 17 |
| 18 var HAS_SETTIMEOUT = typeof setTimeout === 'function'; |
| 19 |
| 20 //@{{{ |
| 21 |
| 22 // Logging support |
| 23 var LOGGING = false; |
| 24 |
| 25 // Show debug warnings |
| 26 var WARNINGS = true; |
| 27 |
| 28 // Aliases support |
| 29 var ENABLE_ALIASES = true; |
| 30 |
| 31 // Packages support |
| 32 var ENABLE_PACKAGES = true; |
| 33 |
| 34 // Web browser support |
| 35 var ENABLE_BROWSER = true; |
| 36 |
| 37 // Web browser should try to make synchronous requests |
| 38 var BROWSER_SYNC = false; |
| 39 |
| 40 // Node.JS support |
| 41 var ENABLE_NODEJS = true; |
| 42 |
| 43 // Spaceport support |
| 44 var ENABLE_SPACEPORT = true; |
| 45 |
| 46 // CommonJS compatibility |
| 47 var COMMONJS_COMPAT = true; |
| 48 |
| 49 // Check for circular dependencies |
| 50 var CHECK_CYCLES = true; |
| 51 |
| 52 //@}}} |
| 53 |
| 54 // Utility functions {{{ |
| 55 var hasOwnProperty = ({ }).hasOwnProperty; |
| 56 var toString = ({ }).toString; |
| 57 |
| 58 // For minification |
| 59 var dot = '.'; |
| 60 var dotdot = '..'; |
| 61 |
| 62 function hasOwn(obj, name) { |
| 63 return obj && hasOwnProperty.call(obj, name); |
| 64 } |
| 65 |
| 66 function isArray(x) { |
| 67 return toString.call(x) === '[object Array]'; |
| 68 } |
| 69 |
| 70 function isPlainOldObject(x) { |
| 71 return toString.call(x) === '[object Object]'; |
| 72 } |
| 73 |
| 74 function map(array, fn, context) { |
| 75 // TODO Fallback if Function.prototype.map is missing |
| 76 return array.map(fn, context); |
| 77 } |
| 78 |
| 79 var forEach = map; |
| 80 |
| 81 function extend(base, extension) { |
| 82 var key; |
| 83 |
| 84 for (key in extension) { |
| 85 if (hasOwn(extension, key)) { |
| 86 base[key] = extension[key]; |
| 87 } |
| 88 } |
| 89 |
| 90 return base; |
| 91 } |
| 92 |
| 93 function clone(object, extension) { |
| 94 return extend(extend({ }, object), extension || { }); |
| 95 } |
| 96 // Utility functions }}} |
| 97 |
| 98 // Path functions {{{ |
| 99 function stringToPath(parts) { |
| 100 parts = isArray(parts) ? parts : [ parts ]; |
| 101 |
| 102 var splitParts = [ ]; |
| 103 var i; |
| 104 |
| 105 for (i = 0; i < parts.length; ++i) { |
| 106 splitParts = splitParts.concat(parts[i].split(/\//g)); |
| 107 } |
| 108 |
| 109 return splitParts; |
| 110 } |
| 111 |
| 112 function pathToString(path) { |
| 113 var s = path |
| 114 .join('/') |
| 115 .replace(/\/+/g, '/'); |
| 116 |
| 117 if (path.length === 0 && path[0] === '') { |
| 118 s = '/' + s; |
| 119 } |
| 120 |
| 121 return s; |
| 122 } |
| 123 |
| 124 function normalizePath(path) { |
| 125 var newPath = [ ]; |
| 126 var i; |
| 127 |
| 128 for (i = 0; i < path.length; ++i) { |
| 129 if (!path[i]) { |
| 130 // Root |
| 131 newPath = [ '' ]; |
| 132 } else if (path[i] === dotdot) { |
| 133 // Go back |
| 134 if (!newPath.length) { |
| 135 newPath = [ dotdot ]; |
| 136 } else if (newPath.length === 1) { |
| 137 if (newPath[0] === dot || !newPath[0]) { |
| 138 newPath = [ dotdot ]; |
| 139 } else { |
| 140 newPath.pop(); |
| 141 } |
| 142 } else { |
| 143 newPath.pop(); |
| 144 } |
| 145 } else if (path[i] === dot) { |
| 146 // Go here |
| 147 if (!newPath.length) { |
| 148 newPath = [ dot ]; |
| 149 } |
| 150 } else { |
| 151 // Everything else |
| 152 newPath.push(path[i]); |
| 153 } |
| 154 } |
| 155 |
| 156 return newPath; |
| 157 } |
| 158 |
| 159 function resolveUrl(cwd, baseUrl, path) { |
| 160 var cwdPath = normalizePath(stringToPath(cwd)); |
| 161 var basePath = normalizePath(stringToPath(baseUrl || dot)); |
| 162 var npath = normalizePath(stringToPath(path)); |
| 163 |
| 164 if (npath[0] === dotdot || npath[0] === dot) { |
| 165 // Relative paths are based on cwd |
| 166 return pathToString(normalizePath(cwdPath.concat(npath))); |
| 167 } else if (npath[0] === '') { |
| 168 // Absolute path stays absolute |
| 169 return pathToString(npath); |
| 170 } else { |
| 171 // Implicit relative paths are based on baseUrl |
| 172 return pathToString(basePath.concat(npath)); |
| 173 } |
| 174 } |
| 175 |
| 176 function resolveCwd(baseUrl, cwd) { |
| 177 var basePath = normalizePath(stringToPath(baseUrl || dot)); |
| 178 var npath = normalizePath(stringToPath(cwd)); |
| 179 |
| 180 if (npath[0] === dotdot || npath[0] === dot) { |
| 181 // Relative paths are absolute |
| 182 return pathToString(npath); |
| 183 } else if (npath[0] === '') { |
| 184 // Absolute path stays absolute |
| 185 return pathToString(npath); |
| 186 } else { |
| 187 // Implicit relative paths are based on baseUrl |
| 188 return pathToString(basePath.concat(npath)); |
| 189 } |
| 190 } |
| 191 |
| 192 function dirname(url) { |
| 193 var path = stringToPath(url); |
| 194 path = path.slice(0, path.length - 1); |
| 195 return pathToString(path); |
| 196 } |
| 197 // Path functions }}} |
| 198 |
| 199 // Argument extraction functions {{{ |
| 200 function defArgs(name, config, deps, callback) { |
| 201 if (typeof name !== 'string') { |
| 202 // Name omitted |
| 203 callback = deps; |
| 204 deps = config; |
| 205 config = name; |
| 206 name = null; |
| 207 } |
| 208 |
| 209 if (!isPlainOldObject(config)) { |
| 210 // Config omitted |
| 211 callback = deps; |
| 212 deps = config; |
| 213 config = { }; |
| 214 } |
| 215 |
| 216 if (!isArray(deps)) { |
| 217 // Dependencies omitted |
| 218 callback = deps; |
| 219 deps = [ ]; |
| 220 } |
| 221 |
| 222 return { |
| 223 name: name, |
| 224 config: config, |
| 225 deps: deps, |
| 226 callback: callback |
| 227 }; |
| 228 } |
| 229 |
| 230 function reqArgs(config, deps, callback) { |
| 231 // TODO require(string) |
| 232 if (typeof config === 'string') { |
| 233 throw new Error('Not supported'); |
| 234 } |
| 235 |
| 236 if (!isPlainOldObject(config)) { |
| 237 // Config omitted |
| 238 callback = deps; |
| 239 deps = config; |
| 240 config = { }; |
| 241 } |
| 242 |
| 243 if (!isArray(deps)) { |
| 244 // Dependencies omitted |
| 245 callback = deps; |
| 246 deps = [ ]; |
| 247 } |
| 248 |
| 249 return { |
| 250 config: config, |
| 251 deps: deps, |
| 252 callback: callback |
| 253 }; |
| 254 } |
| 255 // Argument extraction functions }}} |
| 256 |
| 257 function getScriptName(moduleName, config) { |
| 258 if (ENABLE_ALIASES) { |
| 259 if (hasOwn(config._aliases, moduleName)) { |
| 260 return config._aliases[moduleName]; |
| 261 } |
| 262 } |
| 263 |
| 264 var scriptName = resolveUrl(config.cwd, config.baseUrl, moduleName); |
| 265 scriptName = scriptName + (/\.js$/i.test(scriptName) ? '' : '.js'); |
| 266 return scriptName; |
| 267 } |
| 268 |
| 269 function mergeConfigInto(base, augmentation) { |
| 270 // The order of these checks are important, because changes cascade |
| 271 |
| 272 if (hasOwn(augmentation, 'baseUrl')) { |
| 273 base.baseUrl = resolveUrl(base.cwd, base.baseUrl, augmentation.baseU
rl); |
| 274 } |
| 275 |
| 276 if (hasOwn(augmentation, 'cwd')) { |
| 277 base.cwd = augmentation.cwd; |
| 278 //base.cwd = resolveCwd(base.baseUrl, augmentation.cwd); |
| 279 } |
| 280 |
| 281 if (ENABLE_ALIASES) { |
| 282 if (hasOwn(base, '_aliases')) { |
| 283 base._aliases = clone(base._aliases); |
| 284 } else { |
| 285 base._aliases = { }; |
| 286 } |
| 287 |
| 288 if (hasOwn(augmentation, '_aliases')) { |
| 289 extend(base._aliases, augmentation._aliases); |
| 290 } |
| 291 |
| 292 if (hasOwn(augmentation, 'aliases')) { |
| 293 var aliasName; |
| 294 for (aliasName in augmentation.aliases) { |
| 295 if (!hasOwn(augmentation.aliases, aliasName)) { |
| 296 continue; |
| 297 } |
| 298 |
| 299 var aliasTarget = augmentation.aliases[aliasName]; |
| 300 |
| 301 // Aliases are stored as their full script name |
| 302 base._aliases[aliasName] = getScriptName(aliasTarget, base); |
| 303 } |
| 304 } |
| 305 } |
| 306 |
| 307 if (ENABLE_PACKAGES) { |
| 308 if (hasOwn(base, '_packageOwners')) { |
| 309 base._packageOwners = clone(base._packageOwners); |
| 310 } else { |
| 311 base._packageOwners = { }; |
| 312 } |
| 313 |
| 314 if (hasOwn(augmentation, '_packageOwners')) { |
| 315 extend(base._packageOwners, augmentation._packageOwners); |
| 316 } |
| 317 |
| 318 if (hasOwn(augmentation, 'packages')) { |
| 319 var packageName; |
| 320 for (packageName in augmentation.packages) { |
| 321 if (!hasOwn(augmentation.packages, packageName)) { |
| 322 continue; |
| 323 } |
| 324 |
| 325 var packageOwner = getScriptName(packageName, base); |
| 326 forEach(augmentation.packages[packageName], function (module
Name) { |
| 327 base._packageOwners[getScriptName(moduleName, base)] = p
ackageOwner; |
| 328 }); |
| 329 } |
| 330 } |
| 331 } |
| 332 } |
| 333 |
| 334 function mergeConfigs(first, second) { |
| 335 var base = clone(first); |
| 336 mergeConfigInto(base, second); |
| 337 return base; |
| 338 } |
| 339 |
| 340 function findCycles(graph, vertices) { |
| 341 var vertexIndices = { }; |
| 342 var vertexLowLinks = { }; |
| 343 |
| 344 var index = 0; |
| 345 var stack = [ ]; |
| 346 |
| 347 var cycles = [ ]; |
| 348 |
| 349 function strongConnect(v) { |
| 350 vertexIndices[v] = index; |
| 351 vertexLowLinks[v] = index; |
| 352 ++index; |
| 353 stack.push(v); |
| 354 |
| 355 if (hasOwn(graph, v)) { |
| 356 graph[v].forEach(function (w) { |
| 357 if (!hasOwn(vertexIndices, w)) { |
| 358 strongConnect(w); |
| 359 vertexLowLinks[v] = Math.min(vertexLowLinks[v], vertexLo
wLinks[w]); |
| 360 } else if (stack.indexOf(w) >= 0) { |
| 361 vertexLowLinks[v] = Math.min(vertexLowLinks[v], vertexIn
dices[w]); |
| 362 } |
| 363 }); |
| 364 } |
| 365 |
| 366 if (vertexLowLinks[v] === vertexIndices[v]) { |
| 367 var cycle = [ ]; |
| 368 var w; |
| 369 do { |
| 370 w = stack.pop(); |
| 371 cycle.push(w); |
| 372 } while (w !== v); |
| 373 cycles.push(cycle); |
| 374 } |
| 375 } |
| 376 |
| 377 vertices.forEach(function (vertex) { |
| 378 if (!hasOwn(vertexIndices, vertex)) { |
| 379 strongConnect(vertex); |
| 380 } |
| 381 }); |
| 382 |
| 383 return cycles; |
| 384 } |
| 385 |
| 386 // dependencyGraph :: Map String [String] |
| 387 var dependencyGraph = { }; |
| 388 |
| 389 // pulledScripts :: [String] |
| 390 var pulledScripts = [ ]; |
| 391 |
| 392 function addDependency(from, to) { |
| 393 if (hasOwn(dependencyGraph, from)) { |
| 394 dependencyGraph[from].push(to); |
| 395 } else { |
| 396 dependencyGraph[from] = [ to ]; |
| 397 } |
| 398 } |
| 399 |
| 400 function checkCircularDependencies() { |
| 401 var cycles = findCycles(dependencyGraph, pulledScripts); |
| 402 |
| 403 cycles.forEach(function (cycle) { |
| 404 if (cycle.length > 1) { |
| 405 throw new Error('Circular dependency detected between scripts: '
+ cycle.join(' ')); |
| 406 } |
| 407 }); |
| 408 } |
| 409 |
| 410 function getScriptsDependingUpon(scriptName) { |
| 411 var scripts = [ ]; |
| 412 |
| 413 for (var curScript in dependencyGraph) { |
| 414 if (hasOwn(dependencyGraph, curScript)) { |
| 415 if (dependencyGraph[curScript].indexOf(scriptName) >= 0) { |
| 416 scripts.push(curScript); |
| 417 } |
| 418 } |
| 419 } |
| 420 |
| 421 return scripts; |
| 422 } |
| 423 |
| 424 // requestedScripts :: Map String Bool |
| 425 var requestedScripts = { }; |
| 426 |
| 427 // requestingScriptCount :: Int |
| 428 var requestingScriptCount = 0; |
| 429 |
| 430 // We have two queues here. |
| 431 // |
| 432 // The script complete queue is built up while executing scripts. A define |
| 433 // call adds to this queue. The queue is flushed when the script completes |
| 434 // execution. This allows us to determine which script was executed |
| 435 // exactly for asynchronous loads. |
| 436 // |
| 437 // A load callback queue is built up after a define call knows its complete |
| 438 // name configuration. It is executed when that defined module is |
| 439 // requested. This allows for lazy loading of defiend modules, and also |
| 440 // allows for asynchronous module definitions. There is a mapping of |
| 441 // script name to load callback queue, thus this queue is a hash and not an |
| 442 // array. |
| 443 |
| 444 // scriptCompleteQueue :: [Maybe Error -> Configuration -> IO ()] |
| 445 var scriptCompleteQueue = [ ]; |
| 446 |
| 447 // loadCallbackQueues :: Map String [IO ()] |
| 448 var loadCallbackQueues = { }; |
| 449 |
| 450 // The push-pull mechanism decouples requesters of a module from definers |
| 451 // of a module. When a module is defined, it is "pushed"; when a module is |
| 452 // requested, it is "pulled". If a pull is made on an already-pushed |
| 453 // module name, the pull callback is executed immediately. Else, the pull |
| 454 // callback is executed immediately when the appropriate push is made. |
| 455 |
| 456 // pushed :: Map String a |
| 457 var pushed = { }; |
| 458 |
| 459 // pulling :: Map String [Maybe Error -> a -> IO ()] |
| 460 var pulling = { }; |
| 461 |
| 462 function checkPullForLoadCallback(scriptName) { |
| 463 if (hasOwn(pulling, scriptName) && hasOwn(loadCallbackQueues, scriptName
)) { |
| 464 var callbacks = loadCallbackQueues[scriptName]; |
| 465 delete loadCallbackQueues[scriptName]; |
| 466 |
| 467 forEach(callbacks, function (callback) { |
| 468 callback(); |
| 469 }); |
| 470 } |
| 471 } |
| 472 |
| 473 function checkPullForPush(scriptName, value) { |
| 474 if (hasOwn(pulling, scriptName) && hasOwn(pushed, scriptName)) { |
| 475 var callbacks = pulling[scriptName]; |
| 476 delete pulling[scriptName]; |
| 477 |
| 478 forEach(callbacks, function (callback) { |
| 479 callback(null, pushed[scriptName]); |
| 480 }); |
| 481 } |
| 482 } |
| 483 |
| 484 function enqueueLoadCallback(scriptName, callback) { |
| 485 if (hasOwn(loadCallbackQueues, scriptName)) { |
| 486 loadCallbackQueues[scriptName].push(callback); |
| 487 } else { |
| 488 loadCallbackQueues[scriptName] = [ callback ]; |
| 489 } |
| 490 |
| 491 checkPullForLoadCallback(scriptName); |
| 492 } |
| 493 |
| 494 function enqueueScriptCompleteCallback(callback) { |
| 495 if (requestingScriptCount > 0) { |
| 496 scriptCompleteQueue.push(callback); |
| 497 } else { |
| 498 callback(null, { }); |
| 499 } |
| 500 } |
| 501 |
| 502 function push(scriptName, value) { |
| 503 if (hasOwn(pushed, scriptName)) { |
| 504 throw new Error('Should not push value for ' + scriptName + ' again'
); |
| 505 } |
| 506 |
| 507 pushed[scriptName] = value; |
| 508 |
| 509 checkPullForPush(scriptName); |
| 510 } |
| 511 |
| 512 function pull(scriptName, callback) { |
| 513 if (CHECK_CYCLES) { |
| 514 pulledScripts.push(scriptName); |
| 515 } |
| 516 |
| 517 if (hasOwn(pulling, scriptName)) { |
| 518 pulling[scriptName].push(callback); |
| 519 } else { |
| 520 pulling[scriptName] = [ callback ]; |
| 521 } |
| 522 |
| 523 checkPullForLoadCallback(scriptName); |
| 524 checkPullForPush(scriptName); |
| 525 } |
| 526 |
| 527 function needsRequest(scriptName) { |
| 528 return !hasOwn(requestedScripts, scriptName) && !hasOwn(pushed, scriptNa
me) && !hasOwn(loadCallbackQueues, scriptName); |
| 529 } |
| 530 |
| 531 // Entry points {{{ |
| 532 function create(configuration) { |
| 533 var context = extend({ |
| 534 'require': req, |
| 535 'define': def, |
| 536 'reconfigure': reconfigure, |
| 537 'userCallback': defaultUserCallback |
| 538 }, configuration); |
| 539 |
| 540 var baseConfig = { |
| 541 cwd: '.', |
| 542 baseUrl: '.' |
| 543 }; |
| 544 |
| 545 context.configuration = configuration; |
| 546 req.config = config; |
| 547 req.debug = debug; |
| 548 |
| 549 return context; |
| 550 |
| 551 function config(config) { |
| 552 mergeConfigInto(baseConfig, config); |
| 553 } |
| 554 |
| 555 function defaultUserCallback(scriptName, data, moduleValues, moduleScrip
ts, moduleNames, callback) { |
| 556 if (LOGGING) { |
| 557 console.log('Executing', scriptName); |
| 558 } |
| 559 |
| 560 var moduleValue; |
| 561 if (typeof data === 'function') { |
| 562 if (COMMONJS_COMPAT && data.length === 3 && moduleNames.length =
== 0) { |
| 563 moduleValues = [ |
| 564 // require |
| 565 function () { |
| 566 throw new Error('Not supported'); |
| 567 }, |
| 568 |
| 569 // exports |
| 570 { }, |
| 571 |
| 572 // module |
| 573 { } // TODO |
| 574 ]; |
| 575 } |
| 576 |
| 577 moduleValue = data.apply(null, moduleValues); |
| 578 |
| 579 if (COMMONJS_COMPAT && data.length === 3 && moduleNames.length =
== 0) { |
| 580 if (typeof moduleValue === 'undefined') { |
| 581 moduleValue = moduleValues[1]; // exports |
| 582 } |
| 583 } |
| 584 } else { |
| 585 moduleValue = data; |
| 586 } |
| 587 |
| 588 callback(null, moduleValue); |
| 589 } |
| 590 |
| 591 function reconfigure(configuration) { |
| 592 extend(context, configuration); |
| 593 } |
| 594 |
| 595 function getRequestScriptName(scriptName, config) { |
| 596 if (ENABLE_PACKAGES) { |
| 597 if (hasOwn(config._packageOwners, scriptName)) { |
| 598 return config._packageOwners[scriptName]; |
| 599 } |
| 600 } |
| 601 |
| 602 return scriptName; |
| 603 } |
| 604 |
| 605 function request(scriptName, config, callback) { |
| 606 if (!needsRequest(scriptName)) { |
| 607 throw new Error('Should not request ' + scriptName + ' again'); |
| 608 } |
| 609 |
| 610 if (LOGGING) { |
| 611 console.log('Requesting script ' + scriptName); |
| 612 } |
| 613 |
| 614 requestedScripts[scriptName] = true; |
| 615 ++requestingScriptCount; |
| 616 |
| 617 function done(err) { |
| 618 --requestingScriptCount; |
| 619 |
| 620 var scriptCompleteCallbacks = scriptCompleteQueue; |
| 621 scriptCompleteQueue = [ ]; |
| 622 |
| 623 if (!err) { |
| 624 if (scriptCompleteCallbacks.length === 0) { |
| 625 console.warn('Possibly missing define for script ' + scr
iptName); |
| 626 } |
| 627 } |
| 628 |
| 629 callback(err, scriptCompleteCallbacks); |
| 630 } |
| 631 |
| 632 function tryAsync() { |
| 633 } |
| 634 |
| 635 // Try a sync load first |
| 636 if (context.loadScriptSync) { |
| 637 // We have this setTimeout logic to handle exceptions thrown by |
| 638 // loadScriptSync. We do not catch exceptions (so debugging is |
| 639 // easier for users), or deal with the 'finally' mess, but |
| 640 // still call done(). |
| 641 var timer; |
| 642 if (HAS_SETTIMEOUT) { |
| 643 timer = setTimeout(function () { |
| 644 done(new Error('Script threw exception')); |
| 645 }, 0); |
| 646 } |
| 647 |
| 648 var success = context.loadScriptSync(scriptName, config); |
| 649 |
| 650 if (HAS_SETTIMEOUT) { |
| 651 clearTimeout(timer); |
| 652 } |
| 653 |
| 654 if (success) { |
| 655 done(null); |
| 656 return; |
| 657 } |
| 658 } |
| 659 |
| 660 if (context.loadScriptAsync) { |
| 661 return context.loadScriptAsync(scriptName, done, config); |
| 662 } |
| 663 |
| 664 done(new Error('Failed to load script')); |
| 665 } |
| 666 |
| 667 function requestAndPullMany(scriptNames, config, callback) { |
| 668 var loaded = [ ]; |
| 669 var values = [ ]; |
| 670 var i; |
| 671 var called = false; |
| 672 |
| 673 function checkValues() { |
| 674 if (called) return; |
| 675 |
| 676 var i; |
| 677 |
| 678 for (i = 0; i < scriptNames.length; ++i) { |
| 679 if (!loaded[i]) return; |
| 680 } |
| 681 |
| 682 called = true; |
| 683 callback(null, values, scriptNames); |
| 684 } |
| 685 |
| 686 forEach(scriptNames, function (scriptName, i) { |
| 687 var requestScriptName = getRequestScriptName(scriptName, config)
; |
| 688 |
| 689 if (needsRequest(requestScriptName)) { |
| 690 request(requestScriptName, config, function (err, callbacks)
{ |
| 691 var neoConfig = mergeConfigs(config, { }); |
| 692 neoConfig.cwd = dirname(requestScriptName); |
| 693 neoConfig.scriptName = scriptName; |
| 694 |
| 695 forEach(callbacks, function (callback) { |
| 696 callback(err, neoConfig); |
| 697 }); |
| 698 |
| 699 if (err) { |
| 700 var errorString = 'Failed to load ' + requestScriptN
ame; |
| 701 |
| 702 var dependers = getScriptsDependingUpon(requestScrip
tName); |
| 703 if (dependers.length) { |
| 704 errorString += ' (depended upon by ' + dependers
.join(', ') + ')'; |
| 705 } |
| 706 |
| 707 console.error(errorString, err); |
| 708 } |
| 709 }); |
| 710 } |
| 711 |
| 712 pull(scriptName, function (err, value) { |
| 713 if (err) throw err; |
| 714 |
| 715 loaded[i] = true; |
| 716 values[i] = value; |
| 717 checkValues(); |
| 718 }); |
| 719 }); |
| 720 |
| 721 // In case we have no scripts to load |
| 722 checkValues(); |
| 723 } |
| 724 |
| 725 function req() { |
| 726 // TODO require(string) |
| 727 |
| 728 var args = reqArgs.apply(null, arguments); |
| 729 var config = args.config; |
| 730 var deps = args.deps; |
| 731 var callback = args.callback; |
| 732 |
| 733 if (LOGGING) { |
| 734 console.log('Requiring [ ' + (deps || [ ]).join(', ') + ' ]'); |
| 735 } |
| 736 |
| 737 var effectiveConfig = mergeConfigs(baseConfig, config); |
| 738 |
| 739 enqueueScriptCompleteCallback(function (err, config) { |
| 740 if (err) throw err; |
| 741 |
| 742 mergeConfigInto(effectiveConfig, config); |
| 743 |
| 744 var scriptNames = map(deps, function (dep) { |
| 745 return getScriptName(dep, effectiveConfig); |
| 746 }); |
| 747 |
| 748 requestAndPullMany(scriptNames, effectiveConfig, function (err,
values) { |
| 749 if (err) throw err; |
| 750 |
| 751 context.userCallback(null, callback, values, scriptNames, de
ps.slice(), function (err, value) { |
| 752 if (err) throw err; |
| 753 |
| 754 // Ignore value |
| 755 }); |
| 756 }); |
| 757 }); |
| 758 } |
| 759 |
| 760 function def() { |
| 761 var args = defArgs.apply(null, arguments); |
| 762 var name = args.name; |
| 763 var config = args.config; |
| 764 var deps = args.deps; |
| 765 var callback = args.callback; |
| 766 |
| 767 if (LOGGING) { |
| 768 console.log('Defining ' + (name || 'unnamed package') + ' with d
ependencies [ ' + (deps || [ ]).join(', ') + ' ]'); |
| 769 } |
| 770 |
| 771 var effectiveConfig = mergeConfigs(baseConfig, config); |
| 772 |
| 773 enqueueScriptCompleteCallback(function (err, config) { |
| 774 if (err) throw err; |
| 775 |
| 776 var oldEffectiveConfig = clone(effectiveConfig); |
| 777 |
| 778 // Script name resolution should occur *before* merging config i
nto |
| 779 // effectiveConfig |
| 780 mergeConfigInto(effectiveConfig, config); |
| 781 |
| 782 var scriptName; |
| 783 if (name) { |
| 784 scriptName = getScriptName(name, effectiveConfig); |
| 785 } else { |
| 786 scriptName = config.scriptName; |
| 787 } |
| 788 |
| 789 enqueueLoadCallback(scriptName, function () { |
| 790 var scriptNames = map(deps, function (dep) { |
| 791 return getScriptName(dep, effectiveConfig); |
| 792 }); |
| 793 |
| 794 if (CHECK_CYCLES) { |
| 795 map(scriptNames, function (dep) { |
| 796 addDependency(scriptName, dep); |
| 797 }); |
| 798 } |
| 799 |
| 800 checkCircularDependencies(); |
| 801 |
| 802 requestAndPullMany(scriptNames, effectiveConfig, function (e
rr, values) { |
| 803 if (err) throw err; |
| 804 |
| 805 context.userCallback(scriptName, callback, values, scrip
tNames, deps.slice(), function (err, value) { |
| 806 if (err) throw err; |
| 807 |
| 808 push(scriptName, value); |
| 809 }); |
| 810 }); |
| 811 }); |
| 812 }); |
| 813 } |
| 814 |
| 815 function debug() { |
| 816 console.log('Pulling:', pulling); |
| 817 } |
| 818 } |
| 819 // Entry points }}} |
| 820 |
| 821 (function () { |
| 822 var un; |
| 823 |
| 824 if (ENABLE_SPACEPORT && typeof loadScript === 'function') { |
| 825 // Must be first, because Spaceport has the window object, too. |
| 826 un = create({ |
| 827 'loadScriptAsync': function (scriptName, callback) { |
| 828 loadScript(scriptName, function () { |
| 829 callback(null); |
| 830 }); |
| 831 }, |
| 832 'loadScriptSync': function (scriptName) { |
| 833 return false; |
| 834 } |
| 835 }); |
| 836 |
| 837 // Set globals |
| 838 require = un['require']; |
| 839 define = un['define']; |
| 840 } else if (ENABLE_BROWSER && typeof window !== 'undefined') { |
| 841 var goodResponseCodes = [ 200, 204, 206, 301, 302, 303, 304, 307 ]; |
| 842 var doc = window.document; |
| 843 |
| 844 var onreadystatechange = 'onreadystatechange'; |
| 845 var onload = 'onload'; |
| 846 var onerror = 'onerror'; |
| 847 |
| 848 function isCleanPath(scriptName) { |
| 849 // If the path is "back" too much, it's not clean. |
| 850 var x = stringToPath(dirname(window.location.pathname)) |
| 851 .concat(stringToPath(scriptName)); |
| 852 x = normalizePath(x); |
| 853 return x[0] !== '..'; |
| 854 } |
| 855 |
| 856 var webkitOnloadFlag = false; |
| 857 |
| 858 un = create({ |
| 859 'loadScriptAsync': function loadScriptAsync(scriptName, callback
) { |
| 860 if (!isCleanPath(scriptName)) { |
| 861 setTimeout(function () { |
| 862 callback(new Error('Path ' + scriptName + ' is not c
lean')); |
| 863 }, 0); |
| 864 return; |
| 865 } |
| 866 |
| 867 var script = doc.createElement('script'); |
| 868 script.async = true; |
| 869 |
| 870 // Modelled after jQuery (src/ajax/script.js) |
| 871 script[onload] = script[onreadystatechange] = function () { |
| 872 if (!script.readyState || /loaded|complete/.test(script.
readyState)) { |
| 873 // Remove from DOM |
| 874 var parent = script.parentNode; |
| 875 if (parent) { |
| 876 parent.removeChild(script); |
| 877 } |
| 878 |
| 879 // IE likes memleaks |
| 880 script[onload] = script[onreadystatechange] = script
[onerror] = null; |
| 881 script = null; |
| 882 |
| 883 callback(null); |
| 884 } |
| 885 }; |
| 886 |
| 887 script[onerror] = function () { |
| 888 callback(new Error('Failed to load script')); |
| 889 }; |
| 890 |
| 891 // Remember: we need to attach event handlers before |
| 892 // assigning `src`. Events may be fired as soon as we set |
| 893 // `src`. |
| 894 script.src = scriptName; |
| 895 |
| 896 doc['head'].appendChild(script); |
| 897 }, |
| 898 'loadScriptSync': function loadScriptSync(scriptName) { |
| 899 // We provide synchronous script loading via XHR for |
| 900 // browsers specifically to work around a Webkit bug. |
| 901 // After document.onload is called, any script dynamically |
| 902 // loaded will be loaded from Webkit's local cache; *no |
| 903 // HTTP request is made at all*. |
| 904 |
| 905 if (!BROWSER_SYNC) { |
| 906 if (IS_WEBKIT) { |
| 907 if (/loaded|complete/.test(document.readyState)) { |
| 908 // Don't load synchronously if the document has
already loaded |
| 909 if (WARNINGS && !webkitOnloadFlag) { |
| 910 console.warn('Scripts being loaded after doc
ument.onload; scripts may be loaded from out-of-date cache'); |
| 911 webkitOnloadFlag = true; |
| 912 } |
| 913 |
| 914 if (WARNINGS) { |
| 915 console.warn('Script possibly loaded from ou
t-of-date cache: ' + scriptName); |
| 916 } |
| 917 |
| 918 return false; |
| 919 } |
| 920 |
| 921 // Fall through; load synchronously anyway |
| 922 } else { |
| 923 return false; |
| 924 } |
| 925 } |
| 926 |
| 927 if (!isCleanPath(scriptName)) { |
| 928 return false; |
| 929 } |
| 930 |
| 931 var scriptSource; |
| 932 |
| 933 try { |
| 934 var xhr = new XMLHttpRequest(); |
| 935 xhr.open('GET', scriptName, false); |
| 936 xhr.send(null); |
| 937 |
| 938 if (goodResponseCodes.indexOf(xhr.status) < 0) { |
| 939 return false; |
| 940 } |
| 941 |
| 942 scriptSource = xhr.responseText; |
| 943 scriptSource += '\n\n//*/\n//@ sourceURL=' + scriptName; |
| 944 } catch (e) { |
| 945 return false; |
| 946 } |
| 947 |
| 948 var fn; |
| 949 try { |
| 950 fn = Function(scriptSource); |
| 951 } catch (e) { |
| 952 return false; |
| 953 } |
| 954 |
| 955 // Don't wrap user code in try/catch |
| 956 fn(); |
| 957 |
| 958 return true; |
| 959 } |
| 960 }); |
| 961 |
| 962 window['require'] = un['require']; |
| 963 window['define'] = un['define']; |
| 964 } else if (ENABLE_NODEJS && typeof module !== 'undefined') { |
| 965 un = module.exports = create({ |
| 966 'context': { }, |
| 967 'loadScriptSync': function (scriptName) { |
| 968 // require here is the Node.JS-provided require |
| 969 |
| 970 var code; |
| 971 try { |
| 972 code = require('fs')['readFileSync'](scriptName, 'utf8')
; |
| 973 } catch (e) { |
| 974 // TODO Detect file-not-found errors only |
| 975 return false; |
| 976 } |
| 977 |
| 978 require('vm')['runInNewContext'](code, un['context'] || { },
scriptName); |
| 979 |
| 980 return true; |
| 981 } |
| 982 }); |
| 983 |
| 984 un['context']['define'] = un['define']; |
| 985 un['context']['require'] = un['require']; |
| 986 } else { |
| 987 throw new Error('Unsupported environment'); |
| 988 } |
| 989 }()); |
| 990 |
| 991 //@{{{ |
| 992 }()); |
| 993 //@}}} |
| OLD | NEW |